diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 390b1232..7cbde21f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -54,7 +54,7 @@ jobs:
ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}"
ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}"
run: |
- ./gradlew clean assembleRelease assembleDebug --no-daemon
+ ./gradlew clean assembleDefaultRelease assembleDefaultDebug --no-daemon
- name: Verify signatures
run: |
@@ -67,7 +67,7 @@ jobs:
find app/build/outputs/apk -name '*.apk' -print0 |
while IFS= read -r -d '' line; do
# Wholphin-release-0.2.9-62-g5c12e03-16-arm64-v8a.apk => Wholphin-arm64-v8a.apk
- short_name="$(echo $line | sed -E 's/-[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g[a-fA-F0-9]+-[0-9]+//')"
+ short_name="$(echo $line | sed -E 's/-[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g[a-fA-F0-9]+-[0-9]+//' | sed -E 's/-default//')"
echo "$line => $short_name"
cp "$line" "$short_name"
done
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index dc518c87..bde4e1ef 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -39,19 +39,6 @@ jobs:
- name: Build app
id: buildapp
run: |
- ./gradlew clean assembleDebug testDebugUnitTest --no-daemon
+ ./gradlew clean assembleDefaultDebug testDefaultDebugUnitTest --no-daemon
apks=$(find app/build/outputs \( -name '*.apk' -or -name '*.aab' \) -print0 | tr '\0' ',' | sed 's/,$//')
echo "apks=$apks" >> "$GITHUB_OUTPUT"
-
- test-patch:
- runs-on: ubuntu-latest
- needs: pre-commit
- steps:
- - name: Checkout the code
- uses: actions/checkout@v6
- with:
- fetch-depth: 1
- - name: Test applying patch
- run: |
- git apply app/src/patches/play_store.patch
- git diff
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 466aa8b1..d47134ef 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -36,22 +36,8 @@ jobs:
ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}"
ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}"
run: |
- ./gradlew clean assembleRelease --no-daemon
+ ./gradlew clean assembleDefaultRelease bundleAppstoreRelease --no-daemon
- - name: Build app
- id: buildaab
- env:
- KEY_ALIAS: "${{ secrets.KEY_ALIAS }}"
- KEY_PASSWORD: "${{ secrets.KEY_PASSWORD }}"
- KEY_STORE_PASSWORD: "${{ secrets.KEY_STORE_PASSWORD }}"
- SIGNING_KEY: "${{ secrets.SIGNING_KEY }}"
- ORG_GRADLE_PROJECT_WholphinExtensionsUsername: "${{ secrets.EXTENSIONS_USERNAME }}"
- ORG_GRADLE_PROJECT_WholphinExtensionsPassword: "${{ secrets.EXTENSIONS_PASSWORD }}"
- run: |
- git apply app/src/patches/play_store.patch
- ./gradlew bundleRelease --no-daemon
- aab=$(find app/build/outputs -name '*.aab')
- echo "aab=$aab" >> "$GITHUB_OUTPUT"
- name: Verify signatures
run: |
echo "Verify APK signatures"
@@ -62,13 +48,16 @@ jobs:
run: |
find app/build/outputs/apk -name '*.apk' -print0 |
while IFS= read -r -d '' line; do
- # Wholphin-release-0.2.9-62-g5c12e03-16-arm64-v8a.apk => Wholphin-arm64-v8a.apk
- short_name="$(echo $line | sed -E 's/-release-[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g[a-fA-F0-9]+-[0-9]+//')"
+ # Wholphin-default-release-0.2.9-62-g5c12e03-16-arm64-v8a.apk => Wholphin-arm64-v8a.apk
+ short_name="$(echo $line | sed -E 's/-default-release-[0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g[a-fA-F0-9]+-[0-9]+//')"
echo "$line => $short_name"
cp "$line" "$short_name"
done
apks=$(find app/build/outputs/apk -name '*.apk' -print0 | tr '\0' ',' | sed 's/,$//')
echo "apks=$apks" >> "$GITHUB_OUTPUT"
+
+ aab=$(find app/build/outputs -name '*.aab')
+ echo "aab=$aab" >> "$GITHUB_OUTPUT"
- name: Checksums
run: |
echo "SHA256 checksums:"
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index cbda6b36..80a6b2e4 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -47,6 +47,8 @@ android {
versionCode = gitTags.trim().lines().size
versionName = gitDescribe.trim().removePrefix("v").ifBlank { "0.0.0" }
testInstrumentationRunner = "com.github.damontecres.wholphin.test.WholphinTestRunner"
+
+ buildConfigField("long", "BUILD_TIME", System.currentTimeMillis().toString())
}
signingConfigs {
@@ -108,6 +110,20 @@ android {
}
}
}
+ flavorDimensions += "version"
+ productFlavors {
+ create("default") {
+ dimension = "version"
+ isDefault = true
+ manifestPlaceholders += mapOf("leanback" to false)
+ buildConfigField("boolean", "UPDATING_ENABLED", "true")
+ }
+ create("appstore") {
+ dimension = "version"
+ manifestPlaceholders += mapOf("leanback" to true)
+ buildConfigField("boolean", "UPDATING_ENABLED", "false")
+ }
+ }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
diff --git a/app/src/appstore/AndroidManifest.xml b/app/src/appstore/AndroidManifest.xml
new file mode 100644
index 00000000..8a762a28
--- /dev/null
+++ b/app/src/appstore/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 29b2eb75..00000000
--- a/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4479ae86..8dd32ce9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:required="false" />
+ android:required="${leanback}" />
diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
index f1701416..40a04218 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
@@ -65,7 +65,7 @@ class UpdateChecker
private val NOTE_REGEX = Regex("")
- val ACTIVE = true
+ const val ACTIVE = BuildConfig.UPDATING_ENABLED
}
/**
diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt
index cfae65ba..543d8e2c 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/DebugPage.kt
@@ -54,6 +54,7 @@ import org.jellyfin.sdk.model.DeviceInfo
import timber.log.Timber
import java.io.BufferedReader
import java.io.InputStreamReader
+import java.util.Date
import javax.inject.Inject
@HiltViewModel
@@ -75,6 +76,34 @@ class DebugViewModel
display.supportedModes.orEmpty()
}
+ val av1Included by lazy {
+ try {
+ Class.forName("androidx.media3.decoder.av1.Libdav1dVideoRenderer")
+ true
+ } catch (_: ClassNotFoundException) {
+ false
+ }
+ }
+
+ val ffmpegIncluded by lazy {
+ try {
+ Class.forName("androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer")
+ true
+ } catch (_: ClassNotFoundException) {
+ false
+ }
+ }
+
+ val libMpvLoaded by lazy {
+ try {
+ System.loadLibrary("player")
+ System.loadLibrary("mpv")
+ true
+ } catch (_: Exception) {
+ false
+ }
+ }
+
init {
viewModelScope.launchIO {
serverRepository.currentUser.value?.rowId?.let {
@@ -218,6 +247,7 @@ fun DebugPage(
style = MaterialTheme.typography.displaySmall,
color = MaterialTheme.colorScheme.onSurface,
)
+ val buildTime = Date(BuildConfig.BUILD_TIME)
val pkgInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val installInfo =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -239,6 +269,11 @@ fun DebugPage(
"Version Code: ${pkgInfo.versionCodeLong}",
"ClientInfo: ${viewModel.clientInfo}",
"Build type: ${BuildConfig.BUILD_TYPE}",
+ "Build flavor: ${BuildConfig.FLAVOR}",
+ "Build time: $buildTime",
+ "FFMPEG included: ${viewModel.ffmpegIncluded}",
+ "AV1 included: ${viewModel.av1Included}",
+ "libmpv loaded: ${viewModel.libMpvLoaded}",
"Debug enabled: ${BuildConfig.DEBUG}",
"ABIs: ${Build.SUPPORTED_ABIS.toList()}",
) + installInfo
diff --git a/app/src/patches/play_store.patch b/app/src/patches/play_store.patch
deleted file mode 100644
index c1214f0e..00000000
--- a/app/src/patches/play_store.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-# This patches Wholphin for releasing on app stores where self updating is not permitted
-
-diff --git i/app/src/main/AndroidManifest.xml w/app/src/main/AndroidManifest.xml
-index 4479ae86..80596698 100644
---- i/app/src/main/AndroidManifest.xml
-+++ w/app/src/main/AndroidManifest.xml
-@@ -6,7 +6,6 @@
-
-
-
--
-
-@@ -20,7 +19,7 @@
- android:required="false" />
-
-+ android:required="true" />
-
-diff --git i/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt w/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
-index 9e0665dd..bc1e1c16 100644
---- i/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
-+++ w/app/src/main/java/com/github/damontecres/wholphin/services/UpdateChecker.kt
-@@ -65,7 +65,7 @@ class UpdateChecker
-
- private val NOTE_REGEX = Regex("")
-
-- val ACTIVE = true
-+ val ACTIVE = false
- }
-
- /**
diff --git a/app/src/test/java/com/github/damontecres/wholphin/ui/BasicUiTests.kt b/app/src/test/java/com/github/damontecres/wholphin/ui/BasicUiTests.kt
index 66178a4e..25121739 100644
--- a/app/src/test/java/com/github/damontecres/wholphin/ui/BasicUiTests.kt
+++ b/app/src/test/java/com/github/damontecres/wholphin/ui/BasicUiTests.kt
@@ -1,5 +1,7 @@
package com.github.damontecres.wholphin.ui
+import android.app.Application
+import android.content.pm.ActivityInfo
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
@@ -14,6 +16,7 @@ import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.pressKey
import androidx.compose.ui.test.requestFocus
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
+import androidx.test.core.app.ApplicationProvider
import com.github.damontecres.wholphin.services.ScreensaverService
import com.github.damontecres.wholphin.services.ScreensaverState
import com.github.damontecres.wholphin.services.SetupDestination
@@ -49,8 +52,11 @@ import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import javax.inject.Inject
@@ -61,7 +67,23 @@ class BasicUiTests {
@get:Rule(order = 0)
var hiltRule = HiltAndroidRule(this)
+ // From https://github.com/robolectric/robolectric/pull/4736#issuecomment-1831034882
@get:Rule(order = 1)
+ val addActivityToRobolectricRule =
+ object : TestWatcher() {
+ override fun starting(description: Description?) {
+ super.starting(description)
+ val appContext: Application = ApplicationProvider.getApplicationContext()
+ val activityInfo =
+ ActivityInfo().apply {
+ name = TestActivity::class.java.name
+ packageName = appContext.packageName
+ }
+ shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo)
+ }
+ }
+
+ @get:Rule(order = 2)
val composeTestRule = createAndroidComposeRule()
@Inject