Android Doze mode kills foregreound MediaPlayer service - android

I've been researching awhile about how to keep active a constantly running audio playback in the background (online radio). For last I made a foreground service for it and its works for the most phones, but not on Samsung Android P and above... (as this article show in the "Foreground service limitations" section: https://proandroiddev.com/android-foreground-service-restrictions-d3baa93b2f70)
I heard that there is a advanced tool for audio playback called ExoPlayer. Could this lib help me out?
I'v been tried these solutions:
ping google.com every 2 sec
request battery optimization ignoring
set wake lock for mediplayer with: setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) (still in use)
Starting the service:
viewModel.isMusicControlServiceNeedToStart.observe(this, Observer {
if (it) {
val intent = Intent(this, MusicControlForegroundServiceImpl::class.java).apply { action = ACTION_SHOW_MUSIC_CONTROL }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) startForegroundService(intent) else startService(intent)
} else {
stopService(Intent(this, MusicControlForegroundServiceImpl::class.java))
}
})
The service itself:
class MusicControlForegroundServiceImpl : Service(), KoinComponent {
private val notificationManager: NotificationManager by inject()
private val radioManager: RadioManager by inject()
private val context: Context by inject()
private val preferences: Preferences by inject()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null && intent.action == ACTION_SHOW_MUSIC_CONTROL) {
val lastSelectedRadio = preferences.getJSON(Globals.LAST_SELECTED_RADIO_KEY, Radio::class.java)
?: return START_NOT_STICKY
val notification = notificationManager.createMediaControlNotificationIfNeeded(context, lastSelectedRadio)
startForeground(1, notification)
}
return START_NOT_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) startForegroundService(rootIntent) else startService(rootIntent)
super.onTaskRemoved(rootIntent)
}
override fun onDestroy() {
if (!notificationManager.musicControlServiceRestart) radioManager.release()
synchronized(MUSIC_CONTROL_SERVICE_LOCK) { notificationManager.musicControlServiceRestart = false }
synchronized(MEDIA_PLAYER_LOCK) { radioManager.lastPlayedMediaUrl = null }
stopForeground(true)
super.onDestroy()
}
override fun onBind(intent: Intent?): IBinder? = null
}
The notification creation:
override fun createMediaControlNotificationIfNeeded(context: Context, selectedRadio: Radio): Notification {
val resultIntent = Intent(context, RadioDetailActivity::class.java)
val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(resultIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
val playIntent = Intent(context, NotificationReceiver::class.java).apply {
putExtra(MusicState::class.java.name, MusicState.PLAY)
}
val pauseIntent = Intent(context, NotificationReceiver::class.java).apply {
putExtra(MusicState::class.java.name, MusicState.PAUSE)
}
val notificationManager = NotificationManagerCompat.from(context)
#Suppress("DEPRECATION") val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification_icon)
.setContentTitle(selectedRadio.name)
.setDefaults(0)
.setOngoing(true)
.setNotificationSilent()
.addAction(
R.drawable.ic_notification_pause,
context.getString(R.string.pause),
PendingIntent.getBroadcast(context, 1, pauseIntent, 0)
)
.addAction(
R.drawable.ic_notification_play,
context.getString(R.string.play),
PendingIntent.getBroadcast(context, 2, playIntent, 0)
)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle().setMediaSession(
MediaSessionCompat(
context,
RadioDetailActivity::class.java.name
).sessionToken
)
)
.setContentIntent(resultPendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
context.getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
builder.setChannelId(CHANNEL_ID)
}
return builder.build()
}
If you need any other resources please let me know and help if you can! I'm struggling with this problem for weeks now.. :(
UPDATE
Now I throw my media control notification in every 2 minutes to update previous, so the app can survive like 30 minutes on the affected phone, but still not a working solution...

Related

Canceling running coroutineWorker doesn't fire failure in a certain pattern

