diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6f7d651..dd9a78b 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -11,43 +11,40 @@
android:name="android.permission.ACCESS_NETWORK_STATE"
tools:node="remove" />
-
+
-
-
-
-
-
-
+ android:name=".MainApplication"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:theme="@style/AppTheme">
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
= Build.VERSION_CODES.TIRAMISU) {
- reactApplicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST),
- Context.RECEIVER_NOT_EXPORTED)
- reactApplicationContext.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST),
- Context.RECEIVER_NOT_EXPORTED)
- }
- else {
- reactApplicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST))
- reactApplicationContext.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST))
- }
- }
-
- override fun onHostDestroy() {
- reactApplicationContext.unregisterReceiver(stopReceiver)
- reactApplicationContext.unregisterReceiver(addReceiver)
- }
-
- @ReactMethod
- fun add() {
- Log.d("AlarmModule", "Add 1 min to alarm.")
- countdownTimer?.cancel()
- val newMs = if (running) currentMs.toInt().plus(60000) else 60000
- countdownTimer = getTimer(newMs)
- countdownTimer?.start()
- running = true
- val manager = getManager()
- manager.cancel(AlarmService.NOTIFICATION_ID_DONE)
- val intent = Intent(reactApplicationContext, AlarmService::class.java)
- reactApplicationContext.stopService(intent)
- }
-
- @ReactMethod(isBlockingSynchronousMethod = true)
- fun getCurrent(): Int {
- Log.d("AlarmModule", "currentMs=$currentMs")
- if (running) return currentMs.toInt()
- return 0
- }
-
- @ReactMethod
- fun stop() {
- Log.d("AlarmModule", "Stop alarm.")
- countdownTimer?.cancel()
- running = false
- val intent = Intent(reactApplicationContext, AlarmService::class.java)
- reactApplicationContext?.stopService(intent)
- val manager = getManager()
- manager.cancel(AlarmService.NOTIFICATION_ID_DONE)
- manager.cancel(NOTIFICATION_ID_PENDING)
- val params =
- Arguments.createMap().apply {
- putString("minutes", "00")
- putString("seconds", "00")
- }
- reactApplicationContext
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
- .emit("tick", params)
- }
-
@ReactMethod
fun timer(milliseconds: Int, description: String) {
Log.d("AlarmModule", "Queue alarm for $milliseconds delay")
val intent = Intent(reactApplicationContext, TimerService::class.java)
intent.putExtra("milliseconds", milliseconds)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- reactApplicationContext.startForegroundService(intent)
- }
- else {
- reactApplicationContext.startService(intent)
- }
- }
-
- private fun getTimer(
- endMs: Int,
- ): CountDownTimer {
- val builder = getBuilder()
- return object : CountDownTimer(endMs.toLong(), 1000) {
- override fun onTick(current: Long) {
- currentMs = current
- val seconds =
- floor((current / 1000).toDouble() % 60).toInt().toString().padStart(2, '0')
- val minutes =
- floor((current / 1000).toDouble() / 60).toInt().toString().padStart(2, '0')
- builder.setContentText("$minutes:$seconds")
- .setAutoCancel(false)
- .setDefaults(0)
- .setProgress(endMs, current.toInt(), false)
- .setCategory(NotificationCompat.CATEGORY_PROGRESS)
- .priority = NotificationCompat.PRIORITY_LOW
- val manager = getManager()
- manager.notify(NOTIFICATION_ID_PENDING, builder.build())
- val params =
- Arguments.createMap().apply {
- putString("minutes", minutes)
- putString("seconds", seconds)
- }
- reactApplicationContext
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
- .emit("tick", params)
- }
-
- override fun onFinish() {
- val context = reactApplicationContext
- val intent = Intent(context, AlarmService::class.java)
- context.startService(intent)
- context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
- .emit(
- "tick",
- Arguments.createMap().apply {
- putString("minutes", "00")
- putString("seconds", "00")
- }
- )
- }
- }
- }
-
- @SuppressLint("UnspecifiedImmutableFlag")
- private fun getBuilder(): NotificationCompat.Builder {
- val context = reactApplicationContext
- val contentIntent = Intent(context, MainActivity::class.java)
- val pendingContent =
- PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE)
- val addBroadcast = Intent(ADD_BROADCAST).apply { setPackage(context.packageName) }
- val pendingAdd =
- PendingIntent.getBroadcast(context, 0, addBroadcast, PendingIntent.FLAG_MUTABLE)
- val stopBroadcast = Intent(STOP_BROADCAST)
- stopBroadcast.setPackage(context.packageName)
- val pendingStop =
- PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
- return NotificationCompat.Builder(context, CHANNEL_ID_PENDING)
- .setSmallIcon(R.drawable.ic_baseline_hourglass_bottom_24)
- .setContentTitle(currentDescription)
- .setContentIntent(pendingContent)
- .addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop)
- .addAction(R.drawable.ic_baseline_stop_24, "Add 1 min", pendingAdd)
- .setDeleteIntent(pendingStop)
- }
-
- private fun getManager(): NotificationManager {
- val notificationManager =
- reactApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val timersChannel =
- NotificationChannel(
- CHANNEL_ID_PENDING,
- CHANNEL_ID_PENDING,
- NotificationManager.IMPORTANCE_LOW
- )
- timersChannel.setSound(null, null)
- timersChannel.description = "Progress on rest timers."
- notificationManager.createNotificationChannel(timersChannel)
- }
-
- return notificationManager
- }
-
- companion object {
- const val STOP_BROADCAST = "stop-timer-event"
- const val ADD_BROADCAST = "add-timer-event"
- const val CHANNEL_ID_PENDING = "Timer"
- const val NOTIFICATION_ID_PENDING = 1
- }
-
- override fun onHostResume() {
- TODO("Not yet implemented")
- }
-
- override fun onHostPause() {
- TODO("Not yet implemented")
+ intent.putExtra("description", description)
+ reactApplicationContext.startForegroundService(intent)
}
}
diff --git a/android/app/src/main/java/com/massive/AlarmService.kt b/android/app/src/main/java/com/massive/AlarmService.kt
deleted file mode 100644
index a9c483e..0000000
--- a/android/app/src/main/java/com/massive/AlarmService.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.massive
-
-import android.annotation.SuppressLint
-import android.app.*
-import android.content.Context
-import android.content.Intent
-import android.media.AudioAttributes
-import android.media.MediaPlayer
-import android.media.MediaPlayer.OnPreparedListener
-import android.net.Uri
-import android.os.*
-import androidx.annotation.RequiresApi
-import androidx.core.app.NotificationCompat
-
-class Settings(val sound: String?, val noSound: Boolean, val vibrate: Boolean, val duration: Long)
-
-class AlarmService : Service(), OnPreparedListener {
- private var mediaPlayer: MediaPlayer? = null
- private var vibrator: Vibrator? = null
-
- private fun getBuilder(): NotificationCompat.Builder {
- val context = applicationContext
- val contentIntent = Intent(context, MainActivity::class.java)
- val pendingContent =
- PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_IMMUTABLE)
- val addBroadcast = Intent(AlarmModule.ADD_BROADCAST).apply {
- setPackage(context.packageName)
- }
- val pendingAdd =
- PendingIntent.getBroadcast(context, 0, addBroadcast, PendingIntent.FLAG_MUTABLE)
- val stopBroadcast = Intent(AlarmModule.STOP_BROADCAST)
- stopBroadcast.setPackage(context.packageName)
- val pendingStop =
- PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
- return NotificationCompat.Builder(context, AlarmModule.CHANNEL_ID_PENDING)
- .setSmallIcon(R.drawable.ic_baseline_hourglass_bottom_24).setContentTitle("Resting")
- .setSound(null)
- .setContentIntent(pendingContent)
- .addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop)
- .addAction(R.drawable.ic_baseline_stop_24, "Add 1 min", pendingAdd)
- .setDeleteIntent(pendingStop)
- }
-
-
- @SuppressLint("Range")
- private fun getSettings(): Settings {
- val db = DatabaseHelper(applicationContext).readableDatabase
- val cursor = db.rawQuery("SELECT sound, noSound, vibrate, duration FROM settings", null)
- cursor.moveToFirst()
- val sound = cursor.getString(cursor.getColumnIndex("sound"))
- val noSound = cursor.getInt(cursor.getColumnIndex("noSound")) == 1
- val vibrate = cursor.getInt(cursor.getColumnIndex("vibrate")) == 1
- var duration = cursor.getLong(cursor.getColumnIndex("duration"))
- if (duration.toInt() == 0) duration = 300
- cursor.close()
- return Settings(sound, noSound, vibrate, duration)
- }
-
- private fun playSound(settings: Settings) {
- if (settings.noSound) return
- if (settings.sound == null) {
- mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon)
- mediaPlayer?.start()
- mediaPlayer?.setOnCompletionListener { vibrator?.cancel() }
- } else {
- mediaPlayer = MediaPlayer().apply {
- setAudioAttributes(
- AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
- .setUsage(AudioAttributes.USAGE_MEDIA)
- .build()
- )
- setDataSource(applicationContext, Uri.parse(settings.sound))
- prepare()
- start()
- setOnCompletionListener { vibrator?.cancel() }
- }
- }
- }
-
- private fun doNotify(): Notification {
- val manager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val alarmsChannel = NotificationChannel(
- CHANNEL_ID_DONE,
- CHANNEL_ID_DONE,
- NotificationManager.IMPORTANCE_HIGH
- )
- alarmsChannel.description = "Alarms for rest timers."
- alarmsChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- alarmsChannel.setSound(null, null)
- manager.createNotificationChannel(alarmsChannel)
- }
-
- val builder = getBuilder()
- val context = applicationContext
- val finishIntent = Intent(context, StopAlarm::class.java)
- val finishPending = PendingIntent.getActivity(
- context, 0, finishIntent, PendingIntent.FLAG_IMMUTABLE
- )
- val fullIntent = Intent(context, TimerDone::class.java)
- val fullPending = PendingIntent.getActivity(
- context, 0, fullIntent, PendingIntent.FLAG_IMMUTABLE
- )
- builder.setContentText("Timer finished.").setProgress(0, 0, false)
- .setAutoCancel(true).setOngoing(true).setFullScreenIntent(fullPending, true)
- .setContentIntent(finishPending).setChannelId(CHANNEL_ID_DONE)
- .setCategory(NotificationCompat.CATEGORY_ALARM).priority =
- NotificationCompat.PRIORITY_HIGH
- val notification = builder.build()
- manager.notify(NOTIFICATION_ID_DONE, notification)
- manager.cancel(AlarmModule.NOTIFICATION_ID_PENDING)
- return notification
- }
-
- @RequiresApi(Build.VERSION_CODES.O)
- @SuppressLint("Recycle")
- override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- doNotify()
- val settings = getSettings()
- playSound(settings)
- if (!settings.vibrate) return START_STICKY
- val pattern = longArrayOf(0, settings.duration, 1000, settings.duration, 1000, settings.duration)
- vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- val vibratorManager = getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
- vibratorManager.defaultVibrator
- } else {
- @Suppress("DEPRECATION")
- getSystemService(VIBRATOR_SERVICE) as Vibrator
- }
- vibrator!!.vibrate(VibrationEffect.createWaveform(pattern, -1))
-
- val handler = Handler(Looper.getMainLooper())
- handler.postDelayed({ vibrator!!.cancel() }, 10000)
- return START_STICKY
- }
-
- override fun onBind(intent: Intent): IBinder? {
- return null
- }
-
- override fun onPrepared(player: MediaPlayer) {
- player.start()
- }
-
- override fun onDestroy() {
- super.onDestroy()
- mediaPlayer?.stop()
- mediaPlayer?.release()
- vibrator?.cancel()
- }
-
- companion object {
- const val CHANNEL_ID_DONE = "Alarm"
- const val NOTIFICATION_ID_DONE = 2
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/massive/StopAlarm.kt b/android/app/src/main/java/com/massive/StopAlarm.kt
index d4696a7..9c09913 100644
--- a/android/app/src/main/java/com/massive/StopAlarm.kt
+++ b/android/app/src/main/java/com/massive/StopAlarm.kt
@@ -1,17 +1,11 @@
package com.massive
import android.app.Activity
-import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
-import android.util.AttributeSet
import android.util.Log
-import android.view.View
-import android.view.WindowManager
import androidx.annotation.RequiresApi
-import com.massive.AlarmService
-import com.massive.MainActivity
class StopAlarm : Activity() {
@RequiresApi(Build.VERSION_CODES.O_MR1)
@@ -19,7 +13,7 @@ class StopAlarm : Activity() {
Log.d("AlarmActivity", "Call to AlarmActivity")
super.onCreate(savedInstanceState)
val context = applicationContext
- context.stopService(Intent(context, AlarmService::class.java))
+ context.stopService(Intent(context, TimerService::class.java))
savedInstanceState.apply { setShowWhenLocked(true) }
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/android/app/src/main/java/com/massive/TimerDone.kt b/android/app/src/main/java/com/massive/TimerDone.kt
index 92027c1..e0cbe1b 100644
--- a/android/app/src/main/java/com/massive/TimerDone.kt
+++ b/android/app/src/main/java/com/massive/TimerDone.kt
@@ -1,8 +1,5 @@
package com.massive
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
import android.content.Intent
import android.os.Build
import android.os.Bundle
@@ -10,6 +7,7 @@ import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.NotificationManagerCompat
class TimerDone : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -21,38 +19,11 @@ class TimerDone : AppCompatActivity() {
@Suppress("UNUSED_PARAMETER")
fun stop(view: View) {
Log.d("TimerDone", "Stopping...")
- applicationContext.stopService(Intent(applicationContext, AlarmService::class.java))
- val manager = getManager()
- manager.cancel(AlarmService.NOTIFICATION_ID_DONE)
- manager.cancel(AlarmModule.NOTIFICATION_ID_PENDING)
+ applicationContext.stopService(Intent(applicationContext, TimerService::class.java))
+ val manager = NotificationManagerCompat.from(this)
+ manager.cancel(TimerService.CHANNEL_ID)
val intent = Intent(applicationContext, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
applicationContext.startActivity(intent)
}
-
- @RequiresApi(Build.VERSION_CODES.O)
- fun getManager(): NotificationManager {
- val alarmsChannel = NotificationChannel(
- AlarmService.CHANNEL_ID_DONE,
- AlarmService.CHANNEL_ID_DONE,
- NotificationManager.IMPORTANCE_HIGH
- ).apply {
- description = "Alarms for rest timers."
- lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- }
- val timersChannel = NotificationChannel(
- AlarmModule.CHANNEL_ID_PENDING,
- AlarmModule.CHANNEL_ID_PENDING,
- NotificationManager.IMPORTANCE_LOW
- ).apply {
- setSound(null, null)
- description = "Progress on rest timers."
- }
- val notificationManager = applicationContext.getSystemService(
- NotificationManager::class.java
- )
- notificationManager.createNotificationChannel(alarmsChannel)
- notificationManager.createNotificationChannel(timersChannel)
- return notificationManager
- }
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/massive/TimerService.kt b/android/app/src/main/java/com/massive/TimerService.kt
index 71207fb..5133ead 100644
--- a/android/app/src/main/java/com/massive/TimerService.kt
+++ b/android/app/src/main/java/com/massive/TimerService.kt
@@ -8,19 +8,27 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
+import android.media.AudioAttributes
+import android.media.MediaPlayer
+import android.net.Uri
import android.os.*
import android.util.Log
+import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
+class Settings(val sound: String?, val noSound: Boolean, val vibrate: Boolean, val duration: Long)
+@RequiresApi(Build.VERSION_CODES.O)
class TimerService : Service() {
private lateinit var timerHandler: Handler
private var timerRunnable: Runnable? = null
- private var timeLeftInSeconds: Int = 0
- private var timeTotalInSeconds: Int = 0
- private var notificationId = 1
+ private var secondsLeft: Int = 0
+ private var secondsTotal: Int = 0
+ private var mediaPlayer: MediaPlayer? = null
+ private var vibrator: Vibrator? = null
+ private var currentDescription = ""
private val stopReceiver =
object : BroadcastReceiver() {
@@ -30,6 +38,16 @@ class TimerService : Service() {
}
}
+ private val addReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ secondsLeft += 60;
+ secondsTotal += 60;
+ mediaPlayer?.stop()
+ vibrator?.cancel()
+ }
+ }
+
@SuppressLint("UnspecifiedRegisterReceiverFlag")
override fun onCreate() {
super.onCreate()
@@ -37,27 +55,33 @@ class TimerService : Service() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
applicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST),
Context.RECEIVER_NOT_EXPORTED)
+ applicationContext.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST),
+ Context.RECEIVER_NOT_EXPORTED)
}
else {
applicationContext.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST))
+ applicationContext.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST))
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- timeLeftInSeconds = (intent?.getIntExtra("milliseconds", 0) ?: 0) / 1000
- startForeground(notificationId, createNotification(timeLeftInSeconds))
- Log.d("TimerService", "onStartCommand seconds=$timeLeftInSeconds")
- timeTotalInSeconds = timeLeftInSeconds
+ secondsLeft = (intent?.getIntExtra("milliseconds", 0) ?: 0) / 1000
+ currentDescription = intent?.getStringExtra("description").toString()
+ secondsTotal = secondsLeft
+ startForeground(CHANNEL_ID, getProgress(secondsLeft).build())
+ Log.d("TimerService", "onStartCommand seconds=$secondsLeft")
timerRunnable = object : Runnable {
override fun run() {
- if (timeLeftInSeconds > 0) {
- timeLeftInSeconds--
- updateNotification(timeLeftInSeconds)
+ if (secondsLeft > 0) {
+ secondsLeft--
+ updateNotification(secondsLeft)
timerHandler.postDelayed(this, 1000)
} else {
- startAlarmService()
- stopSelf()
+ val settings = getSettings()
+ vibrate(settings)
+ playSound(settings)
+ notifyFinished()
}
}
}
@@ -69,14 +93,53 @@ class TimerService : Service() {
super.onDestroy()
timerHandler.removeCallbacks(timerRunnable!!)
applicationContext.unregisterReceiver(stopReceiver)
+ applicationContext.unregisterReceiver(addReceiver)
+ mediaPlayer?.stop()
+ mediaPlayer?.release()
+ vibrator?.cancel()
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
- private fun createNotification(timeLeftInSeconds: Int): Notification {
- val notificationTitle = "Timer"
+ @SuppressLint("Range")
+ private fun getSettings(): Settings {
+ val db = DatabaseHelper(applicationContext).readableDatabase
+ val cursor = db.rawQuery("SELECT sound, noSound, vibrate, duration FROM settings", null)
+ cursor.moveToFirst()
+ val sound = cursor.getString(cursor.getColumnIndex("sound"))
+ val noSound = cursor.getInt(cursor.getColumnIndex("noSound")) == 1
+ val vibrate = cursor.getInt(cursor.getColumnIndex("vibrate")) == 1
+ var duration = cursor.getLong(cursor.getColumnIndex("duration"))
+ if (duration.toInt() == 0) duration = 300
+ cursor.close()
+ return Settings(sound, noSound, vibrate, duration)
+ }
+
+ private fun playSound(settings: Settings) {
+ if (settings.noSound) return
+ if (settings.sound == null) {
+ mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon)
+ mediaPlayer?.start()
+ mediaPlayer?.setOnCompletionListener { vibrator?.cancel() }
+ } else {
+ mediaPlayer = MediaPlayer().apply {
+ setAudioAttributes(
+ AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
+ .setUsage(AudioAttributes.USAGE_MEDIA)
+ .build()
+ )
+ setDataSource(applicationContext, Uri.parse(settings.sound))
+ prepare()
+ start()
+ setOnCompletionListener { vibrator?.cancel() }
+ }
+ }
+ }
+
+ private fun getProgress(timeLeftInSeconds: Int): NotificationCompat.Builder {
val notificationText = formatTime(timeLeftInSeconds)
val notificationChannelId = "timer_channel"
val notificationIntent = Intent(this, TimerService::class.java)
@@ -86,16 +149,19 @@ class TimerService : Service() {
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
- val stopBroadcast = Intent(AlarmModule.STOP_BROADCAST)
+ val stopBroadcast = Intent(STOP_BROADCAST)
stopBroadcast.setPackage(applicationContext.packageName)
val pendingStop =
PendingIntent.getBroadcast(applicationContext, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
+ val addBroadcast = Intent(ADD_BROADCAST).apply { setPackage(applicationContext.packageName) }
+ val pendingAdd =
+ PendingIntent.getBroadcast(applicationContext, 0, addBroadcast, PendingIntent.FLAG_MUTABLE)
val notificationBuilder = NotificationCompat.Builder(this, notificationChannelId)
- .setContentTitle(notificationTitle)
+ .setContentTitle(currentDescription)
.setContentText(notificationText)
.setSmallIcon(R.drawable.ic_baseline_timer_24)
- .setProgress(timeTotalInSeconds, timeLeftInSeconds, false)
+ .setProgress(secondsTotal, timeLeftInSeconds, false)
.setContentIntent(pendingIntent)
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setAutoCancel(false)
@@ -104,6 +170,7 @@ class TimerService : Service() {
.setOngoing(true)
.setDeleteIntent(pendingStop)
.addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop)
+ .addAction(R.drawable.ic_baseline_stop_24, "Add 1 min", pendingAdd)
val notificationManager = NotificationManagerCompat.from(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -115,27 +182,64 @@ class TimerService : Service() {
notificationManager.createNotificationChannel(channel)
}
- return notificationBuilder.build()
+ return notificationBuilder
}
- private fun updateNotification(timeLeftInSeconds: Int) {
+ private fun vibrate(settings: Settings) {
+ if (!settings.vibrate) return
+ val pattern = longArrayOf(0, settings.duration, 1000, settings.duration, 1000, settings.duration)
+ vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val vibratorManager = getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
+ vibratorManager.defaultVibrator
+ } else {
+ @Suppress("DEPRECATION")
+ getSystemService(VIBRATOR_SERVICE) as Vibrator
+ }
+ vibrator!!.vibrate(VibrationEffect.createWaveform(pattern, -1))
+
+ val handler = Handler(Looper.getMainLooper())
+ handler.postDelayed({ vibrator!!.cancel() }, 10000)
+ }
+
+ private fun notifyFinished() {
+ val builder = getProgress(0)
+ val fullIntent = Intent(applicationContext, TimerDone::class.java)
+ val fullPending = PendingIntent.getActivity(
+ applicationContext, 0, fullIntent, PendingIntent.FLAG_IMMUTABLE
+ )
+ val finishIntent = Intent(applicationContext, StopAlarm::class.java)
+ val finishPending = PendingIntent.getActivity(
+ applicationContext, 0, finishIntent, PendingIntent.FLAG_IMMUTABLE
+ )
+ builder.setPriority(NotificationCompat.PRIORITY_HIGH)
+ .setCategory(NotificationCompat.CATEGORY_ALARM)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setContentIntent(finishPending)
+ .setFullScreenIntent(fullPending, true)
+ .setOngoing(false)
+ .setProgress(0, 0, false)
val notificationManager = NotificationManagerCompat.from(this)
- val notification = createNotification(timeLeftInSeconds)
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) != PackageManager.PERMISSION_GRANTED
) {
- // TODO: Consider calling
- // ActivityCompat#requestPermissions
- // here to request the missing permissions, and then overriding
- // public void onRequestPermissionsResult(int requestCode, String[] permissions,
- // int[] grantResults)
- // to handle the case where the user grants the permission. See the documentation
- // for ActivityCompat#requestPermissions for more details.
return
}
- notificationManager.notify(notificationId, notification)
+ notificationManager.notify(CHANNEL_ID, builder.build())
+ }
+
+ private fun updateNotification(seconds: Int) {
+ val notificationManager = NotificationManagerCompat.from(this)
+ val notification = getProgress(seconds)
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return
+ }
+ notificationManager.notify(CHANNEL_ID, notification.build())
}
private fun formatTime(timeInSeconds: Int): String {
@@ -144,12 +248,9 @@ class TimerService : Service() {
return String.format("%02d:%02d", minutes, seconds)
}
- private fun startAlarmService() {
- val intent = Intent(applicationContext, AlarmService::class.java)
- applicationContext.startService(intent)
- }
-
companion object {
const val STOP_BROADCAST = "stop-timer-event"
+ const val ADD_BROADCAST = "add-timer-event"
+ const val CHANNEL_ID = 1
}
}