Reputation: 2340
I'm creating an Android app that scans all nearby BLE (Bluetooth Low Energy) devices using Android Studio.
I think I have implemented all these documentations:
But as you can see in the log below, (the problem) there are no BLE devices scanned by the app.
Here are the logs in the logcat:
I think it could happen because the BLE scan callback
is not called (no BLE scan callback in the log).
So my question is what is the solution for my code? Did I miss coding something?
Here is my code
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Example">
<activity android:name=".ui.authentication.signin.SignInActivity" />
<activity android:name=".ui.authentication.signup.SignUpActivity" />
<activity android:name=".ui.home.HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
BluetoothHelper.java:
package com.example.util;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class BluetoothHelper {
static int REQUEST_ENABLE_BT = 1;
static int PERMISSION_CODE = 1;
static String TAG = "Bluetooth";
static boolean isScanning = false;
// SOURCE FOR BLUETOOTH PERMISSION: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#java
// CHECK FOR BLUETOOTH PERMISSION FOR ANDROID 10
public static void android10BluetoothPermission (Context context, Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
PERMISSION_CODE
);
}
}
}
// SOURCE FOR SET UP BLUETOOTH: https://developer.android.com/guide/topics/connectivity/bluetooth/setup#java
// GET BLUETOOTH ADAPTER
public static void setupBluetooth (BluetoothAdapter bluetoothAdapter) {
if (bluetoothAdapter == null) {
Log.d(TAG, "Bluetooth: " + "bluetooth adapter is null");
}
else {
Log.d(TAG, "Bluetooth: " + "bluetooth is adapter not null");
}
}
// ENABLE BLUETOOTH
public static void enableBluetooth (Activity activity, BluetoothAdapter bluetoothAdapter) {
Log.d(TAG, "Bluetooth: " + "bluetooth adapter is enabled: " + bluetoothAdapter.isEnabled());
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
Log.d(TAG, "Bluetooth: " + "bluetooth is enabled");
}
else {
Log.d(TAG, "Bluetooth: " + "bluetooth is already enabled");
}
}
// SOURCE FOR FIND BLUETOOTH DEVICES: https://developer.android.com/guide/topics/connectivity/bluetooth/find-bluetooth-devices
// QUERY PAIRED DEVICES
public static Set<BluetoothDevice> queryPairedDevices (BluetoothAdapter bluetoothAdapter) {
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
Log.d(TAG, "PairedDevices: " + pairedDevices.toString());
return pairedDevices;
}
// GET ALL NAMES AND MAC ADDRESSES
public static ArrayList<HashMap<String, String>> getNamesAndMacAddresses(Set<BluetoothDevice> bluetoothDevices) {
ArrayList<HashMap<String, String>> arrayList = new ArrayList<>();
if (bluetoothDevices.size() > 0) {
for (BluetoothDevice device : bluetoothDevices) {
String deviceName = device.getName();
String deviceMacAddress = device.getAddress();
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("deviceName", deviceName);
hashMap.put("deviceMacAddress", deviceMacAddress);
arrayList.add(hashMap);
}
}
Log.d(TAG, "NamesAndMacAddress: " + arrayList);
return arrayList;
}
// SOURCE FOR FIND BLE DEVICES: https://developer.android.com/guide/topics/connectivity/bluetooth/find-ble-devices#java
// SCAN BLE DEVICES
public static void scanBLEDevices (BluetoothLeScanner bluetoothLeScanner) {
int SCAN_DURATION = 10000;
if(!isScanning) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
isScanning = false;
bluetoothLeScanner.stopScan(bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "stop scanning");
}
}, SCAN_DURATION);
isScanning = true;
bluetoothLeScanner.startScan(bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "start scanning");
}
else {
isScanning = false;
bluetoothLeScanner.stopScan(bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "stop scanning");
}
}
// BLE SCAN CALLBACK
private static ScanCallback bleScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.d(TAG, "ScanCallback: " + result.getDevice());
}
};
}
HomeActivity.java:
package com.example.ui.home;
import androidx.appcompat.app.AppCompatActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.os.Bundle;
import android.view.View;
import com.example.R;
import com.example.databinding.ActivityHomeBinding;
import com.example.util.AuthenticationHelper;
import com.example.util.BluetoothHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class HomeActivity extends AppCompatActivity implements View.OnClickListener {
ActivityHomeBinding binding;
Set<BluetoothDevice> pairedDevices;
ArrayList<HashMap<String, String>> arrayList;
BluetoothLeScanner bluetoothLeScanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityHomeBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setUpBluetooth();
binding.buttonKeluar.setOnClickListener(this);
}
@Override
protected void onStart() {
super.onStart();
AuthenticationHelper.checkHasTheUserLoggedIn(this);
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.buttonKeluar) {
AuthenticationHelper.signOutUser(this);
}
}
private void setUpBluetooth() {
BluetoothHelper.android10BluetoothPermission(this, HomeActivity.this);
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothHelper.setupBluetooth(bluetoothAdapter);
BluetoothHelper.enableBluetooth(this, bluetoothAdapter);
pairedDevices = BluetoothHelper.queryPairedDevices(bluetoothAdapter);
arrayList = BluetoothHelper.getNamesAndMacAddresses(pairedDevices);
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
BluetoothHelper.scanBLEDevices(bluetoothLeScanner);
}
}
I added this code into android10BluetoothPermission()
function in BluetoothHelper.java
class but still didn't work.
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_CODE
);
}
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSION_CODE
);
}
Upvotes: 2
Views: 3013
Reputation: 2340
Finally, I have modified my code so the code now is working. Here it is:
ScanAndPairActivity.java (I'm creating a new activity for scanning and pairing BLE devices):
package com.example.ui.scanandpair;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.R;
import com.example.databinding.ActivityScanAndPairBinding;
import com.example.entity.BLEDeviceEntity;
import java.util.ArrayList;
import java.util.List;
public class ScanAndPairActivity extends AppCompatActivity {
// GENERAL
String TAG = getClass().getSimpleName();
ActivityScanAndPairBinding binding;
// BLUETOOTH
int REQUEST_ENABLE_BT = 1;
boolean isScanning = false;
BluetoothAdapter bluetoothAdapter;
BluetoothLeScanner bluetoothLeScanner;
ScanAndPairAdapter scanAndPairAdapter;
List<BLEDeviceEntity> bleDeviceEntityList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityScanAndPairBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
android10BluetoothPermission();
scanAndPairAdapter = new ScanAndPairAdapter(this);
bleDeviceEntityList = new ArrayList<>();
}
// SOURCE FOR BLUETOOTH PERMISSION: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#java
// CHECK FOR BLUETOOTH PERMISSION FOR ANDROID 10
private void android10BluetoothPermission () {
boolean isLocationPermissionRequired = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
boolean isBGLocationAccessNotGranted = false;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
isBGLocationAccessNotGranted = ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED;
}
boolean isLocationAccessNotGranted = ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED;
if (isLocationPermissionRequired && isBGLocationAccessNotGranted && isLocationAccessNotGranted) {
requestLocationPermission();
}
else {
setUpBluetooth();
}
}
private void requestLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder
.setTitle(getString(R.string.izinkan_lokasi))
.setMessage(getString(R.string.mohon_izinkan_aplikasi_mengakses_lokasi))
.setPositiveButton(getString(R.string.ya), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
makeLocationRequest();
}
});
alertDialogBuilder.show();
} else {
makeLocationRequest();
}
}
}
private void makeLocationRequest() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{"android.permission.ACCESS_FINE_LOCATION"}, 101);
}
}
// ON REQUEST PERMISSION RESULT
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode) {
case 101:
if (grantResults.length != 0 && grantResults[0] == 0) {
setUpBluetooth();
}
break;
default:
Toast.makeText(this, getString(R.string.maaf_izin_lokasi_harus_disetujui), Toast.LENGTH_LONG).show();
}
}
private void setUpBluetooth() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
checkBluetooth(bluetoothAdapter);
enableBluetooth(this, bluetoothAdapter);
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
scanBLEDevices(bluetoothLeScanner);
}
// SOURCE FOR SET UP BLUETOOTH: https://developer.android.com/guide/topics/connectivity/bluetooth/setup#java
// GET BLUETOOTH ADAPTER
private void checkBluetooth (BluetoothAdapter bluetoothAdapter) {
if (bluetoothAdapter == null) {
Log.d(TAG, "Bluetooth: " + "bluetooth adapter is null");
}
else {
Log.d(TAG, "Bluetooth: " + "bluetooth is adapter not null");
}
}
// ENABLE BLUETOOTH
private void enableBluetooth (Activity activity, BluetoothAdapter bluetoothAdapter) {
Log.d(TAG, "Bluetooth: " + "bluetooth adapter is enabled: " + bluetoothAdapter.isEnabled());
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
Log.d(TAG, "Bluetooth: " + "bluetooth is enabled");
}
else {
Log.d(TAG, "Bluetooth: " + "bluetooth is already enabled");
}
}
// SOURCE FOR FIND BLE DEVICES: https://developer.android.com/guide/topics/connectivity/bluetooth/find-ble-devices#java
// SCAN BLE DEVICES
private void scanBLEDevices (BluetoothLeScanner bluetoothLeScanner) {
showProgressBar();
int SCAN_DURATION = 5000;
if(!isScanning) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
isScanning = false;
bluetoothLeScanner.stopScan(bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "stop scanning");
populateDataToRecyclerView();
}
}, SCAN_DURATION);
isScanning = true;
showProgressBar();
bluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "start scanning");
}
else {
isScanning = false;
bluetoothLeScanner.stopScan(bleScanCallback);
Log.d(TAG, "ScanBLEDevices: " + "stop scanning");
populateDataToRecyclerView();
}
}
private void showProgressBar() {
binding.recylerViewFilm.setVisibility(View.GONE);
binding.progressBar.setVisibility(View.VISIBLE);
}
private void hideProgressBar() {
binding.recylerViewFilm.setVisibility(View.VISIBLE);
binding.progressBar.setVisibility(View.GONE);
}
private void populateDataToRecyclerView() {
hideProgressBar();
scanAndPairAdapter.setBleDeviceEntityList(bleDeviceEntityList);
scanAndPairAdapter.notifyDataSetChanged();
binding.recylerViewFilm.setLayoutManager(new LinearLayoutManager(ScanAndPairActivity.this));
binding.recylerViewFilm.setHasFixedSize(true);
binding.recylerViewFilm.setAdapter(scanAndPairAdapter);
scanAndPairAdapter.setOnItemClickCallback(new ScanAndPairAdapter.OnItemClickCallback() {
@Override
public void onItemClicked(BLEDeviceEntity bleDeviceEntity) {
Toast.makeText(
ScanAndPairActivity.this, "try to connect to " + bleDeviceEntity.getName(), Toast.LENGTH_SHORT).show();
}
});
}
// BLE SCAN CALLBACK
private ScanCallback bleScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
String deviceAddress = result.getDevice().getAddress();
String deviceName = result.getDevice().getName();
Log.d(TAG, "ScanCallback, deviceAddress: " + deviceAddress + ", deviceName: " + deviceName);
if(bleDeviceEntityList.size() == 0) {
bleDeviceEntityList.add(new BLEDeviceEntity(deviceAddress, deviceName));
}
else {
for(BLEDeviceEntity bleDeviceEntity : bleDeviceEntityList){
if(!bleDeviceEntity.getAddress().equals(deviceAddress)) {
bleDeviceEntityList.add(new BLEDeviceEntity(deviceAddress, deviceName));
}
}
}
Log.d(TAG, "bleDeviceEntityList: " + bleDeviceEntityList);
}
};
// SOURCE FOR LATEST ANDROID BLE APPLICATION SAMPLE: https://github.com/android/connectivity-samples/tree/main/BluetoothAdvertisementsKotlin
private static List<ScanFilter> buildScanFilters() {
List<ScanFilter> scanFilters = new ArrayList<>();
ScanFilter.Builder builder = new ScanFilter.Builder();
// Comment out the below line to see all BLE devices around you
// builder.setServiceUuid(Constants.Service_UUID);
scanFilters.add(builder.build());
return scanFilters;
}
private static ScanSettings buildScanSettings() {
ScanSettings.Builder builder = new ScanSettings.Builder();
builder.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER);
return builder.build();
}
}
Thank you everyone for your help and special thanks to Isaidamier for showing me the example app here.
Upvotes: 6