Android BLE - How ist onScanResult Methode aufgerufen wird, in ScanCallback?
Dies ist meine erste Zeit tun mit Bluetooth Low Energy im Android-Projekt. Das Projekt, das ich mache, ist grundsätzlich zur Erkennung von Bluetooth-LE-Geräten und verbinden Sie Sie zu entdecken, Ihre Dienstleistungen.
Möchte ich Fragen, ob jemand weiß, wie onScanResult(), onBatchScanResults() und onScanFailed () - Methode aufgerufen wird, in ScanCallback?
Zunächst laufen scanLeDevice () - Methode.
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);
In dieser Methode wird es startScan. Also gehe ich davon aus, dass die scan-Ergebnisse werden geliefert mit diesen Rückruf.
@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);
}
}
Jedoch In ScanCallback, ich habe keine Ahnung, wie es löst onScanResult und liefern die scan-Ergebnis mit dem Rückruf. In meinem Test(siehe unten), weder onScanResult() noch onBatchScanResults() und onScanFailed() aufgerufen werden. Kann jemand erklären, das Konzept zu mir? Es wird mir sehr helfen!
/* 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()
Verwendung von Android-Handy mit API-23
Den code, den ich hier geschrieben habe ist bezeichnet: http://www.truiton.com/2015/04/android-bluetooth-low-energy-ble-example/
[Aktualisiert Code V1]- funktioniert Nicht
Ist hier mein code
Ich habe eine virtuelle Peripherie, und es ist in der Werbung-Modus. Die virtuelle Peripherie entsteht durch eine app namens Hellblau: https://itunes.apple.com/us/app/lightblue-explorer-bluetooth/id557428110?mt=8
Bitte helfen Sie mir, bitte mein 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;
}
}
}
- haben Sie versucht, Sie anzurufen
flushPendingScanResults(ScanCallback callback)
vielleicht in Ihrem postDelayed handler Stoppt den scan? , Das wird zwingen, einen Anruf zu onBatchScanResults. Ich bin mir nicht sicher, ob es wird die Methode aufgerufen, wenn es keine Ergebnisse, aber ich würde erwarten, dass, selbst wenn es gibt keine Geräte zu melden, es wird die Methode aufgerufen, und nur eine leere Liste zurück. Zumindest dann, können Sie bestätigen, wenn Sie Ihre Geräte erkannt werden oder nicht. - Und haben Sie beantragt, BLUETOOTH_ADMIN-Berechtigung in Ihrer manifest-Datei?
- Habe noch nicht versucht
flushPendingScanResults(ScanCallback callback)
und ich werde versuchen, dass jetzt 🙂 Für deine zweite Frage, ja, habe ich beantragt, und andere, die bluetooth-Berechtigung. - Ich sehe aus deiner Antwort unten, dass Sie das problem gelöst, indem ersuchenden BLUETOOTH_ADMIN-Berechtigung. Ich vermutete, dass das problem sein könnte früh auf, aber als ich bei der Berechtigung Fragen, die ich bin, gewohnt zu sehen, eine explizite Nachricht in das Android-system-Protokolle, die besagt, "Sie können nicht dies tun, ohne Erlaubnis", und manchmal ein Absturz. Da Sie nicht haben, dass ich dachte, dass war nicht das problem hier. Da Sie bereits akzeptierte meine Antwort, ich werde es Bearbeiten zu inlcude diese Informationen. Für Vollständigkeit, können Sie überprüfen, was passiert, wenn Sie
startScan()
mit einer leeren Arraylist ScanFilters?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich sehen, dass Sie mit der
public void startScan (List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
Methode derstartScan()
, aber Sie können niemals definieren, ohne Filter. Stattdessen übergeben Sie eine leere ArrayList mit ScanFilters. Damit Sie nicht immer alle Rückrufe, weil Sie nicht, sofern keine Kriterien für die Filter-match gegen.Da Sie sagte, das Sie Scannen möchten, für alle BLE-Geräte, gibt es keine Notwendigkeit zu verwenden die Filter überhaupt. Verwenden Sie stattdessen die einfachere
public void startScan (ScanCallback callback)
Methode, die keine Filter oder spezielle Einstellungen.Bezüglich Ihrer Anfrage zu verstehen, wie alles funktioniert - ich glaube, Sie haben das Konzept auf der Basis Ihres Codes und Ihrer Erwartung, dass die Rückrufe bekommen sollten, ausgelöst. Sie den Suchlauf starten, und das system geht aus und dauert der scan, ohne zu blockieren Ihren code execution (d.h. es tut asynchron). Während der scan ausgeführt wird, wird er rufen Sie eine der drei Methoden in der callback-Objekt, wenn es angemessen ist (siehe API-Dokumentation). Das ist ziemlich viel es.
UPDATE:
Stellen Sie sicher, dass Sie anfordern, BLUETOOTH, BLUETOOTH_ADMIN-Berechtigungen, sowie die ACCESS_COARSE_LOCATION oder Berechtigungen ACCESS_FINE_LOCATION. Diese sind erforderlich, um zu empfangen Rückrufe aus der
startScan()
Methode. Leider, wenn Sie nicht diese Anfrage persmissions, wird der scan nur leise ausfällt. Ich würde es vorziehen, wenn das system liefert eine Warnung in den logs oder löst einen callback auf dieonScanFailed()
Methode mit dem Fehlercode, der angibt, das problem.So.. ich habe endlich die Antwort gefunden.
Für Android-Geräte, die Android 6.0 oder höher (wie mein Handy ist Nexus 5x), beide GPS und Bluetooth in Ihrem Telefon einstellen muss schalten, plus in Ihrem manifest müssen Sie
BLUETOOTH
BLUETOOTH_ADMIN
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
Berechtigung.Nun alles funktioniert gut für mich 🙂