I'm trying stopping running coroutineWorker from notification button. I tried 3 methods and 2 of them calls "Result.failure()" & working fine. However another one doesn't.
Below CoroutineWorker shows foregroundInfo and Starts ringtone.
class RingWork(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
companion object {
val ALARM_CHANNEL_ID = "alarm_channel6"
}
lateinit var ringtoneSound: Ringtone
val context = applicationContext
#RequiresApi(Build.VERSION_CODES.Q)
override suspend fun doWork(): Result {
return try {
val alarmId = inputData.getInt("alarmId", 0)
val notificationMgr =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//CHANNEL
val alarmChannel = NotificationChannel(
ALARM_CHANNEL_ID, "alarm" ,NotificationManager.IMPORTANCE_HIGH
)
alarmChannel.setSound(null, null)
alarmChannel.enableVibration(false)
alarmChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationMgr.createNotificationChannel(alarmChannel)
val fullScreenIntent = Intent(context, LockscreenActivity::class.java).putExtra("alarmId", alarmId)
//This calls "failure" properly
val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
//This calls "failure" properly
val stop1PendingIntent =
WorkManager.getInstance(context).createCancelPendingIntent(getId())
val s2Intent = Intent(context, StopAlarmReceiver::class.java).putExtra("alarmId", alarmId)
//This is not.
val stop2PendingIntent = PendingIntent.getBroadcast(context, 1, s2Intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, ALARM_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle("title")
.setFullScreenIntent(fullScreenPendingIntent, true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setAutoCancel(true)
.setSound(null)
.setVibrate(null)
.addAction(R.drawable.ic_stat_name, "Stop1", stop1PendingIntent)
.addAction(R.drawable.ic_stat_name, "Stop2", stop2PendingIntent)
setForeground(
ForegroundInfo(1999999, builder.build(), FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
)
ringtoneSound =
RingtoneManager.getRingtone(context, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM))
ringtoneSound.play()
delay(30000L)
ringtoneSound.stop()
Result.success()
} catch (e: Exception) {
Result.failure()
} finally {
cleanup()
}
}
fun cleanup(){
ringtoneSound.stop()
}
}
In LockScreenActivity, there is a button to stop ringtone.
binding.stoppingbutton.setOnClickListener {
val workMgr = WorkManager.getInstance(applicationContext)
workMgr.cancelUniqueWork("RingWork-$alarmId")
finish()
}
This calls "result.failure" and "finally" then ringtone will stop, notification will disapear. working fine.
However, if I press "Stop2" button on the notification.
class StopAlarmReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val alarmId = intent.getIntExtra("alarmId", 0)
val workMgr = WorkManager.getInstance(context)
workMgr.cancelUniqueWork("RingWork-$alarmId")
}
}
It cancels worker, but it won't call "result.failure" and "finally", so ringtone won't stop. Notification also won't disappear.
fullScreenPendingIntent and stop2PendingIntent are doing the same thing, but why it won't behave same?
You can edit your PendingIntent like this and it will trigger onReceive:
val stop2PendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
PendingIntent.getBroadcast(context, downloadFile.productId, cancelIntent, PendingIntent.FLAG_IMMUTABLE)
else
PendingIntent.getBroadcast(context, downloadFile.productId, cancelIntent, 0)

How to create multiple notifications in Kotlin in foreground service

