Update API level to Android 17 (#1908)
## Description Updates the compile & target SDKs to 37 (Android 17). The only required change is to support the new `ACCESS_LOCAL_NETWORK` permission. This is required for Android 17 devices to auto discover Jellyfin servers on the local network. Wholphin will prompt for permission and if granted, use the discover servers feature. If permission is not granted, the user must enter the server URL manually. ### Related issues N/A, but several dependency renovate PRs are blocked by this ### Testing I tested with a regular Android 17 emulator. There are no Android TV 17 images (or probably even devices) available yet. ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
cc2e7dfdda
commit
5363db0b80
8 changed files with 60 additions and 6 deletions
|
|
@ -65,14 +65,16 @@ kotlin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Provider<String>.getInt() = get().toInt()
|
||||||
|
|
||||||
configure<ApplicationExtension> {
|
configure<ApplicationExtension> {
|
||||||
namespace = "com.github.damontecres.wholphin"
|
namespace = "com.github.damontecres.wholphin"
|
||||||
compileSdk = 36
|
compileSdk = libs.versions.compileSdk.getInt()
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.github.damontecres.wholphin"
|
applicationId = "com.github.damontecres.wholphin"
|
||||||
minSdk = 23
|
minSdk = libs.versions.minSdk.getInt()
|
||||||
targetSdk = 36
|
targetSdk = libs.versions.targetSdk.getInt()
|
||||||
versionCode = gitTags.trim().lines().size
|
versionCode = gitTags.trim().lines().size
|
||||||
versionName = gitDescribe.trim().removePrefix("v").ifBlank { "0.0.0" }
|
versionName = gitDescribe.trim().removePrefix("v").ifBlank { "0.0.0" }
|
||||||
testInstrumentationRunner = "com.github.damontecres.wholphin.test.WholphinTestRunner"
|
testInstrumentationRunner = "com.github.damontecres.wholphin.test.WholphinTestRunner"
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package com.github.damontecres.wholphin.ui.setup
|
package com.github.damontecres.wholphin.ui.setup
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.slideInVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
|
@ -67,6 +71,7 @@ import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||||
import com.github.damontecres.wholphin.ui.rememberInt
|
import com.github.damontecres.wholphin.ui.rememberInt
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
import com.github.damontecres.wholphin.util.LoadingState
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SwitchServerContent(
|
fun SwitchServerContent(
|
||||||
|
|
@ -294,10 +299,31 @@ private fun AddServerDialog(
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
var showEnterAddress by remember { mutableStateOf(false) }
|
var showEnterAddress by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val permissionLauncher =
|
||||||
|
rememberLauncherForActivityResult(
|
||||||
|
contract = ActivityResultContracts.RequestPermission(),
|
||||||
|
) { isGranted ->
|
||||||
|
if (isGranted) {
|
||||||
|
viewModel.discoverServers()
|
||||||
|
} else {
|
||||||
|
showEnterAddress = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.clearAddServerState()
|
viewModel.clearAddServerState()
|
||||||
if (!showEnterAddress) {
|
if (!showEnterAddress) {
|
||||||
|
if (viewModel.hasPermission) {
|
||||||
viewModel.discoverServers()
|
viewModel.discoverServers()
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CINNAMON_BUN) {
|
||||||
|
permissionLauncher.launch(Manifest.permission.ACCESS_LOCAL_NETWORK)
|
||||||
|
} else {
|
||||||
|
Timber.w(
|
||||||
|
"No ACCESS_LOCAL_NETWORK permission, but API <%s: %s",
|
||||||
|
Build.VERSION_CODES.CINNAMON_BUN,
|
||||||
|
Build.VERSION.SDK_INT,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
package com.github.damontecres.wholphin.ui.setup
|
package com.github.damontecres.wholphin.ui.setup
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
|
|
@ -46,6 +50,17 @@ class SwitchServerViewModel
|
||||||
private val _state = MutableStateFlow(SwitchServerState())
|
private val _state = MutableStateFlow(SwitchServerState())
|
||||||
val state: StateFlow<SwitchServerState> = _state
|
val state: StateFlow<SwitchServerState> = _state
|
||||||
|
|
||||||
|
val hasPermission: Boolean
|
||||||
|
get() =
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CINNAMON_BUN) {
|
||||||
|
ContextCompat.checkSelfPermission(
|
||||||
|
context,
|
||||||
|
Manifest.permission.ACCESS_LOCAL_NETWORK,
|
||||||
|
) == PackageManager.PERMISSION_GRANTED
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fun clearAddServerState() {
|
fun clearAddServerState() {
|
||||||
_state.update { it.copy(addServerState = LoadingState.Pending) }
|
_state.update { it.copy(addServerState = LoadingState.Pending) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(manifest = Config.NONE, sdk = [30])
|
||||||
class IntentServiceTest {
|
class IntentServiceTest {
|
||||||
private val api: ApiClient = mockk()
|
private val api: ApiClient = mockk()
|
||||||
private val serverRepository: ServerRepository = mockk()
|
private val serverRepository: ServerRepository = mockk()
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,12 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(manifest = Config.NONE, sdk = [30])
|
||||||
class PlaybackViewModelTests {
|
class PlaybackViewModelTests {
|
||||||
private val testDispatcher = StandardTestDispatcher()
|
private val testDispatcher = StandardTestDispatcher()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ junitVersion = "1.3.0"
|
||||||
espressoCore = "3.7.0"
|
espressoCore = "3.7.0"
|
||||||
material = "1.14.0"
|
material = "1.14.0"
|
||||||
|
|
||||||
|
compileSdk = "37"
|
||||||
|
targetSdk = "37"
|
||||||
|
minSdk = "23"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
wholphin-extensions-mpv = { module = "com.github.damontecres.wholphin.mpv:wholphin-mpv", version.ref = "wholphin-extensions" }
|
wholphin-extensions-mpv = { module = "com.github.damontecres.wholphin.mpv:wholphin-mpv", version.ref = "wholphin-extensions" }
|
||||||
wholphin-extensions-ffmpeg = { module = "com.github.damontecres.wholphin.media3:decoder-ffmpeg", version.ref = "wholphin-extensions" }
|
wholphin-extensions-ffmpeg = { module = "com.github.damontecres.wholphin.media3:decoder-ffmpeg", version.ref = "wholphin-extensions" }
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@ plugins {
|
||||||
alias(libs.plugins.android.library)
|
alias(libs.plugins.android.library)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Provider<String>.getInt() = get().toInt()
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.github.damontecres.wholphin.mpv"
|
namespace = "com.github.damontecres.wholphin.mpv"
|
||||||
compileSdk {
|
compileSdk {
|
||||||
version = release(36)
|
version = release(libs.versions.compileSdk.getInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 23
|
minSdk = libs.versions.minSdk.getInt()
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue