@@ -17,19 +17,28 @@ import android.content.Intent
1717import android.content.pm.PackageManager
1818import android.service.quicksettings.Tile
1919import android.service.quicksettings.TileService
20+ import android.util.Log
2021import androidx.core.content.ContextCompat
2122import dev.lexip.hecate.Application
2223import dev.lexip.hecate.analytics.AnalyticsLogger
2324import dev.lexip.hecate.data.UserPreferencesRepository
25+ import dev.lexip.hecate.util.DefaultDispatcherProvider
26+ import dev.lexip.hecate.util.DispatcherProvider
2427import kotlinx.coroutines.CoroutineScope
25- import kotlinx.coroutines.Dispatchers
28+ import kotlinx.coroutines.Job
2629import kotlinx.coroutines.SupervisorJob
2730import kotlinx.coroutines.launch
2831
29- private val serviceScope = CoroutineScope (SupervisorJob () + Dispatchers .Main )
32+ private val serviceScope = CoroutineScope (SupervisorJob () + DefaultDispatcherProvider .main)
33+ private const val TAG = " QuickSettingsTileService"
3034
3135class QuickSettingsTileService : TileService () {
3236
37+ private val dispatchers: DispatcherProvider = DefaultDispatcherProvider
38+
39+ private var listeningJob: Job ? = null
40+ private var toggleJob: Job ? = null
41+
3342 private fun hasWriteSecureSettingsPermission (): Boolean {
3443 return packageManager.checkPermission(
3544 Manifest .permission.WRITE_SECURE_SETTINGS ,
@@ -46,54 +55,66 @@ class QuickSettingsTileService : TileService() {
4655 super .onStartListening()
4756 val tile = qsTile ? : return
4857
49- // No permission => tile unavailable
5058 if (! hasWriteSecureSettingsPermission()) {
5159 tile.state = Tile .STATE_UNAVAILABLE
5260 tile.updateTile()
5361 return
5462 }
5563
56- // Load user preference and set tile state
57- val dataStore = (applicationContext as Application ).userPreferencesDataStore
58- val repo = UserPreferencesRepository (dataStore)
59-
60- serviceScope.launch {
64+ listeningJob?.cancel()
65+ listeningJob = serviceScope.launch {
66+ // Load user preference and set tile state
67+ val dataStore = (applicationContext as Application ).userPreferencesDataStore
68+ val repo = UserPreferencesRepository (dataStore)
6169 val prefs = repo.fetchInitialPreferences()
6270 tile.state = if (prefs.adaptiveThemeEnabled) Tile .STATE_ACTIVE else Tile .STATE_INACTIVE
6371 tile.updateTile()
6472 }
6573 }
6674
75+ override fun onStopListening () {
76+ super .onStopListening()
77+ listeningJob?.cancel()
78+ }
79+
6780 override fun onClick () {
6881 super .onClick()
6982 val tile = qsTile ? : return
7083
71- // No permission => tile unavailable
72- if (! hasWriteSecureSettingsPermission()) {
73- tile.state = Tile .STATE_UNAVAILABLE
74- tile.updateTile()
75- return
76- }
77-
78- val dataStore = (applicationContext as Application ).userPreferencesDataStore
79- val repo = UserPreferencesRepository (dataStore)
84+ listeningJob?.cancel()
85+ toggleJob?.cancel()
8086
8187 // Toggle adaptive theme
82- serviceScope.launch {
83- val prefs = repo.fetchInitialPreferences()
84- val newEnabled = ! prefs.adaptiveThemeEnabled
88+ val isEnabled = tile.state == Tile .STATE_ACTIVE
89+ val newEnabled = ! isEnabled
8590
86- repo.updateAdaptiveThemeEnabled(newEnabled)
91+ // Update tile UI immediately
92+ tile.state = if (newEnabled) Tile .STATE_ACTIVE else Tile .STATE_INACTIVE
93+ tile.updateTile()
94+
95+ toggleJob = serviceScope.launch(dispatchers.io) {
96+ val dataStore = (applicationContext as Application ).userPreferencesDataStore
97+ val repo = UserPreferencesRepository (dataStore)
8798
8899 // Start/stop the service
89100 val intent = Intent (applicationContext, BroadcastReceiverService ::class .java)
90101 if (newEnabled) {
91- repo.ensureAdaptiveThemeThresholdDefault()
92- ContextCompat .startForegroundService(applicationContext, intent)
93- AnalyticsLogger .logServiceEnabled(
94- applicationContext,
95- source = " quick_settings_tile"
96- )
102+ intent.putExtra(EXTRA_ENABLE_MONITORING , true )
103+ try {
104+ ContextCompat .startForegroundService(applicationContext, intent)
105+ AnalyticsLogger .logServiceEnabled(
106+ applicationContext,
107+ source = " quick_settings_tile"
108+ )
109+ } catch (e: Exception ) {
110+ Log .e(TAG , " Failed to start service" , e)
111+ // Revert UI if service start fails
112+ launch(dispatchers.main) {
113+ tile.state = Tile .STATE_INACTIVE
114+ tile.updateTile()
115+ }
116+ return @launch
117+ }
97118 } else {
98119 applicationContext.stopService(intent)
99120 AnalyticsLogger .logServiceDisabled(
@@ -102,10 +123,17 @@ class QuickSettingsTileService : TileService() {
102123 )
103124 }
104125
105- // Update tile UI
106- tile.state = if (newEnabled) Tile .STATE_ACTIVE else Tile .STATE_INACTIVE
107- tile.updateTile()
126+ if (newEnabled) {
127+ repo.ensureAdaptiveThemeThresholdDefault()
128+ }
129+ repo.updateAdaptiveThemeEnabled(newEnabled)
108130 }
109131 }
110132
133+ override fun onDestroy () {
134+ super .onDestroy()
135+ listeningJob?.cancel()
136+ toggleJob?.cancel()
137+ }
138+
111139}
0 commit comments