feat(android): add foreground service, Quick Settings tile, proguard rules
This commit is contained in:
parent
449b2dc514
commit
4570c076ec
21
android/app/proguard-rules.pro
vendored
Normal file
21
android/app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# ChronoMind ProGuard Rules
|
||||
|
||||
# Keep Hilt generated classes
|
||||
-keep class dagger.hilt.** { *; }
|
||||
-keep class javax.inject.** { *; }
|
||||
-keep class * extends dagger.hilt.android.internal.managers.ViewComponentManager$FragmentContextWrapper { *; }
|
||||
|
||||
# Keep Kotlin serialization
|
||||
-keepattributes *Annotation*, InnerClasses
|
||||
-dontnote kotlinx.serialization.AnnotationsKt
|
||||
-keepclassmembers class kotlinx.serialization.json.** { *** Companion; }
|
||||
-keepclasseswithmembers class kotlinx.serialization.json.** { kotlinx.serialization.KSerializer serializer(...); }
|
||||
-keep,includedescriptorclasses class com.chronomind.app.**$$serializer { *; }
|
||||
-keepclassmembers class com.chronomind.app.** { *** Companion; }
|
||||
-keepclasseswithmembers class com.chronomind.app.** { kotlinx.serialization.KSerializer serializer(...); }
|
||||
|
||||
# Keep Glance widget receivers
|
||||
-keep class com.chronomind.app.widget.** { *; }
|
||||
|
||||
# Keep notification receivers
|
||||
-keep class com.chronomind.app.notifications.** { *; }
|
||||
@ -69,6 +69,24 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Foreground Service for active timer display -->
|
||||
<service
|
||||
android:name=".service.TimerForegroundService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse" />
|
||||
|
||||
<!-- Quick Settings Tile -->
|
||||
<service
|
||||
android:name=".service.QuickTimerTileService"
|
||||
android:exported="true"
|
||||
android:icon="@android:drawable/ic_lock_idle_alarm"
|
||||
android:label="Quick Timer"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Widgets -->
|
||||
<receiver
|
||||
android:name=".widget.TimerWidgetSmallReceiver"
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.chronomind.app.service
|
||||
|
||||
import android.content.Intent
|
||||
import android.service.quicksettings.TileService
|
||||
import com.chronomind.app.MainActivity
|
||||
|
||||
class QuickTimerTileService : TileService() {
|
||||
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
// Open app to create timer screen
|
||||
val intent = Intent(this, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
putExtra("action", "quick_timer")
|
||||
}
|
||||
startActivityAndCollapse(intent)
|
||||
}
|
||||
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
qsTile?.let { tile ->
|
||||
tile.label = "Quick Timer"
|
||||
tile.subtitle = "Create timer"
|
||||
tile.updateTile()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package com.chronomind.app.service
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.chronomind.app.MainActivity
|
||||
|
||||
class TimerForegroundService : Service() {
|
||||
|
||||
companion object {
|
||||
const val CHANNEL_ID = "chronomind_foreground"
|
||||
const val NOTIFICATION_ID = 9999
|
||||
const val EXTRA_TIMER_LABEL = "timer_label"
|
||||
const val EXTRA_TIMER_REMAINING = "timer_remaining"
|
||||
const val ACTION_STOP = "com.chronomind.STOP_FOREGROUND"
|
||||
|
||||
fun start(context: Context, label: String, remainingFormatted: String) {
|
||||
val intent = Intent(context, TimerForegroundService::class.java).apply {
|
||||
putExtra(EXTRA_TIMER_LABEL, label)
|
||||
putExtra(EXTRA_TIMER_REMAINING, remainingFormatted)
|
||||
}
|
||||
context.startForegroundService(intent)
|
||||
}
|
||||
|
||||
fun stop(context: Context) {
|
||||
context.stopService(Intent(context, TimerForegroundService::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
createChannel()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent?.action == ACTION_STOP) {
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
val label = intent?.getStringExtra(EXTRA_TIMER_LABEL) ?: "Timer"
|
||||
val remaining = intent?.getStringExtra(EXTRA_TIMER_REMAINING) ?: "--:--"
|
||||
|
||||
val notification = buildNotification(label, remaining)
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
private fun createChannel() {
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"Active Timer",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
description = "Shows countdown for the active timer"
|
||||
setShowBadge(false)
|
||||
}
|
||||
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
manager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
private fun buildNotification(label: String, remaining: String): Notification {
|
||||
val openIntent = PendingIntent.getActivity(
|
||||
this, 0,
|
||||
Intent(this, MainActivity::class.java),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val stopIntent = PendingIntent.getService(
|
||||
this, 1,
|
||||
Intent(this, TimerForegroundService::class.java).apply { action = ACTION_STOP },
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setSmallIcon(android.R.drawable.ic_lock_idle_alarm)
|
||||
.setContentTitle(label)
|
||||
.setContentText(remaining)
|
||||
.setOngoing(true)
|
||||
.setSilent(true)
|
||||
.setContentIntent(openIntent)
|
||||
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Stop", stopIntent)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user