Skip to content

Commit 98eb4ca

Browse files
committed
Added device temperature tile
1 parent b8a4a32 commit 98eb4ca

File tree

11 files changed

+243
-12
lines changed

11 files changed

+243
-12
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,5 +312,21 @@
312312
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
313313
android:value="true" />
314314
</service>
315+
316+
<!--temperature quick settings tile service-->
317+
318+
<service
319+
android:name=".tiles.temperature.TemperatureTileService"
320+
android:exported="true"
321+
android:icon="@drawable/ic_temperature_off"
322+
android:label="@string/temperature_tile"
323+
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
324+
<intent-filter>
325+
<action android:name="android.service.quicksettings.action.QS_TILE" />
326+
</intent-filter>
327+
<meta-data
328+
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
329+
android:value="true" />
330+
</service>
315331
</application>
316332
</manifest>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.wstxda.toolkit.manager.temperature
2+
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.content.IntentFilter
6+
import android.os.BatteryManager
7+
import kotlinx.coroutines.CoroutineScope
8+
import kotlinx.coroutines.Dispatchers
9+
import kotlinx.coroutines.Job
10+
import kotlinx.coroutines.SupervisorJob
11+
import kotlinx.coroutines.delay
12+
import kotlinx.coroutines.flow.MutableStateFlow
13+
import kotlinx.coroutines.flow.asStateFlow
14+
import kotlinx.coroutines.isActive
15+
import kotlinx.coroutines.launch
16+
17+
class TemperatureManager(context: Context) {
18+
19+
companion object {
20+
private const val REFRESH_RATE_MS = 1000L
21+
}
22+
23+
private val appContext = context.applicationContext
24+
private val managerScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
25+
26+
private val _isActive = MutableStateFlow(false)
27+
val isActive = _isActive.asStateFlow()
28+
29+
private val _temperature = MutableStateFlow(0f)
30+
val temperature = _temperature.asStateFlow()
31+
32+
private var pollingJob: Job? = null
33+
private var isPanelOpen = false
34+
35+
fun toggle() {
36+
_isActive.value = !_isActive.value
37+
38+
if (_isActive.value) {
39+
updateData()
40+
}
41+
42+
updatePollingState()
43+
}
44+
45+
fun setListening(listening: Boolean) {
46+
isPanelOpen = listening
47+
updatePollingState()
48+
}
49+
50+
private fun updatePollingState() {
51+
val shouldPoll = _isActive.value && isPanelOpen
52+
53+
if (shouldPoll) {
54+
if (pollingJob?.isActive != true) startPolling()
55+
} else {
56+
stopPolling()
57+
}
58+
}
59+
60+
private fun startPolling() {
61+
pollingJob?.cancel()
62+
pollingJob = managerScope.launch {
63+
updateData()
64+
while (isActive) {
65+
delay(REFRESH_RATE_MS)
66+
updateData()
67+
}
68+
}
69+
}
70+
71+
private fun stopPolling() {
72+
pollingJob?.cancel()
73+
pollingJob = null
74+
}
75+
76+
private fun updateData() {
77+
val intent = appContext.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
78+
val tempInt = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0
79+
_temperature.value = tempInt / 10f
80+
}
81+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.wstxda.toolkit.manager.temperature
2+
3+
import android.content.Context
4+
5+
object TemperatureModule {
6+
@Volatile
7+
private var instance: TemperatureManager? = null
8+
9+
fun getInstance(context: Context): TemperatureManager {
10+
return instance ?: synchronized(this) {
11+
instance ?: TemperatureManager(context.applicationContext).also { instance = it }
12+
}
13+
}
14+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.wstxda.toolkit.tiles.temperature
2+
3+
import android.service.quicksettings.Tile
4+
import com.wstxda.toolkit.base.BaseTileService
5+
import com.wstxda.toolkit.manager.temperature.TemperatureManager
6+
import com.wstxda.toolkit.manager.temperature.TemperatureModule
7+
import com.wstxda.toolkit.ui.icon.TemperatureIconProvider
8+
import com.wstxda.toolkit.ui.label.TemperatureLabelProvider
9+
import kotlinx.coroutines.flow.Flow
10+
11+
class TemperatureTileService : BaseTileService() {
12+
13+
private val temperatureManager: TemperatureManager by lazy { TemperatureModule.getInstance(applicationContext) }
14+
private val temperatureLabelProvider by lazy { TemperatureLabelProvider(applicationContext) }
15+
private val temperatureIconProvider by lazy { TemperatureIconProvider(applicationContext) }
16+
17+
override fun onStartListening() {
18+
super.onStartListening()
19+
temperatureManager.setListening(true)
20+
}
21+
22+
override fun onStopListening() {
23+
super.onStopListening()
24+
temperatureManager.setListening(false)
25+
}
26+
27+
override fun onClick() {
28+
temperatureManager.toggle()
29+
}
30+
31+
override fun flowsToCollect(): List<Flow<*>> {
32+
return listOf(
33+
temperatureManager.isActive, temperatureManager.temperature
34+
)
35+
}
36+
37+
override fun updateTile() {
38+
val isActive = temperatureManager.isActive.value
39+
val temp = temperatureManager.temperature.value
40+
41+
setTileState(
42+
state = if (isActive) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE,
43+
label = temperatureLabelProvider.getLabel(isActive, temp),
44+
subtitle = temperatureLabelProvider.getSubtitle(isActive),
45+
icon = temperatureIconProvider.getIcon(isActive)
46+
)
47+
}
48+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.wstxda.toolkit.ui.icon
2+
3+
import android.content.Context
4+
import android.graphics.drawable.Icon
5+
import com.wstxda.toolkit.R
6+
7+
class TemperatureIconProvider(private val context: Context) {
8+
9+
fun getIcon(isActive: Boolean): Icon {
10+
val iconRes = if (isActive) {
11+
R.drawable.ic_temperature_on
12+
} else {
13+
R.drawable.ic_temperature_off
14+
}
15+
return Icon.createWithResource(context, iconRes)
16+
}
17+
}

app/src/main/java/com/wstxda/toolkit/ui/label/MemoryLabelProvider.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ class MemoryLabelProvider(private val context: Context) {
1111
MemoryState.DISABLED -> context.getString(R.string.memory_tile)
1212

1313
MemoryState.RAM -> {
14-
if (detail.isBlank()) return context.getString(R.string.memory_empty)
15-
context.getString(R.string.memory_ram, detail)
14+
if (detail.isBlank()) return context.getString(R.string.memory_tile_empty)
15+
context.getString(R.string.memory_tile_ram, detail)
1616
}
1717

1818
MemoryState.STORAGE -> {
19-
if (detail.isBlank()) return context.getString(R.string.memory_empty)
20-
context.getString(R.string.memory_storage, detail)
19+
if (detail.isBlank()) return context.getString(R.string.memory_tile_empty)
20+
context.getString(R.string.memory_tile_storage, detail)
2121
}
2222
}
2323
}
@@ -28,7 +28,7 @@ class MemoryLabelProvider(private val context: Context) {
2828

2929
MemoryState.RAM, MemoryState.STORAGE -> {
3030
if (used.isBlank() || total.isBlank()) return null
31-
context.getString(R.string.memory_format, used, total)
31+
context.getString(R.string.memory_tile_format, used, total)
3232
}
3333
}
3434
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.wstxda.toolkit.ui.label
2+
3+
import android.content.Context
4+
import com.wstxda.toolkit.R
5+
import java.util.Locale
6+
7+
class TemperatureLabelProvider(private val context: Context) {
8+
9+
fun getLabel(isActive: Boolean, temp: Float): CharSequence {
10+
return if (isActive) {
11+
String.format(Locale.US, context.getString(R.string.temperature_tile_format), temp)
12+
} else {
13+
context.getString(R.string.temperature_tile)
14+
}
15+
}
16+
17+
fun getSubtitle(isActive: Boolean): CharSequence? {
18+
return if (isActive) {
19+
context.getString(R.string.temperature_tile_source)
20+
} else {
21+
context.getString(R.string.tile_off)
22+
}
23+
}
24+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="@android:color/white"
8+
android:pathData="M2.7 3.12c0.4-0.39 1.03-0.39 1.42 0L21.1 20.1c0.4 0.4 0.4 1.03 0 1.42-0.39 0.39-1.02 0.39-1.41 0l-2.92-2.93c-0.24 0.73-0.64 1.38-1.22 1.96C14.56 21.5 13.38 22 12 22s-2.56-0.49-3.54-1.46C7.5 19.56 7 18.38 7 17c0-0.8 0.17-1.55 0.52-2.24C7.87 14.07 8.37 13.48 9 13v-2.17l-6.3-6.3c-0.38-0.39-0.38-1.02 0-1.4ZM12 2c0.83 0 1.54 0.3 2.13 0.88C14.7 3.46 15 4.17 15 5v6.17L12.83 9H13V7h-1V6h1V5c0-0.28-0.1-0.52-0.29-0.71C12.52 4.09 12.28 4 12 4c-0.28 0-0.52 0.1-0.71 0.29C11.09 4.48 11 4.72 11 5v2.17l-2-2V5c0-0.83 0.3-1.54 0.88-2.12C10.46 2.29 11.17 2 12 2Z" />
9+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960">
6+
<path
7+
android:fillColor="@android:color/white"
8+
android:pathData="M480,880Q397,880 338.5,821.5Q280,763 280,680Q280,632 301,590.5Q322,549 360,520L360,200Q360,150 395,115Q430,80 480,80Q530,80 565,115Q600,150 600,200L600,520Q638,549 659,590.5Q680,632 680,680Q680,763 621.5,821.5Q563,880 480,880ZM440,440L520,440L520,400L480,400L480,360L520,360L520,280L480,280L480,240L520,240L520,200Q520,183 508.5,171.5Q497,160 480,160Q463,160 451.5,171.5Q440,183 440,200L440,440Z" />
9+
</vector>

app/src/main/res/values-pt-rBR/strings.xml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,13 @@
111111

112112
<string name="memory_tile">Memória</string>
113113
<!--tile label-->
114-
<string name="memory_format">%1$s de %2$s</string>
115-
<string name="memory_ram">%s em uso</string>
116-
<string name="memory_storage">%s livres</string>
114+
<string name="memory_tile_format">%1$s de %2$s</string>
115+
<string name="memory_tile_ram">%s em uso</string>
116+
<string name="memory_tile_storage">%s livres</string>
117+
118+
<!--device temperature tile-->
119+
120+
<string name="temperature_tile">Temperatura</string>
121+
<!--tile label-->
122+
<string name="temperature_tile_source">Bateria</string>
117123
</resources>

0 commit comments

Comments
 (0)