I am working on a parental control app which notify parent multiple times but when I try to create notification with a background service it generates only one 1.
Here is how I do it:
fun createNotification(parent_name: String, notificationText:String, id: Int){
val MchannelId = channelId+id.toString()
if (Build.VERSION.SDK_INT >= 26) {
val channel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel(
MchannelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT
)
} else {
TODO("VERSION.SDK_INT < O")
}
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(
channel
)
}
val notificationIntent = Intent(this, TabbedActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
id, notificationIntent, 0
)
val notification: Notification = NotificationCompat.Builder(this, "$MchannelId")
.setContentTitle("Hi $parent_name")
.setContentText(notificationText)
.setSmallIcon(R.drawable.icon_child)
//.setContentIntent(pendingIntent)
.build()
startForeground(random_number, notification)
}
My Full-Service Class:
const val TAG2 = "Child Service"
class ParentService: Service() {
val db = FirebaseFirestore.getInstance()
private val channelId = "Notification from Service"
var parent_name = userName
override fun onBind(intent: Intent?): IBinder? = null
//OnBind Function Implementation
init {
Log.d(TAG2, "Started Service!")
}
//onCreate Method Implementation
override fun onCreate() {
super.onCreate()
}
//OnStartCommand Override
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Thread{
while (true){
checkStatus()
Thread.sleep(PARENT_CHECK_TIME)
}
}.start()
return START_STICKY
}
private fun checkStatus() {
var listOfNames = ""
var i = 1
val calendar: Calendar = Calendar.getInstance()
var list = ArrayList<String>()
db.collection(LINKED_CHILDS)
.whereEqualTo(USER_PHONE, userPhone)
.get()
.addOnSuccessListener { documents ->
for (document in documents){
val startTime: Long = calendar.getTimeInMillis()
val diff = startTime - (document.data[ACTIVE_STATUS] as Long)
Log.d("TAG", "Time Difference : $diff")
Log.d("TAG", "${document.data[USER_NAME].toString()}")
if (diff> MAX_GAP_TIME){
Log.d("TAG", "Entered IFF")
list.add(document.data[USER_NAME].toString())
}
}
for (name in list){
listOfNames = listOfNames + "$i. Your child $name is not active\n"
i++
createNotification(parent_name, listOfNames, i)
Log.d("TAG Notification ID:", "ID: $i")
}
Log.d("TAG: ", "$listOfNames")
}
}
fun createNotification(parent_name: String, notificationText:String, id: Int){
val MchannelId = channelId+id.toString()
if (Build.VERSION.SDK_INT >= 26) {
val channel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel(
MchannelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT
)
} else {
TODO("VERSION.SDK_INT < O")
}
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(
channel
)
}
val notificationIntent = Intent(this, TabbedActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
id, notificationIntent, 0
)
val notification: Notification = NotificationCompat.Builder(this, "$MchannelId")
.setContentTitle("Hi $parent_name")
.setContentText(notificationText)
.setSmallIcon(R.drawable.icon_child)
//.setContentIntent(pendingIntent)
.build()
startForeground(id, notification)
}
}
Kinldy let me know how I can create multiple Notifications using this background service. Thank You so much in advance!
Kinldy let me know how I can create multiple Notifications using this background service. Thank You so much in advance!
Kinldy let me know how I can create multiple Notifications using this background service. Thank You so much in advance!
If you create a non-persistent notification, it will show your notifications. The permanent notification will be used for your service to run in the background.
#RequiresApi(Build.VERSION_CODES.O)
private fun createNotification() {
val intent = Intent(this, TabbedActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.icon_child)
.setContentTitle("Hi $parent_name")
.setContentText(notificationText)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
with(NotificationManagerCompat.from(this)) {
notify(notifManagerId, notification.build())
notifManagerId++
}
parmanentNotification()
}
this is a permanent notification will not be lost and destroyed will keep the service running permanently
private fun parmanentNotification() {
val notification=NotificationCompat.Builder(this,channelId)
.setSmallIcon(R.drawable.icon_child)
.setContentTitle("Hi $parent_name")
.setContentText("Application service running in the background")
.build()
startForeground(1,notification)
}
you aren't creating a common Notification in this scenario, you are running a Service, which must have a foreground representation on screen. So Activity visible or sticked, fixed Notification, and you are showing it
Now you can have much Notifications using similar code, but don't show them using startForeground, instead use NotificationManager, preferably compat version
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(uniqueId, notification);
or just like you are using it already when creating channel inside if: (getSystemService(NOTIFICATION_SERVICE) as NotificationManager).notify(...)
foreground-related Notification is sticky and lives as long as Service works in background, they are "tied". other Notifications may be configured to be sticky or swipeable, also should be posted on some own Channel (per child? per action?). Note that if you show yet another sticky Notification then you have to release it by own through code, just killing Service won't dismiss it as it does with foreground-related Notification
some DOC in here, read carefully, all answers are there

Android Forground sevice stops when the app is closed

I am starting a background service which receives data in the background, so for this, I have used android foreground service, the service works perfectly in some mobiles (MI A2 Stock Android), but in some mobiles when I remove the application from background tray the service gets destroyed.
class MyService : Service() {
private val CHANNEL_ID = "ForegroundService"
companion object {
fun stopService(context: Context) {
val stopIntent = Intent(context, MyService::class.java)
context.stopService(stopIntent)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// I get some data from intent
// My code which runs in the background
createNotificationChannel()
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
0, notificationIntent, 0
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("App is syncing")
.setContentText("")
.setPriority(2)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setContentIntent(pendingIntent)
.build()
startForeground(190, notification)
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder? {
return null
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID, "Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(NotificationManager::class.java)
manager!!.createNotificationChannel(serviceChannel)
}
}
}
This how I start the service
val serviceIntent = Intent(this, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
So my question is how can I make my service running even when the APP is removed from the background tray.
Do these things
1) Restart the service when app is closed by overriding this method in
your service class , copy and paste this
override fun onTaskRemoved(rootIntent: Intent?) {
val restartServiceIntent = Intent(applicationContext, this.javaClass)
restartServiceIntent.setPackage(packageName)
val restartServicePendingIntent = PendingIntent.getService(
applicationContext,
1,
restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT
)
val alarmService =
applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmService[AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000] =
restartServicePendingIntent
super.onTaskRemoved(rootIntent)
}
2) Change this START_NOT_STICKY to START_STICKY
3) Ask user to enable autorun permission from settings , this feature
is provided in custom os like mini devices, vivo,huawei and oppo etc.
4) and you forgot to restart the service on device boot up like you
need to use a broadcast receiver to restart service when the device
restarts

Android: Service doesn't work after screen is off

