The Pulsate SDK uses the NotificationCompat.setNumber() API to set the badge count for Android devices. This is the native Android API and shows badges in the default way - for some phones this might be a number, for some it might be a dot, for some custom launchers it might not do anything.

If you want to support more phones and more custom launchers the PulsateSDK returns a callback that informs your App when a push comes or when the badge is changing. Inside that method you can add custom support for more phones / launchers on your own or you can use a 3rd party library like ShortcutBadger to do it for you.

To make sure you get all the badge callbacks make sure you set the badge listener in your Application class in the onCreate callback. If you modify the badge count make sure to return that new badge count in the listener, if you do not modify it make sure to return the original value.

App Icon Badges

If you do not want to show badges on your App Icon you can use the PulsateConfig to turn them off. Remember that the Notification Channel is created only once and can not be later updated. If you have App Icon badge ON during your first install they will stay ON even if you turn them OFF in a future build. The same goes for when setting them to OFF for the first install. During testing make sure to completely uninstall the App when changing App Icon badges from ON to OFF. By default App Icon badges are ON. To change this value in your Application onCreate method call:

override fun onCreate() {
  super.onCreate()

  PulsateConfig.NOTIFICATION_CHANNEL_SHOW_BADGES = false
}

Inside App Badges

Many Apps not only want to show an App Icon badge, but also want to show a badge / unread count inside their App UI to inform users of messages waiting for them in the Pulsate Feed. There are 3 approaches you can take - "setBadgeUpdateListener" or "getFeedUnreadCount" or a combination of both. Both approaches have their pros and cons so test out what works best for you.

Using setBadgeUpdateListener

This method allows you to be constantly updated about badge changes using LiveData. This approach also allows you to modify the badge count if needed. In the example below we add 100 to the badge count just for testing purposes, however you probably will not want to modify it or add your own badge count to it if you use other services other than Pulsate to set your own Push Notifications.

class PulsateDemoApp : Application() {
    override fun onCreate() {
        super.onCreate()

        val pulsateManager = PulsateFactory.getInstance()

        pulsateManager.setBadgeUpdateListener(object : IPulsateBadgeUpdateListener {
            override fun onBadgeUpdate(badge: Int): Int {
                val newBadgeCount = badge + 100
                ShortcutBadger.applyCount(this@PulsateDemoApp, newBadgeCount)
                return newBadgeCount
            }
        })
    }
}

You can also use "setBadgeUpdateListener" inside a ViewModel to show a custom badge icon inside your App.

class MenuFragmentViewModel constructor() : ViewModel() {
    private val _badgeState: MutableLiveData<Int> = MutableLiveData(0)
    val badgeState: LiveData<Int> get() = _badgeState

    init {
        val pulsateManager = PulsateFactory.getInstance()
        pulsateManager.setBadgeUpdateListener(
            object : IPulsateBadgeUpdateListener {
                override fun onBadgeUpdate(badge: Int): Int {
                    _badgeState.postValue(badge)
                    return badge
                }
            },
        )
    }
}

And in your Activity / Fragment just observe the LiveData from the ViewModel

class MenuFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mMenuFragmentViewModel.badgeState.observe(viewLifecycleOwner) { badge ->
            mBinding.inboxBtn.text = "INBOX $badge"
        }
    }
    
}

Using getFeedUnreadCount

If you prefer you can directly access the unread count using "getFeedUnreadCount". This method has a 30sec debounce so you can not directly access unread count more often than once every 30secs. You can use this method to make sure that the inside app unread count is up to date - for example you have a UI element in your App that shows the unread count in a menu, on top of a bottom, to get a user to enter. You can also use this method after the user exits the Feed to make sure the badges are update after the user interacts with the Pulsate Feed. Example impementation:

override fun onCreateView(
  inflater: LayoutInflater,
  container: ViewGroup?,
  savedInstanceState: Bundle?,
): View {
  val binding = createYourViewBinding()
  binding?.feedBtn?.setOnClickListener {
    mPulsateManager?.showFeed(
      object : IPulsateFeedListener {
        override fun onFeedClose() {
          updateBadge()
        }
      }
    )
  }
  return binding!!.root
}

override fun onViewCreated(
  view: View,
  savedInstanceState: Bundle?,
) {
  val pulsateManager = PulsateFactory.getInstance()
  pulsateManager?.startPulsateSessionForAlias(
    serverModel.userModel.alias,
    object : IPulsateRequestListener {
      override fun onSuccess() {
          updateBadge()
      }

      override fun onError(e: Throwable?) {
        e?.printStackTrace()
      }
    },
  )
}

private fun updateBadge() {
  val pulsateManager = PulsateFactory.getInstance()
  pulsateManager?.getFeedUnreadCount(
    object : IPulsateValueListener<Int> {
      override fun onError(e: Throwable) {
        e.printStackTrace()
      }

      override fun onSuccess(value: Int) {
        binding?.feedBtn?.text = "Unread Count $value"
      }
    },
  }
}

Using this approach we update the unread count as soon as the user enters the App and update it as soon as he exits the Pulsate Feed. This approach alone should keep badges up to date most of the time (remember there is a 30sec debounce). If you combine this approach with "setBadgeUpdateListener" you should be able cover all possible edge cases.