Я делаю приложение Android, которое должно подключаться к BLE-модулю и уметь читать его услуги и характеристики. Мое приложение основано на коде приложения Accent Systems "iBKS Hello World" .
Я не использую iBeacons, а использую другой тип BLE-модуля. Но когда я подключаюсь к нему, приложение не показывает список услуг и характеристик, как указывает код, что должно произойти.
Может ли кто-нибудь помочь мне решить эту проблему? Пожалуйста, дайте мне знать!
Мой код:
public class ScanActivity extends AppCompatActivity {
//DEFINE VARS
String TAG = "ScanActivity";
BluetoothAdapter mBluetoothAdapter;
BluetoothGatt mBluetoothGatt;
BluetoothLeScanner scanner;
ScanSettings scanSettings;
private List<String> scannedDeivcesList;
private ArrayAdapter<String> adapter;
//DEFINE LAYOUT
ListView devicesList;
//THIS METHOD RUNS ON APP LAUNCH
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan);
//Define listview in layout
devicesList = (ListView) findViewById(R.id.devicesList);
//Setup list on device click listener
setupListClickListener();
//Initialize de devices list
scannedDeivcesList = new ArrayList<>();
//Initialize the list adapter for the listview with params: Context / Layout file / TextView ID in layout file / Devices list
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, scannedDeivcesList);
//Set the adapter to the listview
devicesList.setAdapter(adapter);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
SpannableString s = new SpannableString("Scan for modules");
s.setSpan(new com.accent_systems.ibkshelloworld.TypefaceSpan(this, "Khand-Bold.ttf"), 0, s.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
s.setSpan(new ForegroundColorSpan(Color.parseColor("#3a3c3e")), 0, s.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
setTitle(s);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
//init Bluetooth adapter
initBT();
//Start scan of bluetooth devices
startLeScan(true);
}
@Override
protected void onStop() {
super.onStop();
startLeScan(false);
}
private void initBT(){
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
//Create the scan settings
ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
//Set scan latency mode. Lower latency, faster device detection/more battery and resources consumption
scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
//Wrap settings together and save on a settings var (declared globally).
scanSettings = scanSettingsBuilder.build();
//Get the BLE scanner from the BT adapter (var declared globally)
scanner = mBluetoothAdapter.getBluetoothLeScanner();
}
private void startLeScan(boolean endis) {
if (endis) {
//********************
//START THE BLE SCAN
//********************
//Scanning parameters FILTER / SETTINGS / RESULT CALLBACK. Filter are used to define a particular
//device to scan for. The Callback is defined above as a method.
scanner.startScan(null, scanSettings, mScanCallback);
}else{
//Stop scan
scanner.stopScan(mScanCallback);
}
}
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
//Here all the detected BLE devices will be received . "result" contains the device
//address and name as a BLEPeripheral, the advertising content as a ScanRecord, the Rx RSSI
//and the timestamp when received. Type result.get... to see all the available methods you can call.
//Convert advertising bytes to string for a easier parsing. GetBytes may return a NullPointerException. Treat it right(try/catch).
String advertisingString = byteArrayToHex(result.getScanRecord().getBytes());
//Print the advertising String in the LOG with other device info (ADDRESS - RSSI - ADVERTISING - NAME)
Log.i(TAG, result.getDevice().getAddress()+" - RSSI: "+result.getRssi()+"\t - "+advertisingString+" - "+result.getDevice().getName());
//Check if scanned device is already in the list by mac address
boolean contains = false;
for(int i=0; i<scannedDeivcesList.size(); i++){
if(scannedDeivcesList.get(i).contains(result.getDevice().getAddress())){
//Device already added
contains = true;
//Replace the device with updated values in that position
scannedDeivcesList.set(i, result.getRssi()+" "+result.getDevice().getName()+ "\n ("+result.getDevice().getAddress()+")");
break;
}
}
if(!contains){
//Scanned device not found in the list. NEW => add to list
scannedDeivcesList.add(result.getRssi()+" "+result.getDevice().getName()+ "\n ("+result.getDevice().getAddress()+")");
}
//After modify the list, notify the adapter that changes have been made so it updates the UI.
//UI changes must be done in the main thread
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
};
//Method to convert a byte array to a HEX. string.
private String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
void setupListClickListener(){
devicesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Stop the scan
Log.i(TAG, "SCAN STOPPED");
scanner.stopScan(mScanCallback);
//Get the string from the item clicked
String fullString = scannedDeivcesList.get(position);
//Get only the address from the previous string. Substring from '(' to ')'
String address = fullString.substring(fullString.indexOf("(")+1, fullString.indexOf(")"));
//Get BLE device with address
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
//******************************
//START CONNECTION WITH DEVICE AND DECLARE GATT
//******************************
Log.i(TAG,"*************************************************");
Log.i(TAG, "CONNECTION STARTED TO DEVICE "+address);
Log.i(TAG,"*************************************************");
//ConnectGatt parameters are CONTEXT / AUTOCONNECT to connect the next time it is scanned / GATT CALLBACK to receive GATT notifications and data
// Note: On Samsung devices, the connection must be done on main thread
mBluetoothGatt = device.connectGatt(ScanActivity.this, false, mGattCallback);
/*
There is also another simplest way to connect to a device. If you already stored
the device in a list (List<BluetoothDevice>) you can retrieve it directly and
connect to it:
mBluetoothGatt = mList.get(position).connectGatt(MainActivity.this, false, mGattCallback);
*/
}
});
}
//Connection callback
BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
//Device connected, start discovering services
Log.i(TAG, "DEVICE CONNECTED. DISCOVERING SERVICES...");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//Device disconnected
Log.i(TAG, "DEVICE DISCONNECTED");
}
}
// On discover services method
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//Services discovered successfully. Start parsing services and characteristics
Log.i(TAG, "SERVICES DISCOVERED. PARSING...");
displayGattServices(gatt.getServices());
} else {
//Failed to discover services
Log.i(TAG, "FAILED TO DISCOVER SERVICES");
}
}
//When reading a characteristic, here you receive the task result and the value
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//READ WAS SUCCESSFUL
Log.i(TAG, "ON CHARACTERISTIC READ SUCCESSFUL");
//Read characteristic value like:
//characteristic.getValue();
//Which it returns a byte array. Convert it to HEX. string.
} else {
Log.i(TAG, "ERROR READING CHARACTERISTIC");
}
}
//When writing, here you can check whether the task was completed successfully or not
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i(TAG, "ON CHARACTERISTIC WRITE SUCCESSFUL");
} else {
Log.i(TAG, "ERROR WRITING CHARACTERISTIC");
}
}
//In this method you can read the new values from a received notification
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i(TAG, "NEW NOTIFICATION RECEIVED");
//New notification received. Check the characteristic it comes from and parse to string
/*if(characteristic.getUuid().toString().contains("0000fff3")){
characteristic.getValue();
}*/
}
//RSSI values from the connection with the remote device are received here
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
Log.i(TAG, "NEW RSSI VALUE RECEIVED");
//Read remote RSSI like: mBluetoothGatt.readRemoteRssi();
//Here you get the gatt table where the rssi comes from, the rssi value and the
//status of the task.
}
};
//Method which parses all services and characteristics from the GATT table.
private void displayGattServices(List<BluetoothGattService> gattServices) {
//Check if there is any gatt services. If not, return.
if (gattServices == null) return;
// Loop through available GATT Services.
for (BluetoothGattService gattService : gattServices) {
Log.i(TAG, "SERVICE FOUND: "+gattService.getUuid().toString());
//Loop through available characteristics for each service
for (BluetoothGattCharacteristic gattCharacteristic : gattService.getCharacteristics()) {
Log.i(TAG, " CHAR. FOUND: "+gattCharacteristic.getUuid().toString());
}
}
//****************************************
// CONNECTION PROCESS FINISHED!
//****************************************
Log.i(TAG, "*************************************");
Log.i(TAG, "CONNECTION COMPLETED SUCCESFULLY");
Log.i(TAG, "*************************************");
}
}