Saving ID and RSSI of visible iBeacons every 0.5seconds - android

Good Day,
I want to scan continuously (every 0.5 seconds) for iBeacons in Android and save the ID and RSSI for this timestamp in a file.
Any ideas what's the smartest way to implement the scanning?
Thanks

I would start with the Android Beacon Library reference app here. Out of the box, this will allow you to scan every 1 second using the RangingActivity.
You can then modify that code to scan every 0.5 seconds by adding two lines to this method:
#Override
public void onBeaconServiceConnect() {
...
beaconManager.setForegroundScanPeriod(500l);
beaconManager.updateScanPeriods();
...
}
Then you can write the results to a file by modifying this method:
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
...
File file = new File(RangingActivity.this.getFilesDir(), "scanned-beacons.txt");
FileWriter fw = null;
try {
fw = new FileWriter(file);
for (Beacon beacon : beacons) {
StringBuilder line = new StringBuilder();
line.append(System.currentTimeMillis()); // timestamp
line.append(",");
line.append(beacon.toString());
line.append(",");
line.append(beacon.getRssi());
fw.write(line.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
...
}

For everyone who uses SensorTags or BLE devices which are not supported by the Android Beacon Library.
I just did it like that:
Here I search for BLE devices with the name "SensorTag".
public class MainActivity extends AppCompatActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 0.2 seconds.
private static final long SCAN_PERIOD = 200;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mLeDeviceListAdapter.printBeacons();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter {
private ArrayList<Beacon> mLeDevices;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<Beacon>();
}
public void printBeacons() {
for (int i = 0; i< mLeDevices.size(); i++) {
System.out.println("Beacon " + mLeDevices.get(i).address + ", Signal: " + mLeDevices.get(i).rssi +", Timestamp: " + mLeDevices.get(i).timestamp);
}
}
public boolean test( Beacon beacon) {
for(int i = 0; i< mLeDevices.size(); i++){
if (mLeDevices.get(i).address.equalsIgnoreCase(beacon.address)){
return true;
}
}
return false;
}
public void addDevice(Beacon beacon) {
if(!test(beacon)) {
mLeDevices.add(beacon);
}
else{
for(int i =0; i<mLeDevices.size(); i++){
if(mLeDevices.get(i).address.equalsIgnoreCase(beacon.address)){
mLeDevices.set(i, beacon);
}
}
}
}
public Beacon getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
public int getCount() {
return mLeDevices.size();
}
public Object getItem(int i) {
return mLeDevices.get(i);
}
public long getItemId(int i) {
return i;
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(device.getName()!= null || device.getName() == "SensorTag"){
Beacon beacon = new Beacon(device.getAddress(), rssi, System.currentTimeMillis());
mLeDeviceListAdapter.addDevice(beacon);
}
}
});
}
};
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
//setListAdapter(mLeDeviceListAdapter);
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
scanLeDevice(true);
mLeDeviceListAdapter.clear();
}
};
//start new Scan Period every second
timer.scheduleAtFixedRate(task, 0 , 1000);
}
}
}
And thats the class Beacon, which represents a Beacon with an address, rssi and the timestamp the beacon was last seen.
public class Beacon {
public String address;
public int rssi;
public long timestamp;
public Beacon(String address, int rssi, long timestamp){
this.address = address;
this.rssi = rssi;
this.timestamp=timestamp;
}
}
The code is simplified.
Greetings
Max

Related

Problem in scanning Bluetooth LE devices (no callback)

