So for some reason my background service crashes, and I don't know why.
So my service contains BLE, and I bind to the service from the MainActivity with:
public void startBluetoothService() {
// Start the BLE Service
Log.d(TAG, "Starting BLE Service");
Intent gattServiceIntent = new Intent(this, BLE_Service.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Log.d(TAG, "Bluetooth is Enabled");
}
This runs, but then I get the following error
10-09 12:51:31.104 14007-14081/com.example.wrd I/ProviderInstaller: Installed default security provider GmsCore_OpenSSL
10-09 12:51:31.114 14007-14007/com.example.wrd D/AndroidRuntime: Shutting down VM
10-09 12:51:31.114 14007-14007/com.example.wrd E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.wrd, PID: 14007
java.lang.RuntimeException: Unable to instantiate service com.example.wrd.ble.BLE_Service: java.lang.InstantiationException: java.lang.Class<com.example.wrd.ble.BLE_Service> has no zero argument constructor
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3841)
at android.app.ActivityThread.access$2100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1909)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7325)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.InstantiationException: java.lang.Class<com.example.wrd.ble.BLE_Service> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3838)
at android.app.ActivityThread.access$2100(ActivityThread.java:229)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1909)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7325)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
My service looks like this:
public class BLE_Service extends Service {
private Home ma;
private boolean mscanning;
public boolean Read = false;
private Handler mHandler;
private long scanPeriod;
private int signalStrength;
//Intent string
private static String DeviceAddress;
private static final String TAG = "BLE_Service";
// Bluetooth objects that we need to interact with
private static BluetoothManager mBluetoothManager;
private static BluetoothAdapter mBluetoothAdapter;
private static BluetoothGatt mBluetoothGatt;
private static BluetoothDevice device;
private static BluetoothGattCharacteristic BLECharacterisitc;
private final static String BaseUuid = "00000000-0000-1000-8000-00805f9b34f";
private final static String CSUuid = "00002902-0000-1000-8000-00805f9b34fb";
private final static String UuidWrite = BaseUuid + "0";
private final static String UuidRead = BaseUuid + "1";
private final static String UuidRead2 = BaseUuid + "2";
private final static String state_RW = BaseUuid + "0";
private final static String treatmentSettings_RW = BaseUuid + "1";
private final static String adjustment_RW = BaseUuid + "2";
private final static String validation_R = BaseUuid + "3";
//Broadcasts
public final static String BROADCAST_ADDED = "added";
public final static String BROADCAST_ADDEDFrag = "added";
// Bluetooth characteristics that we need to read/write
private static BluetoothGattCharacteristic mCharacterisitc, mCharacterisitc2, mCharacterisitcWrite, mCharacterisitc_state_RW,
mCharacterisitc_treatmentSettings_RW, mCharacterisitc_adjustment_RW, mCharacterisitc_validation_R;
private static StringBuilder sb = new StringBuilder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean connecting(String DeviceAddress) {
Log.d(TAG, "Connection State: connect");
device = mBluetoothAdapter.getRemoteDevice(DeviceAddress);
if (device == null) {
Log.d(TAG, "Connection State Device Not Available ");
return false;
} else {
Log.d(TAG, "Connection State Connecting...");
device.connectGatt(this, false, mGattCallback);
return true;
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean disconnect() {
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void checkConnectedDevices() {
if (mBluetoothGatt != null){
String DeviceString = mBluetoothGatt.getDevice().getAddress();
String NameString = mBluetoothGatt.getDevice().getName();
Log.d(TAG, "checkConnectedDevices: " + NameString);
//broadCastHEX(BROADCAST_ADDEDFrag, NameString+";"+DeviceString, "get_conn_BLE_return");
}else{
//broadCastHEX(BROADCAST_ADDEDFrag, null, "Connected_BLE_Devices_return");
}
}
public class LocalBinder extends Binder {
public BLE_Service getService() {
return BLE_Service.this;
}
}
private final IBinder mBinder = new LocalBinder();
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public boolean initialize() {
Log.d(TAG, "mBluetoothManager: service");
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
Log.d(TAG, "mBluetoothManager: initialize");
BluetoothManager bluetoothManager = (BluetoothManager) getBaseContext().getSystemService(Context.BLUETOOTH_SERVICE);
List<BluetoothDevice> devices = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
Log.d(TAG, "mBluetoothManager: initialize device" + devices.toString());
for(BluetoothDevice device : devices) {
if(device.getType() == BluetoothDevice.DEVICE_TYPE_LE) {
Log.d(TAG, "mBluetoothManager: running loop" + device.getName() + "\n");
}else{
Log.d(TAG, "mBluetoothManager: nothing" + device.getName() + "\n");
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public BLE_Service(Home home, long scanPeriod, int signalStrength) {
ma = home;
mHandler = new Handler();
this.scanPeriod = scanPeriod;
this.signalStrength = signalStrength;
final BluetoothManager bluetoothManager =
(BluetoothManager) ma.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
public boolean isScanning() {
return mscanning;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void start() {
if (!Utils.checkBluetooth(mBluetoothAdapter)) {
Utils.requestUserBluetooth(ma);
ma.stopScan();
} else {
scanLeDevice(true);
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void stop() {
scanLeDevice(false);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void scanLeDevice(final boolean enable) {
if (enable && !mscanning) {
Utils.toast(ma.getApplication(), "Starting BLE Scan...");
mHandler.postDelayed(new Runnable() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void run() {
Utils.toast(ma.getApplicationContext(), "Stopping BLE scan...");
mscanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
ma.stopScan();
}
}, scanPeriod);
mscanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
}
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState));
gatt.discoverServices();
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
/*
* Once successfully connected, we must next discover all the services on the
* device before we can read and write their characteristics.
*/
mBluetoothGatt = gatt;
BluetoothDevice device = gatt.getDevice();
Log.d(TAG, "Connection State onConnectionStateChange: " + device);
} else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
/*
* If at any point we disconnect, send a message to clear the weather values
* out of the UI
*/
Log.d(TAG, "Connection State: 2");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
/*
* If there is a failure at any stage, simply disconnect
*/
}
}
/**
* This is called when a service discovery has completed.
*
* It gets the characteristics we are interested in and then
* broadcasts an update to the main activity.
*
* #param gatt The GATT database object
* #param status Status of whether the write was successful.
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {//prøv med ekstra status på denne
if (status == BluetoothGatt.GATT_SUCCESS) {
BluetoothGattService mBluetoothGattService = gatt.getService(UUID.fromString(CSUuid));
if (mBluetoothGattService != null) {
Log.i(TAG, "Connection State: Service characteristic UUID found: " + mBluetoothGattService.getUuid().toString());
mCharacterisitc = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidRead));
mCharacterisitc2 = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidRead2));
mCharacterisitcWrite = mBluetoothGattService.getCharacteristic(UUID.fromString(UuidWrite));
//First activate buttons here....
Log.w(TAG, "Connection State 1: mCharacterisitc " + mCharacterisitc + " " + mCharacterisitc2);
Intent broadcastIntent = new Intent().putExtra("ConnState", true);
broadcastIntent.setAction(BLE_Service.BROADCAST_ADDED);
LocalBroadcastManager.getInstance(BLE_Service.this).sendBroadcast(broadcastIntent);
if(Read){
readCharacteristic(gatt, mCharacterisitc);
}
} else {
Log.i(TAG, "Connection State: Service characteristic not found for UUID: " + UuidRead);
}
}
}
private String connectionState(int status) {
switch (status) {
case BluetoothProfile.STATE_CONNECTED:
return "Connection State: Connected";
case BluetoothProfile.STATE_DISCONNECTED:
return "Connection State: Disconnected";
case BluetoothProfile.STATE_CONNECTING:
return "Connection State: Connecting";
case BluetoothProfile.STATE_DISCONNECTING:
return "Connection State: Disconnecting";
default:
return String.valueOf(status);
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "Connection State: onCharacteristicRead");
Log.w(TAG, "Connection State: Read 1");
// Verify that the read was the LED state
String uuid = characteristic.getUuid().toString();
// In this case, the only read the app does is the LED state.
// If the application had additional characteristics to read we could
// use a switch statement here to operate on each one separately.
if (uuid.equalsIgnoreCase(UuidRead)) {
Log.w(TAG, "Connection State: Read 2");
final int Val = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
broadCast(BROADCAST_ADDEDFrag, Val, "read_Service");
Log.i(TAG, "Connection State: onCharacteristicRead: " + Val);
Log.d(TAG, "Connection State Read state: "+Read);
readCharacteristic(gatt, mCharacterisitc2);
}
if (uuid.equalsIgnoreCase(UuidRead2)) {
Log.w(TAG, "Connection State: Read 3");
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
String msg = "letter: " + new String(data) + "\nHEX: " + stringBuilder.toString();
Log.d(TAG, "Connection State: onCharacteristicRead2: 4 " + msg);
broadCastHEX(BROADCAST_ADDEDFrag, msg, "read_Service2");
}
Read = false; //Has to be set to false in the last read message..
Log.d(TAG, "Connection State Read state: "+Read);
}
}
}
};
/**
* Runs service discovery on the connected device.
*
* #return
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void discoverServices() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.d(TAG, "Connection State BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.discoverServices();
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void Write(Integer integer) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.d(TAG, "Connection State BluetoothAdapter not initialized");
return;
}
Integer Val = integer;
byte[] byteVal;
byteVal = intToByteArray(Val);
mCharacterisitcWrite.setValue(byteVal);
Log.d(TAG, "Connection State write 1: " + byteVal);
mBluetoothGatt.writeCharacteristic(mCharacterisitcWrite);
}
public static byte[] intToByteArray(int a) {
byte[] ret = new byte[4];
ret[3] = (byte) (a & 0xFF);
ret[2] = (byte) ((a >> 8) & 0xFF);
ret[1] = (byte) ((a >> 16) & 0xFF);
ret[0] = (byte) ((a >> 24) & 0xFF);
return ret;
}
/**
* This method is used to read the state of the LED from the device
*/
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void readCharacteristic(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || gatt == null) {
Log.w(TAG, "Connection State: BluetoothAdapter not initialized 2");
return;
}
Log.w(TAG, "Connection State: BluetoothAdapter initialized");
gatt.readCharacteristic(characteristic);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
final int new_rssi = rssi;
if (rssi > signalStrength && device.getName() != null) {
mHandler.post(new Runnable() {
#Override
public void run() {
try {
FragmentBLE.addDevice(device, new_rssi);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
};
public void broadCast(String broadcastTXT, Integer Val, String key) {
Log.d(TAG, "Connection State: -> broadCast: Service Broadcast");
Intent broadcastIntent = new Intent().putExtra(key, Val);
broadcastIntent.setAction(broadcastTXT);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
public void broadCastHEX(String broadcastTXT, String Val, String key) {
Log.d(TAG, "Connection State: -> broadCast: Service Broadcast");
Intent broadcastIntent = new Intent().putExtra(key, Val);
broadcastIntent.setAction(broadcastTXT);
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);
}
}
So what causes this error to occure?
looks like it's somthing to do with java.lang.RuntimeException: Unable to instantiate service com.example.wrd.ble.BLE_Service, and I've been serching on it, but can't seem to find anything that helps.
EDIT
So my filled contructer is done before my empty contructer is set. I bind in my onStart()
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
protected void onStart() {
super.onStart();
// Start the BLE Service
Log.d(TAG, "Starting BLE Service");
Intent gattServiceIntent = new Intent(this, BLE_Service.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Log.d(TAG, "Bluetooth is Enabled");
registerReceiver(mBTStateUpdateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
And then in my oncreate I run the following
mBTLeScanner = new BLE_Service(this, 7500, -75);
but somehow BLE_Service(this, 7500, -75) is finished before onStart()
Create an empty constructor.
BLE_Service(){
}
Related
I am building an app where I need BLE devices to connect with each other and send messages. My problem is when my android device connects to an iOS device, only the iOS devices receives the message that android is advertising. Android never recieves the message iOS is sending. After debugging and testing, I am certain this is a problem with android, not iOS because iOS devices send and receive messages between each other properly.
I am confused on what to fix with my android code in order to have it successfully receive messages from iOS.
public class mapActivity extends AppCompatActivity implements OnMapReadyCallback {
private final Set<Peer> nearbyPeers = new HashSet<>();
private static Map<String, String> times = new HashMap<>();
private int counter = 0;
private static final String TAG2 = "ClientActivity";
private static final int REQUEST_ENABLE_BT = 1;
private static final String docName = "docName";
private boolean mConnected;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private ScanCallback mScanCallback;
private BluetoothGatt mGatt;
public String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
public static final long SCAN_PERIOD = 5000;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
private BluetoothGattServer mGattServer;
private BluetoothGatt gatt;
private boolean mEchoInitialized;
private List<BluetoothDevice> mDevices;
private BluetoothManager mBluetoothManager;
private boolean mInitialized;
FirebaseFirestore db = FirebaseFirestore.getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLogHandler = new Handler(Looper.getMainLooper());
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info"
+ "\nName: " + mBluetoothAdapter.getName()
+ "\nAddress: " + mBluetoothAdapter.getAddress();
mHandler = new Handler();
mDevices = new ArrayList<>();
//End of ServerActivity
startScan();
}
#Override
protected void onResume() {
super.onResume();
//ClientActivity
// Check low energy support
//ServerActivity
// Check if bluetooth is enabled
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
// Request user to enable it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
finish();
return;
}
// Check low energy support
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
// Get a newer device
System.out.println("No LE Support.");
finish();
return;
}
// Check advertising
if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
// Unable to run the server on this device, get a better device
System.out.println("No Advertising Support.");
finish();
return;
}
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
GattServerCallback gattServerCallback = new GattServerCallback();
//try {
if (gattServerCallback == null || this == null || mBluetoothManager == null) {
System.out.println("unable to print gatt server");
return;
}
mGattServer = mBluetoothManager.openGattServer(this, gattServerCallback);
//}
//catch (Exception e) {
//}
#SuppressLint("HardwareIds")
String deviceInfo = "Device Info" + "\nName: " + mBluetoothAdapter.getName() + "\nAddress: " + mBluetoothAdapter.getAddress();
setupServer();
startAdvertising();
//startScan();
}
#Override
protected void onPause() {
super.onPause();
stopAdvertising();
stopServer();
}
//ServerActivity Start Advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startAdvertising() {
if (mBluetoothLeAdvertiser == null) {
return;
}
AdvertiseSettings settings = new AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)
.build();
ParcelUuid parcelUuid = ParcelUuid.fromString(covtraceUUID);
AdvertiseData data = new AdvertiseData.Builder().setIncludeDeviceName(false)
//.addServiceUuid(new ParcelUuid(serviceUUID));
.addServiceUuid(parcelUuid)
.addServiceData( parcelUuid, "d".getBytes(Charset.forName("UTF-8") ) )
.build();
mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
}
//ServerActivity stop advertising
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopAdvertising() {
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
}
}
private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
System.out.println("Peripheral advertising started.");
}
#Override
public void onStartFailure(int errorCode) {
System.out.println("Peripheral advertising failed: " + errorCode);
}
};
//ServerActivity log
public void log1(String msg) {
Log.d(TAG, msg);
}
public void addDevice(BluetoothDevice device) {
System.out.println("Device added: " + device.getAddress());
mHandler.post(() -> mDevices.add(device));
}
public void removeDevice(BluetoothDevice device) {
System.out.println("Device removed: " + device.getAddress());
mHandler.post(() -> {
mDevices.remove(device);
});
}
private static boolean uuidMatches(String uuidString, String... matches) {
for (String match : matches) {
if (uuidString.equalsIgnoreCase(match)) {
return true;
}
}
return false;
}
private static boolean matchesServiceUuidString(String serviceIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(serviceIdString, covtraceUUID);
}
#Nullable
private static BluetoothGattService findService(List<BluetoothGattService> serviceList) {
for (BluetoothGattService service : serviceList) {
String serviceIdString = service.getUuid()
.toString();
if (matchesServiceUuidString(serviceIdString)) {
return service;
}
}
return null;
}
private static boolean characteristicMatches(BluetoothGattCharacteristic characteristic, String uuidString) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return uuidMatches(uuid.toString(), uuidString);
}
#Nullable
private static BluetoothGattCharacteristic findCharacteristic(BluetoothGatt bluetoothGatt, String uuidString) {
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("our service is null!!!!!!!");
return null;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (characteristicMatches(characteristic, uuidString)) {
return characteristic;
}
}
return null;
}
public static byte[] bytesFromString(String string) {
byte[] stringBytes = new byte[0];
try {
stringBytes = string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Failed to convert message string to byte array");
}
return stringBytes;
}
#Nullable
public static BluetoothGattCharacteristic findEchoCharacteristic(BluetoothGatt bluetoothGatt) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return findCharacteristic(bluetoothGatt, covtraceUUID);
}
//ServerActivity send message
private void sendMessage() {
if (!mConnected || !mEchoInitialized) {
return;
}
BluetoothGattCharacteristic characteristic = findEchoCharacteristic(mGatt);
if (characteristic == null) {
logError("Unable to find echo characteristic.");
disconnectGattServer();
return;
}
String message = String.valueOf(P2PKit.getMyPeerId());
byte[] messageBytes = bytesFromString(message);
if (messageBytes.length == 0) {
logError("Unable to convert message to bytes");
return;
}
characteristic.setValue(messageBytes);
boolean success = mGatt.writeCharacteristic(characteristic);
if (success) {
log("Wrote: " + byteArrayInHexFormat(messageBytes));
} else {
logError("Failed to write data");
}
}
//ServerActivity characteristic changed
private class CharacteristicChanged extends BluetoothGattCallback {
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] messageBytes = characteristic.getValue();
String messageString = null;
try {
messageString = new String(messageBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "Unable to convert message bytes to string");
}
Log.d(messageString, "Received message: ");
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
return;
}
BluetoothGattService service = gatt.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(covtraceUUID));
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
mInitialized = gatt.setCharacteristicNotification(characteristic, true);
}
}
public static boolean requiresResponse(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
}
public void sendResponse(BluetoothDevice device, int requestId, int status, int offset, byte[] value) {
mHandler.post(() -> mGattServer.sendResponse(device, requestId, status, 0, null));
}
public static byte[] reverse(byte[] value) {
int length = value.length;
byte[] reversed = new byte[length];
for (int i = 0; i < length; i++) {
reversed[i] = value[length - (i + 1)];
}
return reversed;
}
private static String byteToHex(byte b) {
char char1 = Character.forDigit((b & 0xF0) >> 4, 16);
char char2 = Character.forDigit((b & 0x0F), 16);
return String.format("0x%1$s%2$s", char1, char2);
}
public static String byteArrayInHexFormat(byte[] byteArray) {
if (byteArray == null) {
return null;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("{ ");
for (int i = 0; i < byteArray.length; i++) {
if (i > 0) {
stringBuilder.append(", ");
}
String hexString = byteToHex(byteArray[i]);
stringBuilder.append(hexString);
}
stringBuilder.append(" }");
return stringBuilder.toString();
}
public static boolean requiresConfirmation(BluetoothGattCharacteristic characteristic) {
return (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE;
}
private void notifyCharacteristic(byte[] value, UUID uuid) {
mHandler.post(() -> {
BluetoothGattService service = mGattServer.getService(UUID.fromString(covtraceUUID));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
log("Notifying characteristic " + characteristic.getUuid().toString()
+ ", new value: " + byteArrayInHexFormat(value));
characteristic.setValue(value);
boolean confirm = requiresConfirmation(characteristic);
for(BluetoothDevice device : mDevices) {
mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
}
});
}
public void notifyCharacteristicEcho(byte[] value) {
notifyCharacteristic(value, UUID.fromString(covtraceUUID));
}
private void sendReverseMessage(byte[] message) {
mHandler.post(() -> {
// Reverse message to differentiate original message & response
byte[] response = reverse(message);
log("Sending: " + byteArrayInHexFormat(response));
notifyCharacteristicEcho(response);
});
}
//ServerActivity gattservercallback
private class GattServerCallback extends BluetoothGattServerCallback {
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
addDevice(device);
connectDevice(device);
System.out.println("preparing to send msg 1");
sendMessage();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
removeDevice(device);
}
}
// The Gatt will reject Characteristic Read requests that do not have the permission set,
// so there is no need to check inside the callback
#Override
public void onCharacteristicReadRequest(BluetoothDevice device,
int requestId,
int offset,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
log("onCharacteristicReadRequest "
+ characteristic.getUuid().toString());
if (requiresResponse(characteristic)) {
// Unknown read characteristic requiring response, send failure
sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
}
System.out.println("preparing to send msg 2");
sendMessage();
// Not one of our characteristics or has NO_RESPONSE property set
}
#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 (UUID.fromString(covtraceUUID).equals(characteristic.getUuid())) {
sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
sendReverseMessage(value);
}
System.out.println("preparing to send msg 3");
sendMessage();
}
}
//ServerActivity set up server
private void setupServer() {
BluetoothGattService service = new BluetoothGattService(UUID.fromString(covtraceUUID),
BluetoothGattService.SERVICE_TYPE_PRIMARY);
mGattServer.addService(service);
}
//ServerActivity stop server
private void stopServer() {
if (mGattServer != null) {
mGattServer.close();
}
}
public void log(String msg) {
Log.d(TAG, msg);
mLogHandler.post(() -> {
Log.i(msg, msg + "\n");
});
}
public void logError(String msg) {
log("Error: " + msg);
}
//ClientActivity Scanning
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void startScan() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!hasPermissions() || mScanning) {
return;
}
}
disconnectGattServer();
mScanResults = new HashMap<>();
mScanCallback = new BtleScanCallback(mScanResults);
mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
// Note: Filtering does not work the same (or at all) on most devices. It also is unable to
// search for a mask or anything less than a full UUID.
// Unless the full UUID of the server is known, manual filtering may be necessary.
// For example, when looking for a brand of device that contains a char sequence in the UUID
ScanFilter scanFilter = new ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString(covtraceUUID))
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add(scanFilter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
mHandler = new Handler();
//mHandler.postDelayed(this::stopScan, SCAN_PERIOD);
mScanning = true;
System.out.println("Started scanning.");
}
#RequiresApi(api = Build.VERSION_CODES.M)
private boolean hasPermissions() {
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
requestBluetoothEnable();
return false;
}
return true;
}
private void requestBluetoothEnable() {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
log("Requested user enables Bluetooth. Try starting the scan again.");
}
private void connectDevice(BluetoothDevice device) {
log("Connecting to " + device.getAddress());
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = device.connectGatt(this, false, gattClientCallback);
}
//ClientActivity Stop scan
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void stopScan() {
if (mScanning && mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mBluetoothLeScanner != null) {
mBluetoothLeScanner.stopScan(mScanCallback);
scanComplete();
}
mScanCallback = null;
mScanning = false;
mHandler = null;
System.out.println("Stopped scanning.");
}
//ClientActivity scan Complete
private void scanComplete() {
if (mScanResults.isEmpty()) {
return;
}
for (String deviceAddress : mScanResults.keySet()) {
BluetoothDevice device = mScanResults.get(deviceAddress);
GattServerViewModel viewModel = new GattServerViewModel(device);
}
}
//Client Activity set connected
public void setConnected(boolean connected) {
mConnected = connected;
}
public void initializeEcho() {
mEchoInitialized = true;
}
//ClientActivity disconnect Gatt server
public void disconnectGattServer() {
System.out.println("Closing Gatt connection");
mConnected = false;
mEchoInitialized = false;
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
}
}
private static boolean matchesCharacteristicUuidString(String characteristicIdString) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return uuidMatches(characteristicIdString, covtraceUUID);
}
private static boolean isMatchingCharacteristic(BluetoothGattCharacteristic characteristic) {
if (characteristic == null) {
return false;
}
UUID uuid = characteristic.getUuid();
return matchesCharacteristicUuidString(uuid.toString());
}
public static List<BluetoothGattCharacteristic> findCharacteristics(BluetoothGatt bluetoothGatt) {
List<BluetoothGattCharacteristic> matchingCharacteristics = new ArrayList<>();
List<BluetoothGattService> serviceList = bluetoothGatt.getServices();
BluetoothGattService service = findService(serviceList);
if (service == null) {
System.out.println("cannot find charac");
return matchingCharacteristics;
}
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
if (isMatchingCharacteristic(characteristic)) {
matchingCharacteristics.add(characteristic);
}
}
return matchingCharacteristics;
}
//Client Activity callback
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private class BtleScanCallback extends ScanCallback {
private Map<String, BluetoothDevice> mScanResults;
BtleScanCallback(Map<String, BluetoothDevice> scanResults) {
mScanResults = scanResults;
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
addScanResult(result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
addScanResult(result);
}
}
#Override
public void onScanFailed(int errorCode) {
logError("BLE Scan Failed with code " + errorCode);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void addScanResult(ScanResult result) {
BluetoothDevice device = result.getDevice();
String deviceAddress = device.getAddress();
mScanResults.put(deviceAddress, device);
}
}
#Nullable
public static String stringFromBytes(byte[] bytes) {
String byteString = null;
try {
byteString = new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert message bytes to string");
}
return byteString;
}
public static boolean isEchoCharacteristic(BluetoothGattCharacteristic characteristic) {
String covtraceUUID = "A82AB3FC-1695-4F7A-40F0-FE094CC218F8";
return characteristicMatches(characteristic, covtraceUUID );
}
//Gatt Client Callback
private class GattClientCallback extends BluetoothGattCallback {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
System.out.println("onConnectionStateChange newState: " + newState);
if (status == BluetoothGatt.GATT_FAILURE) {
logError("Connection Gatt failure status " + status);
disconnectGattServer();
return;
} else if (status != BluetoothGatt.GATT_SUCCESS) {
// handle anything not SUCCESS as failure
logError("Connection not GATT sucess status " + status);
disconnectGattServer();
return;
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
System.out.println("Connected to device " + gatt.getDevice().getAddress());
mConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
System.out.println("Disconnected from device");
disconnectGattServer();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status != BluetoothGatt.GATT_SUCCESS) {
log("Device service discovery unsuccessful, status " + status);
return;
}
List<BluetoothGattCharacteristic> matchingCharacteristics = findCharacteristics(gatt);
if (matchingCharacteristics.isEmpty()) {
logError("Unable to find characteristics.");
return;
}
log("Initializing: setting write type and enabling notification");
for (BluetoothGattCharacteristic characteristic : matchingCharacteristics) {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
enableCharacteristicNotification(gatt, characteristic);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic written successfully");
} else {
logError("Characteristic write unsuccessful, status: " + status);
disconnectGattServer();
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
log("Characteristic read successfully");
readCharacteristic(characteristic);
} else {
logError("Characteristic read unsuccessful, status: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
log("Characteristic changed, " + characteristic.getUuid().toString());
readCharacteristic(characteristic);
}
private void enableCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
boolean characteristicWriteSuccess = gatt.setCharacteristicNotification(characteristic, true);
if (characteristicWriteSuccess) {
log("Characteristic notification set successfully for " + characteristic.getUuid().toString());
if (isEchoCharacteristic(characteristic)) {
System.out.println("enters isechocharac... ab to init");
initializeEcho();
System.out.println("preparing to send msg 4");
sendMessage();
}
} else {
logError("Characteristic notification set failure for " + characteristic.getUuid().toString());
}
}
private void readCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] messageBytes = characteristic.getValue();
log("Read: " + byteArrayInHexFormat(messageBytes));
String message = stringFromBytes(messageBytes);
if (message == null) {
logError("Unable to convert bytes to string");
return;
}
log("Received message: " + message);
}
}
#Override
public void onStart() {
super.onStart();
}
I'm trying to connect to random Bluetooth device that match a certain characteristic. I just want to print the incoming messages from the bluetooth device.
I've been trying for the past few days to try and connect to some random bluetooth device that matches a characteristic so that I'll be able to just print the messages from the bluetooth device.
public class main extends AppCompatActivity {
private List Service_UUIDs;
private List Charac_UUIDS;
private List Descriptor_UUIDs;
public static final UUID descriptor = UUID.fromString("863930fc-947c-421b-
9170-9969ea6ad610");
private BluetoothAdapter bluetoothAdapter = null;
private BluetoothLeScanner bluetoothLeScanner;
private ScanCallback scanCallback;
private TextView messageText;
private Handler handler;
private static final int SCAN_TIME = 15000;
private int connectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTED = 2;
private boolean isConnected;
private boolean isScanning;
private BluetoothLeScanner myScanner;
private BluetoothGatt bluetoothGatt;
private String connected = "";
public List<BluetoothGattService> myServices;
private ScanCallback myScanCallBack;
private BluetoothDevice myDevice;
private HashMap<String, BluetoothDevice> myScanResults;
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public static final int REQUEST_ENABLE_BT = 10;
private void unpairDevice(BluetoothDevice device) {
try {
Method m = device.getClass().getMethod("removeBond", (Class[])
null);
m.invoke(device, (Object[]) null);
Log.d("unpairDevice", Integer.toString(device.getBondState()));
}
catch (Exception e) { Log.e("unpairDevice", e.getMessage()); }
}
private void makeToast(String message) {
//creates pop-ups in UI of the message
Context context = getApplicationContext();
CharSequence text = message;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BluetoothManager bluetoothManager = (BluetoothManager)
getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
if(!bluetoothManager.getAdapter().isEnabled()){
Intent btEnable = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(btEnable, REQUEST_ENABLE_BT);
}
messageText = findViewById(R.id.atm_msg);
findViewById(R.id.scan_button).setOnClickListener(new handleScan());
}
class handleScan implements View.OnClickListener{
public void onClick(View view){
startScan();
}
}
private void startScan() {
List<ScanFilter> filters = new ArrayList<>();
ScanFilter scanFilter = new ScanFilter.Builder()
.setServiceUuid(new ParcelUuid(descriptor))
.build();
filters.add(scanFilter);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
myScanResults = new HashMap<>();
myScanCallBack = new BtleScanCallback(myScanResults);
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(myScanCallBack);
isScanning = true;
new Handler().postDelayed(this::stopScan, SCAN_TIME);
}
private void stopScan(){
if(isScanning && bluetoothAdapter != null
&& bluetoothAdapter.isEnabled()
&& bluetoothLeScanner != null){
bluetoothLeScanner.stopScan(myScanCallBack);
scanComplete();
}
myScanCallBack = null;
isScanning = false;
handler = null;
}
private void scanComplete(){
if (myScanResults.isEmpty()){
return;
}
for(BluetoothDevice device: myScanResults.values()){
connectDevice(device);
}
}
protected class BtleScanCallback extends ScanCallback {
private HashMap<String, BluetoothDevice> myScanResults;
BtleScanCallback(HashMap<String, BluetoothDevice> scanResults) {
myScanResults = scanResults;
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
addScanResult(result);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult result : results) {
addScanResult(result);
}
}
#Override
public void onScanFailed(int errorCode) {
makeToast("BLE Scan Failed with code " + errorCode);
}
private void addScanResult(ScanResult result) {
myDevice = result.getDevice();
String deviceAddress = myDevice.getAddress();
myScanResults.put(deviceAddress, myDevice);
}
}
private void connectDevice(BluetoothDevice device) {
bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
}
private final BluetoothGattCallback bluetoothGattCallback = new
BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int
newState) {
super.onConnectionStateChange(gatt, status, newState);
if (status == gatt.GATT_FAILURE){
Log.d("BLE_Assistance", "-----> status: " + gatt.GATT_FAILURE);
disconnectGattServer();
return;
}
if (status == 133){
bluetoothAdapter.disable();
bluetoothAdapter.enable();
Log.d("OCSC: ", "133 GATT_ERROR OCCURRED");
}
if (newState == gatt.STATE_CONNECTED){
Log.d("BLE_Assistance", "-----> state: " +
gatt.STATE_CONNECTED);
connectionState = gatt.STATE_CONNECTED;
isConnected = true;
return;
}
else if (status != gatt.GATT_SUCCESS){
Log.d("BLE_Assistance", "-----> status: could not connect");
disconnectGattServer();
return;
}
else if (newState == gatt.STATE_DISCONNECTED){
Log.d("BLE_Assistance", "status: " + gatt.STATE_DISCONNECTED);
disconnectGattServer();
}
}
public void disconnectGattServer(){
isConnected = false;
connected = "";
if (bluetoothLeScanner != null && scanCallback != null){
bluetoothLeScanner.flushPendingScanResults(scanCallback);
}
if (!myScanResults.isEmpty()){
myScanResults.clear();
}
try {
if (myServices.isEmpty()){
Log.d("Services", "Empty");
}
else{
myServices.clear();
}
} catch (NullPointerException nullPointerException){
Log.d("Services", "" + nullPointerException);
}
bluetoothAdapter.cancelDiscovery();
if(bluetoothGatt != null){
bluetoothGatt.abortReliableWrite();
bluetoothGatt.disconnect();
bluetoothGatt.close();
bluetoothGatt = null;
Log.d("disconnect server", ": Disconnected GATT Server");
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
byte[] msg_bytes = characteristic.getValue();
try {
String message = new String(msg_bytes, 0, msg_bytes.length,
"utf-8");
Log.d("onCharacteristicRead", message);
new Handler(Looper.getMainLooper()).postDelayed(() -> {
makeToast("onCharacteristicRead: " + message);
messageText.append("\nonCharacteristicRead: " + message);
}, 1000);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status){
super.onServicesDiscovered(gatt,status);
Service_UUIDs = new ArrayList();
Charac_UUIDS = new ArrayList();
Descriptor_UUIDs = new ArrayList();
if(status != gatt.GATT_SUCCESS){
return;
}else{
myServices = gatt.getServices();
for (BluetoothGattService service : myServices) {
for (BluetoothGattCharacteristic charac : service.getCharacteristics()) {
if (charac.getUuid().toString().contains("863930fc")) {
Service_UUIDs.add(charac.getService().getUuid().toString());
Charac_UUIDS.add(charac.getUuid().toString());
Descriptor_UUIDs.add(descriptor);
BluetoothGattDescriptor desc = charac.getDescriptor(descriptor);
gatt.setCharacteristicNotification(charac, true);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
}
}
}
Log.d("BLE_Assistance", "------ UUID Lists: " + Service_UUIDs + Charac_UUIDS + Descriptor_UUIDs);
}
}
};
}
I am not completely sure, I am also struggling with this kind of project right now and I am quite new to programming on Android. But I spotted a small mistake in your startScan and stopScan codes
bluetoothLeScanner.startScan(myScanCallBack);
Should be
bluetoothLeScanner.startScan(List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
with your scan filters and settings.
When you only send 'myScanCallback' to your 'bluetoothLeScanner.startScan', you're sending only default parameters with no filters.
https://developer.android.com/reference/android/bluetooth/le/BluetoothLeScanner.html#startScan(java.util.List%3Candroid.bluetooth.le.ScanFilter%3E,%20android.bluetooth.le.ScanSettings,%20android.bluetooth.le.ScanCallback)
This means that you're searching for every device, and not specifically the one you want.
For testing while powerdraw isn't an issue, you can also set your ScanSettings to LOW_LATENCY (LOW_POWER is more intuitive to use with BLE but not a requirement. You can switch it later when you want more battery life while scanning).
I hope it helps you
I do not know much about android. I am trying to send data over BLE.my code is as follows->. I got it from internet https://developer.android.com/guide/topics/connectivity/bluetooth-le#read
how to properly call this method-> mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);There is crash on this line.
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private final IBinder mBinder = new LocalBinder();
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000ffe9-0000-1000-8000-00805f9b34fb")) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
public static String byteToHexStr(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data
// parsing is carried out as per profile specifications.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
stringBuilder.toString());
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;/*return null;*/
}
//...
}
I am calling this class methods from outside like this->
public class DeviceScanActivity extends AppCompatActivity/*ListActivity*/ {
//private LeDeviceListAdapter mLeDeviceListAdapter;
public BluetoothAdapter mBluetoothAdapter;
public /*final*/ BluetoothManager mBluetoothManager;
/*=(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);;*/
private BluetoothLeService mBluetoothService;//= new BluetoothLeService();
public Context cntxt;
ArrayList<ViewHolder> arrayOfUsers2 = new ArrayList<ViewHolder>();
private boolean mScanning;
private boolean mBounded;
private Handler mHandler;
ArrayList<String> mylist = new ArrayList<String>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 50000;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 456;
UsersAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//getActionBar().setTitle("abc");
mHandler = new Handler();
//this.requestPermissions(rqPerm,req);
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
/*final BluetoothManager*/ mBluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null ) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
if( !mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(getIntent(), 1);
}
// Construct the data source
ArrayList<ViewHolder> arrayOfUsers = new ArrayList<ViewHolder>();
// Create the adapter to convert the array to views
adapter = new UsersAdapter(this, arrayOfUsers);
cntxt=this.getApplicationContext();
Intent i = new Intent(this, BluetoothLeService.class);
bindService(this.getIntent(), mConnection, BIND_AUTO_CREATE);; //if checked, start service
ListView listView = (ListView) findViewById(R.id.mobile_list);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ViewHolder entry= (ViewHolder) parent.getAdapter().getItem(position);
String address = entry.deviceAddress;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Toast.makeText(cntxt, address, Toast.LENGTH_SHORT).show();
//mBluetoothService.mBluetoothDeviceAddress=address;
//mBluetoothService.mBluetoothManager=mBluetoothManager;
mBluetoothService.mBluetoothAdapter = mBluetoothAdapter;
mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);
//Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
}});
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
}
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
//Toast.makeText(Client.this, "Service is disconnected", 1000).show();
mBounded = false;
mBluetoothService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
//Toast.makeText(Client.this, "Service is connected", 1000).show();
mBounded = true;
BluetoothLeService.LocalBinder mLocalBinder = (BluetoothLeService.LocalBinder)service;
mBluetoothService = mLocalBinder.getService();
}
};
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
adapter.add(newUser2);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
Iterator<ViewHolder> it=arrayOfUsers2.iterator();
while(it.hasNext()) {
ViewHolder currentX = it.next();
adapter.add(currentX);
}
// Do something with the value
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
//invalidateOptionsMenu();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, yay! Start the Bluetooth device scan.
scanLeDevice(true);
} else {
// Alert the user that this application requires the location permission to perform the scan.
}
}
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//mLeDeviceListAdapter.addDevice(device);
//mLeDeviceListAdapter.notifyDataSetChanged();
//ViewHolder newUser = new ViewHolder("Nathan", "San Diego");
String deviceName=null, deviceAddress=null;
if(device!=null)
deviceName= device.getName();
if (!(deviceName != null && deviceName.length() > 0))
deviceName = "unknown device";
if(device!=null)
deviceAddress= device.getAddress();
ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
ViewHolder newUser2 = new ViewHolder("adtv","vvg");
if(!arrayOfUsers2.contains(newUser))
arrayOfUsers2.add(newUser);
//adapter.add(newUser);
}
});
}
};
public class UsersAdapter extends ArrayAdapter<ViewHolder> {
public UsersAdapter(Context context, ArrayList<ViewHolder> users) {
super(context, 0, users);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
ViewHolder user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);
TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);
// Populate the data into the template view using the data object
tvName.setText(user.deviceName);
tvHome.setText(user.deviceAddress);
// Return the completed view to render on screen
return convertView;
}
}
public class ViewHolder {
String deviceName;
String deviceAddress;
public ViewHolder(String device, String __address) {
this.deviceName =device;
this.deviceAddress= __address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ViewHolder a = (ViewHolder) o;
return Objects.equals(deviceAddress, a.deviceAddress);
}
}
}
where I get scan device results in a list. On clicking anyelement of that list I invoke AdapterView.OnItemClickListener(). Then how to send message to the device. How to read those log messages. How to know if the code has send message. How to receive message in other device.I have already done BLE scan, which working fine.But not added the code here.
the log cat report is as follows
FATAL EXCEPTION: main
Process: com.example.root.securityalert, PID: 27945
java.lang.NullPointerException: Attempt to read from field 'android.bluetooth.BluetoothGattCallback com.example.root.securityalert.BluetoothLeService.mGattCallback' on a null object reference
at com.example.root.securityalert.DeviceScanActivity$1.onItemClick(DeviceScanActivity.java:115)
at android.widget.AdapterView.performItemClick(AdapterView.java:310)
at android.widget.AbsListView.performItemClick(AbsListView.java:1156)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3147)
at android.widget.AbsListView$3.run(AbsListView.java:4062)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6165)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
I also tried with the code
public class BluetoothSendRecv extends BluetoothGattCallback{
public BluetoothManager mBluetoothManager;
public BluetoothAdapter mBluetoothAdapter;
public String mBluetoothDeviceAddress;
public BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
// private final IBinder mBinder = new BluetoothLeService.LocalBinder();
public Context cntxt;
.......
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
// Various callback methods defined by the BLE API.
public final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
for (BluetoothGattService gattService : gatt.getServices()) {
Log.i(TAG, "onServicesDiscovered: ---------------------");
Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());
if (characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/)) {
Log.w(TAG, "onServicesDiscovered: found LED");
String originalString = "560D0F0600F0AA";
byte[] b = hexStringToByteArray(originalString);
characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
mBluetoothGatt.writeCharacteristic(characteristic);
//Toast.makeText(this., "R.string.error_bluetooth_not_supported", Toast.LENGTH_SHORT).show();
//finish()
System.out.println("Writing Mithun");
Toast.makeText(cntxt, originalString, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
}
}
}
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
byte[] data = characteristic.getValue();
System.out.println("reading");
System.out.println(new String(data));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
//...
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
//sendBroadcast(intent);
}
.....
}
Then logcat report is as follows aaaa
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=CC:1E:39:39:62:1C
I/ContentValues: Connected to GATT server.
D/BluetoothGatt: discoverServices() - device: CC:1E:39:39:62:1C
I/ContentValues: Attempting to start service discovery:true
D/BluetoothGatt: onSearchComplete() = Device=CC:1E:39:39:62:1C Status=0
I/ContentValues: onServicesDiscovered: ---------------------
I/ContentValues: onServicesDiscovered: service=00001800-0000-1000-8000-00805f9b34fb
I/ContentValues: onServicesDiscovered: characteristic=00002a00-0000-1000-8000-00805f9b34fb
I think this condition is not fullfilled
if(characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/))
I think you must add "Scan" method before try connect.This is rule of ble architecture.Like this :
private void startScanning(final boolean enable, BluetoothAdapter mBluetoothAdapter) {
bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
List<ScanFilter> scanFilters = new ArrayList<>();
final ScanSettings settings = new ScanSettings.Builder().build();
ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(UUID_SERVICE)).build();
scanFilters.add(scanFilter);
bluetoothLeScanner.startScan(scanFilters, settings, scanCallback);
}
And if Ble Device is founded :
ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
bluetoothDevice = result.getDevice();
Log.d(TAG, "onScanResult: bluetoothDevice.getAddress());
mScanning = false;
String adress = bluetoothDevice.getAddress();
bluetoothLeScanner.stopScan(scanCallback);
connect(bluetoothDevice);
}
i'm trying to pass one array
[the array is inizialized by me {1,2,3,4} and i associate the string "txx"]
between two activity but i recive this error
java.lang.runtimeexception: unable to start activity
componentinfo{com.example.android.bluetoothlegatt/com.example.android.bluetoothlegatt.graphcurrentactivity}:
java.lang.nullpointerexception: attempt to read from null array
from debug mode i see that this array doesn't pass between two activity. i think that there can be an error in delcaration private/public variable..
please help me
activity A
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static String EXTRA_DATA2 =
"com.example.bluetooth.le.EXTRA_DATA2";
public final static String EXTRA_DATA3 =
"com.example.bluetooth.le.EXTRA_DATA3";
public final static String EXTRA_DATA4 =
"com.example.bluetooth.le.EXTRA_DATA4";
public final static String EXTRA_DATA5 =
"com.example.bluetooth.le.EXTRA_DATA5";
public final static String EXTRA_DATA6 =
"com.example.bluetooth.le.EXTRA_DATA6";
public final static String EXTRA_DATA7 =
"com.example.bluetooth.le.EXTRA_DATA7";
byte[] value;
int[] data_info = new int[6];
public int[] grap_curr = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_volt = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_temp = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_soc = new int[] {0,0,0,0,0,0,0,0,0,0};
public int[] grap_soh = new int[] {0,0,0,0,0,0,0,0,0,0};
int i = 0;
int j = 0;
public final static UUID UUID_USER_DATA =
UUID.fromString(SampleGattAttributes.FIRST_NAME);
public ArrayList<String> receivedPackets = new ArrayList<String>();
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
/* Creo le Intent per passare i dati da visualizzare sui grafici alle altre classi */
Intent intentCurr = new Intent(getApplicationContext(), GraphCurrentActivity.class);
//final Intent intentVolt = new Intent(getApplicationContext(), GraphVoltageActivity.class);
//final Intent intentTemp = new Intent(getApplicationContext(), GraphTempActivity.class);
//final Intent intentSoC = new Intent(getApplicationContext(), GraphSoCActivity.class);
//final Intent intentSoH = new Intent(getApplicationContext(), GraphSoHActivity.class);
if (UUID_USER_DATA.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Value format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Value format UINT8.");
}
value = characteristic.getValue();
ByteBuffer bb = ByteBuffer.wrap(value);
bb.order(ByteOrder.LITTLE_ENDIAN);
i++;
if (value != null && value.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(value.length);
for(byte byteChar : value)
stringBuilder.append(String.format("%02X ", byteChar));
//su value ho la stringa ricevuta, quindi posso elaborare il dato per far si che leggo sulla app quello che voglio
Byte b5 = value[5];
Byte b6 = value[6];
Byte b7 = value[7];
data_info[0] = ((value[1] << 8) | (value [2] & 0xFF));//current
data_info[1] = ((value[3] << 8) | (value [4] & 0xFF));//voltage
data_info[2] = b5.intValue();//soc
data_info[3] = b6.intValue();//temp
data_info[4] = b7.intValue();//soh
data_info[5] = ((value[8] << 8) | (value [9] & 0xFF));
//preparo i dati da passare alle alre activity
grap_curr[j]=data_info[2];
grap_volt[j]=data_info[2];
grap_temp[j]=data_info[2];
grap_soc[j]=data_info[2];
grap_soh[j]=data_info[2];
j++;
//dopo 10 cicli invio ai grafici
if (j==3){
intent.putExtra(EXTRA_DATA7, "Riepilogo temporale disponibile");
Bundle curr =new Bundle (); //array da mandare alla activity GraphCurrentActivity
curr.putIntArray("txxx",new int[] {1,2,3,4});
intentCurr.putExtras(curr);
//intentCurr.putExtra("tx",grap_curr);
//intentCurr.putExtra("datavectorcurr",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentVolt.putExtra("datavectorvolt",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentTemp.putExtra("datavectortemp",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentSoC.putExtra("datavectorsoc",new int[] {1,2,3,4,5,6,7,8,9,10});
//intentSoH.putExtra("datavectorsoh",new int[] {1,2,3,4,5,6,7,8,9,10});
j=0;
}
//inserisco i dati negli appositi campi
intent.putExtra(EXTRA_DATA, "Battery Current: " + Integer.toString(data_info[0]) + " [A]" );
intent.putExtra(EXTRA_DATA2, "Battery Voltage: " + Integer.toString(data_info[1]) + " [V]" );
intent.putExtra(EXTRA_DATA3, "SOC: " + Integer.toString(data_info[2]) + " [Ah]" );
intent.putExtra(EXTRA_DATA4, "SOH: " + Integer.toString(data_info[4]) + " [%]");
intent.putExtra(EXTRA_DATA5, "average temperature: " + Integer.toString(data_info[3]) + " [°C]");
intent.putExtra(EXTRA_DATA6, "remaining capacity: " + Integer.toString(data_info[5]) + " [°Ah]");
}
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_USER_DATA.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public void readCustomCharacteristic() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000181c-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
BluetoothGattCharacteristic mNotifyCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002a8a-0000-1000-8000-00805f9b34fb"));
UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor descriptor = mNotifyCharacteristic.getDescriptor(uuid);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
//To receive notification in Android is mandatory to set characteristic notification to true
mBluetoothGatt.setCharacteristicNotification(mNotifyCharacteristic, true);
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002A8A-0000-1000-8000-00805F9B34FB"));
if(mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false){
Log.w(TAG, "Failed to read characteristic");
}
}
public void writeCustomCharacteristic(int value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000181c-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the write characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002a8a-0000-1000-8000-00805f9b34fb"));
mWriteCharacteristic.setValue(value,android.bluetooth.BluetoothGattCharacteristic.FORMAT_UINT8,0);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false){
Log.w(TAG, "Failed to write characteristic");
}
}
}
activty B
public class GraphCurrentActivity extends Activity {
private XYPlot plot;
private GoogleApiClient client;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
// initialize our XYPlot reference:
plot = (XYPlot) findViewById(R.id.plot);
Bundle b=this.getIntent().getExtras();
int[] arraydata;
arraydata = b.getIntArray("txxx");//array that i don't recive
// create a couple arrays of y-values to plot:
final Number[] domainLabels = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//Number[] series1Numbers = {plottdata[0], plottdata[1], plottdata[2], plottdata[3], plottdata[4], plottdata[5], plottdata[6], plottdata[7], plottdata[8], plottdata[9]};
Number[] series1Numbers = {11, 12, 13, 14, 0, 5, 8, 7, 1, 11};
// turn the above arrays into XYSeries':
// (Y_VALS_ONLY means use the element index as the x value)
XYSeries series1 = new SimpleXYSeries(
Arrays.asList(series1Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Battery Current Plot");
LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.RED, Color.GREEN, Color.BLUE, null);
series1Format.setInterpolationParams(
new CatmullRomInterpolator.Params(10, CatmullRomInterpolator.Type.Centripetal));
// add a new series' to the xyplot:
plot.addSeries(series1, series1Format);
plot.getGraph().getLineLabelStyle(XYGraphWidget.Edge.BOTTOM).setFormat(new Format() {
#Override
public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
int i = Math.round(((Number) obj).floatValue());
return toAppendTo.append(domainLabels[i]);
}
#Override
public Object parseObject(String source, ParsePosition pos) {
return null;
}
});
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("GraphCurrent Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
#Override
public void onStart() {
super.onStart();
client.connect();
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
#Override
public void onStop() {
super.onStop();
AppIndex.AppIndexApi.end(client, getIndexApiAction());
client.disconnect();
}
}
Best solution I can suggest is define your array as
public static int[] xyz=new int[]{1,2,3,4};
And now that static int array can be called or used from any activity provided if they are in the same package.
Here for your example in GraphCurrentActivity,
Add this import statement:
import static yourpackagename.BluetoothLeService.xyz;
//And these lines to read that array:
int[] arraydata;
arraydata = xyz;
And let me know if this was wrong.
I am developing an Android app to control stepper motors via a Android Due and a Bluetooth HM-10 BLE module.
So far everything works, but there seems to be a problem on some devices, which cause the app to crash. On my Nexus 5 and 7 it is working fine, but for example on a Samsung Galaxy S5 it keeps crashing. All devices have Andoird 6.0.1, so they should be equal.
I am getting this error report from the user:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattCharacteristic.setValue(byte[])' on a null object reference
at pm.puremoco.BluetoothLeService.WriteValue(BluetoothLeService.java:70)
at pm.puremoco.frag_moviesetlinear$3.onFinish(frag_moviesetlinear.java:266)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
So the error is occuring, when opening, at "onCreateView". There is the command to transmit a value:
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
Here is almost the full fragment:
public class frag_moviesetlinear extends Fragment {
public static final String methodtocall = "ooo";
private final static String TAG = DeviceControlFragment.class.getSimpleName();
public AlertDialog alertTransmitData;
public BluetoothLeService mBluetoothLeService; //TODO evtl. private
public String methodcalled = "aaa";
public String dataLineReceived;
public long countDownTimerDelay = 200;
public AlertDialog alertTimeTooShort;
NumberPicker noPick1 = null;
NumberPicker noPick2 = null;
NumberPicker noPick3 = null;
long alertTransmitDataLength = 21000;
DeviceControlFragment devConFrag;
double minTimeFactor = 0;
TextView vid_maxSpeedU;
TextView vid_maxSpeedV;
TextView vid_maxSpeedW;
TextView vid_maxSpeedX;
TextView vid_maxSpeedY;
TextView vid_maxSpeedZ;
TextView vid_maxSpeedUspline;
TextView vid_maxSpeedVspline;
TextView vid_maxSpeedWspline;
TextView vid_maxSpeedXspline;
TextView vid_maxSpeedYspline;
TextView vid_maxSpeedZspline;
TextView txt_vidDuration;
TextView txt_vidUpdateIntervall;
TextView txt_minTime;
int timeForCalculation = 0;
int calculatedSpeedU = 0;
int calculatedSpeedV = 0;
int calculatedSpeedW = 0;
int calculatedSpeedX = 0;
int calculatedSpeedY = 0;
int calculatedSpeedZ = 0;
boolean movingHome = false;
private String mDeviceAddress;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
getActivity().finish();
}
Log.e(TAG, "mBluetoothLeService is okay");
// Log.e(TAG, mDeviceAddress);
// Automatically connects to the device upon successful start-up initialization.
if (mDeviceAddress == "---") {
Toast.makeText(getActivity(), "Bluetooth-Device not selected!", Toast.LENGTH_SHORT).show();
} else {
mBluetoothLeService.connect(mDeviceAddress);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private String mDeviceName;
private TextView mDataField;
private Button btn_vidSplineStart;
private Button btn_vidUpdateIntervalNeg;
private Button btn_vidUpdateIntervalPos;
private boolean mConnected = false;
// Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.
// ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read
// or notification operations.
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //���ӳɹ�
Log.e(TAG, "Only gatt, just wait");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { //�Ͽ�����
mConnected = false;
getActivity().invalidateOptionsMenu();
// btnSend.setEnabled(false);
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) //���Կ�ʼ�ɻ���
{
mConnected = true;
// mDataField.setText("");
// ShowDialog();
//btnSend.setEnabled(true);
Log.e(TAG, "In what we need");
getActivity().invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { //�յ�����
Log.e(TAG, "RECV DATA");
final String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);
Log.e(TAG, data);
if (data != null && data.substring(0, 1).equals("#") && data.substring(data.length() - 1).equals("$")) {
// if (mDataField.length() > 500)
// mDataField.setText("");
// mDataField.append(data);
dataLineReceived = data.substring(1, data.length() - 1);
ActionHandlerDataReceived();
}
}
}
};
private static IntentFilter makeGattUpdateIntentFilter() { //ע����յ��¼�
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(BluetoothDevice.ACTION_UUID);
return intentFilter;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final Intent intent = getActivity().getIntent();
// mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
// mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
mDeviceAddress = variables.BluetoothAddress;
mDeviceName = variables.BluetoothName;
methodcalled = intent.getStringExtra(methodtocall);
Intent gattServiceIntent = new Intent(getActivity(), BluetoothLeService.class);
Log.d(TAG, "Try to bindService=" + getActivity().bindService(gattServiceIntent, mServiceConnection, getActivity().BIND_AUTO_CREATE));
getActivity().registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#Override
public void onPause() {
super.onPause();
try {
getActivity().unregisterReceiver(mGattUpdateReceiver);
}
catch(Exception e){
}
try {
getActivity().unbindService(mServiceConnection);
}
catch(Exception e){
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "We are in destroy");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.setmovie, null);
vid_maxSpeedU = (TextView) layout.findViewById(R.id.vid_maxSpeedU);
vid_maxSpeedU.setText(String.valueOf(variables.speedU));
vid_maxSpeedV = (TextView) layout.findViewById(R.id.vid_maxSpeedV);
vid_maxSpeedV.setText(String.valueOf(variables.speedV));
vid_maxSpeedW = (TextView) layout.findViewById(R.id.vid_maxSpeedW);
vid_maxSpeedW.setText(String.valueOf(variables.speedW));
vid_maxSpeedX = (TextView) layout.findViewById(R.id.vid_maxSpeedX);
vid_maxSpeedX.setText(String.valueOf(variables.speedX));
vid_maxSpeedY = (TextView) layout.findViewById(R.id.vid_maxSpeedY);
vid_maxSpeedY.setText(String.valueOf(variables.speedY));
vid_maxSpeedZ = (TextView) layout.findViewById(R.id.vid_maxSpeedZ);
vid_maxSpeedZ.setText(String.valueOf(variables.speedZ));
double duration = 3700 * (double) variables.vidUpdateIntervall / 1000;
txt_vidUpdateIntervall = (TextView) layout.findViewById(R.id.txt_vidUpdateIntervall);
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
txt_vidDuration = (TextView) layout.findViewById(R.id.txt_vidDuration);
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
vid_maxSpeedUspline = (TextView) layout.findViewById(R.id.vid_maxSpeedUspline);
vid_maxSpeedVspline = (TextView) layout.findViewById(R.id.vid_maxSpeedVspline);
vid_maxSpeedWspline = (TextView) layout.findViewById(R.id.vid_maxSpeedWspline);
vid_maxSpeedXspline = (TextView) layout.findViewById(R.id.vid_maxSpeedXspline);
vid_maxSpeedYspline = (TextView) layout.findViewById(R.id.vid_maxSpeedYspline);
vid_maxSpeedZspline = (TextView) layout.findViewById(R.id.vid_maxSpeedZspline);
txt_minTime = (TextView) layout.findViewById(R.id.txt_minTime);
btn_vidSplineStart = (Button) layout.findViewById(R.id.btn_vidSplineStart);
btn_vidSplineStart.setOnClickListener(new event_btn_vidSplineStart());
btn_vidUpdateIntervalPos = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalPos);
btn_vidUpdateIntervalPos.setOnClickListener(new event_btn_vidUpdateIntervalPos());
btn_vidUpdateIntervalNeg = (Button) layout.findViewById(R.id.btn_vidUpdateIntervalNeg);
btn_vidUpdateIntervalNeg.setOnClickListener(new event_btn_vidUpdateIntervalNeg());
//-----start-button------
minTimeFactor = 0;
timeForCalculation = variables.vidUpdateIntervall;
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
mBluetoothLeService.WriteValue("2000_" + String.valueOf(variables.linearWithFade) + "#");
}
}.start();
//-----start-button------
transmitDataAlert("calculation");
return layout;
}
private void ActionHandlerDataReceived() {
String variable;
String value;
String[] parts = dataLineReceived.split("_"); // escape .
variable = parts[0];
value = parts[1];
switch (variable) {
case "vidMaxSpeedU":
vid_maxSpeedUspline.setText(String.valueOf(value));
variables.vid_maxSpeedUspline = Integer.parseInt(value);
calculatedSpeedU = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorU = Double.valueOf(value) / variables.speedU;
if (minTimeFactor < FactorU) {
minTimeFactor = FactorU;
}
break;
case "vidMaxSpeedV":
vid_maxSpeedVspline.setText(String.valueOf(value));
variables.vid_maxSpeedVspline = Integer.parseInt(value);
calculatedSpeedV = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorV = Double.valueOf(value) / variables.speedV;
if (minTimeFactor < FactorV) {
minTimeFactor = FactorV;
}
break;
case "vidMaxSpeedW":
vid_maxSpeedWspline.setText(String.valueOf(value));
variables.vid_maxSpeedWspline = Integer.parseInt(value);
calculatedSpeedW = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorW = Double.valueOf(value) / variables.speedW;
if (minTimeFactor < FactorW) {
minTimeFactor = FactorW;
}
break;
case "vidMaxSpeedX":
vid_maxSpeedXspline.setText(String.valueOf(value));
variables.vid_maxSpeedXspline = Integer.parseInt(value);
calculatedSpeedX = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorX = Double.valueOf(value) / variables.speedX;
if (minTimeFactor < FactorX) {
minTimeFactor = FactorX;
}
break;
case "vidMaxSpeedY":
vid_maxSpeedYspline.setText(String.valueOf(value));
variables.vid_maxSpeedYspline = Integer.parseInt(value);
calculatedSpeedY = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorY = Double.valueOf(value) / variables.speedY;
if (minTimeFactor < FactorY) {
minTimeFactor = FactorY;
}
break;
case "vidMaxSpeedZ":
vid_maxSpeedZspline.setText(String.valueOf(value));
variables.vid_maxSpeedZspline = Integer.parseInt(value);
calculatedSpeedZ = Integer.parseInt(value);
if (Integer.parseInt(value) > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
double FactorZ = Double.valueOf(value) / variables.speedZ;
if (minTimeFactor < FactorZ) {
minTimeFactor = FactorZ;
}
alertTransmitData.dismiss();
double vidMin = Math.ceil(minTimeFactor * timeForCalculation);
variables.vidMinIntervall = (int) vidMin;
//txt_minTime.setText(String.valueOf(variables.vidMinIntervall));
double duration = (3700 * (double) variables.vidMinIntervall) / 1000;
txt_minTime.setText(String.format("%.2f", duration) + " s");
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
break;
case "movieFinished":
btn_vidSplineStart.setText("Move home");
btn_vidSplineStart.setEnabled(true);
movingHome = true;
alertTransmitData.dismiss();
break;
case "movieHome":
btn_vidSplineStart.setText("Start");
btn_vidSplineStart.setEnabled(true);
alertTransmitData.dismiss();
break;
}
}
void calculateNewSpeeds() {
//--------------U-Axis-----------------
if (variables.vid_maxSpeedUspline != 0) {
variables.vid_maxSpeedUspline = (timeForCalculation * calculatedSpeedU) / variables.vidUpdateIntervall;
vid_maxSpeedUspline.setText(String.valueOf(variables.vid_maxSpeedUspline));
if (variables.vid_maxSpeedUspline > variables.speedU) {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedUspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------V-Axis-----------------
if (variables.vid_maxSpeedVspline != 0) {
variables.vid_maxSpeedVspline = (timeForCalculation * calculatedSpeedV) / variables.vidUpdateIntervall;
vid_maxSpeedVspline.setText(String.valueOf(variables.vid_maxSpeedVspline));
if (variables.vid_maxSpeedVspline > variables.speedV) {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedVspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------W-Axis-----------------
if (variables.vid_maxSpeedWspline != 0) {
variables.vid_maxSpeedWspline = (timeForCalculation * calculatedSpeedW) / variables.vidUpdateIntervall;
vid_maxSpeedWspline.setText(String.valueOf(variables.vid_maxSpeedWspline));
if (variables.vid_maxSpeedWspline > variables.speedW) {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedWspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------X-Axis-----------------
if (variables.vid_maxSpeedXspline != 0) {
variables.vid_maxSpeedXspline = (timeForCalculation * calculatedSpeedX) / variables.vidUpdateIntervall;
vid_maxSpeedXspline.setText(String.valueOf(variables.vid_maxSpeedXspline));
if (variables.vid_maxSpeedXspline > variables.speedX) {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedXspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Y-Axis-----------------
if (variables.vid_maxSpeedYspline != 0) {
variables.vid_maxSpeedYspline = (timeForCalculation * calculatedSpeedY) / variables.vidUpdateIntervall;
vid_maxSpeedYspline.setText(String.valueOf(variables.vid_maxSpeedYspline));
if (variables.vid_maxSpeedYspline > variables.speedY) {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedYspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
//--------------Z-Axis-----------------
if (variables.vid_maxSpeedZspline != 0) {
variables.vid_maxSpeedZspline = (timeForCalculation * calculatedSpeedZ) / variables.vidUpdateIntervall;
vid_maxSpeedZspline.setText(String.valueOf(variables.vid_maxSpeedZspline));
if (variables.vid_maxSpeedZspline > variables.speedZ) {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FFFF3434"));
} else {
vid_maxSpeedZspline.setTextColor(Color.parseColor("#FF14AA00"));
}
}
}
public void alert_TimeTooShort(int errorCase, int movieLengthSecondsNEW) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
getActivity());
// set title
alertDialogBuilder.setTitle("Error");
String errorMessage = "error";
// set dialog message
alertDialogBuilder
.setMessage(errorMessage)
.setCancelable(false);
alertDialogBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
}
});
// create alert dialog
alertTimeTooShort = alertDialogBuilder.create();
// show it
alertTimeTooShort.show();
}
public void transmitDataAlert(String type) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View promptView = layoutInflater.inflate(R.layout.alert_transmitdata, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setView(promptView);
final ProgressBar progressbar = (ProgressBar) promptView.findViewById(R.id.progressBar_transmitData);
final TextView txt_PleaseWait = (TextView) promptView.findViewById(R.id.txt_PleaseWait);
final TextView txt_timeRemainVideo = (TextView) promptView.findViewById(R.id.txt_timeRemainVideo);
final TextView txt_timeRemainVideoTXT = (TextView) promptView.findViewById(R.id.txt_timeRemainVideoTXT);
new CountDownTimer(alertTransmitDataLength, 1) {
public void onTick(long millisUntilFinished) {
int longtointRemain = (int) millisUntilFinished;
int longtointFull = (int) alertTransmitDataLength;
int percentprogress = 100 - ((100 * longtointRemain) / longtointFull);
progressbar.setProgress(percentprogress);
float duration = (float) millisUntilFinished/1000;
txt_timeRemainVideo.setText(String.format("%.1f", duration) + " s");
}
public void onFinish() {
}
}.start();
}
alertDialogBuilder.setCancelable(false);
alertTransmitData = alertDialogBuilder.create();
alertTransmitData.show();
}
class event_btn_vidSplineStart implements View.OnClickListener {
#Override
public void onClick(View v) {
btn_vidSplineStart.setEnabled(false);
btn_vidSplineStart.setText("Moving...");
new CountDownTimer(countDownTimerDelay * 1, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1900_" + String.valueOf(variables.vidUpdateIntervall) + "#");
}
}.start();
new CountDownTimer(countDownTimerDelay * 2, 1) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//MotionMode
mBluetoothLeService.WriteValue("1110_0#");
}
}.start();
alertTransmitDataLength = (long) variables.vidUpdateIntervall*3700;
if(movingHome==true){
transmitDataAlert("moveHome");
movingHome=false;
}
else {
transmitDataAlert("videomove");
}
}
}
class event_btn_vidUpdateIntervalPos implements View.OnClickListener {
#Override
public void onClick(View v) {
variables.vidUpdateIntervall++;
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
class event_btn_vidUpdateIntervalNeg implements View.OnClickListener {
#Override
public void onClick(View v) {
if (variables.vidUpdateIntervall > 1) {
variables.vidUpdateIntervall--;
}
double duration = (3700 * (double) variables.vidUpdateIntervall) / 1000;
txt_vidDuration.setText(String.format("%.2f", duration) + " s");
txt_vidUpdateIntervall.setText(String.valueOf(variables.vidUpdateIntervall));
calculateNewSpeeds();
if(variables.vidMinIntervall<=variables.vidUpdateIntervall) {
btn_vidSplineStart.setEnabled(true);
}
else{
btn_vidSplineStart.setEnabled(false);
}
}
}
}
And here is the full BluetoothLeService, which I got from the website of the HM-10 Bluetooth manufacturer:
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.util.List;
import java.util.UUID;
/**
* Service for managing connection and data communication with a GATT server hosted on a
* given Bluetooth LE device.
*/
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_NOTIFY =
UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_SERVICE =
UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
public BluetoothGattCharacteristic mNotifyCharacteristic;
public void WriteValue(String strValue)
{
mNotifyCharacteristic.setValue(strValue.getBytes());
mBluetoothGatt.writeCharacteristic(mNotifyCharacteristic);
}
public void findService(List<BluetoothGattService> gattServices)
{
Log.i(TAG, "Count is:" + gattServices.size());
for (BluetoothGattService gattService : gattServices)
{
Log.i(TAG, gattService.getUuid().toString());
Log.i(TAG, UUID_SERVICE.toString());
if(gattService.getUuid().toString().equalsIgnoreCase(UUID_SERVICE.toString()))
{
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
Log.i(TAG, "Count is:" + gattCharacteristics.size());
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics)
{
if(gattCharacteristic.getUuid().toString().equalsIgnoreCase(UUID_NOTIFY.toString()))
{
Log.i(TAG, gattCharacteristic.getUuid().toString());
Log.i(TAG, UUID_NOTIFY.toString());
mNotifyCharacteristic = gattCharacteristic;
setCharacteristicNotification(gattCharacteristic, true);
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
return;
}
}
}
}
}
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
Log.i(TAG, "oldStatus=" + status + " NewStates=" + newState);
if(status == BluetoothGatt.GATT_SUCCESS)
{
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mBluetoothGatt.close();
mBluetoothGatt = null;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "onServicesDiscovered received: " + status);
findService(gatt.getServices());
} else {
if(mBluetoothGatt.getDevice().getUuids() == null)
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int status)
{
Log.e(TAG, "OnCharacteristicWrite");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorRead");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor bd,
int status) {
Log.e(TAG, "onDescriptorWrite");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int a, int b)
{
Log.e(TAG, "onReadRemoteRssi");
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int a)
{
Log.e(TAG, "onReliableWriteCompleted");
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
//final StringBuilder stringBuilder = new StringBuilder(data.length);
//for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
//intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
intent.putExtra(EXTRA_DATA, new String(data));
}
sendBroadcast(intent);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
/*
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
*/
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
if(mBluetoothGatt != null)
{
mBluetoothGatt.close();
mBluetoothGatt = null;
}
mBluetoothGatt = device.connectGatt(this.getApplication(), false, mGattCallback);
//mBluetoothGatt.connect();
Log.d(TAG, "Trying to create a new connection.");
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
/*
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
*/
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables or disables notification on a give characteristic.
*
* #param characteristic Characteristic to act on.
* #param enabled If true, enable notification. False otherwise.
*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
/*
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
*/
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
}