Search code examples
androidibeaconaltbeaconibeacon-androidandroid-ibeacon

Android OnePlus6 can't detect iBeacon using AltBeacon library


I'm using the AltBeacon library for detecting iBeacons in my Android app. The code I have works on the following devices:

  • Xiaomi MI9 (Android 10.0)
  • Motorola Moto G4 (Android 6.0.1)
  • Huawei P Smart (Android 8.0)
  • Samsung Galaxy S8 (Android 9.0)

However, the same code doesn't work for a OnePlus 6 (Android 10, OxygenOS 10.3.2). It doesn't detect any beacons in my app. I tried to detect the beacons using an other app (Locate), that works. The creator of the AltBeacon library told me that Locate uses the AltBeacon library, so the beacons are detectable. This means my code setup is wrong. Can you help me by finding out what is wrong with my setup?

I checked (e.g.) this answer, although it didn't fix my problem. I turned debugging on for the BeaconManager but nothing interesting came out of that (an example at the bottom of this question).

In the ViewModel I call the MyStateManager. It contains a List regionsInRange, which contains beacons that are in range. I left out some code because I think it is irrelevant. If you feel like I left out too much, I will add it.

public class MyStateManager implements BootstrapNotifier {

  private static final MyStateManager instance = new MyStateManager();

  private final MyBeaconHelper myBeaconHelper;

  // ViewModel accessess this List to retrieve the beacons that are found.
  public final List<Region> regionsInRange = new ArrayList<>();

  private PresenceRegistrationStateManager() {
      presenceRegistrationBeaconHelper = new PresenceRegistrationBeaconHelper(this);
      updateScanningRegions();
  }

  @Override
  public Context getApplicationContext() {
      return MyApplication.getAppContext();
  }

  @Override
  public void didEnterRegion(Region region) {
      //Empty method
  }

  @Override
  public void didExitRegion(Region region) {
      //Empty method
  }

  @Override
  public void didDetermineStateForRegion(int status, Region region) {
      if (status == OUTSIDE) {
          regionsInRange.remove(region);
      } else {
          if (!regionsInRange.contains(region)) {
              regionsInRange.add(region);
          }
      }
      updateState();
  }

  public static MyStateManager getInstance() {
      return instance;
  }

  public void updateState() {
    // Own implementation here
  } 

  private void updateScanningRegions() {
    // add all the regions here
  }
}

In addition, this is the MyBeaconHelper:

public class MyBeaconHelper implements BeaconConsumer, Serializable {

  private transient final RegionBootstrap regionBootstrap;

  private List<Region> scanRegions = new ArrayList<>();

  public MyBeaconHelper(BootstrapNotifier bootstrapNotifier) {
      BeaconManager beaconManager = BeaconManager.getInstanceForApplication(getApplicationContext());
    
      beaconManager.getBeaconParsers().clear();
      beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
      LogManager.setVerboseLoggingEnabled(true);
      beaconManager.bind(this);

      regionBootstrap = new RegionBootstrap(bootstrapNotifier, new ArrayList<>());
  }

  @Override
  public void onBeaconServiceConnect() {
      //Empty method
  }

  @Override
  public Context getApplicationContext() {
      return MyApplication.getAppContext();
  }

  @Override
  public void unbindService(ServiceConnection serviceConnection) {
      getApplicationContext().unbindService(serviceConnection);
  }

  @Override
  public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) {
      return getApplicationContext().bindService(intent, serviceConnection, i);
  }

  public void updateScanRegions(List<Region> newRegions) {
      for (Region oldRegion : this.scanRegions) {
          if (!newRegions.contains(oldRegion)) {
              regionBootstrap.removeRegion(oldRegion);
          }
      }
      for (Region newRegion : newRegions) {
          if (!this.scanRegions.contains(newRegion)) {
              regionBootstrap.addRegion(newRegion);
          }
      }
      this.scanRegions = newRegions;
  }
}

When I turned debugging on for the BeaconManager, it showed me this a lot of times:

2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: starting a new scan cycle

2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: We are already scanning and have been for 1134 millis

2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: Waiting to stop scan cycle for another 1100 milliseconds

2020-03-31 11:57:30.181 25259-25259/com.my.app D/CycledLeScanner: Scan started

2020-03-31 11:57:31.213 25259-25259/com.my.app D/CycledLeScanner: Waiting to stop scan cycle for another 69 milliseconds

2020-03-31 11:57:31.323 25259-25259/com.my.app D/CycledLeScanner: Done with scan cycle

It keeps printing these lines over and over again...


Solution

  • The log messages shown (these are for OnePlus, yes?) indicate that BLE scanning is started. Do you see any log lines showing hex bytes of the packets detected? If BLE scanning is actually functioning you should. You may want to compare the logs output by the other devices.

    Are you certain proper location permission has been granted to your app on the OnePlus? You can check in Settings -> Apps - > You App -> Permissions. Also confirm Bluetooth is on and location is on for the global phone settings (but if Locate works on the same device, this should not be a problem .)

    It is not clear if this is related, but the use of beaconManager.bind() at the same time as RegionBootstrap is unnecessary and may cause conflicts. The code appears to not use the BeaconConsumer interface that is called back by the bind method. I suggest you remove the bind call, the use of BeaconConsumer and remove all that interface's callback methods just to be sure.