Android BLE - Comment est onScanResult méthode appelée dans ScanCallback?
C'est ma première fois de faire de Bluetooth de Basse Énergie dans le projet Android. Le projet que je suis en train de faire est de détecter tous les appareils Bluetooth LE et de les connecter à découvrir leurs services.
Je voudrais demander si quelqu'un sait comment onScanResult(), onBatchScanResults() et onScanFailed() les méthodes sont appelés dans ScanCallback?
Au Premier abord, exécutez scanLeDevice() la méthode.
BluetoothLeScanner mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build();
List<ScanFilter> filters = new ArrayList<ScanFilter>();
scanLeDevice(true);
Dans cette méthode, il sera startScan. Donc je suppose que les résultats de l'analyse sont présentées à l'aide de ces de rappel.
@TargetApi(21)
private void scanLeDevice(final boolean enable) {
if (enable) {
//stops scanning after a pre-defined scan period
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("BLE//mLEScanner.stopScan(mScanCallback) ");
mLEScanner.stopScan(mScanCallback);
}
}
}, SCAN_PERIOD);
System.out.println("BLE//mLEScanner.startScan(filters, settings, mScanCallback)");
mLEScanner.startScan(filters, settings, mScanCallback);
} else {
System.out.println("BLE//mLEScanner.stopScan(mScanCallback)");
mLEScanner.stopScan(mScanCallback);
}
}
Cependant, Dans ScanCallback, je n'ai aucune idée de comment il se déclenche onScanResult et de livrer le résultat de l'analyse à l'aide de la fonction de rappel. Lors de mes tests(comme illustré ci-dessous), ni onScanResult() ni onBatchScanResults() et onScanFailed() sera appelée. Quelqu'un peut m'expliquer le concept de moi? Il va beaucoup m'aider!
/* Scan result for SDK >= 21 */
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
System.out.println("BLE//onScanResult");
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
System.out.println("BLE//onBatchScanResults");
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
@Override
public void onScanFailed(int errorCode) {
System.out.println("BLE//onScanFailed");
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
02-17 10:38:38.513 878-895/? D/BluetoothManagerService: Added callback: android.bluetooth.IBluetoothManagerCallback$Stub$Proxy@8334cf4:true
02-17 10:38:38.520 782-782/? D/BluetoothAdapter: STATE_ON
02-17 10:38:38.529 21554-21590/? D/BtGatt.GattService: registerClient() - UUID=835342c6-81eb-4e09-9729-5bbe1c22bc86
02-17 10:38:38.529 21554-21570/? D/BtGatt.GattService: onClientRegistered() - UUID=835342c6-81eb-4e09-9729-5bbe1c22bc86, clientIf=5
02-17 10:38:38.530 782-793/? D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
02-17 10:38:38.530 21554-21599/? D/BtGatt.GattService: start scan with filters
02-17 10:38:38.532 782-782/? I/System.out: BLE//mLEScanner.startScan(filters, settings, mScanCallback)
02-17 10:38:38.532 21554-21573/? D/BtGatt.ScanManager: handling starting scan
02-17 10:38:38.534 21576-21577/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK ON using UART driver's ioctl()
02-17 10:38:38.542 21554-21570/? D/BtGatt.GattService: onScanFilterEnableDisabled() - clientIf=5, status=0, action=1
02-17 10:38:38.543 21554-21570/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
02-17 10:38:38.543 21554-21573/? D/BtGatt.ScanManager: configureFilterParamter 500 10000 1 0
02-17 10:38:38.547 21554-21570/? D/BtGatt.GattService: onScanFilterParamsConfigured() - clientIf=5, status=0, action=0, availableSpace=15
02-17 10:38:38.547 21554-21570/? D/BtGatt.ScanManager: callback done for clientIf - 5 status - 0
02-17 10:38:38.548 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams() - queue=1
02-17 10:38:38.548 487-2827/? I/ACDB-LOADER: ACDB AFE returned = -19
02-17 10:38:38.549 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams() - ScanSetting Scan mode=0 mLastConfiguredScanSetting=-2147483648
02-17 10:38:38.549 21554-21573/? D/BtGatt.ScanManager: configureRegularScanParams - scanInterval = 8000configureRegularScanParams - scanWindow = 800
02-17 10:38:38.549 21554-21570/? D/BtGatt.GattService: onScanParamSetupCompleted : 0
02-17 10:38:38.568 21554-21574/? W/bt_hci: filter_incoming_event command complete event with no matching command. opcode: 0x0.
02-17 10:38:38.603 21554-21570/? D/bt_btif_gattc: btif_gattc_update_properties BLE device name=Polar HR Sensor len=15 dev_type=2
02-17 10:38:39.571 21576-21585/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()
02-17 10:38:43.526 782-782/? I/System.out: BLE//mLEScanner.stopScan(mScanCallback)
02-17 10:38:43.599 21576-21576/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK ON using UART driver's ioctl()
02-17 10:38:43.967 21576-21576/? I/WCNSS_FILTER: ibs_msm_serial_clock_vote: vote UART CLK OFF using UART driver's ioctl()
À l'aide d'un Téléphone Android avec l'API 23
Le code que j'ai écrit ici est appelé: http://www.truiton.com/2015/04/android-bluetooth-low-energy-ble-example/
[Mise à jour du Code V1]- Pas de travail
Voici tout mon code
J'ai créé un Périphérique virtuel et il est dans la publicité de mode. Le Périphérique virtuel est créé grâce à une application appelée LightBlue: https://itunes.apple.com/us/app/lightblue-explorer-bluetooth/id557428110?mt=8
S'il vous plaît aider moi pour vérifier mon code 🙂
@TargetApi(21)
public class BluetoothLE extends Fragment {
View view;
private BluetoothAdapter mBluetoothAdapter;
private int REQUEST_ENABLE_BT = 1;
private Handler mHandler;
private static final long SCAN_PERIOD = 5000; //Stops scanning after 5 seconds
private BluetoothLeScanner mLEScanner;
private BluetoothGatt mGatt; //To provide bluetooth communication
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
private int permissionCheck;
public BluetoothLE(){
//empty constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_bluetooth, container, false);
mHandler = new Handler();
/* check if BLE is supported in this phone */
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(getActivity(), "BLE Not Supported", Toast.LENGTH_SHORT).show();
getActivity().finish();
}
/* Enable bluetooth without leaving app */
final BluetoothManager bluetoothManager =
(BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
/* Build ScanSetting */
ScanSettings.Builder scanSetting = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setReportDelay(5000);
settings = scanSetting.build();
return view;
}
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onResume() {
super.onResume();
/* Ensures Bluetooth is available on the device and it is enabled. If not, displays a dialog requesting user permission to enable Bluetooth. */
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { //Unable to obtain a BluetoothAdapter
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); //trigger onActivityResult
} else {
if (Build.VERSION.SDK_INT >= 21) {
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build();
filters = new ArrayList<ScanFilter>();
}
if(Build.VERSION.SDK_INT >= 23){
checkLocationPermission();
}
scanLeDevice(true);
}
}
@Override
public void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
@Override
public void onDestroy() {
if (mGatt == null) {
return;
}
mGatt.close();
mGatt = null;
super.onDestroy();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("BLE//onActivityResult");
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_CANCELED) {
//Bluetooth not enabled.
getActivity().finish();
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
//stops scanning after a pre-defined scan period
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (Build.VERSION.SDK_INT < 21) {
System.out.println("BLE//mBluetoothAdapter.stopLeScan(mLeScanCallback) ");
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
mLEScanner.stopScan(mScanCallback);
System.out.println("BLE//mLEScanner.stopScan(mScanCallback) ");
}
}
}, SCAN_PERIOD);
if (Build.VERSION.SDK_INT < 21) {
System.out.println("BLE//mBluetoothAdapter.startLeScan(mLeScanCallback)");
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mLEScanner.startScan(mScanCallback);
//mLEScanner.startScan(filters, settings, mScanCallback);
System.out.println("BLE//mLEScanner.startScan(mScanCallback) ");
}
} else {
if (Build.VERSION.SDK_INT < 21) {
System.out.println("BLE//mBluetoothAdapter.stopLeScan(mLeScanCallback)");
mBluetoothAdapter.stopLeScan(mLeScanCallback);
} else {
System.out.println("BLE//mLEScanner.stopScan(mScanCallback)");
mLEScanner.stopScan(mScanCallback);
}
}
}
/* Scan result for SDK >= 21 */
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
System.out.println("BLE//onScanResult");
super.onScanResult(callbackType, result);
Log.i("callbackType", String.valueOf(callbackType));
Log.i("result", result.toString());
Log.i("Device Name: ", result.getDevice().getName());
System.out.println("Signal: " + result.getRssi());
BluetoothDevice btDevice = result.getDevice();
connectToDevice(btDevice);
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
System.out.println("BLE//onBatchScanResults");
for (ScanResult sr : results) {
Log.i("ScanResult - Results", sr.toString());
}
}
@Override
public void onScanFailed(int errorCode) {
System.out.println("BLE//onScanFailed");
Log.e("Scan Failed", "Error Code: " + errorCode);
}
};
//scan results are returned here SDK < 21
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
System.out.println("BLE//DEVICDE FOUND");
Log.i("onLeScan", device.toString());
connectToDevice(device);
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
System.out.println("BLE//connectToDevice()");
if (mGatt == null) {
mGatt = device.connectGatt(getActivity(), false, gattCallback); //Connect to a GATT Server
//scanLeDevice(false);//will stop after first device detection
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
System.out.println("BLE//BluetoothGattCallback");
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.i("gattCallback", "STATE_CONNECTED");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_CONNECTING:
Log.i("gattCallback", "STATE_CONNECTING");
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED");
break;
default:
Log.e("gattCallback", "STATE_OTHER");
}
}
@Override
//New services discovered
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
//Result of a characteristic read operation
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic
characteristic, int status) {
Log.i("onCharacteristicRead", characteristic.toString());
gatt.disconnect();
}
};
public void checkLocationPermission(){
permissionCheck = ContextCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_COARSE_LOCATION);
switch(permissionCheck){
case PackageManager.PERMISSION_GRANTED:
break;
case PackageManager.PERMISSION_DENIED:
if(ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), android.Manifest.permission.ACCESS_COARSE_LOCATION)){
//Show an explanation to user *asynchronouselly* -- don't block
//this thread waiting for the user's response! After user sees the explanation, try again to request the permission
Snackbar.make(view, "Location access is required to show Bluetooth devices nearby.",
Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
else{
//No explanation needed, we can request the permission
ActivityCompat.requestPermissions(getActivity(), new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
break;
}
}
}
flushPendingScanResults(ScanCallback callback)
, peut-être dans votre postDelayed gestionnaire qui s'arrête à l'analyse? Qui va forcer un appel à onBatchScanResults. Je ne suis pas certain si il va appeler la méthode si il n'y a pas des résultats, mais je m'attends à ce que, même si il n'y a pas de dispositifs de rapport, il va appeler la méthode et il suffit de retourner une liste vide. Au moins, vous pouvez vérifier si vos périphériques sont détectés à tous ou non.Et avez-vous demandé BLUETOOTH_ADMIN permission dans votre fichier de manifeste?
Pas encore essayé
flushPendingScanResults(ScanCallback callback)
et je vais essayer ça de suite 🙂 Pour ta deuxième question, oui, j'ai demandé à l'un et l'autre bluetooth autorisation.Je vois de votre réponse ci-dessous que vous avez résolu le problème en demandant BLUETOOTH_ADMIN autorisation. Je me doutais que pourrait être le problème au début, mais quand j'ai rencontré des problèmes d'autorisation, je suis habitué à voir un message explicite dans le système Android journaux que les états "vous ne pouvez pas le faire sans la permission", et parfois un crash. Puisque vous n'avez pas que je pensais que ce n'était pas le problème ici. Puisque vous avez déjà accepté ma réponse, je vais éditer pour les suivants de cette information. Pour être complet, pouvez-vous vérifier ce qui se passe si vous utilisez
startScan()
avec un vide Arraylist de ScanFilters?
OriginalL'auteur janice chau | 2016-02-17
Vous devez vous connecter pour publier un commentaire.
Je vois que vous utilisez le
public void startScan (List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
méthode destartScan()
, mais vous ne jamais définir des filtres. Au lieu de cela, vous passez un vide ArrayList de ScanFilters. Si vous n'êtes pas obtenir jamais rappels parce que vous n'avez pas fourni tous les critères pour que les filtres match contre.Puisque vous avez dit que vous voulez numériser pour tous BLE appareils, il n'est pas nécessaire d'utiliser des filtres à tous. Au lieu de cela, l'utilisation la plus simple
public void startScan (ScanCallback callback)
méthode, qui permet de ne pas utiliser des filtres ou des établissements spécialisés.Concernant votre demande de comprendre comment tout cela fonctionne - je pense que vous avez le concept de la baisse en fonction de votre code et de vos attentes que les rappels doivent se déclencher. Vous commencez la numérisation, et le système s'éteint et ne l'analyse sans bloquer votre exécution de code (c'est à dire il le fait de manière asynchrone). Alors que le scan est en cours, il va appeler l'une des trois méthodes dans votre objet de rappel à chaque fois que nécessaire (comme décrit dans la documentation de l'API). C'est assez bien.
Mise à JOUR:
Assurez-vous que vous demande le BLUETOOTH, BLUETOOTH_ADMIN autorisations, ainsi que la ACCESS_COARSE_LOCATION ou ACCESS_FINE_LOCATION autorisations. Ces données sont nécessaires pour recevoir les rappels de l'
startScan()
méthode. Malheureusement, si vous n'avez pas de demande de ces permissions, l'analyse juste silencieusement échoue. Je préfère, si le système fournit un message d'avertissement dans les journaux ou déclenche un rappel à laonScanFailed()
méthode avec le code d'erreur indiquant que le problème.Êtes-vous certain que vous avez BLE des dispositifs de proximité, qui sont dans la publicité de mode? Merci de poster le code à jour.
Salut rothloup, j'ai post mon code dans la réponse que le commentaire ici a la limite de caractères. Merci 🙂
janice - vous pouvez mettre à jour votre message original par l'édition. Poster une réponse de dérouter les lecteurs avec les mêmes problèmes que vous, quand ils viennent à travers cette question.
Avez-vous été en mesure de confirmer, à l'aide de logiciel qui est appelé à travailler pour la détection de BLE périphériques (c'est à dire Android bluetooth intégrée fonctions de recherche), que l'appareil est détectable? Je déteste chasser un SW bug jamais juste pour découvrir que ce n'est pas détecter quoi que ce soit car il n'y a rien à détecter.
OriginalL'auteur rothloup
Donc.. j'ai enfin trouvé la réponse.
Pour les Appareils Android qui sont Android 6.0 ou supérieur (comme mon téléphone est Nexus 5x), les deux GPS et Bluetooth dans votre téléphone doit être activer, en plus dans votre manifeste, vous devez ajouter
BLUETOOTH
BLUETOOTH_ADMIN
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
autorisation.Maintenant tout fonctionne bien pour moi 🙂
Il a été "Emplacement" pour moi, les principaux paramètres du téléphone. C'était, même si l'application correctement les autorisations demandées (et obtenu), rien n'a été trouvé parce que l'Endroit a été réglé sur "Off". Ugh.
OriginalL'auteur janice chau