Мне нужно приложение для Android, которое считывает частоту пульса. Первым делом необходимо просканировать устройства и подключиться к выбранному. У меня есть код, но он не работает. BLE активен, другие приложения могут подключаться и отображать частоту пульса, но в этом случае я получаю только «Начало сканирования» и ничего больше.
Знаете, что не так?
BR,
Марцин
Вот мой код. (ниже есть обновление)
package com.example.edgetest1;
import static androidx.core.location.LocationManagerCompat.isLocationEnabled;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends Activity {
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private ListView bleList;
private TextView pulse;
private BluetoothGatt bluetoothGatt;
private List bleDevices = new ArrayList();
private ArrayAdapter bleListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pulse = findViewById(R.id.pulse);
bleList = findViewById(R.id.bleList);
Button findBleButton = findViewById(R.id.findBle);
Button connectForceButton = findViewById(R.id.forceConnect);
Button connectButton = findViewById(R.id.connect);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
bleList.setAdapter(bleListAdapter);
findBleButton.setOnClickListener(v -> startBleScan());
connectForceButton.setOnClickListener( v -> {
}
);
connectButton.setOnClickListener(v -> {
int position = bleList.getCheckedItemPosition();
if (position != ListView.INVALID_POSITION) {
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
} else {
msg("Please select a device to connect");
}
});
}
private void startBleScan() {
if (bluetoothLeScanner != null) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
msg("No SCAN permission 1");
return;
}
bluetoothLeScanner.stopScan(scanCallback);
bleDevices.clear();
bleListAdapter.clear();
if (!bluetoothAdapter.isEnabled()) {
msg("Please enable Bluetooth");
return;
}
// Check if location services are enabled
if (!isLocationEnabled()) {
msg("Please enable location services");
return;
}
bluetoothLeScanner.startScan(scanCallback); // Start a new scan
msg("Starting scan...");
}
}
private boolean isLocationEnabled() {
/* Check if location services are enabled */
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
};
private final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
msg("Have the results...");
BluetoothDevice device = result.getDevice();
if (!bleDevices.contains(device)) {
bleDevices.add(device);
if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 1");
return;
}
bleListAdapter.add(device.getName() + " (" + device.getAddress() + ")");
bleListAdapter.notifyDataSetChanged();
}
}
@Override
public void onBatchScanResults(List results) {
msg("Have the bath results...");
for (ScanResult result : results) {
onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
}
}
@Override
public void onScanFailed(int errorCode) {
msg("BLE scan failed with error code: " + errorCode);
}
};
private void connectToDevice(BluetoothDevice device) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 2");
return;
}
msg("Trying to connect");
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed");
// Handle connection state changes
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
BluetoothGattService service = gatt.getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb"));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"));
if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 3");
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
int value = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
runOnUiThread(() -> pulse.setText("Pulse: " + value));
}
};
public void msg(String message){
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
Полагаю, все разрешения имеются.
ОБНОВЛЕНИЕ
Мне каким-то образом удалось пойти еще дальше. Теперь сканирует устройства, пытается подключиться, но безуспешно. Вот код (разделён на три класса).
package com.example.edgetest1;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends Activity {
public static final int REQUEST_LOCATION_PERMISSION = 100;
public BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private ListView bleList;
public TextView pulse;
BluetoothGatt bluetoothGatt;
List bleDevices = new ArrayList();
ArrayAdapter bleListAdapter;
private long scanStart;
private Handler handler = new Handler();
private static final long SCAN_PERIOD = 10000; // 10 seconds
public void msg(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pulse = findViewById(R.id.pulse);
bleList = findViewById(R.id.bleList);
Button findBleButton = findViewById(R.id.findBle);
Button connectButton = findViewById(R.id.connect);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
bleList.setAdapter(bleListAdapter);
bleList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
msg("Selected: " + (position + 1) + " . Connecting");
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
}
});
findBleButton.setOnClickListener(v -> startBleScan());
connectButton.setOnClickListener(v -> {
int position = bleList.getCheckedItemPosition();
if (position != ListView.INVALID_POSITION) {
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
} else {
msg("Please select a device to connect");
}
});
}
public void bleDevicesAdd(BluetoothDevice device){
bleDevices.add(device);
}
public boolean bleDevicesContains(BluetoothDevice device){
return bleDevices.contains(device);
}
;
public void bleListAdapterAdd(String deviceInfo){
bleListAdapter.add(deviceInfo);
}
private void startBleScan() {
if (bluetoothLeScanner != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
return;
}
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
msg("No SCAN permission");
return;
}
bluetoothLeScanner.stopScan(scanCallback);
bleDevices.clear();
bleListAdapter.clear();
//backupBleDevList.clear();
if (!bluetoothAdapter.isEnabled()) {
msg("Please enable Bluetooth");
return;
}
if (!isLocationEnabled()) {
msg("Please enable location services");
return;
}
scanStart = System.currentTimeMillis() / 1000;
bluetoothLeScanner.startScan(scanCallback);
msg("Starting scan...");
handler.postDelayed(() -> {
bluetoothLeScanner.stopScan(scanCallback);
msg("End of scan");
}, SCAN_PERIOD);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startBleScan();
} else {
msg("Location permission is required for BLE scanning");
}
}
}
private boolean isLocationEnabled() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private final ScanCallback scanCallback = new MyScanCallback(this, MainActivity.this);
private final BluetoothGattCallback gattCallback = new MyGattCallback(this, MainActivity.this);
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save Bluetooth devices
ArrayList deviceAddresses = new ArrayList();
for (BluetoothDevice device : bleDevices) {
deviceAddresses.add(device.getAddress());
}
outState.putStringArrayList("bleDevices", deviceAddresses);
msg("Backup: "+bleDevices.size());
// Save adapter data
ArrayList adapterData = new ArrayList();
for (int i = 0; i < bleListAdapter.getCount(); i++) {
adapterData.add(bleListAdapter.getItem(i));
}
outState.putStringArrayList("bleListAdapter", adapterData);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
// Restore Bluetooth devices
ArrayList deviceAddresses = savedInstanceState.getStringArrayList("bleDevices");
if (deviceAddresses != null) {
bleDevices = new ArrayList();
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
for (String address : deviceAddresses) {
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
bleDevices.add(device);
}
}
// Restore adapter data
ArrayList adapterData = savedInstanceState.getStringArrayList("bleListAdapter");
if (adapterData != null) {
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, adapterData);
}
msg("Restored "+ adapterData.size());
}
}
private void connectToDevice(BluetoothDevice device) {
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
msg("Bluetooth is not available or not enabled");
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_LOCATION_PERMISSION);
msg("No CONNECT permission 1");
return;
}
} else {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
msg("No LOCATION permission");
return;
}
}
msg("Trying to connect to device: " + device.getName());
bluetoothGatt = device.connectGatt(this, false, gattCallback);
if (bluetoothGatt == null) {
msg("Failed to connect to the device");
}
}
};
##################################### ####
package com.example.edgetest1;
import android.Manifest;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.UUID;
public class MyGattCallback extends BluetoothGattCallback {
private final Context context;
private final MainActivity activity;
public MyGattCallback(Context context, MainActivity activity) {
this.activity = activity;
this.context = context;
}
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed: " + status + " -> " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
msg("Successfully connected to GATT server.");
if (ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 3");
return;
}
gatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
msg("Disconnected from GATT server.");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
msg("Connection failed with status: " + status);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
msg("Services discovered successfully.");
BluetoothGattService service = gatt.getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb"));
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"));
if (characteristic != null) {
msg("Char is null");
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 2");
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
} else {
msg("Heart Rate service not found.");
}
} else {
msg("Service discovery failed with status: " + status);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"))) {
int heartRate = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
activity.runOnUiThread(() -> activity.pulse.setText("Pulse: " + heartRate));
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
msg("GATT_SUCCESS");
}
}
public void msg(String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
##################################### #
package com.example.edgetest1;
import static com.example.edgetest1.MainActivity.REQUEST_LOCATION_PERMISSION;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.pm.PackageManager;
import android.os.Build;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.List;
import android.content.Context;
public class MyScanCallback extends ScanCallback {
private final Context context;
private final MainActivity activity;
public MyScanCallback(Context context, MainActivity activity) {
this.activity = activity;
this.context = context;
}
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
if (!activity.bleDevicesContains(device)) {
msg("Have new results");
//bleDevices.add(device);
activity.bleDevices.add(device);
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
String deviceInfo = device.getName() + " (" + device.getAddress() + ")";
//backupBleDevList.add(deviceInfo); // Add device info to backup list
//bleListAdapter.add(deviceInfo);
activity.bleListAdapter.add(deviceInfo);
//bleListAdapter.notifyDataSetChanged();
activity.bleListAdapter.notifyDataSetChanged();
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed: " + status + " -> " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
msg("Successfully connected to GATT server.");
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
gatt.discoverServices(); // Discover services on the connected device
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
msg("Disconnected from GATT server.");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
msg("Connection failed with status: " + status);
}
}
};
@Override
public void onBatchScanResults(List results) {
msg("Have the batch results...");
for (ScanResult result : results) {
onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
}
}
@Override
public void onScanFailed(int errorCode) {
msg("BLE scan failed with error code: " + errorCode);
}
private void connectToDevice(BluetoothDevice device) {
if (activity.bluetoothAdapter == null || activity.bluetoothAdapter.isEnabled()) {
msg("Bluetooth is not available or not enabled");
return;
}
// Check necessary permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_LOCATION_PERMISSION);
msg("No CONNECT permission");
return;
}
} else {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
msg("No LOCATION permission");
return;
}
}
msg("Trying to connect to device: " + device.getName());
activity.bluetoothGatt = device.connectGatt(context, false, gattCallback);
if (activity.bluetoothGatt == null) {
msg("Failed to connect to the device");
//retryConnection(device);
}
}
public void msg(String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... ng-android
Сканирование устройств BLE — Android ⇐ JAVA
Программисты JAVA общаются здесь
1736862392
Anonymous
Мне нужно приложение для Android, которое считывает частоту пульса. Первым делом необходимо просканировать устройства и подключиться к выбранному. У меня есть код, но он не работает. BLE активен, другие приложения могут подключаться и отображать частоту пульса, но в этом случае я получаю только «Начало сканирования» и ничего больше.
Знаете, что не так?
BR,
Марцин
Вот мой код. (ниже есть обновление)
package com.example.edgetest1;
import static androidx.core.location.LocationManagerCompat.isLocationEnabled;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends Activity {
private BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private ListView bleList;
private TextView pulse;
private BluetoothGatt bluetoothGatt;
private List bleDevices = new ArrayList();
private ArrayAdapter bleListAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pulse = findViewById(R.id.pulse);
bleList = findViewById(R.id.bleList);
Button findBleButton = findViewById(R.id.findBle);
Button connectForceButton = findViewById(R.id.forceConnect);
Button connectButton = findViewById(R.id.connect);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
bleList.setAdapter(bleListAdapter);
findBleButton.setOnClickListener(v -> startBleScan());
connectForceButton.setOnClickListener( v -> {
}
);
connectButton.setOnClickListener(v -> {
int position = bleList.getCheckedItemPosition();
if (position != ListView.INVALID_POSITION) {
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
} else {
msg("Please select a device to connect");
}
});
}
private void startBleScan() {
if (bluetoothLeScanner != null) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
msg("No SCAN permission 1");
return;
}
bluetoothLeScanner.stopScan(scanCallback);
bleDevices.clear();
bleListAdapter.clear();
if (!bluetoothAdapter.isEnabled()) {
msg("Please enable Bluetooth");
return;
}
// Check if location services are enabled
if (!isLocationEnabled()) {
msg("Please enable location services");
return;
}
bluetoothLeScanner.startScan(scanCallback); // Start a new scan
msg("Starting scan...");
}
}
private boolean isLocationEnabled() {
/* Check if location services are enabled */
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
};
private final ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
msg("Have the results...");
BluetoothDevice device = result.getDevice();
if (!bleDevices.contains(device)) {
bleDevices.add(device);
if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 1");
return;
}
bleListAdapter.add(device.getName() + " (" + device.getAddress() + ")");
bleListAdapter.notifyDataSetChanged();
}
}
@Override
public void onBatchScanResults(List results) {
msg("Have the bath results...");
for (ScanResult result : results) {
onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
}
}
@Override
public void onScanFailed(int errorCode) {
msg("BLE scan failed with error code: " + errorCode);
}
};
private void connectToDevice(BluetoothDevice device) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 2");
return;
}
msg("Trying to connect");
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed");
// Handle connection state changes
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
BluetoothGattService service = gatt.getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb"));
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"));
if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 3");
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
int value = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
runOnUiThread(() -> pulse.setText("Pulse: " + value));
}
};
public void msg(String message){
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
Полагаю, все разрешения имеются.
ОБНОВЛЕНИЕ
Мне каким-то образом удалось пойти еще дальше. Теперь сканирует устройства, пытается подключиться, но безуспешно. Вот код (разделён на три класса).
package com.example.edgetest1;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MainActivity extends Activity {
public static final int REQUEST_LOCATION_PERMISSION = 100;
public BluetoothAdapter bluetoothAdapter;
private BluetoothLeScanner bluetoothLeScanner;
private ListView bleList;
public TextView pulse;
BluetoothGatt bluetoothGatt;
List bleDevices = new ArrayList();
ArrayAdapter bleListAdapter;
private long scanStart;
private Handler handler = new Handler();
private static final long SCAN_PERIOD = 10000; // 10 seconds
public void msg(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pulse = findViewById(R.id.pulse);
bleList = findViewById(R.id.bleList);
Button findBleButton = findViewById(R.id.findBle);
Button connectButton = findViewById(R.id.connect);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
bleList.setAdapter(bleListAdapter);
bleList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
msg("Selected: " + (position + 1) + " . Connecting");
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
}
});
findBleButton.setOnClickListener(v -> startBleScan());
connectButton.setOnClickListener(v -> {
int position = bleList.getCheckedItemPosition();
if (position != ListView.INVALID_POSITION) {
BluetoothDevice device = bleDevices.get(position);
connectToDevice(device);
} else {
msg("Please select a device to connect");
}
});
}
public void bleDevicesAdd(BluetoothDevice device){
bleDevices.add(device);
}
public boolean bleDevicesContains(BluetoothDevice device){
return bleDevices.contains(device);
}
;
public void bleListAdapterAdd(String deviceInfo){
bleListAdapter.add(deviceInfo);
}
private void startBleScan() {
if (bluetoothLeScanner != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
return;
}
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
msg("No SCAN permission");
return;
}
bluetoothLeScanner.stopScan(scanCallback);
bleDevices.clear();
bleListAdapter.clear();
//backupBleDevList.clear();
if (!bluetoothAdapter.isEnabled()) {
msg("Please enable Bluetooth");
return;
}
if (!isLocationEnabled()) {
msg("Please enable location services");
return;
}
scanStart = System.currentTimeMillis() / 1000;
bluetoothLeScanner.startScan(scanCallback);
msg("Starting scan...");
handler.postDelayed(() -> {
bluetoothLeScanner.stopScan(scanCallback);
msg("End of scan");
}, SCAN_PERIOD);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startBleScan();
} else {
msg("Location permission is required for BLE scanning");
}
}
}
private boolean isLocationEnabled() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private final ScanCallback scanCallback = new MyScanCallback(this, MainActivity.this);
private final BluetoothGattCallback gattCallback = new MyGattCallback(this, MainActivity.this);
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save Bluetooth devices
ArrayList deviceAddresses = new ArrayList();
for (BluetoothDevice device : bleDevices) {
deviceAddresses.add(device.getAddress());
}
outState.putStringArrayList("bleDevices", deviceAddresses);
msg("Backup: "+bleDevices.size());
// Save adapter data
ArrayList adapterData = new ArrayList();
for (int i = 0; i < bleListAdapter.getCount(); i++) {
adapterData.add(bleListAdapter.getItem(i));
}
outState.putStringArrayList("bleListAdapter", adapterData);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
// Restore Bluetooth devices
ArrayList deviceAddresses = savedInstanceState.getStringArrayList("bleDevices");
if (deviceAddresses != null) {
bleDevices = new ArrayList();
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
for (String address : deviceAddresses) {
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
bleDevices.add(device);
}
}
// Restore adapter data
ArrayList adapterData = savedInstanceState.getStringArrayList("bleListAdapter");
if (adapterData != null) {
bleListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, adapterData);
}
msg("Restored "+ adapterData.size());
}
}
private void connectToDevice(BluetoothDevice device) {
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
msg("Bluetooth is not available or not enabled");
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_LOCATION_PERMISSION);
msg("No CONNECT permission 1");
return;
}
} else {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
msg("No LOCATION permission");
return;
}
}
msg("Trying to connect to device: " + device.getName());
bluetoothGatt = device.connectGatt(this, false, gattCallback);
if (bluetoothGatt == null) {
msg("Failed to connect to the device");
}
}
};
##################################### ####
package com.example.edgetest1;
import android.Manifest;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.UUID;
public class MyGattCallback extends BluetoothGattCallback {
private final Context context;
private final MainActivity activity;
public MyGattCallback(Context context, MainActivity activity) {
this.activity = activity;
this.context = context;
}
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed: " + status + " -> " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
msg("Successfully connected to GATT server.");
if (ActivityCompat.checkSelfPermission(activity, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 3");
return;
}
gatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
msg("Disconnected from GATT server.");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
msg("Connection failed with status: " + status);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
msg("Services discovered successfully.");
BluetoothGattService service = gatt.getService(UUID.fromString("0000180d-0000-1000-8000-00805f9b34fb"));
if (service != null) {
BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"));
if (characteristic != null) {
msg("Char is null");
if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
msg("No CONNECT permission 2");
return;
}
gatt.setCharacteristicNotification(characteristic, true);
}
} else {
msg("Heart Rate service not found.");
}
} else {
msg("Service discovery failed with status: " + status);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"))) {
int heartRate = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
activity.runOnUiThread(() -> activity.pulse.setText("Pulse: " + heartRate));
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
msg("GATT_SUCCESS");
}
}
public void msg(String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
##################################### #
package com.example.edgetest1;
import static com.example.edgetest1.MainActivity.REQUEST_LOCATION_PERMISSION;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.pm.PackageManager;
import android.os.Build;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import java.util.List;
import android.content.Context;
public class MyScanCallback extends ScanCallback {
private final Context context;
private final MainActivity activity;
public MyScanCallback(Context context, MainActivity activity) {
this.activity = activity;
this.context = context;
}
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
if (!activity.bleDevicesContains(device)) {
msg("Have new results");
//bleDevices.add(device);
activity.bleDevices.add(device);
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
String deviceInfo = device.getName() + " (" + device.getAddress() + ")";
//backupBleDevList.add(deviceInfo); // Add device info to backup list
//bleListAdapter.add(deviceInfo);
activity.bleListAdapter.add(deviceInfo);
//bleListAdapter.notifyDataSetChanged();
activity.bleListAdapter.notifyDataSetChanged();
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
msg("Connection state changed: " + status + " -> " + newState);
if (newState == BluetoothGatt.STATE_CONNECTED) {
msg("Successfully connected to GATT server.");
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
gatt.discoverServices(); // Discover services on the connected device
} else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
msg("Disconnected from GATT server.");
} else if (status != BluetoothGatt.GATT_SUCCESS) {
msg("Connection failed with status: " + status);
}
}
};
@Override
public void onBatchScanResults(List results) {
msg("Have the batch results...");
for (ScanResult result : results) {
onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
}
}
@Override
public void onScanFailed(int errorCode) {
msg("BLE scan failed with error code: " + errorCode);
}
private void connectToDevice(BluetoothDevice device) {
if (activity.bluetoothAdapter == null || activity.bluetoothAdapter.isEnabled()) {
msg("Bluetooth is not available or not enabled");
return;
}
// Check necessary permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_LOCATION_PERMISSION);
msg("No CONNECT permission");
return;
}
} else {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
msg("No LOCATION permission");
return;
}
}
msg("Trying to connect to device: " + device.getName());
activity.bluetoothGatt = device.connectGatt(context, false, gattCallback);
if (activity.bluetoothGatt == null) {
msg("Failed to connect to the device");
//retryConnection(device);
}
}
public void msg(String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79331423/ble-devices-scanning-android[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия