/* * Copyright (C) 2017 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 com.googlecode.android_scripting.facade.bluetooth; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattServer; import android.bluetooth.BluetoothGattServerCallback; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.os.Bundle; import com.googlecode.android_scripting.Log; import com.googlecode.android_scripting.MainThread; import com.googlecode.android_scripting.facade.EventFacade; import com.googlecode.android_scripting.facade.FacadeManager; import com.googlecode.android_scripting.jsonrpc.RpcReceiver; import com.googlecode.android_scripting.rpc.Rpc; import com.googlecode.android_scripting.rpc.RpcParameter; import java.lang.reflect.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.concurrent.Callable; public class GattServerFacade extends RpcReceiver { private final EventFacade mEventFacade; private BluetoothAdapter mBluetoothAdapter; private BluetoothManager mBluetoothManager; private final Service mService; private final Context mContext; private final HashMap mCharacteristicList; private final HashMap mDescriptorList; private final HashMap mBluetoothGattServerList; private final HashMap mBluetoothGattServerCallbackList; private final HashMap mGattServiceList; private final HashMap> mBluetoothGattDiscoveredServicesList; private final HashMap> mGattServerDiscoveredDevicesList; private static int sCharacteristicCount; private static int sDescriptorCount; private static int sGattServerCallbackCount; private static int sGattServerCount; private static int sGattServiceCount; public GattServerFacade(FacadeManager manager) { super(manager); mService = manager.getService(); mContext = mService.getApplicationContext(); mBluetoothAdapter = MainThread.run(mService, new Callable() { @Override public BluetoothAdapter call() throws Exception { return BluetoothAdapter.getDefaultAdapter(); } }); mBluetoothManager = (BluetoothManager) mContext.getSystemService(Service.BLUETOOTH_SERVICE); mEventFacade = manager.getReceiver(EventFacade.class); mCharacteristicList = new HashMap(); mDescriptorList = new HashMap(); mBluetoothGattServerList = new HashMap(); mBluetoothGattServerCallbackList = new HashMap(); mGattServiceList = new HashMap(); mBluetoothGattDiscoveredServicesList = new HashMap>(); mGattServerDiscoveredDevicesList = new HashMap>(); } /** * Open a new Gatt server. * * @param index the bluetooth gatt server callback to open on * @return the index of the newly opened gatt server * @throws Exception */ @Rpc(description = "Open new gatt server") public int gattServerOpenGattServer(@RpcParameter(name = "index") Integer index) throws Exception { if (mBluetoothGattServerCallbackList.get(index) != null) { BluetoothGattServer mGattServer = mBluetoothManager.openGattServer(mContext, mBluetoothGattServerCallbackList.get( index)); sGattServerCount += 1; int in = sGattServerCount; mBluetoothGattServerList.put(in, mGattServer); return in; } else { throw new Exception("Invalid index input:" + Integer.toString(index)); } } /** * Add a service to a bluetooth gatt server * * @param index the bluetooth gatt server to add a service to * @param serviceIndex the service to add to the bluetooth gatt server * @throws Exception */ @Rpc(description = "Add service to bluetooth gatt server") public void gattServerAddService(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "serviceIndex") Integer serviceIndex) throws Exception { if (mBluetoothGattServerList.get(index) != null) { if (mGattServiceList.get(serviceIndex) != null) { mBluetoothGattServerList.get(index).addService(mGattServiceList.get(serviceIndex)); } else { throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex)); } } else { throw new Exception("Invalid index input:" + Integer.toString(index)); } } /** * Add a service to a bluetooth gatt server * * @param index the bluetooth gatt server to add a service to * @throws Exception */ @Rpc(description = "Clear services from bluetooth gatt server") public void gattServerClearServices( @RpcParameter(name = "index") Integer index) throws Exception { if (mBluetoothGattServerList.get(index) != null) { mBluetoothGattServerList.get(index).clearServices(); } else { throw new Exception("Invalid index input:" + Integer.toString(index)); } } /** * Get connected devices of the gatt server * * @param gattServerIndex the gatt server index * @throws Exception */ @Rpc(description = "Return a list of connected gatt devices.") public List gattServerGetConnectedDevices( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex) throws Exception { if (mBluetoothGattServerList.get(gattServerIndex) == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER); mGattServerDiscoveredDevicesList.put(gattServerIndex, connectedDevices); return connectedDevices; } /** * Get connected devices of the gatt server * * @param gattServerIndex the gatt server index * @param bluetoothDeviceIndex the remotely connected bluetooth device * @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 * @throws Exception */ @Rpc(description = "Send a response after a write.") public void gattServerSendResponse( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex, @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex, @RpcParameter(name = "requestId") Integer requestId, @RpcParameter(name = "status") Integer status, @RpcParameter(name = "offset") Integer offset, @RpcParameter(name = "value") byte[] value) throws Exception { BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex); if (gattServer == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER); BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex); gattServer.sendResponse(bluetoothDevice, requestId, status, offset, value); } /** * Notify that characteristic was changed * * @deprecated Use {@link #gattServerNotifyCharacteristicChangedByInstanceId( * gattServerIndex, bluetoothDeviceIndex, instanceId, confirm)} instead. * @param gattServerIndex the gatt server index * @param bluetoothDeviceIndex the remotely connected bluetooth device * @param characteristicIndex characteristic index * @param confirm shall we expect confirmation * @throws Exception */ @Deprecated @Rpc(description = "Notify that characteristic was changed.") public void gattServerNotifyCharacteristicChanged( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex, @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex, @RpcParameter(name = "characteristicIndex") Integer characteristicIndex, @RpcParameter(name = "confirm") Boolean confirm) throws Exception { BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex); if (gattServer == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER); if (connectedDevices == null) { throw new Exception( "Connected device list empty for gattServerIndex:" + Integer.toString( gattServerIndex)); } BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex); if (bluetoothDevice == null) { throw new Exception( "Invalid bluetoothDeviceIndex: " + Integer.toString(bluetoothDeviceIndex)); } BluetoothGattCharacteristic bluetoothCharacteristic = mCharacteristicList.get( characteristicIndex); if (bluetoothCharacteristic == null) { throw new Exception( "Invalid characteristicIndex: " + Integer.toString(characteristicIndex)); } gattServer.notifyCharacteristicChanged(bluetoothDevice, bluetoothCharacteristic, confirm); } /** * Notify that characteristic was changed * * @param gattServerIndex the gatt server index * @param bluetoothDeviceIndex the remotely connected bluetooth device * @param characteristicIndex characteristic index * @param confirm shall we expect confirmation * @throws Exception */ @Rpc(description = "Notify that characteristic was changed by Instance Id.") public void gattServerNotifyCharacteristicChangedByInstanceId( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex, @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex, @RpcParameter(name = "instanceId") Integer instanceId, @RpcParameter(name = "confirm") Boolean confirm) throws Exception { BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex); if (gattServer == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER); if (connectedDevices == null) { throw new Exception( "Connected device list empty for gattServerIndex:" + Integer.toString( gattServerIndex)); } BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex); if (bluetoothDevice == null) { throw new Exception( "Invalid bluetoothDeviceIndex: " + Integer.toString(bluetoothDeviceIndex)); } for (BluetoothGattCharacteristic mGattChar : mCharacteristicList.values()) { if (mGattChar.getInstanceId() == instanceId) { Log.i("Found Characteristic to get value. instanceId: " + Integer.toString(instanceId) + " UUID: " + mGattChar.getUuid().toString()); gattServer.notifyCharacteristicChanged(bluetoothDevice, mGattChar, confirm); } } } /** * Create a new bluetooth gatt service * * @param uuid the UUID that characterises the service * @param serviceType the service type * @return The index of the new bluetooth gatt service */ @Rpc(description = "Create new bluetooth gatt service") public int gattServerCreateService(@RpcParameter(name = "uuid") String uuid, @RpcParameter(name = "serviceType") Integer serviceType) { sGattServiceCount += 1; int index = sGattServiceCount; mGattServiceList.put(index, new BluetoothGattService(UUID.fromString(uuid), serviceType)); return index; } /** * Add a characteristic to a bluetooth gatt service * * @param index the bluetooth gatt service index * @param serviceUuid the service Uuid to get * @param characteristicIndex the character index to use * @throws Exception */ @Rpc(description = "Add a characteristic to a bluetooth gatt service") public void gattServiceAddCharacteristic( @RpcParameter(name = "index") Integer index, @RpcParameter(name = "serviceUuid") String serviceUuid, @RpcParameter(name = "characteristicIndex") Integer characteristicIndex) throws Exception { if (mBluetoothGattServerList.get(index) != null && mBluetoothGattServerList.get(index).getService( UUID.fromString(serviceUuid)) != null && mCharacteristicList.get(characteristicIndex) != null) { mBluetoothGattServerList.get(index).getService(UUID.fromString(serviceUuid)) .addCharacteristic(mCharacteristicList.get(characteristicIndex)); } else { if (mBluetoothGattServerList.get(index) == null) { throw new Exception("Invalid index input:" + index); } else if (mCharacteristicList.get(characteristicIndex) == null) { throw new Exception("Invalid characteristicIndex input:" + characteristicIndex); } else { throw new Exception("Invalid serviceUuid input:" + serviceUuid); } } } /** * Add a characteristic to a bluetooth gatt service * * @param index the bluetooth gatt service to add a characteristic to * @param characteristicIndex the characteristic to add * @throws Exception */ @Rpc(description = "Add a characteristic to a bluetooth gatt service") public void gattServerAddCharacteristicToService(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "characteristicIndex") Integer characteristicIndex ) throws Exception { if (mGattServiceList.get(index) != null) { if (mCharacteristicList.get(characteristicIndex) != null) { mGattServiceList.get(index).addCharacteristic(mCharacteristicList.get( characteristicIndex)); } else { throw new Exception("Invalid index input:" + index); } } else { throw new Exception("Invalid index input:" + index); } } /** * Close a bluetooth gatt * * @param index the bluetooth gatt index to close * @throws Exception */ @Rpc(description = "Close a bluetooth gatt") public void gattServerClose(@RpcParameter(name = "index") Integer index) throws Exception { if (mBluetoothGattServerList.get(index) != null) { mBluetoothGattServerList.get(index).close(); } else { throw new Exception("Invalid index input:" + index); } } /** * Get a list of Bluetooth Devices connnected to the bluetooth gatt * * @param index the bluetooth gatt index * @return List of BluetoothDevice Objects * @throws Exception */ @Rpc(description = "Get a list of Bluetooth Devices connnected to the bluetooth gatt") public List gattGetConnectedDevices( @RpcParameter(name = "index") Integer index) throws Exception { if (mBluetoothGattServerList.get(index) != null) { return mBluetoothGattServerList.get(index).getConnectedDevices(); } else { throw new Exception("Invalid index input:" + index); } } /** * Read the current transmitter PHY and receiver PHY of the connection. * * @param gattServerIndex the bluetooth gatt index * @throws Exception */ @Rpc(description = "Read PHY") public void gattServerReadPhy( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex, @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex) throws Exception { BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex); if (gattServer == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mGattServerDiscoveredDevicesList.get( gattServerIndex); if (connectedDevices == null) { throw new Exception( "Connected device list empty for gattServerIndex:" + Integer.toString( gattServerIndex)); } BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex); if (bluetoothDevice == null) { throw new Exception( "Invalid bluetoothDeviceIndex: " + Integer.toString(bluetoothDeviceIndex)); } if (mBluetoothGattServerList.get(gattServerIndex) != null) { mBluetoothGattServerList.get(gattServerIndex).readPhy(bluetoothDevice); } else { throw new Exception("Invalid index input:" + gattServerIndex); } } /** * Set the preferred connection PHY. * * @param gattServerIndex the bluetooth gatt index * @throws Exception */ @Rpc(description = "Set the preferred connection PHY") public void gattServerSetPreferredPhy( @RpcParameter(name = "gattServerIndex") Integer gattServerIndex, @RpcParameter(name = "bluetoothDeviceIndex") Integer bluetoothDeviceIndex, @RpcParameter(name = "txPhy") Integer txPhy, @RpcParameter(name = "rxPhy") Integer rxPhy, @RpcParameter(name = "txPhy") Integer phyOptions) throws Exception { BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex); if (gattServer == null) { throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex)); } List connectedDevices = mGattServerDiscoveredDevicesList.get( gattServerIndex); if (connectedDevices == null) { throw new Exception( "Connected device list empty for gattServerIndex:" + Integer.toString( gattServerIndex)); } BluetoothDevice bluetoothDevice = connectedDevices.get(bluetoothDeviceIndex); if (bluetoothDevice == null) { throw new Exception( "Invalid bluetoothDeviceIndex: " + Integer.toString(bluetoothDeviceIndex)); } if (mBluetoothGattServerList.get(gattServerIndex) != null) { mBluetoothGattServerList.get(gattServerIndex) .setPreferredPhy(bluetoothDevice, txPhy, rxPhy, phyOptions); } else { throw new Exception("Invalid index input:" + gattServerIndex); } } /** * Get GATT Server UUID by characteristic index * * @param charIndex of the characteristic * @return String Uuid * @throws Exception */ @Rpc(description = "Get UUID of the input characteristic") public String gattServerGetCharacteristicUuid( @RpcParameter(name = "charIndex") Integer charIndex) throws Exception { BluetoothGattCharacteristic gattChar = mCharacteristicList.get(charIndex); if (gattChar == null) { throw new Exception("Invalid index input: " + charIndex); } return gattChar.getUuid().toString(); } /** * Get GATT Server UUID by characteristic index * * @param charIndex of the characteristic * @return Integer instanceId * @throws Exception */ @Rpc(description = "Get instanceId of the input characteristic") public Integer gattServerGetCharacteristicInstanceId( @RpcParameter(name = "charIndex") Integer charIndex) throws Exception { BluetoothGattCharacteristic gattChar = mCharacteristicList.get(charIndex); if (gattChar == null) { throw new Exception("Invalid index input: " + charIndex); } return gattChar.getInstanceId(); } /** * Get the service from an input UUID * * @param index the bluetooth gatt index * @return BluetoothGattService related to the bluetooth gatt * @throws Exception */ @Rpc(description = "Get the service from an input UUID") public ArrayList gattGetServiceUuidList(@RpcParameter(name = "index") Integer index) throws Exception { if (mBluetoothGattServerList.get(index) != null) { ArrayList serviceUuidList = new ArrayList(); for (BluetoothGattService service : mBluetoothGattServerList.get(index).getServices()) { serviceUuidList.add(service.getUuid().toString()); } return serviceUuidList; } else { throw new Exception("Invalid index input:" + index); } } /** * Get the service from an input UUID * * @param index the bluetooth gatt index * @param uuid the String uuid that matches the service * @return BluetoothGattService related to the bluetooth gatt * @throws Exception */ @Rpc(description = "Get the service from an input UUID") public BluetoothGattService gattGetService(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "uuid") String uuid) throws Exception { if (mBluetoothGattServerList.get(index) != null) { return mBluetoothGattServerList.get(index).getService(UUID.fromString(uuid)); } else { throw new Exception("Invalid index input:" + index); } } /** * Add a descriptor to a bluetooth gatt characteristic * * @param index the bluetooth gatt characteristic to add a descriptor to * @param descriptorIndex the descritor index to add to the characteristic * @throws Exception */ @Rpc(description = "add descriptor to blutooth gatt characteristic") public void gattServerCharacteristicAddDescriptor(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "descriptorIndex") Integer descriptorIndex) throws Exception { if (mCharacteristicList.get(index) != null) { if (mDescriptorList.get(descriptorIndex) != null) { mCharacteristicList.get(index).addDescriptor(mDescriptorList.get(descriptorIndex)); } else { throw new Exception("Invalid descriptorIndex input:" + descriptorIndex); } } else { throw new Exception("Invalid index input:" + index); } } /** * Create a new Characteristic object * * @param characteristicUuid uuid The UUID for this characteristic * @param property Properties of this characteristic * @param permission permissions Permissions for this characteristic * @return */ @Rpc(description = "Create a new Characteristic object") public int gattServerCreateBluetoothGattCharacteristic( @RpcParameter(name = "characteristicUuid") String characteristicUuid, @RpcParameter(name = "property") Integer property, @RpcParameter(name = "permission") Integer permission) { sCharacteristicCount += 1; int index = sCharacteristicCount; BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic( UUID.fromString(characteristicUuid), property, permission); mCharacteristicList.put(index, characteristic); return index; } /** * Set value to a bluetooth gatt characteristic * * @deprecated Use {@link #gattServerCharacteristicSetValueByInstanceId( * instanceId, value)} instead. * @param index the bluetooth gatt characteristic * @param value value * @throws Exception */ @Deprecated @Rpc(description = "Set byte value to a Characteristic") public void gattServerCharacteristicSetValue(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "value") byte[] value) throws Exception { if (mCharacteristicList.get(index) != null) { mCharacteristicList.get(index).setValue(value); } else { throw new Exception("Invalid index input:" + index); } } /** * Set value to a bluetooth gatt characteristic by instance id * * @param index the bluetooth gatt characteristic by instance id * @param value value * @throws Exception */ @Rpc(description = "Set byte value to a Characteristic by instance id") public boolean gattServerCharacteristicSetValueByInstanceId( @RpcParameter(name = "instanceId") Integer instanceId, @RpcParameter(name = "value") byte[] value) throws Exception { for (BluetoothGattCharacteristic mGattChar : mCharacteristicList.values()) { //test this to be sure if (mGattChar.getInstanceId() == instanceId) { return mGattChar.setValue(value); } } throw new Exception("Cannot find instance ID:" + instanceId); } /** * Set value to a bluetooth gatt characteristic * * @param index the bluetooth gatt characteristic * @param value value * @throws Exception */ @Rpc(description = "Set Characteristic Byte Value") public boolean gattServerCharacteristicSetByteValue(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "value") byte[] value) throws Exception { if (mCharacteristicList.get(index) != null) { return mCharacteristicList.get(index).setValue(value); } else { throw new Exception("Invalid index input:" + index); } } /** * Set value to a bluetooth gatt descriptor * * @param index the bluetooth gatt descriptor * @param value byte[] value to set * @throws Exception */ @Rpc(description = "Set Characteristic Byte Value") public boolean gattServerDescriptorSetByteValue( @RpcParameter(name = "index") Integer index, @RpcParameter(name = "value") byte[] value) throws Exception { if (mDescriptorList.get(index) != null) { return mDescriptorList.get(index).setValue(value); } else { throw new Exception("Invalid index input:" + index); } } /** * Get Read value by instance ID * * @param instanceId of the Characteristic of the Descriptor to get the value of * @throws Exception */ @Rpc(description = "Returns the read value of a matching instanceId") public byte[] gattServerGetReadValueByInstanceId( @RpcParameter(name = "instanceId") Integer instanceId) throws Exception { for (BluetoothGattCharacteristic mGattChar : mCharacteristicList.values()) { if (mGattChar.getInstanceId() == instanceId) { Log.i("Found Characteristic to get value. instanceId: " + Integer.toString(instanceId) + " UUID: " + mGattChar.getUuid().toString()); return mGattChar.getValue(); } List descList = mGattChar.getDescriptors(); for (BluetoothGattDescriptor mGattDesc : descList) { if (mGattDesc.getInstanceId() == instanceId) { Log.i("Found Descriptor to get value. instanceId: " + Integer.toString(instanceId) + " UUID: " + mGattDesc.getUuid().toString()); return mGattDesc.getValue(); } } } throw new Exception("Cannot find instance ID:" + instanceId); } /** * Set value by instance ID * * @param instanceId of the Characteristic of the Descriptor to get the value of * @value value set bytearray value * @throws Exception */ @Rpc(description = "Sets the value of a Characteristic or Descriptor by instance id") public boolean gattServerSetByteArrayValueByInstanceId( @RpcParameter(name = "instanceId") Integer instanceId, @RpcParameter(name = "value") byte[] value) throws Exception { for (BluetoothGattCharacteristic mGattChar : mCharacteristicList.values()) { if (mGattChar.getInstanceId() == instanceId) { Log.i("Found Characteristic to get value. instanceId: " + Integer.toString(instanceId) + " UUID: " + mGattChar.getUuid().toString()); return mGattChar.setValue(value); } List descList = mGattChar.getDescriptors(); for (BluetoothGattDescriptor mGattDesc : descList) { if (mGattDesc.getInstanceId() == instanceId) { Log.i("Found Descriptor to set value. instanceId: " + Integer.toString(instanceId) + " UUID: " + mGattDesc.getUuid().toString()); return mGattDesc.setValue(value); } } } throw new Exception("Cannot find instance ID:" + instanceId); } /** * Set BluetoothGattService instance ID to input value * * @param index the bluetooth gatt service * @param instanceId instanceId * @throws Exception */ @Rpc(description = "GATT Server Set Instance ID of Service") public void gattServerServiceSetInstanceId( @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "instanceId") Integer instanceId) throws Exception { if (mGattServiceList.get(serviceIndex) == null) { throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex)); } Class bluetoothGattServiceClass = Class.forName("android.bluetooth.BluetoothGattService"); Method setInstanceIdMethod = bluetoothGattServiceClass.getMethod( "setInstanceId", int.class); setInstanceIdMethod.invoke(mGattServiceList.get(serviceIndex), instanceId); } /** * GATT Server set the number of handles to reserve for this service * * @param index the bluetooth gatt service * @param numHandles number of handles to reserve * @throws Exception */ @Rpc(description = "GATT Server Set the number of handles to reserve for this service") public void gattServerServiceSetHandlesToReserve( @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "numHandles") Integer numHandles) throws Exception { if (mGattServiceList.get(serviceIndex) == null) { throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex)); } Class bluetoothGattServiceClass = Class.forName("android.bluetooth.BluetoothGattService"); Method setHandlesMethod = bluetoothGattServiceClass.getMethod( "setHandles", int.class); setHandlesMethod.invoke(mGattServiceList.get(serviceIndex), numHandles); } /** * GATT Server set service advertise perferred value * * @param index the bluetooth gatt service * @param isPreferred if advertisement is preferred or not * @throws Exception */ @Rpc(description = "GATT Server Set the number of handles to reserve for this service") public void gattServerServiceIsAdvertisePreferred( @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "isPreferred") Boolean isPreferred) throws Exception { if (mGattServiceList.get(serviceIndex) == null) { throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex)); } Class bluetoothGattServiceClass = Class.forName("android.bluetooth.BluetoothGattService"); Method setAdvertisePreferredMethod = bluetoothGattServiceClass.getMethod( "setAdvertisePrefereed", boolean.class); setAdvertisePreferredMethod.invoke(mGattServiceList.get(serviceIndex), isPreferred); } /** * GATT Service add included service. * * @param index the bluetooth gatt service * @param serviceIncludedIndex index of the service to be included * @throws Exception */ @Rpc(description = "Gatt Server add included service") public void gattServerServiceaddIncludedService( @RpcParameter(name = "serviceIndex") Integer serviceIndex, @RpcParameter(name = "serviceIncludedIndex") Integer serviceIncludedIndex) throws Exception { if (mGattServiceList.get(serviceIndex) == null) { throw new Exception("Invalid serviceIndex input:" + Integer.toString(serviceIndex)); } if (mGattServiceList.get(serviceIncludedIndex) == null) { throw new Exception("Invalid serviceIncludedIndex input:" + Integer.toString( serviceIncludedIndex)); } Class bluetoothGattServiceClass = Class.forName("android.bluetooth.BluetoothGattService"); Method addIncludedServiceMethod = bluetoothGattServiceClass.getMethod( "addIncludedService", BluetoothGattService.class); addIncludedServiceMethod.invoke( mGattServiceList.get(serviceIndex), mGattServiceList.get(serviceIncludedIndex)); } /** * Set value to a bluetooth gatt characteristic * * @param index the bluetooth gatt characteristic * @param value value * @throws Exception */ @Rpc(description = "add descriptor to blutooth gatt characteristic") public boolean gattServerCharacteristicSetStringValue( @RpcParameter(name = "index") Integer index, @RpcParameter(name = "value") String value) throws Exception { if (mCharacteristicList.get(index) != null) { return mCharacteristicList.get(index).setValue(value); } else { throw new Exception("Invalid index input:" + index); } } /** * Set value to a bluetooth gatt characteristic * * @param index the bluetooth gatt characteristic * @param value value * @throws Exception */ @Rpc(description = "add descriptor to blutooth gatt characteristic") public boolean gattServerCharacteristicSetIntValue(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "value") Integer value, @RpcParameter(name = "type") Integer type, @RpcParameter(name = "offset") Integer offset) throws Exception { if (mCharacteristicList.get(index) != null) { return mCharacteristicList.get(index).setValue(value, type, offset); } else { throw new Exception("Invalid index input:" + index); } } /** * Set the instance id of the Bluetooth Gatt Characteristic * * @param index the bluetooth gatt characteristic * @param instanceId the instanceId to set * @throws Exception */ @Rpc(description = "Set Caracteristic Instance id") public void gattServerCharacteristicSetInstanceId(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "instanceId") Integer instanceId) throws Exception { if (mCharacteristicList.get(index) != null) { mCharacteristicList.get(index).setInstanceId(instanceId); } else { throw new Exception("Invalid index input:" + index); } } /** * Set the instance id of the Bluetooth Gatt Descriptor * * @param index the bluetooth gatt descriptor * @param instanceId the instanceId to set * @throws Exception */ @Rpc(description = "Set Descriptor Instance Id") public void gattServerDescriptorSetInstanceId(@RpcParameter(name = "index") Integer index, @RpcParameter(name = "instanceId") Integer instanceId) throws Exception { if (mDescriptorList.get(index) != null) { Class bluetoothGattDescriptorClass = Class.forName( "android.bluetooth.BluetoothGattDescriptor"); Method setInstanceIdMethod = bluetoothGattDescriptorClass.getMethod( "setInstanceId", int.class); setInstanceIdMethod.invoke( mDescriptorList.get(index), instanceId); } else { throw new Exception("Invalid index input:" + index); } } /** * Get the instance id of the Bluetooth Gatt Characteristic * * @param index the bluetooth gatt characteristic * @throws Exception * @return the instance id of the characteristic */ @Rpc(description = "add descriptor to blutooth gatt characteristic") public int gattServerCharacteristicGetInstanceId( @RpcParameter(name = "index") Integer index) throws Exception { if (mCharacteristicList.get(index) != null) { return mCharacteristicList.get(index).getInstanceId(); } else { throw new Exception("Invalid index input:" + index); } } /** * Create a new GattCallback object * * @return the index of the callback object */ @Rpc(description = "Create a new GattCallback object") public Integer gattServerCreateGattServerCallback() { sGattServerCallbackCount += 1; int index = sGattServerCallbackCount; mBluetoothGattServerCallbackList.put(index, new BtGattServerCallback(index)); return index; } /** * Create a new Descriptor object * * @param descriptorUuid the UUID for this descriptor * @param permissions Permissions for this descriptor * @return the index of the Descriptor object */ @Rpc(description = "Create a new Descriptor object") public int gattServerCreateBluetoothGattDescriptor( @RpcParameter(name = "descriptorUuid") String descriptorUuid, @RpcParameter(name = "permissions") Integer permissions) { sDescriptorCount += 1; int index = sDescriptorCount; BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(UUID.fromString(descriptorUuid), permissions); mDescriptorList.put(index, descriptor); return index; } private class BtGattServerCallback extends BluetoothGattServerCallback { private final Bundle mResults; private final int mIndex; private final String mEventType; BtGattServerCallback(int idx) { mResults = new Bundle(); mEventType = "GattServer"; mIndex = idx; } @Override public void onServiceAdded(int status, BluetoothGattService service) { Log.d("gatt_server change onServiceAdded " + mEventType + " " + mIndex); mResults.putString("serviceUuid", service.getUuid().toString()); mResults.putInt("instanceId", service.getInstanceId()); mEventFacade.postEvent(mEventType + mIndex + "onServiceAdded", mResults.clone()); mResults.clear(); } @Override public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { Log.d("gatt_server change onCharacteristicReadRequest " + mEventType + " " + mIndex); mResults.putInt("requestId", requestId); mResults.putInt("offset", offset); mResults.putInt("instanceId", characteristic.getInstanceId()); mResults.putInt("properties", characteristic.getProperties()); mResults.putString("uuid", characteristic.getUuid().toString()); mResults.putInt("permissions", characteristic.getPermissions()); mEventFacade.postEvent( mEventType + mIndex + "onCharacteristicReadRequest", mResults.clone()); mResults.clear(); } @Override public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d("gatt_server change onCharacteristicWriteRequest " + mEventType + " " + mIndex); mResults.putInt("requestId", requestId); mResults.putInt("offset", offset); mResults.putParcelable("BluetoothDevice", device); mResults.putBoolean("preparedWrite", preparedWrite); mResults.putBoolean("responseNeeded", responseNeeded); mResults.putByteArray("value", value); mResults.putInt("instanceId", characteristic.getInstanceId()); mResults.putInt("properties", characteristic.getProperties()); mResults.putString("uuid", characteristic.getUuid().toString()); mResults.putInt("permissions", characteristic.getPermissions()); mEventFacade.postEvent( mEventType + mIndex + "onCharacteristicWriteRequest", mResults.clone()); mResults.clear(); } @Override public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { Log.d("gatt_server change onDescriptorReadRequest " + mEventType + " " + mIndex); mResults.putInt("requestId", requestId); mResults.putInt("offset", offset); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("instanceId", descriptor.getInstanceId()); mResults.putInt("permissions", descriptor.getPermissions()); mResults.putString("uuid", descriptor.getUuid().toString()); mEventFacade.postEvent( mEventType + mIndex + "onDescriptorReadRequest", mResults.clone()); mResults.clear(); } @Override public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d("gatt_server change onDescriptorWriteRequest " + mEventType + " " + mIndex); mResults.putInt("requestId", requestId); mResults.putInt("offset", offset); mResults.putParcelable("BluetoothDevice", device); mResults.putBoolean("preparedWrite", preparedWrite); mResults.putBoolean("responseNeeded", responseNeeded); mResults.putByteArray("value", value); mResults.putInt("instanceId", descriptor.getInstanceId()); mResults.putInt("permissions", descriptor.getPermissions()); mResults.putString("uuid", descriptor.getUuid().toString()); mEventFacade.postEvent( mEventType + mIndex + "onDescriptorWriteRequest", mResults.clone()); mResults.clear(); } @Override public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { Log.d("gatt_server change onExecuteWrite " + mEventType + " " + mIndex); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("requestId", requestId); mResults.putBoolean("execute", execute); mEventFacade.postEvent(mEventType + mIndex + "onExecuteWrite", mResults.clone()); mResults.clear(); } @Override public void onNotificationSent(BluetoothDevice device, int status) { Log.d("gatt_server change onNotificationSent " + mEventType + " " + mIndex); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("status", status); mEventFacade.postEvent(mEventType + mIndex + "onNotificationSent", mResults.clone()); mResults.clear(); } @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { Log.d("gatt_server change onConnectionStateChange " + mEventType + " " + mIndex); if (newState == BluetoothProfile.STATE_CONNECTED) { Log.d("State Connected to mac address " + device.getAddress() + " status " + status); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { Log.d("State Disconnected from mac address " + device.getAddress() + " status " + status); } mResults.putParcelable("BluetoothDevice", device); mResults.putInt("status", status); mResults.putInt("newState", newState); mEventFacade.postEvent( mEventType + mIndex + "onConnectionStateChange", mResults.clone()); mResults.clear(); } @Override public void onMtuChanged(BluetoothDevice device, int mtu) { Log.d("gatt_server change onMtuChanged " + mEventType + " " + mIndex); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("MTU", mtu); mEventFacade.postEvent(mEventType + mIndex + "onMtuChanged", mResults.clone()); mResults.clear(); } @Override public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) { Log.d("gatt_server change onPhyRead " + mEventType + " " + mIndex); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("TxPhy", txPhy); mResults.putInt("RxPhy", rxPhy); mResults.putInt("Status", status); mEventFacade.postEvent(mEventType + mIndex + "onPhyRead", mResults.clone()); mResults.clear(); } @Override public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) { Log.d("gatt_server change onPhyUpdate " + mEventType + " " + mIndex); mResults.putParcelable("BluetoothDevice", device); mResults.putInt("TxPhy", txPhy); mResults.putInt("RxPhy", rxPhy); mResults.putInt("Status", status); mEventFacade.postEvent(mEventType + mIndex + "onPhyUpdate", mResults.clone()); mResults.clear(); } public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, int status) { Log.d("gatt_server change onConnecitonUpdated " + mEventType + " " + mIndex + ", interval: " + interval + ", latency: " + latency + ", timeout: " + timeout + ", status: " + status); mResults.putInt("Status", status); mResults.putInt("Interval", interval); mResults.putInt("Latency", latency); mResults.putInt("Timeout", timeout); mEventFacade.postEvent(mEventType + mIndex + "onConnectionUpdated", mResults.clone()); mResults.clear(); } } @Override public void shutdown() { if (!mBluetoothGattServerList.isEmpty()) { if (mBluetoothGattServerList.values() != null) { for (BluetoothGattServer mBluetoothGattServer : mBluetoothGattServerList.values()) { mBluetoothGattServer.close(); } } } } }