package com.example.fmassive import android.annotation.SuppressLint import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.Build import android.os.CountDownTimer import android.util.Log import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import kotlin.math.floor @RequiresApi(Build.VERSION_CODES.O) class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, FLUTTER_CHANNEL).setMethodCallHandler { call, result -> if (call.method == "timer") { val args = call.arguments as ArrayList<*> timer(args[0] as Int) } else { result.notImplemented() } } } private var countdownTimer: CountDownTimer? = null var currentMs: Long = 0 private var running = false private val stopReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { Log.d("MainActivity", "Received stop broadcast intent") stop() } } private val addReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { add() } } init { } fun add() { Log.d("MainActivity", "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(context, AlarmService::class.java) context.stopService(intent) } fun stop() { Log.d("MainActivity", "Stop alarm.") countdownTimer?.cancel() running = false val intent = Intent(context, AlarmService::class.java) context.stopService(intent) val manager = getManager() manager.cancel(AlarmService.NOTIFICATION_ID_DONE) manager.cancel(NOTIFICATION_ID_PENDING) } fun timer(milliseconds: Int) { context.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST)) context.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST)) Log.d("MainActivity", "Queue alarm for $milliseconds delay") val manager = getManager() manager.cancel(AlarmService.NOTIFICATION_ID_DONE) val intent = Intent(context, AlarmService::class.java) context.stopService(intent) countdownTimer?.cancel() countdownTimer = getTimer(milliseconds) countdownTimer?.start() running = true } 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.toInt(), current.toInt(), false) .setCategory(NotificationCompat.CATEGORY_PROGRESS).priority = NotificationCompat.PRIORITY_LOW val manager = getManager() Log.d("MainActivity", "current=$current") manager.notify(NOTIFICATION_ID_PENDING, builder.build()) } override fun onFinish() { Log.d("MainActivity", "Finish") context.startForegroundService(Intent(context, AlarmService::class.java)) } } } @SuppressLint("UnspecifiedImmutableFlag") private fun getBuilder(): NotificationCompat.Builder { 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.baseline_hourglass_bottom_24).setContentTitle("Resting") .setContentIntent(pendingContent) .addAction(R.drawable.baseline_hourglass_bottom_24, "Stop", pendingStop) .addAction(R.drawable.baseline_hourglass_bottom_24, "Add 1 min", pendingAdd) .setDeleteIntent(pendingStop) } private fun getManager(): NotificationManager { val notificationManager = context.getSystemService( NotificationManager::class.java ) 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 const val FLUTTER_CHANNEL = "com.massive/android" } }