IndoorLocation Android SDK latency

IndoorLocationManager.setOnPositionUpdateListener() is retrieving updates almost every second, but the location updates are not being calculated quick enough, even though iOS works fast enough, the position updates are so much laggy, and it happens every 5+ seconds.

The “lag” is mostly affected by the frequency with which the OS/smartphone detects Bluetooth data from nearby beacons, and reports them to our SDK. iOS devices generally tend to perform better in that regard—see for example this Stack Overflow post from earlier this month:

That said, you could try changing the scan settings to LOW LATENCY. To do that, you will need to manually set up a Bluetooth scanner, and feed the scan results to the Indoor SDK:

So instead of this:

ScanningIndoorLocationManager indoorLocationManager =
    new IndoorLocationManagerBuilder(this, location,
        new EstimoteCloudCredentials("YOUR-APP-ID", "YOUR-APP-TOKEN"))
    .withDefaultScanner()
    .build();

… you’d start with something like this:

IndoorLocationManager indoorLocationManager =
    new IndoorLocationManagerBuilder(this, location,
        new EstimoteCloudCredentials("YOUR-APP-ID", "YOUR-APP-TOKEN"))
    .build();

Then, you need to set up the scanner. You can use this documentation we have for scanning for Telemetry packets:

https://developer.estimote.com/sensors/estimote-telemetry/#android

… except instead of estimoteTelemetryFrameAScan, you’ll use estimoteLocationScan to scan for Estimote Location packets. And then set it up to feed the scan results to the IndoorLocationManager:

.withOnPacketFoundAction {
    Log.d("Scanner", "location packet detected: $it")
    indoorLocationManager.onScannedLocationPackets(listOf($it))
}

Oh, and for reconfiguring the scanner to use LOW LATENCY mode, you also need to add withLowLatencyPowerMode() when building your scanner. So the whole thing could look, for example, like this:

bluetoothScanner = EstimoteBluetoothScannerFactory(applicationContext).getSimpleScanner()
locationScanHandler = bluetoothScanner
    .estimoteLocationScan()
    .withLowLatencyPowerMode() // <===
    .withOnPacketFoundAction {
        Log.d("Scanner", "location packet detected: $it")
        indoorLocationManager.onScannedLocationPackets(listOf($it))
    }
    .withOnScanErrorAction { Log.e("Scanner", "scan failed: $it") }
    .start()

