1

I have an application scanning BluetoothLE devices (temperature). The application is whitelisted in the list for battery optimizations and uses a PARTIAL_WAKE_LOCK.

It works like a charm with a Zebra TC25 Android 7.1.2 using a thread scanning BLE devices every 10 minutes independently of the android device state.

However the same application does not work at all with a samsung galaxy S10+ Android 10 when the screen is off (it works when screen is on). I know that the simple thread method will not work because of doze mode. So I also tried these ways :

setExactAndAllowWhileIdle(TJAlarmManager.JavaClass.RTC_WAKEUP, time,PendingIntent) and firebase cloud messaging sending high priority message. Alarm method has limitations but fcm has not as far as I know.

These 2 ways also failed. The fcm message is received and the alarm triggers, both run the BLEDiscover procedure below to run a bluetooth scan, but no bluetooth device are discovered.

Here is what happens in two situations. In the fisrt one, the screen is on, it always works :

12-08 12:39:58.994: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.994: D/BluetoothLeScanner(30351): could not find callback wrapper
12-08 12:39:58.995: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.997: D/BluetoothAdapter(30351): STATE_ON
12-08 12:39:58.997: D/BluetoothLeScanner(30351): Start Scan with callback
12-08 12:39:59.001: D/BluetoothLeScanner(30351): onScannerRegistered() - status=0 scannerId=14 mScannerId=0
12-08 12:39:59.965: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - device touvé : C_T_801362
12-08 12:39:59.977: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - TAG touvé : C_T_801362
12-08 12:39:59.977: I/info(30351): FMX: tags (Nil): 4154326484 - Trame 6E2A7207 - T° 19,06
12-08 12:39:59.983: I/info(30351): FMX: alerte (Nil): 4154326484 - BLEAlerte
12-08 12:40:04.928: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - device touvé : P_T_8038DB
12-08 12:40:04.948: I/info(30351): FMX: tags (Nil): 4154326484 - BLEDiscoverLEDevice - TAG touvé : P_T_8038DB
12-08 12:40:04.948: I/info(30351): FMX: tags (Nil): 4154326484 - Trame 6E2A6C07 - T° 19,00
12-08 12:40:04.955: I/info(30351): FMX: alerte (Nil): 4154326484 - BLEAlerte
12-08 12:40:19.038: D/BluetoothAdapter(30351): STATE_ON
12-08 12:40:19.038: D/BluetoothLeScanner(30351): Stop Scan with callback

As soon as the screen is off, it never works:

12-08 12:44:02.094: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.094: D/BluetoothLeScanner(30351): could not find callback wrapper
12-08 12:44:02.096: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.098: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:02.098: D/BluetoothLeScanner(30351): Start Scan with callback
12-08 12:44:02.101: D/BluetoothLeScanner(30351): onScannerRegistered() - status=0 scannerId=10 mScannerId=0
12-08 12:44:23.110: D/BluetoothAdapter(30351): STATE_ON
12-08 12:44:23.110: D/BluetoothLeScanner(30351): Stop Scan with callback

So thread, alarm and fcm lead to the same result, that is when screen is off, no BLE devices are discoverd.

Here is the code :

// Discovering BLE devices
procedure TfData.BLEDiscover();
begin
    FBluetoothManagerLE := TBluetoothLEManager.Current;
    FBluetoothManagerLE.OnDiscoverLEDevice := BLEDiscoverLEDevice;
    FBluetoothManagerLE.StartDiscovery(10000);
end;
 

procedure TfData.BLEDiscoverLEDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice; Rssi: Integer; const ScanResponse: TScanResponse);
var tag, i: Integer;
    vals : TArray<Byte>;
    trame : string;
    temperature : single;
