blob: aef8c239927514b9abe8fbefa358c9908f59dede [file] [log] [blame]
package com.googlecode.android_scripting.facade.bluetooth;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Bundle;
import com.googlecode.android_scripting.ConvertUtils;
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;
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<Integer, BluetoothGattCharacteristic> mCharacteristicList;
private final HashMap<Integer, BluetoothGattDescriptor> mDescriptorList;
private final HashMap<Integer, BluetoothGattServer> mBluetoothGattServerList;
private final HashMap<Integer, myBluetoothGattServerCallback> mBluetoothGattServerCallbackList;
private final HashMap<Integer, BluetoothGattService> mGattServiceList;
private final HashMap<Integer, List<BluetoothGattService>> mBluetoothGattDiscoveredServicesList;
private final HashMap<Integer, List<BluetoothDevice>> mGattServerDiscoveredDevicesList;
private static int CharacteristicCount;
private static int DescriptorCount;
private static int GattServerCallbackCount;
private static int GattServerCount;
private static int GattServiceCount;
public GattServerFacade(FacadeManager manager) {
super(manager);
mService = manager.getService();
mContext = mService.getApplicationContext();
mBluetoothAdapter = MainThread.run(mService, new Callable<BluetoothAdapter>() {
@Override
public BluetoothAdapter call() throws Exception {
return BluetoothAdapter.getDefaultAdapter();
}
});
mBluetoothManager = (BluetoothManager) mContext.getSystemService(Service.BLUETOOTH_SERVICE);
mEventFacade = manager.getReceiver(EventFacade.class);
mCharacteristicList = new HashMap<Integer, BluetoothGattCharacteristic>();
mDescriptorList = new HashMap<Integer, BluetoothGattDescriptor>();
mBluetoothGattServerList = new HashMap<Integer, BluetoothGattServer>();
mBluetoothGattServerCallbackList = new HashMap<Integer, myBluetoothGattServerCallback>();
mGattServiceList = new HashMap<Integer, BluetoothGattService>();
mBluetoothGattDiscoveredServicesList = new HashMap<Integer, List<BluetoothGattService>>();
mGattServerDiscoveredDevicesList = new HashMap<Integer, List<BluetoothDevice>>();
}
/**
* 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));
GattServerCount += 1;
int in = GattServerCount;
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));
}
}
/**
* 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<BluetoothDevice> gattServerGetConnectedDevices(
@RpcParameter(name = "gattServerIndex") Integer gattServerIndex) throws Exception {
if (mBluetoothGattServerList.get(gattServerIndex) == null) {
throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex));
}
List<BluetoothDevice> 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") String value) throws Exception {
BluetoothGattServer gattServer = mBluetoothGattServerList.get(gattServerIndex);
if (gattServer == null)
throw new Exception("Invalid gattServerIndex: " + Integer.toString(gattServerIndex));
List<BluetoothDevice> 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));
gattServer.sendResponse(bluetoothDevice, requestId, status, offset,
ConvertUtils.convertStringToByteArray(value));
}
/**
* 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) {
GattServiceCount += 1;
int index = GattServiceCount;
mGattServiceList.put(index, new BluetoothGattService(UUID.fromString(uuid), serviceType));
return index;
}
// TODO: Finish this for bluetooth device, need to create a bt device list.
/*
* @Rpc(description = "cancel gatt server connection by device") public void
* gattServerCancelConnection(
*
* @RpcParameter(name = "index") Integer index,
*
* @RpcParameter(name = "deviceIndex") Integer bluetoothDevice ) throws Exception { if
* (mBluetoothGattServerList.get(index) != null) {
* mBluetoothGattServerList.get(index).cancelConnection(bluetoothDevice); } else { throw new
* Exception("Invalid index input:" + Integer.toString(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<BluetoothDevice> 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);
}
}
/**
* 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<String> gattGetServiceUuidList(@RpcParameter(name = "index") Integer index)
throws Exception {
if (mBluetoothGattServerList.get(index) != null) {
ArrayList<String> serviceUuidList = new ArrayList<String>();
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) {
CharacteristicCount += 1;
int index = CharacteristicCount;
BluetoothGattCharacteristic characteristic =
new BluetoothGattCharacteristic(UUID.fromString(characteristicUuid), property, permission);
mCharacteristicList.put(index, characteristic);
return index;
}
/**
* Create a new GattCallback object
*
* @return the index of the callback object
*/
@Rpc(description = "Create a new GattCallback object")
public Integer gattServerCreateGattServerCallback() {
GattServerCallbackCount += 1;
int index = GattServerCallbackCount;
mBluetoothGattServerCallbackList.put(index, new myBluetoothGattServerCallback(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) {
DescriptorCount += 1;
int index = DescriptorCount;
BluetoothGattDescriptor descriptor =
new BluetoothGattDescriptor(UUID.fromString(descriptorUuid), permissions);
mDescriptorList.put(index, descriptor);
return index;
}
private class myBluetoothGattServerCallback extends BluetoothGattServerCallback {
private final Bundle mResults;
private final int index;
private final String mEventType;
public myBluetoothGattServerCallback(int idx) {
mResults = new Bundle();
mEventType = "GattServer";
index = idx;
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
Log.d("gatt_server change onServiceAdded " + mEventType + " " + index);
mResults.putString("serviceUuid", service.getUuid().toString());
mResults.putInt("instanceId", service.getInstanceId());
mEventFacade.postEvent(mEventType + index + "onServiceAdded", mResults.clone());
mResults.clear();
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattCharacteristic characteristic) {
Log.d("gatt_server change onCharacteristicReadRequest " + mEventType + " " + index);
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 + index + "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 + " " + index);
mResults.putInt("requestId", requestId);
mResults.putInt("offset", offset);
mResults.putParcelable("BluetoothDevice", device);
mResults.putBoolean("preparedWrite", preparedWrite);
mResults.putBoolean("responseNeeded", responseNeeded);
mResults.putString("value", ConvertUtils.convertByteArrayToString(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 + index + "onCharacteristicWriteRequest", mResults.clone());
mResults.clear();
}
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset,
BluetoothGattDescriptor descriptor) {
Log.d("gatt_server change onDescriptorReadRequest " + mEventType + " " + index);
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 + index + "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 + " " + index);
mResults.putInt("requestId", requestId);
mResults.putInt("offset", offset);
mResults.putParcelable("BluetoothDevice", device);
mResults.putBoolean("preparedWrite", preparedWrite);
mResults.putBoolean("responseNeeded", responseNeeded);
mResults.putString("value", ConvertUtils.convertByteArrayToString(value));
mResults.putInt("instanceId", descriptor.getInstanceId());
mResults.putInt("permissions", descriptor.getPermissions());
mResults.putString("uuid", descriptor.getUuid().toString());
mEventFacade.postEvent(mEventType + index + "onDescriptorWriteRequest", mResults.clone());
mResults.clear();
}
@Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
Log.d("gatt_server change onExecuteWrite " + mEventType + " " + index);
mResults.putParcelable("BluetoothDevice", device);
mResults.putInt("requestId", requestId);
mResults.putBoolean("execute", execute);
mEventFacade.postEvent(mEventType + index + "onExecuteWrite", mResults.clone());
mResults.clear();
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
Log.d("gatt_server change onNotificationSent " + mEventType + " " + index);
mResults.putParcelable("BluetoothDevice", device);
mResults.putInt("status", status);
mEventFacade.postEvent(mEventType + index + "onNotificationSent", mResults.clone());
mResults.clear();
}
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
Log.d("gatt_server change onConnectionStateChange " + mEventType + " " + index);
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 + index + "onConnectionStateChange", mResults.clone());
mResults.clear();
}
@Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
Log.d("gatt_server change onMtuChanged " + mEventType + " " + index);
mResults.putParcelable("BluetoothDevice", device);
mResults.putInt("mtu", mtu);
mEventFacade.postEvent(mEventType + index + "onMtuChanged", mResults.clone());
mResults.clear();
}
}
@Override
public void shutdown() {
if (!mBluetoothGattServerList.isEmpty()) {
if (mBluetoothGattServerList.values() != null) {
for (BluetoothGattServer mBluetoothGattServer : mBluetoothGattServerList.values()) {
mBluetoothGattServer.close();
}
}
}
}
}