Apologies for slight chaos and for mixing Java and Kotlin, I’ve been assembling pieces of codes from various places for this post (: But hopefully it points you in the right direction.

@heypiotr
Thanks for your reply and support,

I tried this with a separately set-up Bluetooth scanner, but the lag is still the same, the position barely gets updated.

this is how I managed to do that in java :

locationScanHandler = bluetoothScanner
                        .estimoteLocationScan()
                        .withLowLatencyPowerMode()
                        .withOnPacketFoundAction(new Function1<EstimoteLocation, Unit>() {
                            @Override
                            public Unit invoke(EstimoteLocation estimoteLocation) {
                                Log.d("Scanner", "location packet detected: "+estimoteLocation.getDeviceId()+" ///"+estimoteLocation.getMeasuredPower());

                                indoorManager.onScannedLocationPackets(estimoteLocation);
                                return null;
                            }
                        })
                        .withOnScanErrorAction(new Function1<Throwable, Unit>() {
                            @Override
                            public Unit invoke(Throwable throwable) {
                                Log.e("LocationScanHandler","SCAN FAILED");
                                return null;
                            }
                        })
                        .start(); 

here the log shows different UUID with the same exact measured power.
might this be solved if I switch to Kotlin as I could feed the indoorSDK with a list instead of a single EstimoteLocation here?

@heypiotr
here is a log snippet

D/Scanner: location packet detected: 18F6981149618D162C307489E606F61B ///-55
D/Scanner: location packet detected: FA1598DCE384E64421028D7B6DA3E80E ///-55
D/Scanner: location packet detected: 4C3D1D5AFB6474DB9F5E480DB7D01731 ///-55
D/Scanner: location packet detected: 18F6981149618D162C307489E606F61B ///-55
D/Scanner: location packet detected: C247A94BBDFAB32757FADCC02E0C0C27 ///-55
D/Scanner: location packet detected: 1E04AFC676A8731EA93627F8E4C1FE29 ///-55
D/Scanner: location packet detected: FA1598DCE384E64421028D7B6DA3E80E ///-55
D/Scanner: location packet detected: 64B344B1B1ED23232FA1CF869051A723 ///-55
D/Scanner: location packet detected: 4C3D1D5AFB6474DB9F5E480DB7D01731 ///-55
D/Scanner: location packet detected: C9E30F3180B0660876C75D6A8164731D ///-55
D/Scanner: location packet detected: 18F6981149618D162C307489E606F61B ///-55
D/Scanner: location packet detected: C247A94BBDFAB32757FADCC02E0C0C27 ///-55
D/Scanner: location packet detected: 1E04AFC676A8731EA93627F8E4C1FE29 ///-55
D/Scanner: location packet detected: 4C3D1D5AFB6474DB9F5E480DB7D01731 ///-55
D/Scanner: location packet detected: C9E30F3180B0660876C75D6A8164731D ///-55
D/Scanner: location packet detected: 1E04AFC676A8731EA93627F8E4C1FE29 ///-55
D/Scanner: location packet detected: FA1598DCE384E64421028D7B6DA3E80E ///-55

Your code looks good! For the logs, it’d be useful to see the timestamps, so that we can see the frequency of the detections.

the delay is not with Scanning Packets but with location updates, the LocationUpdateListener gets called with same coordinates for up to 10 to 12 seconds after moving the device.

Gotcha, so if you already confirmed that the input data (= scanned packets) arrive with good frequency, then we’ve narrowed it down => the lag seems to originate somewhere inside the Indoor SDK. Can you report your findings as an issue on https://github.com/estimote/android-indoor-sdk?

D/Scanner: 862572595770142
D/Scanner: 862572650194569
D/Scanner: 862572709889621
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862572742171183
D/Scanner: 862572759333215
D/Scanner: 862572764812486
D/Scanner: 862572789582069
D/Scanner: 862572810395350
D/Scanner: 862572920277173
    862572922669360
D/Scanner: 862572946929673
D/Scanner: 862573058964881
D/Scanner: 862573472745714
D/Scanner: 862573656946600
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862573769849985
D/Scanner: 862573805992068
D/Scanner: 862573847166652
D/Scanner: 862573857678631
D/Scanner: 862573942722329
D/Scanner: 862573974062589
D/Scanner: 862573980025610
D/Scanner: 862574086527173
D/Scanner: 862574146367277
D/Scanner: 862574165586131
D/Scanner: 862574247477641
D/Scanner: 862574431533787
D/Scanner: 862574447681495
D/Scanner: 862574491010193
D/Scanner: 862574577520089
D/Scanner: 862574614399724
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862574766614568
D/Scanner: 862574776974360
D/Scanner: 862574860534933
D/Scanner: 862574889709933
D/Scanner: 862574985606808
D/Scanner: 862575131477953
D/Scanner: 862575182356964
D/Scanner: 862575185118162
D/Scanner: 862575232545766
D/Scanner: 862575312892328
D/Scanner: 862575434068005
D/Scanner: 862575439830974
D/Scanner: 862575441889568
D/Scanner: 862575456566391
D/Scanner: 862575468915766
D/Scanner: 862575482291807
D/Scanner: 862575599218266
D/Scanner: 862575641822537
D/Scanner: 862575659209151
D/Scanner: 862575679104776
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862576017256911
D/Scanner: 862576146427432
D/Scanner: 862576262596286
D/Scanner: 862576448748161
D/Scanner: 862576464564515
    862576466973942
D/Scanner: 862576549617224
D/Scanner: 862576567350297
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862576735205349
D/Scanner: 862576837856651
D/Scanner: 862576846036599
D/Scanner: 862576873200661
D/Scanner: 862576903508786
D/Scanner: 862576967721390
D/Scanner: 862576969834671
D/Scanner: 862577183364880
D/Scanner: 862577211294046
D/Scanner: 862577314589515
    862577324928369
D/Scanner: 862577389828473
D/Scanner: 862577476493942
D/Scanner: 862577485012900
D/Scanner: 862577531752327
D/Scanner: 862577545588005
D/Scanner: 862577679419671
D/Scanner: 862577710940661
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862577747736754
    862577753342744
D/Scanner: 862577773344359
D/Scanner: 862577796632952
D/Scanner: 862577804150400
D/Scanner: 862577964000713
D/Scanner: 862577975766754
D/Scanner: 862577992679775
D/Scanner: 862578004619098
D/Scanner: 862578164680817
D/Scanner: 862578170509150
D/Scanner: 862578440390817
D/Scanner: 862578641174827
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862578744410296
D/Scanner: 862578769323369
    862578781424254
D/Scanner: 862578841225139
D/Scanner: 862579050947431
D/Scanner: 862579169316858
D/Scanner: 862579203460556
D/Scanner: 862579252105764
    862579262200452
D/Scanner: 862579363933473
D/Scanner: 862579374231702
D/Scanner: 862579467425764
D/Scanner: 862579474358889
D/Scanner: 862579673309566
D/Scanner: 862579677466806
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862579850443212
D/Scanner: 862579858593108
D/Scanner: 862579882824722
D/Scanner: 862579941698056
D/Scanner: 862579979164774
D/Scanner: 862579994664306
D/Scanner: 862580081559566
D/Scanner: 862580141125972
D/Scanner: 862580248651806
D/Scanner: 862580252341962
D/Scanner: 862580283238160
D/Scanner: 862580285522795
D/Scanner: 862580295170295
D/Scanner: 862580434245503
D/Scanner: 862580449976389
D/Scanner: 862580476310503
D/Scanner: 862580571475555
D/Scanner: 862580646371233
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862580776362951
D/Scanner: 862580982525972
D/Scanner: 862581241841753
D/Scanner: 862581356202326
D/Scanner: 862581432247326
D/Scanner: 862581551207326
D/Scanner: 862581658835868
D/Scanner: 862581685297065
D/Scanner: 862581709300190
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862581736017482
D/Scanner: 862581889777013
D/Scanner: 862581932935555
D/Scanner: 862581936829930
D/Scanner: 862581964966753
D/Scanner: 862582034135242
D/Scanner: 862582088910763
D/Scanner: 862582133942534
D/Scanner: 862582145568211
D/Scanner: 862582180460347
D/Scanner: 862582247686024
D/Scanner: 862582282752274
D/Scanner: 862582295003836
D/Scanner: 862582467009148
D/Scanner: 862582500712951
D/Scanner: 862582553964826
D/Scanner: 862582563611961
D/Scanner: 862582635104617
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862582737204669
D/Scanner: 862582933652065
D/Scanner: 862582951889200
D/Scanner: 862582957094200
D/Scanner: 862582965659357
D/Scanner: 862583081140450
D/Scanner: 862583143654304
D/Scanner: 862583290596648
D/Scanner: 862583335692898
D/Scanner: 862583355490346
D/Scanner: 862583359990606
D/Scanner: 862583384123940
D/Scanner: 862583387962325
D/Scanner: 862583435061388
D/Scanner: 862583541835033
D/Scanner: 862583562779148
    862583566921700
D/Scanner: 862583586047794
D/Scanner: 862583590211075
D/onPositionUpdate: X : 16.66068835019017, Y : 7.8946914599552205
D/Scanner: 862583785498002
D/Scanner: 862583789025294
D/Scanner: 862583834661283
D/Scanner: 862583857368263
D/Scanner: 862583982609356
D/Scanner: 862584059473835
D/Scanner: 862584157497377
D/Scanner: 862584181853940
D/Scanner: 862584185280606
    862584187690450
D/Scanner: 862584256273731
D/Scanner: 862584435986127
    862584441231648
D/Scanner: 862584463454408
D/Scanner: 862584635172585
D/Scanner: 862584657761596
D/Scanner: 862584676392116
D/onPositionUpdate: X : 17.518763250884895, Y : 8.588367877295239
D/Scanner: 862584796967116
D/Scanner: 862584845973627
D/Scanner: 862584886278366
D/Scanner: 862585002824720
D/Scanner: 862585068999929
D/Scanner: 862585075724043
D/Scanner: 862585253207272
D/Scanner: 862585275583314
D/Scanner: 862585466204824
D/Scanner: 862585481629460
D/Scanner: 862585556810606
D/Scanner: 862585578096647
D/Scanner: 862585615627585
D/onPositionUpdate: X : 17.518763250884895, Y : 8.588367877295239
D/Scanner: 862585761993262
D/Scanner: 862585836805137
    862585840951647
    862585844505397
D/Scanner: 862585854406751
D/Scanner: 862585882205606
D/Scanner: 862585889926022
D/Scanner: 862585967804043
D/Scanner: 862586289841907
D/Scanner: 862586345964355
D/Scanner: 862586348638053
D/Scanner: 862586378144980
D/Scanner: 862586450778626
D/Scanner: 862586464972793
D/Scanner: 862586484759720
D/Scanner: 862586695712168
D/Scanner: 862586720228886
D/onPositionUpdate: X : 17.518763250884895, Y : 8.588367877295239
D/Scanner: 862586766297845
D/Scanner: 862586801544095
D/Scanner: 862586881513261
D/Scanner: 862586887148678
D/Scanner: 862586903620345
    862586910396334
D/Scanner: 862586935286230
D/Scanner: 862587068276074
D/Scanner: 862587089320970
D/Scanner: 862587093732845
D/Scanner: 862587106869720
D/Scanner: 862587133962480
D/Scanner: 862587201189772
D/Scanner: 862587278335084
D/Scanner: 862587302935657
D/Scanner: 862587309898209
D/Scanner: 862587341427428
D/Scanner: 862587515236438
D/Scanner: 862587540718417
D/Scanner: 862587544633209
D/Scanner: 862587562087584
D/Scanner: 862587639262949
D/Scanner: 862587698165969
D/onPositionUpdate: X : 17.518763250884895, Y : 8.588367877295239
D/Scanner: 862587752582688
D/Scanner: 862587891477636
D/Scanner: 862587960180292
D/Scanner: 862587976555136
D/Scanner: 862588046940605
D/Scanner: 862588101249615
D/Scanner: 862588132531750
D/Scanner: 862588267277844
D/Scanner: 862588336970240
D/Scanner: 862588379636802
    862588385647167
D/Scanner: 862588444500709

Yea, this looks very good actually, multiple detections per second. The only idea left I have is, are these the scan results for the good beacons, i.e., for the beacons that actually make the location. From your previous logs, I can see these 7 beacons:

18F6981149618D162C307489E606F61B
FA1598DCE384E64421028D7B6DA3E80E
4C3D1D5AFB6474DB9F5E480DB7D01731
C247A94BBDFAB32757FADCC02E0C0C27
1E04AFC676A8731EA93627F8E4C1FE29
64B344B1B1ED23232FA1CF869051A723
C9E30F3180B0660876C75D6A8164731D

Other than that, maybe our indoor algos are tuned too conservatively on Android. Have you by any chance tried the iOS Indoor SDK, or the iOS Indoor Location demo app, and if yes, was the latency for your setup okay there?

Yes actually the IOS SDK is working perfectly with same beacons, and we are receiving updated coordinates with every positionUpdate call.

Thanks for your support
I’ve just initiated an issue on the GitHub repo for android-indoor-sdk, here is the link :

1 Like

Thanks for sharing this info.