Massive/android/app/src/main/java/com/massive/AlarmModule.kt

206 lines
8.5 KiB
Kotlin
Raw Normal View History

2022-07-05 00:43:04 +00:00
package com.massive
import android.annotation.SuppressLint
import android.app.*
import android.content.ActivityNotFoundException
2022-10-28 03:48:29 +00:00
import android.content.BroadcastReceiver
import android.content.Context
2022-07-05 00:43:04 +00:00
import android.content.Intent
2022-10-28 03:48:29 +00:00
import android.content.IntentFilter
import android.net.Uri
2022-07-05 00:43:04 +00:00
import android.os.Build
import android.os.CountDownTimer
import android.os.PowerManager
import android.provider.Settings
2022-07-05 00:43:04 +00:00
import android.util.Log
import android.widget.Toast
2022-07-05 03:33:42 +00:00
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.facebook.react.bridge.Callback
2022-07-05 03:33:42 +00:00
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import kotlin.math.floor
2022-07-05 00:43:04 +00:00
2022-07-05 00:43:04 +00:00
class AlarmModule internal constructor(context: ReactApplicationContext?) :
ReactContextBaseJavaModule(context) {
2022-07-05 03:33:42 +00:00
var countdownTimer: CountDownTimer? = null
2022-07-05 00:43:04 +00:00
override fun getName(): String {
return "AlarmModule"
}
2022-10-28 03:48:29 +00:00
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(reactApplicationContext, "called from test receiver", Toast.LENGTH_SHORT)
.show()
}
2022-10-28 03:48:29 +00:00
}
init {
2022-10-28 03:48:29 +00:00
reactApplicationContext.registerReceiver(broadcastReceiver, IntentFilter(STOP_BROADCAST))
}
2022-09-26 01:38:25 +00:00
@RequiresApi(api = Build.VERSION_CODES.O)
@ReactMethod
fun add(milliseconds: Int, vibrate: Boolean, sound: String?) {
Log.d("AlarmModule", "Add 1 min to alarm.")
val addIntent = Intent(reactApplicationContext, TimerService::class.java)
addIntent.action = "add"
addIntent.putExtra("vibrate", vibrate)
addIntent.putExtra("sound", sound)
addIntent.data = Uri.parse("$milliseconds")
reactApplicationContext.startService(addIntent)
}
@RequiresApi(api = Build.VERSION_CODES.O)
@ReactMethod
fun stop() {
Log.d("AlarmModule", "Stop alarm.")
val timerIntent = Intent(reactApplicationContext, TimerService::class.java)
reactApplicationContext.stopService(timerIntent)
val alarmIntent = Intent(reactApplicationContext, AlarmService::class.java)
reactApplicationContext.stopService(alarmIntent)
2022-09-26 01:38:25 +00:00
}
2022-07-05 00:43:04 +00:00
@RequiresApi(api = Build.VERSION_CODES.O)
@ReactMethod
fun timer(milliseconds: Int, vibrate: Boolean, sound: String?, noSound: Boolean = false) {
2022-07-05 00:43:04 +00:00
Log.d("AlarmModule", "Queue alarm for $milliseconds delay")
val intent = Intent(reactApplicationContext, AlarmModule::class.java)
currentActivity?.startActivityForResult(intent, 0)
val manager = getManager()
manager.cancel(NOTIFICATION_ID_DONE)
reactApplicationContext.stopService(
Intent(
2022-10-28 03:48:29 +00:00
reactApplicationContext, AlarmService::class.java
)
)
countdownTimer?.cancel()
countdownTimer = getTimer(milliseconds, vibrate, sound)
countdownTimer?.start()
2022-07-05 00:43:04 +00:00
}
@RequiresApi(Build.VERSION_CODES.M)
@ReactMethod
2022-07-19 04:38:58 +00:00
fun ignoringBattery(callback: Callback) {
val packageName = reactApplicationContext.packageName
2022-10-28 03:48:29 +00:00
val pm = reactApplicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
callback.invoke(pm.isIgnoringBatteryOptimizations(packageName))
} else {
callback.invoke(true)
}
}
@SuppressLint("BatteryLife")
@RequiresApi(Build.VERSION_CODES.M)
@ReactMethod
fun ignoreBattery() {
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.data = Uri.parse("package:" + reactApplicationContext.packageName)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
try {
reactApplicationContext.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(
reactApplicationContext,
"Requests to ignore battery optimizations are disabled on your device.",
Toast.LENGTH_LONG
).show()
}
}
@RequiresApi(Build.VERSION_CODES.M)
private fun getTimer(endMs: Int, vibrate: Boolean, sound: String?): CountDownTimer {
val builder = getBuilder()
return object : CountDownTimer(endMs.toLong(), 1000) {
@RequiresApi(Build.VERSION_CODES.O)
override fun onTick(current: Long) {
2022-10-28 03:48:29 +00:00
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)
2022-10-28 03:48:29 +00:00
.setCategory(NotificationCompat.CATEGORY_PROGRESS).priority =
NotificationCompat.PRIORITY_LOW
val manager = getManager()
manager.notify(NOTIFICATION_ID_PENDING, builder.build())
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onFinish() {
val context = reactApplicationContext
val finishIntent = Intent(context, StopAlarm::class.java)
2022-10-28 03:48:29 +00:00
val finishPending = PendingIntent.getActivity(
context, 0, finishIntent, PendingIntent.FLAG_IMMUTABLE
)
val fullIntent = Intent(context, TimerDone::class.java)
2022-10-28 03:48:29 +00:00
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 manager = getManager()
manager.notify(NOTIFICATION_ID_DONE, builder.build())
manager.cancel(NOTIFICATION_ID_PENDING)
val alarmIntent = Intent(context, AlarmService::class.java)
alarmIntent.putExtra("vibrate", vibrate)
alarmIntent.putExtra("sound", sound)
context.startService(alarmIntent)
}
}
}
@SuppressLint("UnspecifiedImmutableFlag")
@RequiresApi(Build.VERSION_CODES.M)
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)
2022-10-28 03:48:29 +00:00
val stopIntent = Intent(STOP_BROADCAST)
val pendingStop =
PendingIntent.getService(context, 0, stopIntent, PendingIntent.FLAG_IMMUTABLE)
return NotificationCompat.Builder(context, CHANNEL_ID_PENDING)
2022-10-28 03:48:29 +00:00
.setSmallIcon(R.drawable.ic_baseline_hourglass_bottom_24).setContentTitle("Resting")
.setContentIntent(pendingContent)
.addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop)
.setDeleteIntent(pendingStop)
}
@RequiresApi(Build.VERSION_CODES.O)
fun getManager(): NotificationManager {
val alarmsChannel = NotificationChannel(
2022-10-28 03:48:29 +00:00
CHANNEL_ID_DONE, CHANNEL_ID_DONE, NotificationManager.IMPORTANCE_HIGH
)
alarmsChannel.description = "Alarms for rest timers."
alarmsChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
val notificationManager = reactApplicationContext.getSystemService(
NotificationManager::class.java
)
notificationManager.createNotificationChannel(alarmsChannel)
2022-10-28 03:48:29 +00:00
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 {
2022-10-28 03:48:29 +00:00
const val STOP_BROADCAST = "stop-timer-event"
const val CHANNEL_ID_PENDING = "Timer"
const val CHANNEL_ID_DONE = "Alarm"
const val NOTIFICATION_ID_PENDING = 1
const val NOTIFICATION_ID_DONE = 2
}
2022-07-05 03:33:42 +00:00
}