package com.bluetooth.le; import android.annotation.TargetApi; import android.app.Activity; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattServer; import android.bluetooth.BluetoothGattServerCallback; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; import android.bluetooth.le.AdvertiseCallback; import android.bluetooth.le.AdvertiseData; import android.bluetooth.le.AdvertiseSettings; import android.bluetooth.le.BluetoothLeAdvertiser; import android.os.Build; import android.os.ParcelUuid; import com.bluetooth.IBService; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Queue; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; /** * Created by seiji on 2/10/16. */ public class BLEServicePeripheral extends BLEServiceBase implements IBService { private static final String TAG = "BLEServicePeripheral"; private BluetoothLeAdvertiser mBtAdvertiser; private BluetoothGattServer mBtGattServer; private BluetoothLeAdvertiser mBleAdvertiser; private AdvertiseData.Builder mDataBuilder; private AdvertiseSettings.Builder mSettingsBuilder; private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() { @Override public void onStartFailure(int errorCode) { super.onStartFailure(errorCode); } @Override public void onStartSuccess(AdvertiseSettings settingsInEffect) { super.onStartSuccess(settingsInEffect); } }; private Queue<byte[]> mTransmitQueue = new ConcurrentLinkedQueue<byte[]>(); private BluetoothDevice mConnectedDevice; ArrayList<BLEServicePeripheralListener> listeners = new ArrayList<BLEServicePeripheralListener>(); @TargetApi(Build.VERSION_CODES.LOLLIPOP) public BLEServicePeripheral(final Activity activity) { super(activity); mBtAdvertiser = mBtAdapter.getBluetoothLeAdvertiser(); mBtGattCharacteristic = new BluetoothGattCharacteristic( UUID.fromString(CHARACTERISTIC_UUID), BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE , BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ); BluetoothGattDescriptor dataDescriptor = new BluetoothGattDescriptor( UUID.fromString(CHARACTERISTIC_CONFIG_UUID), BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ); mBtGattCharacteristic.addDescriptor(dataDescriptor); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void start(String uuidString) { mServiceUUID = UUID.fromString(uuidString); if (mBtAdvertiser == null) { return; } BluetoothGattService btGattService = new BluetoothGattService(mServiceUUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); btGattService.addCharacteristic(mBtGattCharacteristic); BluetoothGattServerCallback btGattServerCallback = createGattServerCallback(mServiceUUID, UUID.fromString(CHARACTERISTIC_UUID)); mBtGattServer = mBtManager.openGattServer(mActivity.getApplicationContext(), btGattServerCallback); mBtGattServer.addService(btGattService); mDataBuilder = new AdvertiseData.Builder(); mDataBuilder.setIncludeTxPowerLevel(false); mDataBuilder.addServiceUuid(new ParcelUuid(mServiceUUID)); mSettingsBuilder=new AdvertiseSettings.Builder(); mSettingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED); mSettingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH); mBleAdvertiser = mBtAdapter.getBluetoothLeAdvertiser(); mBleAdvertiser.startAdvertising(mSettingsBuilder.build(), mDataBuilder.build(), mAdvertiseCallback); } @Override public void pause() { mBleAdvertiser.stopAdvertising(mAdvertiseCallback); } @Override public void resume() { mTransmitQueue = new ConcurrentLinkedQueue<byte[]>(); mBleAdvertiser.startAdvertising(mSettingsBuilder.build(), mDataBuilder.build(), mAdvertiseCallback); } @Override public void stop() { pause(); mBleAdvertiser = null; mBtAdapter = null; } @Override public void read() { // nothing } @Override public boolean write(byte[] data) { mTransmitQueue.offer(data); processTransmitQueue(); return true; } private void processTransmitQueue() { byte[] data = mTransmitQueue.poll(); if (data != null) { while (mBtGattCharacteristic.setValue(data) && mBtGattServer.notifyCharacteristicChanged(mConnectedDevice, mBtGattCharacteristic, false) && mIsConnected ) { data = mTransmitQueue.poll(); if (data == null) { break; } } } } public void addListener(BLEServicePeripheralListener listener){ listeners.add(listener); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private BluetoothGattServerCallback createGattServerCallback(final UUID serviceUUID, final UUID characteristicUUID) { return new BluetoothGattServerCallback() { @Override public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { super.onCharacteristicReadRequest(device, requestId, offset, characteristic); for (BLEServicePeripheralListener listener:listeners){ listener.onCharacteristicReadRequest(device, requestId, offset, characteristic); } } @Override public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); if (responseNeeded) { mBtGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value); } for (BLEServicePeripheralListener listener:listeners){ listener.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); } } @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { super.onConnectionStateChange(device, status, newState); if (newState == BluetoothProfile.STATE_CONNECTED) { mIsConnected = true; mConnectedDevice = device; } else { mIsConnected = false; } for (BLEServicePeripheralListener listener:listeners){ listener.onConnectionStateChange(device, status, newState); } } @Override public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { super.onDescriptorReadRequest(device, requestId, offset, descriptor); for (BLEServicePeripheralListener listener:listeners){ listener.onDescriptorReadRequest(device, requestId, offset, descriptor); } } @Override public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); if (responseNeeded) { mBtGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value); } for (BLEServicePeripheralListener listener:listeners){ listener.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); } } @Override public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { super.onExecuteWrite(device, requestId, execute); for (BLEServicePeripheralListener listener:listeners){ listener.onExecuteWrite(device, requestId, execute); } } @Override public void onMtuChanged(BluetoothDevice device, int mtu) { super.onMtuChanged(device, mtu); for (BLEServicePeripheralListener listener:listeners){ listener.onMtuChanged(device, mtu); } } @Override public void onNotificationSent(BluetoothDevice device, int status) { super.onNotificationSent(device, status); for (BLEServicePeripheralListener listener:listeners){ listener.onNotificationSent(device, status); } } @Override public void onServiceAdded(int status, BluetoothGattService service) { super.onServiceAdded(status, service); for (BLEServicePeripheralListener listener:listeners){ listener.onServiceAdded(status, service); } } }; } }