I am trying to develop an Android app capable to connect to a BLE device. But i have a problem to find ble devices. The scanLeDevice methods run but I have no callback. You can find my code below: I use Log.i() to display ble devices.
With another app (downloaded from the store) I can find my ble device and others bluetooth around. So It's not my phone's problem.
Thanks for help!
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter;
private final int REQUEST_ENABLE_BT = 1;
private boolean mScanning;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity", "Begin");
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Log.i("MainActivity", "End for permissions");
if(Build.VERSION.SDK_INT < 21){
scanLeDevice(true);
}else{
scanDevice(true);
}
}
private Handler handler = new Handler();
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
bluetoothAdapter.startLeScan(leScanCallback);
Log.i("MainActivity", "scanning");
} else {
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback leScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Ici///////////////////////////////////////
Log.i("MainActivity", "Nam: "+device.getName()+" Adresse: "+device.getAddress());
if(device.getName() != null && device.getName().equals("RN4871-85D7"))
scanLeDevice(false);
}
});
}
};
///////////////////Scan for API 21
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothLeScanner mLEScanner;
private void scanDevice(final boolean enable){
if (mLEScanner==null){
mLEScanner = bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
}
if (enable) {
if (mScanning) return;
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!mScanning) return;
try {
mScanning = false;
//Log.d("MainActivity","STOP SCAN AFTER DELAY");
mLEScanner.stopScan(mScanCallback);
Log.i("MainActivity", "stop scanning API 21");
} catch (Exception e){Log.e("MainActivity",e.getMessage());}
}
}, SCAN_PERIOD);
mScanning = true;
//Log.d("MainActivity","START SCAN FROM EXPLICIT CALL");
mLEScanner.startScan(filters, settings, mScanCallback);
Log.i("MainActivity", "scanning API 21");
} else if (mLEScanner!=null){
if (!mScanning) return;
mScanning = false;
try {
//Log.d("MainActivity","STOP SCAN FROM EXPLICIT CALL");
mLEScanner.stopScan(mScanCallback);
Log.i("MainActivity", "stop scanning API 21");
} catch (Exception e){Log.i("MainActivity",e.getMessage());}
}
}
//call back for API 21
//#TargetApi(21)
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i("MainActivity", "onScanResult API 21");
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.i("MainActivity", "onBatchScanResults API 21");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.i("MainActivity", "onScanFailed API 21");
}
};
}
Thanks for your help``
I found what was the problem about the location.
In fact, if you work with a API >= 23, you have to authorize you app to access to the location (not only in the Manifest file, but in you code it self).
So if you have the same problem:
First, manualy, go to your phon's setting and autorize your app to access to location: to be sure that was the problem.
Then add the code below so that, The application ask the user to authorize the application to access the location
/////////////////////////Location/////
#TargetApi(Build.VERSION_CODES.M)
private void loadPermissions(String perm,int requestCode) {
if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) {
ActivityCompat.requestPermissions(this, new String[]{perm},requestCode);
}
} else if (checkLocationEnabled())
initScanner();
}
private boolean checkLocationEnabled(){
LocationManager lm = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
boolean gps_enabled = false;
boolean network_enabled = false;
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch(Exception ex) {}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch(Exception ex) {}
if(!gps_enabled && !network_enabled) {
// notify user
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setMessage("GPS desabled");
dialog.setPositiveButton("Open GPS settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// TODO Auto-generated method stub
Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
//get gps
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// TODO Auto-generated method stub
}
});
dialog.show();
return false;
} else return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// granted
if (checkLocationEnabled())
initScanner();
}
else{
// no granted
}
return;
}
}
}
I had this problem too because I was using ACCESS_COARSE_LOCATION on the permission.
When I changed to ACCESS_FINE_LOCATION, it finally works for me!

Read and notify BLE android