I am trying to create service which will be fetch data from server (periodicaly) and send notification to user. I achieved almost my goal, but service stops work when screen is off. When I turn on my phone I get plenty of notifications from previous time.
Service code:
class MyService: Service() {
override fun onCreate() {
super.onCreate()
val handler = Handler()
val runnable = object: Runnable {
override fun run() {
getDataFromServer()
handler.postDelayed(this, 1800000)
}
}
handler.post(runnable)
}
private fun getDataFromServer() {
// fetch data
displayNotification(description)
}
private fun displayNotification(description: String) {
val intent = Intent(this, MainActivity::class.java)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationId = (0..300).random()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val adminChannelName = "Messages channel"
val adminChannelDescription = "Notification about new data"
NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_HIGH).apply {
description = adminChannelDescription
enableLights(true)
lightColor = Color.RED
enableVibration(true)
notificationManager.createNotificationChannel(this)
}
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_ONE_SHOT
)
val notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
.setSmallIcon(R.drawable.icon_small)
.setContentTitle(getText(R.string.notification_new_data_title))
.setContentText(getString(R.string.notification_new_data_text, description))
.setAutoCancel(true)
.setSound(notificationSoundUri)
.setContentIntent(pendingIntent)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
notificationBuilder.color = ContextCompat.getColor(context, R.color.icon_background)
}
notificationManager.notify(notificationId, notificationBuilder.build())
}
override fun onBind(intent: Intent): IBinder ? {
return null
}
}
Thank you for your help!
Try to start you service using the startForegroundService instead of startService, whether you need a background service, you can convert you Service to JobIntentService:
https://developer.android.com/reference/androidx/core/app/JobIntentService

Periodic Task in Background

I'm currently building an app that starts a session by sending a request to the backend. After that, the app has to send a heartbeat request every 4.5 minutes. If the app does not send a request to the backend after 4.5 minutes since the last successful request, the session will get terminated. The heartbeat request can be sent earlier which also means that the next heartbeat has to be sent 4.5 minutes after that request.
Once the user has started the session, he should be able to put the app to the background to use the device for other things.
I'm struggling with coming up with a solution that works with the background restrictions (doze mode, etc).
I'm currently running the app with a foreground service. But the requests stop after a couple of minutes if I don't use the device actively. I tried the WorkManager and the AlarmManager. But the requests keep getting delayed.
I played around with REQUEST_IGNORE_BATTERY_OPTIMIZATIONS and this seems to work but I don't want to use that approach since Google seems to really dislike apps using this permission.
I created a test app to play around with different approaches. Maybe I'm doing something completely wrong?
Service:
class MainService : Service() {
private lateinit var wakeLock: PowerManager.WakeLock
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= 26) {
val appName = getString(R.string.app_name)
val channelName = "$appName channel name"
val channelImportance = NotificationManager.IMPORTANCE_HIGH
val channelDescription = "$appName channel description"
createNotificationChannel(this, NOTIFICATION_CHANNEL_ID, channelName, channelImportance, channelDescription)
}
val notification = createOngoingNotification(this, NOTIFICATION_REQUEST_CODE, R.mipmap.ic_launcher_round, "Content Text")
startForeground(1000, notification)
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag").apply {
acquire(1 * 60 * 60 * 1000L)
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.action?.let {
if (it == "Heartbeat") {
val v = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE))
}
}
}
setNext()
return START_STICKY
}
private fun setNext() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val intent = Intent(applicationContext, MainService::class.java)
intent.action = "Heartbeat"
val pendingIntent = PendingIntent.getService(applicationContext, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5 * 1000, pendingIntent)
}
}
override fun onDestroy() {
stopForeground(true)
wakeLock.release()
super.onDestroy()
}
companion object {
const val REQUEST_CODE = 101
const val NOTIFICATION_REQUEST_CODE = 100
const val NOTIFICATION_CHANNEL_ID = "notification_channel_id"
fun createOngoingNotification(context: Context, requestCode: Int, icon: Int, text: String): Notification {
val contentIntent = Intent(context, MainActivity::class.java)
.setAction(Intent.ACTION_MAIN)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
val contentPendingIntent = PendingIntent.getActivity(context, requestCode, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT)
return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setOngoing(true)
.setSmallIcon(icon)
.setContentTitle("Test Notification")
.setContentText(text)
.setContentIntent(contentPendingIntent)
.build()
}
#RequiresApi(api = 26)
fun createNotificationChannel(context: Context,
id: String, name: String, importance: Int,
description: String) {
val channel = NotificationChannel(id, name, importance)
channel.description = description
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
I think that foreground service may be stopped as you are not executing anything inside it after you set the alarm. Foreground service keeps running if you are using it, so for making it work periodically i would put an observable that emits a value every 5 seconds for example. You only need the one emmited after 4.5 minutes but that will keep the foreground service active until you need it. Using rxjava:
Observable.intervalRange( 0 , 54, 0, 5, TimeUnit.SECONDS )
.doOnNext{
//You may not need this
}
.doOnComplete {
//heartbeat
//start this observable again for other 4.5 minutes
}
You will emit a value every 5 seconds 54 times. 54x5 = 270 seconds (what is 4.5 minutes)

Categories

Resources