AltBeacon / android-beacon-library

Allows Android apps to interact with BLE beacons
Apache License 2.0
2.83k stars 834 forks source link

Scanning is broken after return to fragment - rangedBeacons.observe not work properly. #1073

Closed NimaaZx closed 2 years ago

NimaaZx commented 2 years ago

Redmi note 3 pro - AOSP Version 9.

'org.altbeacon:android-beacon-library:2.19.3'

Hey David. Thanks for improving your library. I have created another issue a year and half ago. I was familiar with your library. after updating to latest version , I saw you added observer and some new functions. You added them in "https://altbeacon.github.io/android-beacon-library/samples.html" , Ranging Example Code part.

so I decided to use them. but I guess there are bugs. I wanted to scan one time for 7 seconds and stop until I start again by button. this issue is not related to button function. when fragment oncreateview is loaded scanning is triggered (permission checked).


class InFragment() : androidx.fragment.app.Fragment(){
     lateinit var region : Region
     lateinit var beaconManager: BeaconManager`

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
        beaconManager =  BeaconManager.getInstanceForApplication(requireContext())
        region = Region("all-beacons-region", null, null, null)
        beaconManager.getBeaconParsers().add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))

        BeaconManager.setDebug(true)
        beaconManager.updateScanPeriods()
        beaconManager.foregroundScanPeriod=7000L
        // Set up a Live Data observer so this Activity can get ranging callbacks
        beaconManager.getRegionViewModel(region).rangedBeacons.observe(viewLifecycleOwner, rangingObserver)

        if(checkGPS_BLE())
            beaconManager.startRangingBeacons(region)

}

    override fun onDestroyView() {
    //adding or removing this part does not affect.
       beaconManager.stopRangingBeacons(region)
        super.onDestroyView()
    }

    val rangingObserver = Observer<Collection<Beacon>> { beacons ->
        Log.d(TAG, "Ranged: ${beacons.count()} beacons")
        Log.d("meme","before for")
        for (beacon: Beacon in beacons) {
            Log.d("meme","in for loop")
            Log.d(TAG, "$beacon about ${beacon.distance} meters away")
        }
        Log.d("meme","after for")
      //  here --> "beaconManager.stopRangingBeacons(region)" 
    }

problem 1 : rangingObserver should be called once in each cycle of scanning as I found out . it is ok when I don't use stopRangingBeacons. each 7 seconds scaning is done. but if I put "stopRangingBeacons" end of observer scanning process not work properly. return list size 0 and it is called multiple times.

my Logs:

2022-02-16 22:22:24.463 3180-3180/  D/meme: before for
2022-02-16 22:22:24.463 3180-3180/  D/meme: in for loop
2022-02-16 22:22:24.466 3180-3180/ D/meme: after for
2022-02-16 22:22:24.592 3180-3180/  D/meme: before for
2022-02-16 22:22:24.592 3180-3180/  D/meme: after for

sometimes does not find anything , it does not show "in for loop" .

Problem 2 : after changing my fragment and back to scan fragment. Scanning failed and is not work at all. It seems " ranged regions" is not set.

your logs debug (debug:true) :

2022-02-16 22:34:47.601 5433-5433/ D/lifecycl: it is oncreate 
2022-02-16 22:34:47.605 5433-5433/ D/lifecycl: it is oncreateview
2022-02-16 22:34:47.632 5433-5433/ W/DataBinding: Setting the fragment as the LifecycleOwner might cause memory leaks because views lives shorter than the Fragment. Consider using Fragment's view lifecycle
2022-02-16 22:34:47.633 5433-5433/  D/BeaconParser: Parsing beacon layout: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24
2022-02-16 22:34:47.637 5433-5433/  D/BeaconManager: updating background flag to false
2022-02-16 22:34:47.637 5433-5433/ D/BeaconManager: updating scan period to 7000, 0
2022-02-16 22:34:47.644 5433-5433/  D/BeaconManager: startRanging
2022-02-16 22:34:47.645 5433-5433 D/BeaconManager: This consumer is not bound.  Binding now: org.altbeacon.beacon.BeaconManager$1@f215cd7
2022-02-16 22:34:47.645 5433-5433/ D/BeaconManager: Not starting beacon scanning service. Using scheduled jobs
2022-02-16 22:34:47.646 5433-5433/ D/BeaconManager: startRangingBeaconsInRegion
2022-02-16 22:34:47.646 5433-5433/  D/ScanJobScheduler: Applying settings to ScanJob
2022-02-16 22:34:47.674 5433-5433/  D/ScanState: Scan state restore regions: monitored=0 ranged=0
2022-02-16 22:34:47.674 5433-5433/ D/ScanState: ranged regions: old=0 new=1
2022-02-16 22:34:47.674 5433-5433/ D/ScanState: monitored regions: old=0 new=0
2022-02-16 22:34:47.674 5433-5433/  D/ScanState: Starting ranging region: id1: null id2: null id3: null
2022-02-16 22:34:47.674 5433-5433/ D/ScanState: Updated state with 1 ranging regions and 0 monitoring regions.
2022-02-16 22:34:47.697 5433-5433/  D/ScanState: Temp file is /data/user/0/me.mythird.simpleloginregister/files/android-beacon-library-scan-state-temp
2022-02-16 22:34:47.697 5433-5433/  D/ScanState: Perm file is /data/user/0/me.mythird.simpleloginregister/files/android-beacon-library-scan-state
2022-02-16 22:34:47.697 5433-5433/ D/MonitoringStatus: saveMonitoringStatusIfOn()
2022-02-16 22:34:47.698 5433-5433/ D/ScanJobScheduler: Applying scan job settings with background mode false
2022-02-16 22:34:47.699 5433-5433/  D/BeaconLocalBroadcastProcessor: Register calls: global=0
2022-02-16 22:34:47.699 5433-5433/  D/ScanState: ScanState says background mode for ScanJob is false
2022-02-16 22:34:47.699 5433-5433/ r D/ScanJobScheduler: Scheduling immediate ScanJob to run in 50 millis
2022-02-16 22:34:47.701 5433-5433/  I/ScanJob: Using immediateScanJobId from manifest: 208352939
2022-02-16 22:34:47.705 5433-5433/  D/ScanJobScheduler: First immediate scan job scheduled successful, change the flag to false.
2022-02-16 22:34:47.707 5433-5433/  I/ScanJob: Using periodicScanJobId from manifest: 208352940
2022-02-16 22:34:47.707 5433-5433/  W/JobInfo: Requested interval +5m0s0ms for job 208352940 is too small; raising to +15m0s0ms
2022-02-16 22:34:47.707 5433-5433/ W/JobInfo: Requested flex 0 for job 208352940 is too small; raising to +5m0s0ms
2022-02-16 22:34:47.707 5433-5433/   D/ScanJobScheduler: Scheduling periodic ScanJob (job:208352940/me.mythird.simpleloginregister/org.altbeacon.beacon.service.ScanJob) to run every 300000 millis
2022-02-16 22:34:47.710 5433-5433/ D/BeaconManager: consumer count is now: 1
2022-02-16 22:34:47.716 5433-5433/ D/Monitoring: Ranged: 0 beacons
2022-02-16 22:34:47.716 5433-5433/  D/meme: before for
2022-02-16 22:34:47.716 5433-5433/  D/meme: after for
2022-02-16 22:34:47.716 5433-5433/  D/BeaconManager: stopRangingBeacons
2022-02-16 22:34:47.716 5433-5433/  D/BeaconManager: stopRangingBeaconsInRegion
2022-02-16 22:34:47.718 5433-5433/  D/ScanJobScheduler: Applying settings to ScanJob
2022-02-16 22:34:47.742 5433-5433/  D/ScanState: Scan state restore regions: monitored=0 ranged=1
2022-02-16 22:34:47.742 5433-5433/  D/ScanState: ranged regions: old=1 new=0
2022-02-16 22:34:47.742 5433-5433/  D/ScanState: monitored regions: old=0 new=0
2022-02-16 22:34:47.742 5433-5433/  D/ScanState: Stopping ranging region: id1: null id2: null id3: null
2022-02-16 22:34:47.742 5433-5433/me.mythird.simpleloginregister D/ScanState: Updated state with 0 ranging regions and 0 monitoring regions.
2022-02-16 22:34:47.759 5433-5433/me.mythird.simpleloginregister D/ScanState: Temp file is /data/user/0/me.mythird.simpleloginregister/files/android-beacon-library-scan-state-temp
2022-02-16 22:34:47.760 5433-5433/me.mythird.simpleloginregister D/ScanState: Perm file is /data/user/0/me.mythird.simpleloginregister/files/android-beacon-library-scan-state
2022-02-16 22:34:47.760 5433-5433/  D/MonitoringStatus: saveMonitoringStatusIfOn()
2022-02-16 22:34:47.761 5433-5433/  D/ScanJobScheduler: Applying scan job settings with background mode false
2022-02-16 22:34:47.761 5433-5433/  D/BeaconLocalBroadcastProcessor: Register calls: global=0
2022-02-16 22:34:47.761 5433-5433/  D/ScanState: ScanState says background mode for ScanJob is false
2022-02-16 22:34:47.761 5433-5433/  D/ScanJobScheduler: We are not monitoring or ranging any regions.  We are going to cancel all scan jobs.
2022-02-16 22:34:47.763 5433-5433/  I/ScanJob: Using immediateScanJobId from manifest: 208352939
2022-02-16 22:34:47.768 5433-5433/  I/ScanJob: Using periodicScanJobId from manifest: 208352940
2022-02-16 22:34:47.771 5433-5433/ D/ScanHelper: new ScanHelper
2022-02-16 22:34:47.777 5433-5433/  D/BluetoothAdapter: isLeEnabled(): ON
2022-02-16 22:34:47.780 5433-5433/ D/BeaconManager: Unbinding
2022-02-16 22:34:47.780 5433-5433/ D/BeaconManager: Not unbinding from scanning service as we are using scan jobs.
2022-02-16 22:34:47.780 5433-5433/ D/BeaconManager: Before unbind, consumer count is 1
2022-02-16 22:34:47.780 5433-5433/ D/BeaconManager: After unbind, consumer count is 0
2022-02-16 22:34:47.780 5433-5433/  I/BeaconManager: Cancelling scheduled jobs after unbind of last consumer.
2022-02-16 22:34:47.781 5433-5433/ I/ScanJob: Using immediateScanJobId from manifest: 208352939
2022-02-16 22:34:47.783 5433-5433/ I/ScanJob: Using periodicScanJobId from manifest: 208352940
2022-02-16 22:34:47.786 5433-5433/ D/lifecycl: in onResume

it may be useful , before using this new method I tried to use removeAllRangeNotifiers() and addRangeNotifier instead of observers . for each scanning cycle I called them . for scanning once and back to scan fragment, both problems that I said ,there was no problem . it was worked at least in android 9.

I don't know it is correct way to scanning or not.

   if(checkGPS_BLE())
            beaconManager.startRangingBeacons(region)
            beaconManager.removeAllRangeNotifiers()
          beaconManager.addRangeNotifier(object : RangeNotifier {
            override fun didRangeBeaconsInRegion(p0: MutableCollection<Beacon>?, p1: Region?) {
                Log.d("TAG", "it is called")
                if (p0!!.size > 0) {
                    Log.d("TAG", "uuid:  " + p0.iterator().next().id1)
                }

                Log.d("TAG", "end of finding")

                beaconManager.stopRangingBeacons(region)
                beaconManager.removeRangeNotifier(this)
            }

        })

my Logs:

2022-02-16 22:50:28.674 8909-8909/  D/TAG: it is called
2022-02-16 22:50:28.675 8909-8909/  D/TAG: uuid:  00000000-0000-0000-0000-000000000000
2022-02-16 22:50:28.675 8909-8909/  D/TAG: end of finding

I used it for start/stop scanning button too.

davidgyoung commented 2 years ago

Thanks for this detailed report @NimaaZx . There are several distinct issues here so I may close this and open a few different issues to track them individually. Let me run some tests first with the reference app to see what I can reproduce.

NimaaZx commented 2 years ago

ok. no problem. Thank You David. right now I use RangeNotifier .let me know If you need any other detail .

davidgyoung commented 2 years ago

@NimaaZx after testing with the official reference app here, I am unable to reproduce either issue you report.

Here is my test setup:

  1. Turn off all beacons in the vicinity.
  2. Use Android Studio to debug the reference app on a Google Pixel 4a with Android 12 and all requested permissions granted.
  3. Turn on a test beacon transmitter using an iPhone running Locate Beacon. The test transmitter emits an iBeacon at 10Hz
  4. Verify the beacon is detected by the app and "Ranging enabled: 1 beacon(s) detected" appears on the screen with one beacon row where the RSSI and distance estimate updates every ~1s
  5. Tap the STOP RANGING button on the reference app
  6. Set a breakpoint on the rangingObserver in the reference app's MainActivity.kt
  7. Verify the breakpoint is not hit
  8. Turn off the beacon transmitter on the iPhone
  9. Tap the START RANGING button on the reference app
  10. Verify the breakpoint above is hit.
  11. Disable the breakpoint
  12. Verify app updates resume normally.

I think the problems you describe are most likely application-specific problems caused by complexities of the Android lifecycle and perhaps having multiple ranged regions going at the same time.

A few tips for troubleshooting:

  1. Try to simplify your architecture and make as few calls as possible to start and stop ranging. Use the reference app linked above as a guide to setting this up.
  2. Use only one Region for ranging if possible.
  3. Uninstall and reinstall your app to clear state when things get too confusing.

If you keep having trouble, please try to reproduce your issues with the reference app, making as few modifications as necessary to reproduce the problem. If you can reproduce the problem with the reference app, please create a new issue.