I wrote a code in which I am able to read a notify value from a hear rate sensor when it changes.
But I need also to read the battery level of the device, which is another service from the emulated device, but whenever I try to read the battery value, the first part don't even send the notify values from the heart rate.
Here is the code:
public class MainActivity extends AppCompatActivity {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
Button startScanningButton;
Button stopScanningButton;
TextView peripheralTextView;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
Boolean btScanning = false;
int deviceIndex = 0;
ArrayList<BluetoothDevice> devicesDiscovered = new ArrayList<BluetoothDevice>();
EditText deviceIndexInput;
Button connectToDevice;
Button disconnectDevice;
BluetoothGatt bluetoothGatt;
UUID HEART_RATE_SERVICE_UUID = convertFromInteger(0x180D);
UUID HEART_RATE_MEASUREMENT_CHAR_UUID = convertFromInteger(0x2A37);
UUID HEART_RATE_CONTROL_POINT_CHAR_UUID = convertFromInteger(0x2A39);
UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = convertFromInteger(0x2902);
UUID BATTERY_LEVEL = convertFromInteger(0x2A19);
UUID BATTERY_SERVICE = convertFromInteger(0x180F);
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 Map<String, String> uuids = new HashMap<String, String>();
// Stops scanning after 5 seconds.
private Handler mHandler = new Handler();
private static final long SCAN_PERIOD = 1000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
peripheralTextView.setMovementMethod(new ScrollingMovementMethod());
deviceIndexInput = (EditText) findViewById(R.id.InputIndex);
deviceIndexInput.setText("0");
connectToDevice = (Button) findViewById(R.id.ConnectButton);
connectToDevice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
connectToDeviceSelected();
}
});
disconnectDevice = (Button) findViewById(R.id.DisconnectButton);
disconnectDevice.setVisibility(View.INVISIBLE);
disconnectDevice.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
disconnectDeviceSelected();
}
});
startScanningButton = (Button) findViewById(R.id.StartScanButton);
startScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startScanning();
}
});
stopScanningButton = (Button) findViewById(R.id.StopScanButton);
stopScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
stopScanning();
}
});
stopScanningButton.setVisibility(View.INVISIBLE);
btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
btScanner = btAdapter.getBluetoothLeScanner();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
/* if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect peripherals.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}*/
//client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
// Device scan callback.
private ScanCallback leScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
peripheralTextView.append("Index: " + deviceIndex + ", Device Name: " + result.getDevice().getName() + " rssi: " + result.getRssi() + ", MAC: " + result.getDevice().getAddress() + "\n");
devicesDiscovered.add(result.getDevice());
deviceIndex++;
// auto scroll for text view
final int scrollAmount = peripheralTextView.getLayout().getLineTop(peripheralTextView.getLineCount()) - peripheralTextView.getHeight();
// if there is no need to scroll, scrollAmount will be <=0
if (scrollAmount > 0) {
peripheralTextView.scrollTo(0, scrollAmount);
}
}
};
// Device connect call back
private final BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// this will get called anytime you perform a read or write characteristic operation
final byte[] teste = characteristic.getValue();
final String batida = teste.toString();
final String result = "result";
int format = BluetoothGattCharacteristic.FORMAT_UINT8;
final int heartRate = characteristic.getIntValue(format, 1);
String TAG = "d";
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
Log.v(result , batida);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("value of sensor (BPM) "+ heartRate + "\n");
}
});
}
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
// this will get called when a device connects or disconnects
System.out.println(newState);
switch (newState) {
case 0:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device disconnected\n");
connectToDevice.setVisibility(View.VISIBLE);
disconnectDevice.setVisibility(View.INVISIBLE);
}
});
break;
case 2:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device connected\n");
connectToDevice.setVisibility(View.INVISIBLE);
disconnectDevice.setVisibility(View.VISIBLE);
}
});
// discover services and characteristics for this device
bluetoothGatt.discoverServices();
break;
default:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("we encounterned an unknown state, uh oh\n");
}
});
break;
}
}
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("device services have been discovered\n");
}
});
displayGattServices(bluetoothGatt.getServices());
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID).getCharacteristic(HEART_RATE_MEASUREMENT_CHAR_UUID);
//BluetoothGattCharacteristic battery = gatt.getService(BATTERY_SERVICE).getCharacteristic(BATTERY_LEVEL);
//gatt.readCharacteristic(battery);
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
BluetoothGattCharacteristic characteristic = gatt.getService(HEART_RATE_SERVICE_UUID).getCharacteristic(HEART_RATE_CONTROL_POINT_CHAR_UUID);
characteristic.setValue(new byte[]{1,1});
gatt.writeCharacteristic(characteristic);
}
#Override
// Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
};
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
System.out.println(characteristic.getUuid());
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void startScanning() {
System.out.println("start scanning");
btScanning = true;
deviceIndex = 0;
devicesDiscovered.clear();
peripheralTextView.setText("");
peripheralTextView.append("Started Scanning\n");
startScanningButton.setVisibility(View.INVISIBLE);
stopScanningButton.setVisibility(View.VISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.startScan(leScanCallback);
}
});
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
stopScanning();
}
}, SCAN_PERIOD);
}
public void stopScanning() {
System.out.println("stopping scanning");
peripheralTextView.append("Stopped Scanning\n");
btScanning = false;
startScanningButton.setVisibility(View.VISIBLE);
stopScanningButton.setVisibility(View.INVISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.stopScan(leScanCallback);
}
});
}
public void connectToDeviceSelected() {
peripheralTextView.append("Trying to connect to device at index: " + deviceIndexInput.getText() + "\n");
int deviceSelected = Integer.parseInt(deviceIndexInput.getText().toString());
bluetoothGatt = devicesDiscovered.get(deviceSelected).connectGatt(this, false, btleGattCallback);
}
public void disconnectDeviceSelected() {
peripheralTextView.append("Disconnecting from device\n");
bluetoothGatt.disconnect();
}
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null) return;
// Loops through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
final String uuid = gattService.getUuid().toString();
System.out.println("Service discovered: " + uuid);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("Service disovered: "+uuid+"\n");
}
});
new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics =
gattService.getCharacteristics();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic :
gattCharacteristics) {
final String charUuid = gattCharacteristic.getUuid().toString();
System.out.println("Characteristic discovered for service: " + charUuid);
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
peripheralTextView.append("Characteristic discovered for service: "+charUuid+"\n");
}
});
}
}
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
super.onStop();
}
public UUID convertFromInteger(int i) {
final long MSB = 0x0000000000001000L;
final long LSB = 0x800000805f9b34fbL;
long value = i & 0xFFFFFFFF;
return new UUID(MSB | (value << 32), LSB);
}
}
How can I read without interrupting the notify from BLE?
As you've observed, you can't start these two operations simultaneously (the first one will be overwritten and never executes):
gatt.readCharacteristic(battery);
gatt.writeDescriptor(descriptor);
Instead, you have to do the first operation, wait for it to finish (in your example, by waiting for onCharacteristicRead to be called), and then start the second operation. A common way to implement this is to use a queue to store pending operations, then pop items off the front of the queue and execute them one at a time in the rest of your code.
This required queuing is an annoying aspect of the Android BLE APIs that is not described in the documentation. For more details, check out my talk or list of resources for Android BLE.

