Search code examples
androidandroid-studiobluetooth-lowenergyaltbeaconeddystone

Altbeacon library not able to find/trace transmitting beacon near device


I am using altbeacon library for contact tracing. But i am not able to find/trace my device when it comes near my other scanning phone. I have two mobiles basically, one i am using for scanning and other as beacon transmitter. I am able to transmit as beacon from my phone number 2. I tested also in Locate Beacon app. It showed my phone in that. But when i am testing on my phone number 1, its not working. I am not able to see any beacon on any logs even though my didDetermineStateForRegion and onBeaconServiceConnect is being called.

Here is my application class below:

package com.example.mybeaconprojectaye

import android.app.*
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseSettings
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.RemoteException
import android.util.Log
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.altbeacon.beacon.*
import org.altbeacon.beacon.startup.BootstrapNotifier
import org.altbeacon.beacon.startup.RegionBootstrap
import java.util.*

class MyApplication : Application(), BootstrapNotifier, BeaconConsumer {


    val CHANNEL_ID = "myproximityservice"
    val CHANNEL_NAME = "My Proximity Service Channel"
    val backgroundBetweenScanPeriod = 6200L
    val backgroundScanPeriod = 3000L
    val TAG: String = "xoxo"
    val REGIONID = "rangeid"


    val uuidString: String= "id1"

    lateinit var beaconManager: BeaconManager
    private var regionBootstrap: RegionBootstrap? = null


    override fun onCreate() {
        super.onCreate()

        beaconManager = BeaconManager.getInstanceForApplication(this)
        setupBeaconScanning()
        beaconManager.bind(this)
    }

    override fun onBeaconServiceConnect() {

        Log.e(TAG, "Service connected ")
        val rangeNotifier = RangeNotifier { beacons, region ->
            if (beacons.size > 0) {
                Log.e(TAG, "found new beacons  " + beacons.size)
                for (beacon: Beacon in beacons){
                    Log.e(TAG,"New Beacon before condition check=${beacon.id2}-${beacon.id3}-${beacon.id1}")

                    GlobalScope.launch {

                        try {
                            val deviceUUID: String = beacon.id1.toString()
                            Log.e(TAG, "  before condition check=${deviceUUID}")
                                Log.e(
                                    TAG,
                                    "New Beacon=${beacon.id2}/${beacon.id3}/${beacon.id1}"
                                )
                              Log.e("xoxo","${beacon.id2}/${beacon.id3}/${beacon.id1} + "+ beacon.distance.toLong())


                                if (beacon.distance.toInt() < 2) {
                                    /*  val intentNotification = Intent(this@BeaconApp, HomeActivity::class.java)
                                  intentNotification.putExtra(Constants.DeviceConstants.IS_VIBRATOR, true)

                                  intentNotification.flags =
                                      Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK

                                  startActivity(intentNotification)*/



                                    //sendSafetyNotification()



                            }
                        }catch (ex: Exception){

                            Log.e(TAG, "  EXCEPTION: "+ex.toString())

                        }

                    }
                }
                //  sendBroadcast(Intent(NEW_DEVICE_ACTION))
            }
        }
        try {
            beaconManager.startRangingBeaconsInRegion(
                Region(
                    REGIONID,
                    null,
                    null,
                    null
                )
            )
            beaconManager.addRangeNotifier(rangeNotifier)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }

    }

    override fun didDetermineStateForRegion(state: Int, p1: Region?) {

        Log.e("xoxo", "didDetermineStateForRegion state: "+state )

    }

    override fun didEnterRegion(p0: Region?) {

        Log.e("xoxo", "i just saw a beacon")


    }

    override fun didExitRegion(p0: Region?) {
    }


    fun setupBeaconScanning() {
        beaconManager.beaconParsers.clear()

        val altbeaconParser =
            BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25")
        altbeaconParser.setHardwareAssistManufacturerCodes(intArrayOf(0x0118))
        beaconManager.beaconParsers
            .add(altbeaconParser)

        val iBeaconParser =
            BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")
        iBeaconParser.setHardwareAssistManufacturerCodes(intArrayOf(0x004c))

        beaconManager.beaconParsers
            .add(iBeaconParser)
        beaconManager.beaconParsers
            .add(BeaconParser().setBeaconLayout(BeaconParser.URI_BEACON_LAYOUT))
        beaconManager.beaconParsers
            .add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT))
        beaconManager.beaconParsers
            .add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
        beaconManager.beaconParsers
            .add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT))


        /* beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))
         beaconManager.beaconParsers
             .add(BeaconParser().setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"))


 */
        BeaconManager.setDebug(false)


        val builder = Notification.Builder(this)
        builder.setSmallIcon(R.drawable.ic_launcher_background)
        builder.setContentTitle("Proximity Service Running")
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        builder.setContentIntent(pendingIntent)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT
            )
            channel.description = "Used for scanning near by device"
            val notificationManager = getSystemService(
                Context.NOTIFICATION_SERVICE
            ) as NotificationManager
            notificationManager.createNotificationChannel(channel)
            builder.setChannelId(channel.id)
        }
        beaconManager.enableForegroundServiceScanning(builder.build(), 456)

        // For the above foreground scanning service to be useful, you need to disable
        // JobScheduler-based scans (used on Android 8+) and set a fast background scan
        // cycle that would otherwise be disallowed by the operating system.


        beaconManager.setEnableScheduledScanJobs(false)
        beaconManager.backgroundBetweenScanPeriod = backgroundBetweenScanPeriod
        beaconManager.backgroundScanPeriod = backgroundScanPeriod

        Log.d(TAG, "setting up background monitoring for beacons and power saving")
        // wake up the app when a beacon is seen
        // wake up the app when a beacon is seentitle getting
        val region = Region(
            REGIONID,
            null, null, null
        )
        regionBootstrap = RegionBootstrap(this, region)
    }


    fun startAdvertising(listener: AdvertiseListener):Boolean {

        val result = BeaconTransmitter.checkTransmissionSupported(this)
        Log.e("xoxo", "BLE TRANSMITTER STATUS " +(result== BeaconTransmitter.SUPPORTED).toString())
        if (BeaconTransmitter.SUPPORTED != result)
            return false
        val beacon = Beacon.Builder()
            .setId1("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")
            .setId2("1")
            .setId3("2")
            .setManufacturer(0x0118) // Radius Networks.  Change this for other beacon layouts
            .setTxPower(-59)
            .setDataFields(Arrays.asList(*arrayOf(0L))) // Remove this for beacon layouts without d: fields
            .build()


        // Change the layout below for other beacon types
        val beaconParser = BeaconParser()
            .setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25")
        val beaconTransmitter =
            BeaconTransmitter(applicationContext, beaconParser)
        beaconTransmitter.startAdvertising(beacon, object : AdvertiseCallback() {
            override fun onStartFailure(errorCode: Int) {
                Log.e(TAG, "Advertisement start failed with code: $errorCode")
                listener.onAdvertiseStatus(false)
            }

            override fun onStartSuccess(settingsInEffect: AdvertiseSettings) {
                Log.e(TAG, "Advertisement start succeeded. uuid"+uuidString)
                listener.onAdvertiseStatus(true)

            }
        })
        return true
    }


    interface AdvertiseListener{
        fun onAdvertiseStatus(success:Boolean)
    }

}

