Skip to content

Commit eac756f

Browse files
committed
Update to support SDK 36
1 parent 9da748e commit eac756f

File tree

8 files changed

+53
-23
lines changed

8 files changed

+53
-23
lines changed

.github/workflows/cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99
build:
1010
runs-on: ubuntu-latest
11-
container: alvrme/alpine-android:android-34-jdk17
11+
container: alvrme/alpine-android:android-36-jdk21
1212
env:
1313
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
1414
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99
build:
1010
runs-on: ubuntu-latest
11-
container: alvrme/alpine-android:android-34-jdk17
11+
container: alvrme/alpine-android:android-36-jdk21
1212
env:
1313
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
1414
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}

app/build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ plugins {
55

66
android {
77
namespace = "de.klimek.compass"
8-
compileSdk = 34
8+
compileSdk = 36
99

1010
signingConfigs {
1111
create("release") {
@@ -19,7 +19,7 @@ android {
1919
defaultConfig {
2020
applicationId = "de.klimek.compass"
2121
minSdk = 26
22-
targetSdk = 34
22+
targetSdk = 36
2323
versionCode = 8
2424
versionName = "1.4.1"
2525
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
@@ -34,7 +34,7 @@ android {
3434
}
3535

3636
kotlin {
37-
jvmToolchain(17)
37+
jvmToolchain(21)
3838
}
3939

4040
dependenciesInfo {
@@ -45,5 +45,5 @@ android {
4545
}
4646

4747
dependencies {
48-
implementation("androidx.appcompat:appcompat:1.7.0")
48+
implementation("androidx.appcompat:appcompat:1.7.1")
4949
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package de.klimek.compass
2+
3+
import android.app.Notification
4+
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
5+
import android.os.Build.VERSION
6+
import android.os.Build.VERSION_CODES
7+
import androidx.core.app.ServiceCompat
8+
9+
fun TileService.startForegroundCompat(notificationId: Int, notification: Notification) {
10+
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
11+
ServiceCompat.startForeground(this, notificationId, notification, FOREGROUND_SERVICE_TYPE_MANIFEST)
12+
} else {
13+
startForeground(notificationId, notification)
14+
}
15+
}

app/src/main/java/de/klimek/compass/TileService.kt

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package de.klimek.compass
22

3+
import android.app.ForegroundServiceStartNotAllowedException
34
import android.app.NotificationManager
4-
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
55
import android.graphics.drawable.Icon
66
import android.hardware.Sensor
77
import android.hardware.SensorEvent
88
import android.hardware.SensorEventListener
99
import android.hardware.SensorManager
1010
import android.hardware.display.DisplayManager
11-
import android.os.Build
11+
import android.os.Build.VERSION
12+
import android.os.Build.VERSION_CODES
1213
import android.service.quicksettings.Tile
1314
import android.util.Log
1415
import android.view.Display
@@ -21,9 +22,16 @@ import de.klimek.compass.tile.update
2122
private const val TAG = "TileService"
2223
private const val SENSOR_DELAY = SensorManager.SENSOR_DELAY_UI
2324

25+
// Note: Sensor data is only accessible in foreground, so we need to start this service as a foreground service.
26+
// This is done either on onCreate, onClick or onStartListening, depending on Android version.
27+
2428
// On Android 14 foreground service can not be started in onClick or onStartListening due to a bug:
2529
// https://issuetracker.google.com/issues/299506164
26-
private val START_FOREGROUND_IMMEDIATELY = Build.VERSION.SDK_INT == Build.VERSION_CODES.UPSIDE_DOWN_CAKE
30+
private val START_FOREGROUND_IMMEDIATELY = VERSION.SDK_INT == VERSION_CODES.UPSIDE_DOWN_CAKE
31+
32+
// On Android 15+ foreground service can only be started after user interaction (onClick or sometimes onStartListening):
33+
// https://developer.android.com/about/versions/15/behavior-changes-15#fgs-hardening
34+
private val CAN_ONLY_START_FOREGROUND_ON_CLICK = VERSION.SDK_INT >= VERSION_CODES.VANILLA_ICE_CREAM
2735

2836
class TileService : android.service.quicksettings.TileService(), SensorEventListener {
2937

@@ -57,7 +65,7 @@ class TileService : android.service.quicksettings.TileService(), SensorEventList
5765
iconFactory = IconFactory(applicationContext, R.drawable.ic_qs_compass_on)
5866
notificationManager?.createNotificationChannel(channel())
5967
if (START_FOREGROUND_IMMEDIATELY) {
60-
startForeground(NOTIFICATION_ID, notification(), FOREGROUND_SERVICE_TYPE_MANIFEST)
68+
startForegroundCompat(NOTIFICATION_ID, notification())
6169
}
6270
}
6371

@@ -68,12 +76,14 @@ class TileService : android.service.quicksettings.TileService(), SensorEventList
6876
}
6977

7078
override fun onStartListening() {
79+
Log.i(TAG, "Start listening")
7180
when (qsTile?.state) {
7281
Tile.STATE_ACTIVE -> startCompass()
7382
}
7483
}
7584

7685
override fun onStopListening() {
86+
Log.i(TAG, "Stop listening")
7787
when (qsTile?.state) {
7888
Tile.STATE_ACTIVE -> stopCompass()
7989
}
@@ -109,12 +119,20 @@ class TileService : android.service.quicksettings.TileService(), SensorEventList
109119
}
110120

111121
private fun startCompass() {
112-
Log.i(TAG, "Start")
113-
// Sensor data is only accessible in foreground, so we need to start this service as a foreground service.
114-
if (!START_FOREGROUND_IMMEDIATELY) {
115-
startForeground(NOTIFICATION_ID, notification())
122+
try {
123+
Log.i(TAG, "Start")
124+
if (!START_FOREGROUND_IMMEDIATELY) {
125+
startForegroundCompat(NOTIFICATION_ID, notification())
126+
}
127+
sensorManager?.registerListener(this, sensor, SENSOR_DELAY)
128+
} catch (e: Exception) {
129+
if (CAN_ONLY_START_FOREGROUND_ON_CLICK && e is ForegroundServiceStartNotAllowedException) {
130+
Log.w(TAG, "Foreground service start not allowed", e)
131+
setInactive()
132+
} else {
133+
throw e // Crash on other exceptions
134+
}
116135
}
117-
sensorManager?.registerListener(this, sensor, SENSOR_DELAY)
118136
}
119137

120138
private fun stopCompass() {

app/src/main/java/de/klimek/compass/tile/IconFactory.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
package de.klimek.compass.tile
22

33
import android.content.Context
4-
import android.graphics.Bitmap
54
import android.graphics.Canvas
65
import android.graphics.Color
76
import android.graphics.PorterDuff
87
import android.graphics.drawable.Icon
98
import androidx.annotation.DrawableRes
109
import androidx.core.content.ContextCompat
10+
import androidx.core.graphics.createBitmap
1111

1212
/** Factory for creating (and caching) rotated icons. */
1313
class IconFactory(context: Context, @DrawableRes drawableRes: Int) {
1414

1515
// drawable and bitmap cache for better memory
1616
private val arrowDrawable = ContextCompat.getDrawable(context, drawableRes)!!
17-
private val iconBitmap = Bitmap.createBitmap(
18-
arrowDrawable.intrinsicWidth, arrowDrawable.intrinsicHeight,
19-
Bitmap.Config.ARGB_8888
20-
)
17+
private val iconBitmap = createBitmap(arrowDrawable.intrinsicWidth, arrowDrawable.intrinsicHeight)
2118

2219
fun build(degrees: Float): Icon {
2320
Canvas(iconBitmap).apply {

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
plugins {
22
// AGP (https://developer.android.com/build/releases/gradle-plugin)
3-
id("com.android.application") version "8.5.2" apply false
3+
id("com.android.application") version "8.12.2" apply false
44

55
// Kotlin (https://kotlinlang.org/docs/releases.html#release-details)
6-
id ("org.jetbrains.kotlin.android") version "2.0.20" apply false
6+
id ("org.jetbrains.kotlin.android") version "2.2.10" apply false
77
}

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip

0 commit comments

Comments
 (0)