BLE connected with Lollipop but not connected with Nougat

I'm new in android develop and I'm developing an app that transmit/receive data to a BLE module via Uart service.
With smartphone android 5.x.x the app works fine, it connects with the hardware and receive/transmit data.
With smartphone android 7.x.x the app doesn't connects.
Below you can see a snippet of MainActivity.java:
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_CONNECT_MSG");
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}
}
});
}
It's seem that when SendData, the GATT operation is not yet finished. Smartphone show the message "Device doesn't support UART over BLE. Disconnecting..." due to action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART).
If I delete the if(isConnected)...else... statement also smartphone with android 7.x.x will connects.
My question is what's happen and how can I resolve this issue?
My goal is to send a command to hardware via BLE so when the mcu is connected, a buzzer make a sound.
Thanks for help….
EDIT
Below you can find the whole MainActivity:
public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
public static final String TAG = "DEBUG ";
public static final String DEV_NAME_FILTER = "";
private static final int REQUEST_SELECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int UART_PROFILE_READY = 10;
private static final int UART_PROFILE_CONNECTED = 20;
public static final int UART_PROFILE_DISCONNECTED = 21;
private static final int STATE_OFF = 10;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
TextView mRemoteRssiVal;
RadioGroup mRg;
private int mState = UART_PROFILE_DISCONNECTED;
private static UartService mService = null;
private static BluetoothDevice mDevice = null;
private BluetoothAdapter mBtAdapter = null;
private ListView messageListView;
private ArrayAdapter<String> listAdapter;
private Button SelectButton, DisconnectButton;
private EditText edtMessage;
private static Context context;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
private static TextView DeviceInfo;
private static TextView DeviceName;
private static TextView Manufacturer;
public static boolean isConnected;
public static boolean isSetting;
public static boolean isReading;
public static boolean isManual;
public static boolean isFunctional;
public static boolean isBootloader;
public static byte[] SettingValues;
public static byte[] ReadingValues;
public static byte[] ManualValues;
public static byte[] FunctionalValues;
private static byte[] Connectcmd = new byte[5];
public static int STX = 0x3E; // '>'
public static int ETX = 0x23; // '#'
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DeviceInfo = (TextView) findViewById(R.id.deviceInfo);
DeviceName = (TextView) findViewById(R.id.deviceName);
Manufacturer= (TextView) findViewById(R.id.manufacturer);
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
context = this;
//Enable location
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
SelectButton = (Button) findViewById(R.id.button);
DisconnectButton = (Button) findViewById(R.id.disconnect);
DisconnectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x44; // 'D';
Connectcmd[3] = (byte) 0x43; // 'C'
Connectcmd[4] = (byte) ETX;
try {
//send data to Banner service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
MainActivity.disconnected();
setContentView(R.layout.activity_main);
finish();
} catch (Exception e) {
Log.e(TAG, "Disconnect error");
}
}
});
// Handle Select device button
SelectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (SelectButton.getText().equals("SELECT CELU")) {
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Log.i(TAG, "Push button CONNECT");
Intent newIntent = new Intent(context, DeviceListActivity.class);
((Activity) context).startActivityForResult(newIntent, MainActivity.REQUEST_SELECT_DEVICE);
} else {
//Disconnect button pressed
disconnected();
}
}
}
});
// Set initial UI state
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
//UART service connected/disconnected
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
mService = ((UartService.LocalBinder) rawBinder).getService();
Log.d(TAG, "onServiceConnected mService= " + mService);
if (!mService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
//// mService.disconnect(mDevice);
mService = null;
}
};
private Handler mHandler = new Handler() {
#Override
//Handler events that received from UART service
public void handleMessage(Message msg) {
}
};
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
Log.d(TAG, "CELU_CONNECT_MSG");
//btnConnectDisconnect.setText("Disconnect");
//edtMessage.setEnabled(true);
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
//IF COMMENTED THE APP CONNECTS!!!!!!!!!!!!!!!!!!
//ELSE IF NOT COMMENTED THE APP NEVER CONNECTS
/*if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}*/
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_DISCONNECT_MSG");
DisconnectButton.setEnabled(false);
DeviceName.setText("Not Connected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
//setUiState();
}
});
}
//Enable notifivcation on UART service//
if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
try {
ParsingPacket(txValue);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART)) {
showMessage("Device doesn't support UART over BLE Celu . Disconnecting");
mService.disconnect();
}
}
};
private static void ParsingPacket(byte[] packet) throws Exception {
if (packet.length == 0) {
// received empty packet
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
}
if(isSetting){
isSetting = false;
SettingValues = packet.clone();
String text = new String(SettingValues, "UTF-8");
Log.d(TAG, text);
}
if(isReading){
ReadingValues= packet;
ReadActivity.updateMeasure(ReadingValues);
//ReadActivity.addData(packet);
//String text = new String(ReadingValues, "UTF-8");
Log.d("Length ", String.format("%02d", (int) ReadingValues.length));
for(int i=0; i<ReadingValues.length; i++) {
String text = String.format("%02x", (int) ReadingValues[i]);
Log.d(TAG, text);
}
}
if(isManual){
isManual = false;
ManualValues = packet.clone();
String text = new String(ManualValues, "UTF-8");
Log.d(TAG, text);
}
if(isFunctional){
isFunctional = false;
FunctionalValues = packet.clone();
String text = new String(FunctionalValues, "UTF-8");
Log.d(TAG, text);
}
if(isBootloader){
isBootloader = false;
// do samething
}
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
if(DeviceName.getText()!="Not Connected") {
Intent connectedIntent = new Intent(getApplicationContext(), MenuActivity.class); //new Intent("com.antertech.mybleapplication.MenuActivity");
startActivity(connectedIntent);
}
}
};
private void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UartService.ACTION_GATT_CONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(UartService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART);
return intentFilter;
}
#Override
public void onStart() {
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
#Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.end(client, getIndexApiAction());
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.disconnect();
}
#Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
#Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onResume - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_SELECT_DEVICE:
//When the DeviceListActivity return, with the selected device address
if (resultCode == Activity.RESULT_OK && data != null) {
String deviceAddress = data.getStringExtra(BluetoothDevice.EXTRA_DEVICE);
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
Log.d(TAG, "... onActivityResultdevice.address==" + mDevice + " mserviceValue " + mService);
mService.connect(deviceAddress);
//setContentView(R.layout.activity_setting);
((TextView) findViewById(R.id.deviceName)).setText(mDevice.getName() + " - Connecting...");
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Bluetooth has turned on ", Toast.LENGTH_SHORT).show();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(this, "Problem in BT Turning ON ", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
Log.e(TAG, "wrong request code");
break;
}
}
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
}
public static void SendData(byte[] text) {
mService.writeRXCharacteristic(text);
Log.i(TAG, "Message send to Target");
}
public static void disconnected() {
if (mDevice != null) {
mService.disconnect();
Log.i(TAG, "Push Button DISCONNECT");
}
}
private void showMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onBackPressed() {
if (mState == UART_PROFILE_CONNECTED) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
showMessage("CELU TPE running in background.\n Disconnect to exit");
} else {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.popup_title)
.setMessage(R.string.popup_message)
.setPositiveButton(R.string.popup_yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton(R.string.popup_no, null)
.show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("Main 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();
}
}

