diff --git a/app/src/main/java/com/example/helios_alarm_clock/receiver/AlarmReceiver.kt b/app/src/main/java/com/example/helios_alarm_clock/receiver/AlarmReceiver.kt index 7b866c4..1dd8553 100644 --- a/app/src/main/java/com/example/helios_alarm_clock/receiver/AlarmReceiver.kt +++ b/app/src/main/java/com/example/helios_alarm_clock/receiver/AlarmReceiver.kt @@ -3,8 +3,7 @@ package com.example.helios_alarm_clock.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.os.PowerManager -import com.example.helios_alarm_clock.ui.AlarmActivity +import com.example.helios_alarm_clock.service.AlarmRingService class AlarmReceiver : BroadcastReceiver() { @@ -12,23 +11,9 @@ class AlarmReceiver : BroadcastReceiver() { val alarmId = intent.getStringExtra(EXTRA_ALARM_ID) ?: return val label = intent.getStringExtra(EXTRA_ALARM_LABEL) ?: "Alarm" - // Wake lock to keep CPU alive while we launch the activity - val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager - val wl = pm.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, - "helios::alarm_receiver" - ) - wl.acquire(10_000L) - - // Launch AlarmActivity directly — no notification - val activityIntent = Intent(context, AlarmActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_NEW_TASK or - Intent.FLAG_ACTIVITY_CLEAR_TOP or - Intent.FLAG_ACTIVITY_NO_USER_ACTION - putExtra(EXTRA_ALARM_ID, alarmId) - putExtra(EXTRA_ALARM_LABEL, label) - } - context.startActivity(activityIntent) + // Start foreground service with full-screen intent notification. + // Direct startActivity() from a BroadcastReceiver is blocked on Android 10+. + AlarmRingService.start(context, alarmId, label) } companion object { diff --git a/app/src/main/java/com/example/helios_alarm_clock/service/AlarmRingService.kt b/app/src/main/java/com/example/helios_alarm_clock/service/AlarmRingService.kt index 7a3b190..8c4bce4 100644 --- a/app/src/main/java/com/example/helios_alarm_clock/service/AlarmRingService.kt +++ b/app/src/main/java/com/example/helios_alarm_clock/service/AlarmRingService.kt @@ -9,8 +9,6 @@ import android.media.AudioAttributes import android.media.MediaPlayer import android.media.RingtoneManager import android.os.IBinder -import android.os.VibrationEffect -import android.os.Vibrator import android.util.Log import androidx.core.app.NotificationCompat import com.example.helios_alarm_clock.HeliosApp @@ -32,7 +30,6 @@ class AlarmRingService : Service() { @Inject lateinit var alarmDao: AlarmDao private var mediaPlayer: MediaPlayer? = null - private var vibrator: Vibrator? = null private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -57,7 +54,6 @@ class AlarmRingService : Service() { } startSound() - startVibration() // Delete the fired alarm from the database if (alarmId.isNotEmpty()) { @@ -86,8 +82,6 @@ class AlarmRingService : Service() { } catch (_: Exception) {} } mediaPlayer = null - vibrator?.cancel() - vibrator = null scope.cancel() super.onDestroy() } @@ -116,16 +110,6 @@ class AlarmRingService : Service() { } } - private fun startVibration() { - try { - vibrator = getSystemService(Vibrator::class.java) - val pattern = longArrayOf(0, 800, 400, 800, 400) - vibrator?.vibrate(VibrationEffect.createWaveform(pattern, 0)) - } catch (e: Exception) { - Log.e(TAG, "Failed to start vibration", e) - } - } - private fun buildNotification(alarmId: String, label: String): android.app.Notification { val fullScreenIntent = Intent(this, AlarmActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP diff --git a/app/src/main/java/com/example/helios_alarm_clock/ui/AlarmActivity.kt b/app/src/main/java/com/example/helios_alarm_clock/ui/AlarmActivity.kt index 374e231..e56ac63 100644 --- a/app/src/main/java/com/example/helios_alarm_clock/ui/AlarmActivity.kt +++ b/app/src/main/java/com/example/helios_alarm_clock/ui/AlarmActivity.kt @@ -1,11 +1,6 @@ package com.example.helios_alarm_clock.ui -import android.media.AudioAttributes -import android.media.MediaPlayer -import android.media.RingtoneManager import android.os.Bundle -import android.os.VibrationEffect -import android.os.Vibrator import android.util.Log import android.view.WindowManager import androidx.activity.ComponentActivity @@ -30,6 +25,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.helios_alarm_clock.data.AlarmDao +import com.example.helios_alarm_clock.service.AlarmRingService import com.example.helios_alarm_clock.ui.theme.HeliosTheme import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope @@ -45,8 +41,6 @@ class AlarmActivity : ComponentActivity() { @Inject lateinit var alarmDao: AlarmDao - private var mediaPlayer: MediaPlayer? = null - private var vibrator: Vibrator? = null private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) override fun onCreate(savedInstanceState: Bundle?) { @@ -60,8 +54,7 @@ class AlarmActivity : ComponentActivity() { val alarmId = intent.getStringExtra(EXTRA_ALARM_ID) ?: "" val label = intent.getStringExtra(EXTRA_ALARM_LABEL) ?: "Alarm" - startSound() - startVibration() + // Sound + vibration are handled by AlarmRingService // Delete the fired alarm from the database if (alarmId.isNotEmpty()) { @@ -91,47 +84,7 @@ class AlarmActivity : ComponentActivity() { } private fun stopAlarm() { - mediaPlayer?.let { - try { - if (it.isPlaying) it.stop() - it.release() - } catch (_: Exception) {} - } - mediaPlayer = null - vibrator?.cancel() - vibrator = null - } - - private fun startSound() { - try { - val alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM) - ?: RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) - ?: return - mediaPlayer = MediaPlayer().apply { - setAudioAttributes( - AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_ALARM) - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .build() - ) - setDataSource(this@AlarmActivity, alarmUri) - isLooping = true - prepare() - start() - } - } catch (e: Exception) { - Log.e(TAG, "Failed to start alarm sound", e) - } - } - - private fun startVibration() { - try { - vibrator = getSystemService(Vibrator::class.java) - val pattern = longArrayOf(0, 800, 400, 800, 400) - vibrator?.vibrate(VibrationEffect.createWaveform(pattern, 0)) - } catch (e: Exception) { - Log.e(TAG, "Failed to start vibration", e) - } + AlarmRingService.stop(this) } companion object {