diff options
Diffstat (limited to 'core/java/android/bluetooth/BluetoothGattServer.java')
-rw-r--r-- | core/java/android/bluetooth/BluetoothGattServer.java | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java new file mode 100644 index 0000000..91a1a94 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothProfile.ServiceListener; +import android.bluetooth.IBluetoothManager; +import android.bluetooth.IBluetoothStateChangeCallback; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.ParcelUuid; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * Public API for the Bluetooth Gatt Profile server role. + * + * <p>This class provides Bluetooth Gatt server role functionality, + * allowing applications to create and advertise Bluetooth Smart services + * and characteristics. + * + * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service + * via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the + * BluetoothGatt proxy object. + * @hide + */ +public final class BluetoothGattServer implements BluetoothProfile { + private static final String TAG = "BluetoothGattServer"; + private static final boolean DBG = true; + + private Context mContext; + private ServiceListener mServiceListener; + private BluetoothAdapter mAdapter; + private IBluetoothGatt mService; + private BluetoothGattServerCallback mCallback; + private int mServerIf; + + private List<BluetoothGattService> mServices; + + /** + * Bluetooth state change handlers + */ + private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + public void onBluetoothStateChange(boolean up) { + if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); + if (!up) { + if (DBG) Log.d(TAG,"Unbinding service..."); + synchronized (mConnection) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (DBG) Log.d(TAG,"Binding service..."); + if (!mContext.bindService(new + Intent(IBluetoothGatt.class.getName()), + mConnection, 0)) { + Log.e(TAG, "Could not bind to Bluetooth GATT Service"); + } + } + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + }; + + /** + * Service binder handling + */ + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothGatt.Stub.asInterface(service); + ServiceListener serviceListner = mServiceListener; + if (serviceListner != null) { + serviceListner.onServiceConnected(BluetoothProfile.GATT_SERVER, + BluetoothGattServer.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + ServiceListener serviceListner = mServiceListener; + if (serviceListner != null) { + serviceListner.onServiceDisconnected(BluetoothProfile.GATT_SERVER); + } + } + }; + + /** + * Bluetooth GATT interface callbacks + */ + private final IBluetoothGattServerCallback mBluetoothGattServerCallback = + new IBluetoothGattServerCallback.Stub() { + /** + * Application interface registered - app is ready to go + * @hide + */ + public void onServerRegistered(int status, int serverIf) { + if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status + + " serverIf=" + serverIf); + mServerIf = serverIf; + try { + mCallback.onAppRegistered(status); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Callback reporting an LE scan result. + * @hide + */ + public void onScanResult(String address, int rssi, byte[] advData) { + if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + + try { + mCallback.onScanResult(mAdapter.getRemoteDevice(address), + rssi, advData); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Server connection state changed + * @hide + */ + public void onServerConnectionState(int status, int serverIf, + boolean connected, String address) { + if (DBG) Log.d(TAG, "onServerConnectionState() - status=" + status + + " serverIf=" + serverIf + " device=" + address); + try { + mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status, + connected ? BluetoothProfile.STATE_CONNECTED : + BluetoothProfile.STATE_DISCONNECTED); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Service has been added + * @hide + */ + public void onServiceAdded(int status, int srvcType, + int srvcInstId, ParcelUuid srvcId) { + UUID srvcUuid = srvcId.getUuid(); + if (DBG) Log.d(TAG, "onServiceAdded() - service=" + srvcUuid + + "status=" + status); + + BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); + if (service == null) return; + + try { + mCallback.onServiceAdded((int)status, service); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Remote client characteristic read request. + * @hide + */ + public void onCharacteristicReadRequest(String address, int transId, + int offset, boolean isLong, int srvcType, int srvcInstId, + ParcelUuid srvcId, int charInstId, ParcelUuid charId) { + UUID srvcUuid = srvcId.getUuid(); + UUID charUuid = charId.getUuid(); + if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - " + + "service=" + srvcUuid + ", characteristic=" + charUuid); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); + if (service == null) return; + + BluetoothGattCharacteristic characteristic = service.getCharacteristic( + charUuid); + if (characteristic == null) return; + + try { + mCallback.onCharacteristicReadRequest(device, transId, offset, characteristic); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Remote client descriptor read request. + * @hide + */ + public void onDescriptorReadRequest(String address, int transId, + int offset, boolean isLong, int srvcType, int srvcInstId, + ParcelUuid srvcId, int charInstId, ParcelUuid charId, + ParcelUuid descrId) { + UUID srvcUuid = srvcId.getUuid(); + UUID charUuid = charId.getUuid(); + UUID descrUuid = descrId.getUuid(); + if (DBG) Log.d(TAG, "onCharacteristicReadRequest() - " + + "service=" + srvcUuid + ", characteristic=" + charUuid + + "descriptor=" + descrUuid); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); + if (service == null) return; + + BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid); + if (characteristic == null) return; + + BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid); + if (descriptor == null) return; + + try { + mCallback.onDescriptorReadRequest(device, transId, offset, descriptor); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Remote client characteristic write request. + * @hide + */ + public void onCharacteristicWriteRequest(String address, int transId, + int offset, int length, boolean isPrep, boolean needRsp, + int srvcType, int srvcInstId, ParcelUuid srvcId, + int charInstId, ParcelUuid charId, byte[] value) { + UUID srvcUuid = srvcId.getUuid(); + UUID charUuid = charId.getUuid(); + if (DBG) Log.d(TAG, "onCharacteristicWriteRequest() - " + + "service=" + srvcUuid + ", characteristic=" + charUuid); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); + if (service == null) return; + + BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid); + if (characteristic == null) return; + + try { + mCallback.onCharacteristicWriteRequest(device, transId, characteristic, + isPrep, needRsp, offset, value); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + + } + + /** + * Remote client descriptor write request. + * @hide + */ + public void onDescriptorWriteRequest(String address, int transId, + int offset, int length, boolean isPrep, boolean needRsp, + int srvcType, int srvcInstId, ParcelUuid srvcId, + int charInstId, ParcelUuid charId, ParcelUuid descrId, + byte[] value) { + UUID srvcUuid = srvcId.getUuid(); + UUID charUuid = charId.getUuid(); + UUID descrUuid = descrId.getUuid(); + if (DBG) Log.d(TAG, "onDescriptorWriteRequest() - " + + "service=" + srvcUuid + ", characteristic=" + charUuid + + "descriptor=" + descrUuid); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + + BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType); + if (service == null) return; + + BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid); + if (characteristic == null) return; + + BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descrUuid); + if (descriptor == null) return; + + try { + mCallback.onDescriptorWriteRequest(device, transId, descriptor, + isPrep, needRsp, offset, value); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + /** + * Execute pending writes. + * @hide + */ + public void onExecuteWrite(String address, int transId, + boolean execWrite) { + if (DBG) Log.d(TAG, "onExecuteWrite() - " + + "device=" + address + ", transId=" + transId + + "execWrite=" + execWrite); + + BluetoothDevice device = mAdapter.getRemoteDevice(address); + if (device == null) return; + + try { + mCallback.onExecuteWrite(device, transId, execWrite); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + }; + + /** + * Create a BluetoothGattServer proxy object. + */ + /*package*/ BluetoothGattServer(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + mServices = new ArrayList<BluetoothGattService>(); + + IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE); + if (b != null) { + IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b); + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException re) { + Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re); + } + } else { + Log.e(TAG, "Unable to get BluetoothManager interface."); + throw new RuntimeException("BluetoothManager inactive"); + } + + //Bind to the service only if the Bluetooth is ON + if(mAdapter.isEnabled()){ + if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) { + Log.e(TAG, "Could not bind to Bluetooth Gatt Service"); + } + } + } + + /** + * Close the connection to the gatt service. + */ + /*package*/ void close() { + if (DBG) Log.d(TAG, "close()"); + + unregisterApp(); + mServiceListener = null; + + IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE); + if (b != null) { + IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b); + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException re) { + Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + + /** + * Returns a service by UUID, instance and type. + * @hide + */ + /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) { + for(BluetoothGattService svc : mServices) { + if (svc.getType() == type && + svc.getInstanceId() == instanceId && + svc.getUuid().equals(uuid)) { + return svc; + } + } + return null; + } + + /** + * Register an application callback to start using Gatt. + * + * <p>This is an asynchronous call. The callback is used to notify + * success or failure if the function returns true. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param callback Gatt callback handler that will receive asynchronous + * callbacks. + * @return true, if application was successfully registered. + */ + public boolean registerApp(BluetoothGattServerCallback callback) { + if (DBG) Log.d(TAG, "registerApp()"); + if (mService == null) return false; + + mCallback = callback; + UUID uuid = UUID.randomUUID(); + if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid); + + try { + mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Unregister the current application and callbacks. + */ + public void unregisterApp() { + if (DBG) Log.d(TAG, "unregisterApp() - mServerIf=" + mServerIf); + if (mService == null || mServerIf == 0) return; + + try { + mCallback = null; + mService.unregisterServer(mServerIf); + mServerIf = 0; + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + /** + * Starts a scan for Bluetooth LE devices. + * + * <p>Results of the scan are reported using the + * {@link BluetoothGattServerCallback#onScanResult} callback. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @return true, if the scan was started successfully + */ + public boolean startScan() { + if (DBG) Log.d(TAG, "startScan()"); + if (mService == null || mServerIf == 0) return false; + + try { + mService.startScan(mServerIf, true); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Starts a scan for Bluetooth LE devices, looking for devices that + * advertise given services. + * + * <p>Devices which advertise all specified services are reported using the + * {@link BluetoothGattServerCallback#onScanResult} callback. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param serviceUuids Array of services to look for + * @return true, if the scan was started successfully + */ + public boolean startScan(UUID[] serviceUuids) { + if (DBG) Log.d(TAG, "startScan() - with UUIDs"); + if (mService == null || mServerIf == 0) return false; + + try { + ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(serviceUuids[i]); + } + mService.startScanWithUuids(mServerIf, true, uuids); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Stops an ongoing Bluetooth LE device scan. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + */ + public void stopScan() { + if (DBG) Log.d(TAG, "stopScan()"); + if (mService == null || mServerIf == 0) return; + + try { + mService.stopScan(mServerIf, true); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + /** + * Initiate a connection to a Bluetooth Gatt capable device. + * + * <p>The connection may not be established right away, but will be + * completed when the remote device is available. A + * {@link BluetoothGattCallback#onConnectionStateChange} callback will be + * invoked when the connection state changes as a result of this function. + * + * <p>The autoConnect paramter determines whether to actively connect to + * the remote device, or rather passively scan and finalize the connection + * when the remote device is in range/available. Generally, the first ever + * connection to a device should be direct (autoConnect set to false) and + * subsequent connections to known devices should be invoked with the + * autoConnect parameter set to false. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device Remote device to connect to + * @param autoConnect Whether to directly connect to the remote device (false) + * or to automatically connect as soon as the remote + * device becomes available (true). + * @return true, if the connection attempt was initiated successfully + */ + public boolean connect(BluetoothDevice device, boolean autoConnect) { + if (DBG) Log.d(TAG, "connect: " + device.getAddress() + ", auto: " + autoConnect); + if (mService == null || mServerIf == 0) return false; + + try { + mService.serverConnect(mServerIf, device.getAddress(), + autoConnect ? false : true); // autoConnect is inverse of "isDirect" + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Disconnects an established connection, or cancels a connection attempt + * currently in progress. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device Remote device + */ + public void cancelConnection(BluetoothDevice device) { + if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress()); + if (mService == null || mServerIf == 0) return; + + try { + mService.serverDisconnect(mServerIf, device.getAddress()); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + /** + * Send a response to a read or write request to a remote device. + * + * <p>This function must be invoked in when a remote read/write request + * is received by one of these callback methots: + * + * <ul> + * <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest} + * <li>{@link BluetoothGattServerCallback#onCharacteristicWriteRequest} + * <li>{@link BluetoothGattServerCallback#onDescriptorReadRequest} + * <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest} + * </ul> + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device The remote device to send this response to + * @param requestId The ID of the request that was received with the callback + * @param status The status of the request to be sent to the remote devices + * @param offset Value offset for partial read/write response + * @param value The value of the attribute that was read/written (optional) + */ + public boolean sendResponse(BluetoothDevice device, int requestId, + int status, int offset, byte[] value) { + if (DBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress()); + if (mService == null || mServerIf == 0) return false; + + try { + mService.sendResponse(mServerIf, device.getAddress(), requestId, + status, offset, value); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + return true; + } + + /** + * Send a notification or indication that a local characteristic has been + * updated. + * + * <p>A notification or indication is sent to the remote device to signal + * that the characteristic has been updated. This function should be invoked + * for every client that requests notifications/indications by writing + * to the "Client Configuration" descriptor for the given characteristic. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device The remote device to receive the notification/indication + * @param characteristic The local characteristic that has been updated + * @param confirm true to request confirmation from the client (indication), + * false to send a notification + * @return true, if the notification has been triggered successfully + */ + public boolean notifyCharacteristicChanged(BluetoothDevice device, + BluetoothGattCharacteristic characteristic, boolean confirm) { + if (DBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress()); + if (mService == null || mServerIf == 0) return false; + + BluetoothGattService service = characteristic.getService(); + if (service == null) return false; + + try { + mService.sendNotification(mServerIf, device.getAddress(), + service.getType(), service.getInstanceId(), + new ParcelUuid(service.getUuid()), characteristic.getInstanceId(), + new ParcelUuid(characteristic.getUuid()), confirm, + characteristic.getValue()); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Add a service to the list of services to be advertised. + * + * <p>Once a service has been addded to the the list, the service and it's + * included characteristics will be advertised by the local device. + * + * <p>If the local device is already advertising services when this function + * is called, a service update notification will be sent to all clients. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param service Service to be added to the list of services advertised + * by this device. + * @return true, if the service has been added successfully + */ + public boolean addService(BluetoothGattService service) { + if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid()); + if (mService == null || mServerIf == 0) return false; + + mServices.add(service); + + try { + mService.beginServiceDeclaration(mServerIf, service.getType(), + service.getInstanceId(), service.getHandles(), + new ParcelUuid(service.getUuid())); + + List<BluetoothGattService> includedServices = service.getIncludedServices(); + for (BluetoothGattService includedService : includedServices) { + mService.addIncludedService(mServerIf, + includedService.getType(), + includedService.getInstanceId(), + new ParcelUuid(includedService.getUuid())); + } + + List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics(); + for (BluetoothGattCharacteristic characteristic : characteristics) { + int permission = ((characteristic.getKeySize() - 7) << 12) + + characteristic.getPermissions(); + mService.addCharacteristic(mServerIf, + new ParcelUuid(characteristic.getUuid()), + characteristic.getProperties(), permission); + + List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors(); + for (BluetoothGattDescriptor descriptor: descriptors) { + mService.addDescriptor(mServerIf, + new ParcelUuid(descriptor.getUuid()), + descriptor.getPermissions()); + } + } + + mService.endServiceDeclaration(mServerIf); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Removes a service from the list of services to be advertised. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param service Service to beremoved. + * @return true, if the service has been removed + */ + public boolean removeService(BluetoothGattService service) { + if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid()); + if (mService == null || mServerIf == 0) return false; + + BluetoothGattService intService = getService(service.getUuid(), + service.getInstanceId(), service.getType()); + if (intService == null) return false; + + try { + mService.removeService(mServerIf, service.getType(), + service.getInstanceId(), new ParcelUuid(service.getUuid())); + mServices.remove(intService); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Remove all services from the list of advertised services. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + */ + public void clearServices() { + if (DBG) Log.d(TAG, "clearServices()"); + if (mService == null || mServerIf == 0) return; + + try { + mService.clearServices(mServerIf); + mServices.clear(); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + /** + * Returns a list of GATT services offered bu this device. + * + * <p>An application must call {@link #addService} to add a serice to the + * list of services offered by this device. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @return List of services. Returns an empty list + * if no services have been added yet. + */ + public List<BluetoothGattService> getServices() { + return mServices; + } + + /** + * Returns a {@link BluetoothGattService} from the list of services offered + * by this device. + * + * <p>If multiple instances of the same service (as identified by UUID) + * exist, the first instance of the service is returned. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param uuid UUID of the requested service + * @return BluetoothGattService if supported, or null if the requested + * service is not offered by this device. + */ + public BluetoothGattService getService(UUID uuid) { + for (BluetoothGattService service : mServices) { + if (service.getUuid().equals(uuid)) { + return service; + } + } + + return null; + } + + /** + * Get the current connection state of the profile. + * + * <p>This is not specific to any application configuration but represents + * the connection state of the local Bluetooth adapter for this profile. + * This can be used by applications like status bar which would just like + * to know the state of the local adapter. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device Remote bluetooth device. + * @return State of the profile connection. One of + * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} + */ + @Override + public int getConnectionState(BluetoothDevice device) { + if (DBG) Log.d(TAG,"getConnectionState()"); + if (mService == null) return STATE_DISCONNECTED; + + List<BluetoothDevice> connectedDevices = getConnectedDevices(); + for(BluetoothDevice connectedDevice : connectedDevices) { + if (device.equals(connectedDevice)) { + return STATE_CONNECTED; + } + } + + return STATE_DISCONNECTED; + } + + /** + * Get connected devices for the Gatt profile. + * + * <p> Return the set of devices which are in state {@link #STATE_CONNECTED} + * + * <p>This is not specific to any application configuration but represents + * the connection state of the local Bluetooth adapter for this profile. + * This can be used by applications like status bar which would just like + * to know the state of the local adapter. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @return List of devices. The list will be empty on error. + */ + @Override + public List<BluetoothDevice> getConnectedDevices() { + if (DBG) Log.d(TAG,"getConnectedDevices"); + + List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>(); + if (mService == null) return connectedDevices; + + try { + connectedDevices = mService.getDevicesMatchingConnectionStates( + new int[] { BluetoothProfile.STATE_CONNECTED }); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + + return connectedDevices; + } + + /** + * Get a list of devices that match any of the given connection + * states. + * + * <p> If none of the devices match any of the given states, + * an empty list will be returned. + * + * <p>This is not specific to any application configuration but represents + * the connection state of the local Bluetooth adapter for this profile. + * This can be used by applications like status bar which would just like + * to know the state of the local adapter. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param states Array of states. States can be one of + * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, + * @return List of devices. The list will be empty on error. + */ + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates"); + + List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); + if (mService == null) return devices; + + try { + devices = mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + + return devices; + } +} |