diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 34ee1fc0..6f17fa7b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,9 +50,26 @@ + + + + + + + + diff --git a/app/src/main/java/com/github/muellerma/coffee/BootReceiver.kt b/app/src/main/java/com/github/muellerma/coffee/BootReceiver.kt index 9fec4016..04f32f1d 100644 --- a/app/src/main/java/com/github/muellerma/coffee/BootReceiver.kt +++ b/app/src/main/java/com/github/muellerma/coffee/BootReceiver.kt @@ -4,6 +4,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build +import com.github.muellerma.coffee.tiles.ToggleTile class BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -12,7 +13,7 @@ class BootReceiver : BroadcastReceiver() { } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - CoffeeTile.requestTileStateUpdate(context) + ToggleTile.requestTileStateUpdate(context) } } } \ No newline at end of file diff --git a/app/src/main/java/com/github/muellerma/coffee/CoffeeApplication.kt b/app/src/main/java/com/github/muellerma/coffee/CoffeeApplication.kt index daf40cc8..88d03ed8 100644 --- a/app/src/main/java/com/github/muellerma/coffee/CoffeeApplication.kt +++ b/app/src/main/java/com/github/muellerma/coffee/CoffeeApplication.kt @@ -3,6 +3,8 @@ package com.github.muellerma.coffee import android.app.Application import android.os.Build import androidx.preference.PreferenceManager +import com.github.muellerma.coffee.tiles.TimeoutTile +import com.github.muellerma.coffee.tiles.ToggleTile import com.google.android.material.color.DynamicColors class CoffeeApplication : Application() { @@ -16,7 +18,8 @@ class CoffeeApplication : Application() { PreferenceManager.setDefaultValues(this, R.xml.pref_main, false) DynamicColors.applyToActivitiesIfAvailable(this) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - observers.add(CoffeeTile.TileServiceStatusObserver(this)) + observers.add(ToggleTile.TileServiceStatusObserver(this)) + observers.add(TimeoutTile.TileServiceStatusObserver(this)) } } diff --git a/app/src/main/java/com/github/muellerma/coffee/CoffeeTile.kt b/app/src/main/java/com/github/muellerma/coffee/CoffeeTile.kt deleted file mode 100644 index d0dfef72..00000000 --- a/app/src/main/java/com/github/muellerma/coffee/CoffeeTile.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.github.muellerma.coffee - -import android.content.ComponentName -import android.content.Context -import android.os.Build -import android.service.quicksettings.Tile.STATE_ACTIVE -import android.service.quicksettings.Tile.STATE_INACTIVE -import android.service.quicksettings.TileService -import android.util.Log -import androidx.annotation.RequiresApi - -@RequiresApi(Build.VERSION_CODES.N) -class CoffeeTile : TileService() { - override fun onClick() { - Log.d(TAG, "onClick()") - ForegroundService.changeState(this, ForegroundService.Companion.STATE.TOGGLE, false) - } - - override fun onStartListening() { - Log.d(TAG, "onStartListening()") - setTileState() - super.onStartListening() - } - - override fun onTileAdded() { - Log.d(TAG, "onTileAdded()") - setTileState() - super.onTileAdded() - } - - private fun setTileState() { - val currentStatus = coffeeApp().lastStatusUpdate - Log.d(TAG, "setTileState(): running = ${currentStatus.toString()}") - val tile = qsTile ?: return - - val (tileState, tileSubtitle) = when (currentStatus) { - is ServiceStatus.Stopped -> Pair(STATE_INACTIVE, "") - is ServiceStatus.Running -> { - if (currentStatus.remainingSeconds == null) { - Pair(STATE_ACTIVE, "") - } else { - Pair(STATE_ACTIVE, currentStatus.remainingSeconds.toFormattedTime()) - } - } - } - - tile.apply { - state = tileState - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - subtitle = tileSubtitle - } - updateTile() - } - } - - @RequiresApi(Build.VERSION_CODES.N) - companion object { - private val TAG = CoffeeTile::class.java.simpleName - - fun requestTileStateUpdate(context: Context) { - Log.d(TAG, "requestTileStateUpdate()") - requestListeningState(context, ComponentName(context, CoffeeTile::class.java)) - } - } - - class TileServiceStatusObserver(private val context: Context) : ServiceStatusObserver { - override fun onServiceStatusUpdate(status: ServiceStatus) { - requestTileStateUpdate(context) - } - - } -} \ No newline at end of file diff --git a/app/src/main/java/com/github/muellerma/coffee/ForegroundService.kt b/app/src/main/java/com/github/muellerma/coffee/ForegroundService.kt index 2a96f446..a7e48783 100644 --- a/app/src/main/java/com/github/muellerma/coffee/ForegroundService.kt +++ b/app/src/main/java/com/github/muellerma/coffee/ForegroundService.kt @@ -23,6 +23,7 @@ class ForegroundService : Service(), ServiceStatusObserver { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d(TAG, "onStartCommand()") + val prefs = Prefs(applicationContext) when (intent?.action) { ACTION_STOP -> { Log.d(TAG, "Received stop action") @@ -31,13 +32,11 @@ class ForegroundService : Service(), ServiceStatusObserver { } ACTION_CHANGE_PREF_TIMEOUT -> { Log.d(TAG, "Change timeout") - Prefs(applicationContext).timeout = - intent.getStringExtra(EXTRA_CHANGE_PREF_VALUE)?.toIntOrNull() ?: 0 + prefs.timeout = prefs.nextTimeout } ACTION_CHANGE_PREF_ALLOW_DIMMING -> { Log.d(TAG, "Change allow dimming") - Prefs(applicationContext).allowDimming = - intent.getBooleanExtra(EXTRA_CHANGE_PREF_VALUE, false) + prefs.allowDimming = !prefs.allowDimming } } @@ -177,23 +176,16 @@ class ForegroundService : Service(), ServiceStatusObserver { return getBaseNotification(title) .setContentText(getString(R.string.tap_to_turn_off)) .setContentIntent(getPendingIntentForService(stopIntent, PendingIntent_Immutable, 0)) - .addAction(getTimeoutAction(prefs)) + .addAction(getTimeoutAction()) .addAction(getDimmingAction(prefs)) .setPublicVersion(getBaseNotification(title).build()) .build() } - private fun getTimeoutAction(prefs: Prefs): NotificationCompat.Action { + private fun getTimeoutAction(): NotificationCompat.Action { Log.d(TAG, "getTimeoutAction()") val intent = Intent(this, ForegroundService::class.java).apply { action = ACTION_CHANGE_PREF_TIMEOUT - - val allTimeouts = applicationContext.resources.getStringArray(R.array.timeout_values) - val currentIndex = allTimeouts.indexOf(prefs.timeout.toString()) - val nextIndex = (currentIndex + 1).mod(allTimeouts.size) - val nextTimeout = allTimeouts[nextIndex] - - putExtra(EXTRA_CHANGE_PREF_VALUE, nextTimeout) } return NotificationCompat.Action( R.drawable.ic_baseline_access_time_24, @@ -205,7 +197,6 @@ class ForegroundService : Service(), ServiceStatusObserver { private fun getDimmingAction(prefs: Prefs): NotificationCompat.Action { val intent = Intent(this, ForegroundService::class.java).apply { action = ACTION_CHANGE_PREF_ALLOW_DIMMING - putExtra(EXTRA_CHANGE_PREF_VALUE, !prefs.allowDimming) } val title = if (prefs.allowDimming) R.string.allow_dimming_disable else R.string.allow_dimming_enable return NotificationCompat.Action( @@ -278,9 +269,8 @@ class ForegroundService : Service(), ServiceStatusObserver { companion object { private val TAG = ForegroundService::class.java.simpleName private const val ACTION_STOP = "stop_action" - private const val ACTION_CHANGE_PREF_TIMEOUT = "change_pref_timeout" + const val ACTION_CHANGE_PREF_TIMEOUT = "change_pref_timeout" private const val ACTION_CHANGE_PREF_ALLOW_DIMMING = "change_pref_dimming" - private const val EXTRA_CHANGE_PREF_VALUE = "change_pref_value" const val NOTIFICATION_ID = 1 const val NOTIFICATION_CHANNEL_ID = "foreground_service" @@ -313,5 +303,7 @@ class ForegroundService : Service(), ServiceStatusObserver { STOP, TOGGLE } + + } } diff --git a/app/src/main/java/com/github/muellerma/coffee/Prefs.kt b/app/src/main/java/com/github/muellerma/coffee/Prefs.kt index 21e4be5b..2106bd48 100644 --- a/app/src/main/java/com/github/muellerma/coffee/Prefs.kt +++ b/app/src/main/java/com/github/muellerma/coffee/Prefs.kt @@ -5,7 +5,7 @@ import android.content.SharedPreferences import androidx.core.content.edit import androidx.preference.PreferenceManager -class Prefs(context: Context) { +class Prefs(private val context: Context) { var sharedPrefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) private set @@ -13,6 +13,20 @@ class Prefs(context: Context) { get() = sharedPrefs.getString("timeout", "0")?.toInt() ?: 0 set(value) = sharedPrefs.edit { putString("timeout", value.toString()) } + val nextTimeout: Int + get() { + val allTimeouts = context.resources.getStringArray(R.array.timeout_values) + val currentIndex = allTimeouts.indexOf(timeout.toString()) + val nextIndex = (currentIndex + 1).mod(allTimeouts.size) + return allTimeouts[nextIndex].toIntOrNull() ?: 0 + } + + val firstTimeout: Int + get() { + val allTimeouts = context.resources.getStringArray(R.array.timeout_values) + return allTimeouts[1].toIntOrNull() ?: 0 + } + var allowDimming: Boolean get() = sharedPrefs.getBoolean("allow_dimming", false) set(value) = sharedPrefs.edit { putBoolean("allow_dimming", value) } diff --git a/app/src/main/java/com/github/muellerma/coffee/tiles/AbstractTile.kt b/app/src/main/java/com/github/muellerma/coffee/tiles/AbstractTile.kt new file mode 100644 index 00000000..5912ce97 --- /dev/null +++ b/app/src/main/java/com/github/muellerma/coffee/tiles/AbstractTile.kt @@ -0,0 +1,56 @@ +package com.github.muellerma.coffee.tiles + +import android.os.Build +import android.service.quicksettings.Tile +import android.service.quicksettings.TileService +import android.util.Log +import androidx.annotation.RequiresApi +import com.github.muellerma.coffee.R +import com.github.muellerma.coffee.ServiceStatus +import com.github.muellerma.coffee.coffeeApp +import com.github.muellerma.coffee.toFormattedTime + +@RequiresApi(Build.VERSION_CODES.N) +abstract class AbstractTile : TileService() { + override fun onStartListening() { + Log.d(TAG, "onStartListening()") + setTileState() + super.onStartListening() + } + + override fun onTileAdded() { + Log.d(TAG, "onTileAdded()") + setTileState() + super.onTileAdded() + } + + private fun setTileState() { + val currentStatus = coffeeApp().lastStatusUpdate + Log.d(TAG, "setTileState(): running = $currentStatus") + val tile = qsTile ?: return + + val (tileState, tileSubtitle) = when (currentStatus) { + is ServiceStatus.Stopped -> Pair(Tile.STATE_INACTIVE, "") + is ServiceStatus.Running -> { + if (currentStatus.remainingSeconds == null) { + Pair(Tile.STATE_ACTIVE, "") + } else { + Pair(Tile.STATE_ACTIVE, currentStatus.remainingSeconds.toFormattedTime()) + } + } + } + + tile.apply { + state = tileState + label = getString(R.string.app_name) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + subtitle = tileSubtitle + } + updateTile() + } + } + + companion object { + private val TAG = AbstractTile::class.java.simpleName + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/muellerma/coffee/tiles/TimeoutTile.kt b/app/src/main/java/com/github/muellerma/coffee/tiles/TimeoutTile.kt new file mode 100644 index 00000000..74273baa --- /dev/null +++ b/app/src/main/java/com/github/muellerma/coffee/tiles/TimeoutTile.kt @@ -0,0 +1,46 @@ +package com.github.muellerma.coffee.tiles + +import android.content.ComponentName +import android.content.Context +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.github.muellerma.coffee.* + +@RequiresApi(Build.VERSION_CODES.N) +class TimeoutTile : AbstractTile() { + override fun onClick() { + Log.d(TAG, "onClick()") + val prefs = Prefs(applicationContext) + when { + coffeeApp().lastStatusUpdate is ServiceStatus.Stopped -> { + prefs.timeout = prefs.firstTimeout + ForegroundService.changeState(this, ForegroundService.Companion.STATE.START, false) + } + prefs.nextTimeout == 0 -> { + prefs.timeout = 0 + ForegroundService.changeState(this, ForegroundService.Companion.STATE.STOP, false) + } + else -> { + prefs.timeout = prefs.nextTimeout + } + + } + } + + @RequiresApi(Build.VERSION_CODES.N) + companion object { + private val TAG = TimeoutTile::class.java.simpleName + + fun requestTileStateUpdate(context: Context) { + Log.d(TAG, "requestTileStateUpdate()") + requestListeningState(context, ComponentName(context, TimeoutTile::class.java)) + } + } + + class TileServiceStatusObserver(private val context: Context) : ServiceStatusObserver { + override fun onServiceStatusUpdate(status: ServiceStatus) { + requestTileStateUpdate(context) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/muellerma/coffee/tiles/ToggleTile.kt b/app/src/main/java/com/github/muellerma/coffee/tiles/ToggleTile.kt new file mode 100644 index 00000000..4af7943b --- /dev/null +++ b/app/src/main/java/com/github/muellerma/coffee/tiles/ToggleTile.kt @@ -0,0 +1,33 @@ +package com.github.muellerma.coffee.tiles + +import android.content.ComponentName +import android.content.Context +import android.os.Build +import android.util.Log +import androidx.annotation.RequiresApi +import com.github.muellerma.coffee.* + +@RequiresApi(Build.VERSION_CODES.N) +class ToggleTile : AbstractTile() { + override fun onClick() { + Log.d(TAG, "onClick()") + ForegroundService.changeState(this, ForegroundService.Companion.STATE.TOGGLE, false) + } + + @RequiresApi(Build.VERSION_CODES.N) + companion object { + private val TAG = ToggleTile::class.java.simpleName + + fun requestTileStateUpdate(context: Context) { + Log.d(TAG, "requestTileStateUpdate()") + requestListeningState(context, ComponentName(context, ToggleTile::class.java)) + } + } + + class TileServiceStatusObserver(private val context: Context) : ServiceStatusObserver { + override fun onServiceStatusUpdate(status: ServiceStatus) { + requestTileStateUpdate(context) + } + + } +} \ No newline at end of file