Basically, I am an iOS developer. I have a requirement to scan, connect & disconnect BLE devices. Everything works fine in iOS. Then I tried the following code to scan in Android. None of the devices re scanned at anytime. Could anyone help me, if I am doing something wrong.
public class MainActivity extends AppCompatActivity {
BluetoothAdapter bluetoothAdapter;
TextView statusTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTextView = (TextView)findViewById(R.id.statusTxtView);
}
#Override
protected void onStart() {
super.onStart();
enableBluetooth();
}
private void enableBluetooth() {
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
statusTextView.setText("BT disabled");
Intent enableBtIntent =
new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
} else {
statusTextView.setText("BT enabled");
}
boolean status = bluetoothAdapter.startDiscovery();
if (status == true) {
statusTextView.setText("Start scanning");
} else {
statusTextView.setText("Failed scanning");
}
}
BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
statusTextView.setText(device.getName());
}
};
}
You've not started scanning. After starting bluetooth discovery using bluetoothAdapter.startDiscovery(), you have to start scanning in order to get scan results. Use the following code to start scan.
I've not tested it but it should work as follows:
BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner();
scanner.startScan(scanCallback);
where scanCallback is the above callback you have created but unused.
Make sure that you have BLUETOOTH_ADMIN permission.
First you have to scan device
#SuppressLint("NewApi")
private void turnonBLE() {
// TODO Auto-generated method stub
manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBLEAdapter = manager.getAdapter();
mLeScanner = mBLEAdapter.getBluetoothLeScanner();
mBLEAdapter.enable();
scanLeDevice(true);
Toast.makeText(getApplicationContext(), "BTLE ON Service",
Toast.LENGTH_LONG).show();
Log.e("BLE_Scanner", "TurnOnBLE");
}
If you are not using any uuid then scan without uuid
public void scanLeDevice(final boolean enable) {
if (enable) {
if (Build.VERSION.SDK_INT < 21) {
mBLEAdapter.startLeScan(mLeScanCallback);
} else {
ParcelUuid uuid = ParcelUuid.fromString(UUIDList.SENSOR_MAIN_SERVICE_UUID_STRING.toString());
ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(uuid).build();
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build();
if (mLeScanner != null)
mLeScanner.startScan(Collections.singletonList(scanFilter), settings, mScanCallback);
}
} else {
if (Build.VERSION.SDK_INT < 21) {
mBLEAdapter.stopLeScan(mLeScanCallback);
} else {
mLeScanner.stopScan(mScanCallback);
}
}
}
From that call scanCallback
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice, result.getScanRecord().getBytes());
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
Log.e("ScanResult - Results", sr.toString());
}
}
#Override
public void onScanFailed(int errorCode) {
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
for connect device call gattCallback
private synchronized void connectToDevice(BluetoothDevice device, byte[] scanRecord) {
mGatt = device.connectGatt(getApplicationContext(), false, mBtGattCallback);
}
private BluetoothGattCallback mBtGattCallback = new BluetoothGattCallback() {
// override all methods
}
Related
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!
I am working on BLE devices android application. i am trying to get available bluetooth devices using scanCallBack. It was working fine some days ago but suddenly it stopped. onScanResults or onScanFailed nothing are NOT executing. I have given the ACCESS_COARSE_LOCATION, BLUETOOTH_ADMIN, BLUETOOTH and ACCESS_FINE_LOCATION in manifest and request permissions at run time also.Bluetooth is on and location is also on. Please help.
Measurement.java
public class MeasurementScreen extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter;
static int REQUEST_ENABLE_BT = 1001;
private Boolean spinnerStatus= false;
private Handler handler = new Handler(Looper.getMainLooper());
final BluetoothAdapter mBluetoothAdapter =
BluetoothAdapter.getDefaultAdapter();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_reading_screen);
Objects.requireNonNull(getSupportActionBar()).hide();
if (Build.VERSION.SDK_INT >= 23) {
int permissionCheck = ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION);
if (permissionCheck == -1 ) {
ActivityCompat.requestPermissions(this,
new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION
}, 0);
}
}
final Button tryAgain = findViewById(R.id.tryagain);
next = findViewById(R.id.next);
back = findViewById(R.id.back);
progressDialog = new ProgressDialog(this);
bluetoothscan();
}
void bluetoothscan(){
spinner();
scanBLEDevices(true);
}
private void scanBLEDevices(final boolean enable){
final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
final BLEScanCallback scanCallback = new BLEScanCallback();
if (enable){
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
bluetoothLeScanner.stopScan(scanCallback);
}
}, 10000);
mScanning = true;
bluetoothLeScanner.startScan(scanCallback);
}else{
mScanning = false;
bluetoothLeScanner.stopScan(scanCallback);
}
}
public class BLEScanCallback extends ScanCallback{
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.e("Scan Success", "Scan Success");
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.e("Scan Success", "Scan Success Batch");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e("Scan Failed", "Error Code: " + errorCode);
}
}
}
This is the log output:-
D/BluetoothAdapter: STATE_ON
D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=6
mClientIf=0
I have an Arduino code driven ESP32 chip.
For Android code, it setup a callback for connection attempt
mGatt = device.connectGatt(this, false, gattCallback, TRANSPORT_LE );
but
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback()
do not happen.
However, from Arduino side, it does see a connected happen and start to send data out. ESP32 also blink connected LED.
Any idea what was wrong?
SDK version is 26,
minSDK is 23,
targetSDK is 23,
run on Samsung Galaxy S7
thanks a lot!
#TargetApi(21)
public class MainActivity extends AppCompatActivity {
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;
private TextView line_1, line_2, line_3, line_4;
private ImageButton btnTrash, btnEmail;
private UUID uuid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uuid = UUID.fromString("8dc99748-0ad4-11e8-ba89-0ed5f89f718b");
line_1 = (TextView) findViewById(R.id.textLine1);
line_2 = (TextView) findViewById(R.id.textLine2);
line_3 = (TextView) findViewById(R.id.textLine3);
line_4 = (TextView) findViewById(R.id.textLine4);
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();
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
line_3.setText("" + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
line_1.setText(" connected ");
Toast.makeText(getApplicationContext()," connected ", Toast.LENGTH_LONG);
// 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();
line_1.setText(" server discover");
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();
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic)
{
line_1.setText(" charactertics changed");
}
};
#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);
// mLEScanner.startScan(filters, settings, mScanCallback);
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
line_1.setText(" mLEScanner ");
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) {
super.onScanResult(callbackType, result);
BluetoothDevice btDevice = result.getDevice();
line_2.setText("try connect to " + btDevice.getName());
connectToDevice(btDevice);
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
line_2.setText(" batch scan result");
}
}
#Override
public void onScanFailed(int errorCode) {
line_2.setText("scan fail");
}
};
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) {
try {
BluetoothSocket temp = device.createRfcommSocketToServiceRecord(uuid);
mGatt = device.connectGatt(this, false, gattCallback, TRANSPORT_LE );
} catch( Exception e)
{
}
line_3.setText( device.getAddress());
line_4.setText( "device type: "+ device.getType());
scanLeDevice(false);// will stop after first device detection
}
}
}
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();
}
};
}
I'm currently connecting my android device with another bluetooth device using BLE.
The issue is, how do I scan for already connected devices?
In my first approach, I did not call stopLeScan before the connection method.
This had no problem with the above issue, but it caused the ui to break(too short interval ui update) and sometimes connection time to be very very slow.
After I made my app to call stopLeDevice before connection, every issuses has been resolved, but a new issue popped out. The new issue is that I can no longer see the connected device on my scanResult. It only displays the disconnected devices. I still want to moniter my connected device. How can I acheive this?
Use this class to start automatic to new BLE Devices.
BLEScanner Services
public class BLEScanner extends Service {
private BluetoothAdapter mBluetoothAdapter;
private ArrayList<BluetoothDevice> mLeDevices;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mLeDevices = new ArrayList<BluetoothDevice>();
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
startLeScan();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void startLeScan() {
scanLeDevice(true);
}
private void stopLeScan() {
scanLeDevice(false);
}
private void scanLeDevice(boolean enable) {
if (enable) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (!mLeDevices.contains(device)) {
mLeDevices.add(device);
connectToDevice(device);
}
}
};
private void connectToDevice(final BluetoothDevice device) {
if (device != null) {
Log.i("Tag", "Name: " + device.getAddress() + " Connecting");
if (device.getName() != null)
device.connectGatt(this.getApplicationContext(), false, new BluetoothCallBack(this.getApplicationContext(), BLEScanner.this));
}
}
#Override
public void onDestroy() {
super.onDestroy();
stopLeScan();
mLeDevices.clear();
}
public void removeDevice(BluetoothDevice mDevice) {
try {
if (mLeDevices != null && mLeDevices.size() > 0)
mLeDevices.remove(mDevice);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now Callback Class to check BLE Device Connect or not
public class BluetoothCallBack extends BluetoothGattCallback {
private BLEScanner mServiceObject;
public BluetoothCallBack(Context mContext, BLEScanner mServiceObject) {
this.mServiceObject = mServiceObject;
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("Tag", "CONNECTED DEVICE: " + gatt.getDevice().getAddress());
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.e("Tag", "DISCONNECTED DEVICE: " + gatt.getDevice().getAddress());
gatt.disconnect();
gatt.close();
mServiceObject.removeDevice(gatt.getDevice());
}
}
}