begin
  log('tags', 'BLEDiscoverLEDevice - device touvé : ' + ADevice.DeviceName);
  lockTags.Acquire;
  if ADevice.DeviceName <> '' then begin
    for tag := Low(Tags) to High(Tags) do begin
      if (ADevice.DeviceName = Tags[tag].K_TAG) then begin
          log('tags', 'BLEDiscoverLEDevice - TAG touvé : ' + ADevice.DeviceName);
          trame := '';
          vals := ADevice.AdvertisedData.ExtractPair(TScanResponseKey.ServiceData).Value;
          for i  := 0 to length(vals) - 1 do begin
            trame := trame + IntToHex(vals[i]);
          end;
          temperature:=BLEReadTrame(trame);
          log('tags', 'Trame '+trame + ' - T° '+ formatFloat('0.00',temperature));
          if (temperature <> tagNullTemp) then begin
            Tags[tag].T_LAST := temperature;
            Tags[tag].DtLastTemp := now;
          end;
        end;
        break;
      end;
    end;
  end;
  lockTags.Release;
end;

Edit : Please note I use fcm method to get real time gps position, so the device gets GPS and sends it to server over Internet, it always works , even screen off.

user2244705
  • 361
  • 4
  • 16

2 Answers2

1

Android 10+ requires ACCESS_BACKGROUND_LOCATION permission for Bluetooth scanning in the background.

If you're using Delphi 10.4.1, check the Access background location checkbox in the Application > Uses Permissions section of the Project Options. For earlier versions of Delphi you may need to modify AndroidManifest.template.xml to add the permission:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Also use the PermissionsService to request the permissions at runtime.

Dave Nottage
  • 3,411
  • 1
  • 20
  • 57
  • Thanks Dave, I didn't know that so I tried. The device asked for the permission so it confirms the permission is granted. But still not working using thread nor fcm. Note that location works without this permission using fcm, so I'm not surprised because fcm wakes the device, so it's not really background operation. – user2244705 Dec 09 '20 at 06:22
  • "wakes the device" does not mean it's no longer a background operation. It's possible it may need to happen in a service, which may need to run as a "foreground" service – Dave Nottage Dec 09 '20 at 06:32
  • How to explain that location itself does not need ACCESS_BACKGROUND_LOCATION to work ? Using fcm, a request location works without this permission, so I guess it is not a background operation. So why bluetooth LE scanning would be ? I'm a bit confused and can't find any clear information about bluetooth LE. – user2244705 Dec 09 '20 at 12:29
  • That's the explanation for why location in background works in my case : The documentation says if your app runs on Android 10 or higher but targets Android 9 (API level 28) or lower, and app uses ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION, the system automatically adds ACCESS_BACKGROUND_LOCATION. I'm targeting 28, so ok, the permission was already granted. It still not explains Bluetooth problem, so I'm still searching. – user2244705 Dec 09 '20 at 14:29
0

I tried using a foreground service, I get exactly the same result : Screen on, service background, the discover works. Screen off, service foreground, discover does not work at all cause the call back function is never called. I guess the problem is Samsung hardware, not Android. Maybe Samsung disables Bluetooth scan when screen is off. That's stupid, particularly for bluetooth "LE". The tags (for temperature measure) I use are as big as a coin but have 5 to 15 years autonomy sending bluetooth trames every 3 seconds. So even if bluetooth scan consumes a bit more energy (not sure), it can not be a battery drainer assuming you scan everys 5 or 10 minutes. Not more than a location service. Note that in France we have an application "Anticovid" based on bluetooth... probably it does not work at all with Samsung phones as long as theses phones screens stay off ?

Edit : I found a workaround using this post Android: How to turn screen on and off programmatically?

WakeLock := PowerManager.newWakeLock(TJPowerManager.JavaClass.SCREEN_BRIGHT_WAKE_LOCK or TJPowerManager.JavaClass.ACQUIRE_CAUSES_WAKEUP, StringToJString('myapp'));

Before calling the bluetooth scan, I call this code, it turns on the screen for some seconds, enough to scan BLE devices, it works fine. So one solution is to check whether the device is able to scan with screen off and to activate this code only for devices unable to scan.

Not already sure it's a good way, but it's the only one in my case.

user2244705
  • 361
  • 4
  • 16
  • This should have been posted in a comment, not an answer. – fpiette Dec 11 '20 at 18:14
  • Yes, I tried but too long for a comment and split it into several comments is not very clear. And finally, I think that is the answer : Not possible with Samsung S10. – user2244705 Dec 12 '20 at 07:45