and my MainActivity:

package com.example.mybeaconprojectaye

import android.Manifest
import android.app.AlertDialog
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
import org.altbeacon.beacon.BeaconTransmitter

class MainActivity : AppCompatActivity() {

    companion object {
        private const val PERMISSION_REQUEST_FINE_LOCATION = 1
        private const val PERMISSION_REQUEST_BACKGROUND_LOCATION = 2
    }

    val TAG = "xoxo"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var result : Int = BeaconTransmitter.checkTransmissionSupported(this@MainActivity)

        Log.e("xoxo", "result: "+result)



        btn.setOnClickListener(object : View.OnClickListener {
            override fun onClick(v: View?) {

                requestPerms()


            }
        })

    }


    fun requestPerms() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
                        != PackageManager.PERMISSION_GRANTED
                    ) {
                        val builder =
                            AlertDialog.Builder(this)
                        builder.setTitle("Location is off")
                        builder.setMessage("Please allow location permission.")
                        builder.setPositiveButton(android.R.string.ok, null)
                        builder.setOnDismissListener {
                            requestPermissions(
                                arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                                PERMISSION_REQUEST_BACKGROUND_LOCATION
                            )
                        }
                        builder.show()
                    } else startAdvertiseBeacons()

                } else startAdvertiseBeacons()
            } else {
                requestPermissions(
                    arrayOf(
                        Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_BACKGROUND_LOCATION
                    ),
                    PERMISSION_REQUEST_FINE_LOCATION
                )
            }
        } else startAdvertiseBeacons()
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        when (requestCode) {
            PERMISSION_REQUEST_FINE_LOCATION -> {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "fine location permission granted")
                    requestPerms()
                } else {
                    val builder =
                        AlertDialog.Builder(this)
                    builder.setTitle("Functionality limited")
                    builder.setMessage("Since location access has not been granted, this app will not be able to discover devices.")
                    builder.setPositiveButton(android.R.string.ok, null)
                    builder.setOnDismissListener { }
                    builder.show()
                }
                return
            }
            PERMISSION_REQUEST_BACKGROUND_LOCATION -> {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "background location permission granted")
                    requestPerms()
                } else {
                    val builder =
                        AlertDialog.Builder(this)
                    builder.setTitle("Functionality limited")
                    builder.setMessage("Since background location access has not been granted, this app will not be able to discover devices when in the background.")
                    builder.setPositiveButton(
                        android.R.string.ok,
                        DialogInterface.OnClickListener { dialog, which ->
                            dialog.cancel()
                            requestPerms()
                        })
                    builder.setOnDismissListener {
                        requestPerms()
                    }
                    builder.show()
                }
                return
            }
        }
    }

    private fun startAdvertiseBeacons() {
        (application as MyApplication).startAdvertising(object : MyApplication.AdvertiseListener {
            override fun onAdvertiseStatus(success: Boolean) {

            }
        })
    }

}

And here are all the logs that are being printed:

2020-06-07 05:20:25.566 23822-23822/? E/libc: Access denied finding property "persist.vendor.sys.activitylog"
2020-06-07 05:20:26.468 23822-23822/com.example.mybeaconprojectaye E/xoxo: result: 0
2020-06-07 05:20:26.810 23822-23822/com.example.mybeaconprojectaye E/xoxo: Service connected 
2020-06-07 05:20:26.848 23822-23822/com.example.mybeaconprojectaye E/xoxo: didDetermineStateForRegion state: 0

Can anyone please tell me what i am doing wrong or if some step is missing. I tried looking into other answers on stackoverflow, but this is the only library where i am seeing new classes and interfaces everywhere in all answers. Too much confusion.

P.S.

I am trying to make contact tracing app. Any other library or something you can suggest will also be appreciated.


Solution

  • Try reversing phones 1 and 2 for your tests. If you use BeaconScope to scan, can it see the transmissions of both phones 1&2? If you use BeaconScope to transmit, can your app on either phone 1 or 2 see the beacon tranamission?

    If you cannot detect beacon scope on one or both phones, check app permissions to confirm that location permission has been granted to your app. Go to Settings -> Applications -> Your App and check the granted permissions.

    Also check that location is enabled globally on the phone and that Bluetooth is on.