Trying to fetch a list of all my beacons nearby. but nothing is returned

I have all the permissions granted.
I use the beaconManager. which I create like this:
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT));
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT));
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT));
beaconManager.bind(this);
OnBeaconConnect I do this:
#Override
public void onBeaconServiceConnect() {
ArrayList<Identifier> identifiers = new ArrayList<>();
// Set null to indicate that we want to match beacons with any value
identifiers.add(null);
// Represents a criteria of fields used to match beacon
try {
Region region = new Region("all-beacons-region", null, null, null);
Region region2 = new Region("de3be3ce-4770-477b-8893-0f0e5aeb9b98", null, null, null);
// Tells the BeaconService to start looking for beacons that match the passed Region object
beaconManager.startRangingBeaconsInRegion(region);
beaconManager.startRangingBeaconsInRegion(region2);
beaconManager.startMonitoringBeaconsInRegion(region);
beaconManager.startMonitoringBeaconsInRegion(region2);
} catch (RemoteException e) {
e.printStackTrace();
}
// Specifies a class that should be called each time the BeaconService gets ranging data, once per second by default
beaconManager.addRangeNotifier(this);
beaconManager.addMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(Region region) {
Log.i(TAG, "I just saw an beacon for the first time!");
}
#Override
public void didExitRegion(Region region) {
Log.i(TAG, "I no longer see an beacon");
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
Log.i(TAG, "I have just switched from seeing/not seeing beacons: " + state);
}
});
}
And didRangeBeaconsInRegion has this:
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Log.i(TAG, "The first beacon I see is about " + beacons.iterator().next().getDistance() + " meters away.");
}
}
But the monitorNotifier never gets called, and the rangeNotifier gets called, but beacons size is always 0.
Why don't I get the beacons here?
PS: I even tried hardcoding a beacon, using the UUID, but still I get nothing in monitorNotifier, and still size 0 in the range notifier
It looks to me like you set up three beacon parsers for the Eddystone formats, but you are trying to detect a beacon sending out the iBeacon format. (I say this based on the first identifier in the second region definition being a 16 byte UUID.) If this is indeed what you are trying to do, please add a beacon parser for the iBeacon format. You can find that here:
https://beaconlayout.wordpress.com/
Also, if you are trying to detect on Android 6+ make sure you have obtained location permissions otherwise you won't detect anything. See here:
https://altbeacon.github.io/android-beacon-library/requesting_permission.html
you can try this
public class BLEActivity extends ActionBarActivity {
private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private Handler mHandler;
private static final long SCAN_PERIOD = 10000;
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "BLE Not Supported",
Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
#Override
protected void onResume() {
super.onResume();
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
} else {
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
}
scanLeDevice(true);
}
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
#Override
protected void onDestroy() {
if (mGatt == null) {
return;
}
mGatt.close();
mGatt = null;
super.onDestroy();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_CANCELED) {
//Bluetooth not enabled.
finish();
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(filters, settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
}
}
}
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
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() {
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
if (mGatt == null) {
mGatt = device.connectGatt(this, false, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.i("gattCallback", "STATE_CONNECTED");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
break;
default:
Log.e("gattCallback", "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
Log.i("onServicesDiscovered", services.toString());
gatt.readCharacteristic(services.get(1).getCharacteristics().get
(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
gatt.disconnect();
}
};
}

how to detect bluetooth scanner connected to Android

I want to find if bluetooth scanner is connected to my android mobile or not after every 7 seconds. For that I created a receiver where I found the bondeddevices and then its majorclass. But its not working not finding any device. What might be the problem?
Here's the Activity class:
public class Activity_Home extends ActionBarActivity implements
OnClickListener {
CountDownTimer wifiTimer, timer;
BluetoothAdapter mBluetoothAdapter;
BluetoothDevice bluetoothDevice;
CheckBluetoothScanner mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new CheckBluetoothScanner();
isScannerConnected();
}
private void isScannerConnected() {
timer = new CountDownTimer(Long.MAX_VALUE, 7000) { // -------call
// amethod
// after
// certain
// time
// interval-------
// This is called every interval. (Every 7 seconds in this example)
public void onTick(long millisUntilFinished) {
Log.d("test", "Timer tick");
System.out.println("=======bluetooth--start");
try {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter.isEnabled()) {
IntentFilter filter = new IntentFilter(
BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery();
System.out.println("============utility: "
+ Utility.SCANNER_ON);
if (Utility.SCANNER_ON.equalsIgnoreCase("true")) {
tv_scanner
.setBackgroundResource(R.drawable.scanner);
} else {
tv_scanner.setBackgroundResource(0);
}
} else {
tv_scanner.setBackgroundResource(0);
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public void onFinish() {
Log.d("test", "Timer last tick");
timer.cancel();
}
}.start();
}
Here's the receiver class:
public class CheckBluetoothScanner extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
}
else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = (BluetoothDevice) intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Set pairedDevices = BluetoothAdapter.getDefaultAdapter()
.getBondedDevices();
BluetoothDevice device1 = null;
for (Object item : pairedDevices) {
device1 = (BluetoothDevice) item;
}
BluetoothClass bluetoothClass = device1.getBluetoothClass();
System.out.println("======bluetoothClass"+bluetoothClass);
if (bluetoothClass != null) {
int deviceClass = bluetoothClass.getDeviceClass();
System.out.println("=======deviceclass:"+deviceClass);
if (deviceClass == Device.Major.IMAGING
|| deviceClass == Device.Major.PERIPHERAL) {
Utility.SCANNER_ON = "true";
} else {
Utility.SCANNER_ON = "false";
}
}
}
}
};

Categories

Resources