I found a way for running the timer - i.e. chronometer
setUp chronometer in fragment or activity layout something like this
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FirstFragment">
<Button
android:id="@+id/button_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/chronometer" />
<Chronometer
android:id="@+id/chronometer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@android:color/holo_red_dark"
android:textSize="48sp"
android:textStyle="bold"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Start timer on button click or whichever scenario you want to -
private fun startTimer(startTime: Long) {
chronometer.base = startTime
chronometer.setOnChronometerTickListener {
Log.i("Timer--->", "Countdown---> " + chronometer.base)
// formattedTime = getFormattedTime(chronometer.base)
}
chronometer.start()
}
The main thing comes to post a notification with chronometer - here I will let you know how to do it
override fun onPause() {
super.onPause()
val intent = Intent(activity, MyTimerService::class.java)
intent.action = MyTimerService.START_FOREGROUND_SERVICE
intent.putExtra("timer", chronometer.base)
activity?.startService(intent)
}
This is the Service class - make sure you register it in manifest and provide the foreground user's permission
class MyTimerService : Service() {
private lateinit var notificationView: RemoteViews
private lateinit var notiBuilder: Notification
companion object {
const val NOTIFICATION_CHANNEL_ID = "100"
const val NOTIFICATION_ID = 10
const val START_FOREGROUND_SERVICE = "start_foreground_service"
const val STOP_FOREGROUND_SERVICE = "stop_foreground_service"
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
notificationView = RemoteViews(packageName, R.layout.notification_layout)
createNotification()
}
private fun getPendingIntent(): PendingIntent? {
// Create an explicit intent for an Activity in your app
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
}
// intent.putExtra("timer", notificationView.)
return PendingIntent.getActivity(this, 0, intent, 0)
}
private fun createNotification() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannelForOreo()
} else {
createNotificationBelowOreo()
}
}
private fun createNotificationBelowOreo() {
// Create notification builder.
val builder = NotificationCompat.Builder(this)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_baseline_timer_24)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationView)
.setContentIntent(getPendingIntent())
.setContentTitle(baseContext.getString(R.string.app_name))
.setContentText("Active Session")
.setAutoCancel(true)
.setPriority(Notification.PRIORITY_MAX)
// Build the notification.
notiBuilder = builder.build()
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannelForOreo() {
val chan =
NotificationChannel(
NOTIFICATION_CHANNEL_ID,
baseContext.getString(R.string.channel_name),
NotificationManager.IMPORTANCE_DEFAULT
)
// chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val manager = (getSystemService(NOTIFICATION_SERVICE) as NotificationManager)
manager.createNotificationChannel(chan)
val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
notiBuilder = notificationBuilder.setOngoing(true)
.setSmallIcon(R.drawable.ic_baseline_timer_24)
.setContentTitle(baseContext.getString(R.string.app_name))
.setContentText("Active Session")
.setAutoCancel(true)
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(notificationView)
.setCategory(Notification.CATEGORY_SERVICE)
.setContentIntent(getPendingIntent())
.build()
val notificationManager = NotificationManagerCompat.from(this)
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
}
private fun showNotification() {
// Start foreground service.
startForeground(NOTIFICATION_ID, notiBuilder)
}
override fun onDestroy() {
super.onDestroy()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if (intent?.extras != null) {
when (intent.action) {
START_FOREGROUND_SERVICE -> {
val timestamp = intent.getLongExtra("timer", 0)
// set chronometer
notificationView.setChronometer(R.id.chronometer, timestamp, null, true)
// show notification
showNotification()
}
STOP_FOREGROUND_SERVICE -> {
stopForeground(true)
stopSelf()
}
}
}
return START_STICKY
}
}
To handle the timer persistence save the chronometer time in onPause -
override fun onPause() {
super.onPause()
**Make sure you are saving this time at central place**
MainActivity.appPauseTime = chronometer.base
}
In onResume -
override fun onResume() {
super.onResume()
if (MainActivity.appPauseTime > 0L) {
startTimer(MainActivity.appPauseTime)
val intent = Intent(activity, MyTimerService::class.java)
intent.action = MyTimerService.STOP_FOREGROUND_SERVICE
activity?.stopService(intent)
}
}
Let me know and upVote incase you found it helpful.