Search code examples
androidkotlinpush-notificationbeaconeddystone

Display notification when device is out of beacon range


With the help of this link I am able to display a notification when my device enters the range of a beacon. I also want to display a notification when the device moves out of the beacon range. Where should I mention that?

This is my code

override fun didRangeBeaconsInRegion(p0: MutableCollection<Beacon>?, p1: Region?) {

        for (beacon in p0!!) {
            if (beacon.getServiceUuid() == 0xfeaa && beacon.getBeaconTypeCode() == 0x00) {
                // This is a Eddystone-UID frame
                val namespaceId = beacon.getId1()
                val instanceId = beacon.getId2()
                Log.d("RangingActivity", "I see a beacon transmitting namespace id: " + namespaceId +
                        " and instance id: " + instanceId +
                        " approximately " + beacon.getDistance() + " meters away.")
                runOnUiThread {
                    showNotification("Entry", "Hello world")
                }
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    @RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
    fun showNotification(title: String, message: String) {
        val notifyIntent = Intent(this, MainActivity::class.java)
        notifyIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
        val pendingIntent: PendingIntent = PendingIntent.getActivities(
                this,
                0,
                arrayOf(notifyIntent),
                PendingIntent.FLAG_UPDATE_CURRENT
        )

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val mChannel = NotificationChannel("1", "Notify Channel", NotificationManager.IMPORTANCE_HIGH)
            val notification = NotificationCompat.Builder(this, "1")
                    .setSmallIcon(R.drawable.ic_location_arrow)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent)
                    .setChannelId("1")
                    .build()
            notification.defaults = notification.defaults or Notification.DEFAULT_SOUND
            val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(mChannel)
            notificationManager.notify(1, notification)
            startForegroundService(notifyIntent)
        } else {
            val notification = NotificationCompat.Builder(this, "1")
                    .setSmallIcon(R.drawable.ic_location_arrow)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent)
                    .setChannelId("1")
                    .build()
            notification.defaults = notification.defaults or Notification.DEFAULT_SOUND
            val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.notify(1, notification)
        }
    }

Also, I receive notifications continuously when I'm inside the beacon's range. Once I am inside the range, I want my notification to be displayed only once.


Solution

  • A few tips:

    1. Use beacon monitoring, not beacon ranging. Monitoring APIs give you one callback when the beacon first appears (didEnterRegion) and one when it disappears (didExitRegion). You can move your logic into those callbacks. See the "Getting notified when beacons appear in the area here.

    2. Currently the code checks that it is a Eddystone beacon by checking the service UUID and type code manually. Don't do this. Instead, clear all BeaconParsers except the one for Eddystone so you know when you get a callback.