diff --git a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt index efb27fa02..294812bdc 100644 --- a/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt +++ b/app/src/main/java/eu/kanade/domain/ui/UiPreferences.kt @@ -1,5 +1,6 @@ package eu.kanade.domain.ui +import android.os.Build import eu.kanade.domain.ui.model.AppTheme import eu.kanade.domain.ui.model.TabletUiMode import eu.kanade.domain.ui.model.ThemeMode @@ -15,7 +16,10 @@ class UiPreferences( private val preferenceStore: PreferenceStore, ) { - fun themeMode() = preferenceStore.getEnum("pref_theme_mode_key", ThemeMode.SYSTEM) + fun themeMode() = preferenceStore.getEnum( + "pref_theme_mode_key", + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ThemeMode.SYSTEM } else { ThemeMode.LIGHT }, + ) fun appTheme() = preferenceStore.getEnum( "pref_app_theme", diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt index 21057a634..43e9ac158 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaCoverDialog.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.manga.components import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable +import android.os.Build import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -175,9 +176,14 @@ fun MangaCoverDialog( // Copy bitmap in case it came from memory cache // Because SSIV needs to thoroughly read the image val copy = (drawable as? BitmapDrawable)?.let { + val config = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Bitmap.Config.HARDWARE + } else { + Bitmap.Config.ARGB_8888 + } BitmapDrawable( view.context.resources, - it.bitmap.copy(Bitmap.Config.HARDWARE, false), + it.bitmap.copy(config, false), ) } ?: drawable view.setImage(copy, ReaderPageImageView.Config(zoomDuration = 500)) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index 6b8cc1454..97d852e50 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -3,6 +3,7 @@ package eu.kanade.presentation.more.settings.screen import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Intent +import android.os.Build import android.provider.Settings import android.webkit.WebStorage import android.webkit.WebView @@ -80,50 +81,62 @@ object SettingsAdvancedScreen : SearchableSettings { val basePreferences = remember { Injekt.get() } val networkPreferences = remember { Injekt.get() } - return listOf( - Preference.PreferenceItem.SwitchPreference( - pref = basePreferences.acraEnabled(), - title = stringResource(R.string.pref_enable_acra), - subtitle = stringResource(R.string.pref_acra_summary), - enabled = isPreviewBuildType || isReleaseBuildType, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_dump_crash_logs), - subtitle = stringResource(R.string.pref_dump_crash_logs_summary), - onClick = { - scope.launch { - CrashLogUtil(context).dumpLogs() - } - }, - ), - Preference.PreferenceItem.SwitchPreference( - pref = networkPreferences.verboseLogging(), - title = stringResource(R.string.pref_verbose_logging), - subtitle = stringResource(R.string.pref_verbose_logging_summary), - onValueChanged = { - context.toast(R.string.requires_app_restart) - true - }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_debug_info), - onClick = { navigator.push(DebugInfoScreen()) }, - ), - Preference.PreferenceItem.TextPreference( - title = stringResource(R.string.pref_manage_notifications), - onClick = { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) - }, - ), - getBackgroundActivityGroup(), - getDataGroup(), - getNetworkGroup(networkPreferences = networkPreferences), - getLibraryGroup(), - getExtensionsGroup(basePreferences = basePreferences), - ) + return buildList { + addAll( + listOf( + Preference.PreferenceItem.SwitchPreference( + pref = basePreferences.acraEnabled(), + title = stringResource(R.string.pref_enable_acra), + subtitle = stringResource(R.string.pref_acra_summary), + enabled = isPreviewBuildType || isReleaseBuildType, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_dump_crash_logs), + subtitle = stringResource(R.string.pref_dump_crash_logs_summary), + onClick = { + scope.launch { + CrashLogUtil(context).dumpLogs() + } + }, + ), + Preference.PreferenceItem.SwitchPreference( + pref = networkPreferences.verboseLogging(), + title = stringResource(R.string.pref_verbose_logging), + subtitle = stringResource(R.string.pref_verbose_logging_summary), + onValueChanged = { + context.toast(R.string.requires_app_restart) + true + }, + ), + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_debug_info), + onClick = { navigator.push(DebugInfoScreen()) }, + ), + ), + ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + add( + Preference.PreferenceItem.TextPreference( + title = stringResource(R.string.pref_manage_notifications), + onClick = { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + }, + ), + ) + } + addAll( + listOf( + getBackgroundActivityGroup(), + getDataGroup(), + getNetworkGroup(networkPreferences = networkPreferences), + getLibraryGroup(), + getExtensionsGroup(basePreferences = basePreferences), + ), + ) + } } @Composable diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt index 0ee26274f..4540aee95 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAppearanceScreen.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.more.settings.screen import android.app.Activity import android.content.Context +import android.os.Build import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatDelegate import androidx.compose.runtime.Composable @@ -80,11 +81,18 @@ object SettingsAppearanceScreen : SearchableSettings { Preference.PreferenceItem.ListPreference( pref = themeModePref, title = stringResource(R.string.pref_theme_mode), - entries = mapOf( - ThemeMode.SYSTEM to stringResource(R.string.theme_system), - ThemeMode.LIGHT to stringResource(R.string.theme_light), - ThemeMode.DARK to stringResource(R.string.theme_dark), - ), + entries = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mapOf( + ThemeMode.SYSTEM to stringResource(R.string.theme_system), + ThemeMode.LIGHT to stringResource(R.string.theme_light), + ThemeMode.DARK to stringResource(R.string.theme_dark), + ) + } else { + mapOf( + ThemeMode.LIGHT to stringResource(R.string.theme_light), + ThemeMode.DARK to stringResource(R.string.theme_dark), + ) + }, ), Preference.PreferenceItem.CustomPreference( title = stringResource(R.string.pref_app_theme), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index 0f343aa3d..14e0fd9df 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -58,6 +58,7 @@ object SettingsReaderScreen : SearchableSettings { pref = readerPref.trueColor(), title = stringResource(R.string.pref_true_color), subtitle = stringResource(R.string.pref_true_color_summary), + enabled = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O, ), Preference.PreferenceItem.SwitchPreference( pref = readerPref.pageTransitions(), diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index 6b5fceda7..bcbf7110f 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -79,7 +79,6 @@ fun ScreenTransition( targetState = navigator.lastItem, transitionSpec = transition, modifier = modifier, - label = "ScreenTransition", ) { screen -> navigator.saveableState("transition", screen) { content(screen) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 4323200dd..822c66b81 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -171,19 +171,22 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { } override fun getPackageName(): String { - try { - // Override the value passed as X-Requested-With in WebView requests - val stackTrace = Looper.getMainLooper().thread.stackTrace - val chromiumElement = stackTrace.find { - it.className.equals( - "org.chromium.base.BuildInfo", - ignoreCase = true, - ) + // This causes freezes in Android 6/7 for some reason + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + // Override the value passed as X-Requested-With in WebView requests + val stackTrace = Looper.getMainLooper().thread.stackTrace + val chromiumElement = stackTrace.find { + it.className.equals( + "org.chromium.base.BuildInfo", + ignoreCase = true, + ) + } + if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { + return WebViewUtil.SPOOF_PACKAGE_NAME + } + } catch (e: Exception) { } - if (chromiumElement?.methodName.equals("getAll", ignoreCase = true)) { - return WebViewUtil.SPOOF_PACKAGE_NAME - } - } catch (e: Exception) { } return super.getPackageName() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt index fb1278614..e0a5ffe8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/coil/TachiyomiImageDecoder.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.coil +import android.os.Build import androidx.core.graphics.drawable.toDrawable import coil.ImageLoader import coil.decode.DecodeResult @@ -47,7 +48,8 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti ImageUtil.findImageType(it) } return when (type) { - ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL, ImageUtil.ImageType.HEIF -> true + ImageUtil.ImageType.AVIF, ImageUtil.ImageType.JXL -> true + ImageUtil.ImageType.HEIF -> Build.VERSION.SDK_INT < Build.VERSION_CODES.O else -> false } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 22c19cab0..566da8e9c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -5,6 +5,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import androidx.core.net.toUri import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupRestoreJob @@ -367,18 +368,20 @@ class NotificationReceiver : BroadcastReceiver() { When programmatically dismissing this notification, the group notification is not automatically dismissed. */ - val groupKey = context.notificationManager.activeNotifications.find { - it.id == notificationId - }?.groupKey + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val groupKey = context.notificationManager.activeNotifications.find { + it.id == notificationId + }?.groupKey - if (groupId != null && groupId != 0 && !groupKey.isNullOrEmpty()) { - val notifications = context.notificationManager.activeNotifications.filter { - it.groupKey == groupKey - } + if (groupId != null && groupId != 0 && groupKey != null && groupKey.isNotEmpty()) { + val notifications = context.notificationManager.activeNotifications.filter { + it.groupKey == groupKey + } - if (notifications.size == 2) { - context.cancelNotification(groupId) - return + if (notifications.size == 2) { + context.cancelNotification(groupId) + return + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt index 0d785e3a6..6cc4efd33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/installer/ShizukuInstaller.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.installer import android.app.Service import android.content.pm.PackageManager +import android.os.Build import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.system.getUriSize @@ -49,7 +50,11 @@ class ShizukuInstaller(private val service: Service) : Installer(service) { try { val size = service.getUriSize(entry.uri) ?: throw IllegalStateException() service.contentResolver.openInputStream(entry.uri)!!.use { - val createCommand = "pm install-create --user current -r -i ${service.packageName} -S $size" + val createCommand = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + "pm install-create --user current -r -i ${service.packageName} -S $size" + } else { + "pm install-create -r -i ${service.packageName} -S $size" + } val createResult = exec(createCommand) sessionId = SESSION_ID_REGEX.find(createResult.out)?.value ?: throw RuntimeException("Failed to create install session") diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt index f86d36485..94a65ddcd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/storage/FileExtensions.kt @@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.util.storage import android.content.Context import android.net.Uri +import android.os.Build import androidx.core.content.FileProvider +import androidx.core.net.toUri import eu.kanade.tachiyomi.BuildConfig import java.io.File @@ -15,7 +17,11 @@ val Context.cacheImageDir: File * @param context context of application */ fun File.getUriCompat(context: Context): Uri { - return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) + } else { + this.toUri() + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt index 18e16baac..8d72a9c86 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/NetworkExtensions.kt @@ -18,7 +18,8 @@ fun Context.isOnline(): Boolean { val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false val maxTransport = when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> NetworkCapabilities.TRANSPORT_LOWPAN - else -> NetworkCapabilities.TRANSPORT_WIFI_AWARE + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> NetworkCapabilities.TRANSPORT_WIFI_AWARE + else -> NetworkCapabilities.TRANSPORT_VPN } return (NetworkCapabilities.TRANSPORT_CELLULAR..maxTransport).any(networkCapabilities::hasTransport) } diff --git a/buildSrc/src/main/kotlin/AndroidConfig.kt b/buildSrc/src/main/kotlin/AndroidConfig.kt index 9a5cc2f6b..f63c07729 100644 --- a/buildSrc/src/main/kotlin/AndroidConfig.kt +++ b/buildSrc/src/main/kotlin/AndroidConfig.kt @@ -1,6 +1,6 @@ object AndroidConfig { const val compileSdk = 34 - const val minSdk = 26 + const val minSdk = 23 const val targetSdk = 29 const val ndk = "22.1.7171670" } diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt index 6547a46e0..93ce0337d 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewClientCompat.kt @@ -1,5 +1,7 @@ package eu.kanade.tachiyomi.util.system +import android.annotation.TargetApi +import android.os.Build import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse @@ -26,6 +28,7 @@ abstract class WebViewClientCompat : WebViewClient() { ) { } + @TargetApi(Build.VERSION_CODES.N) final override fun shouldOverrideUrlLoading( view: WebView, request: WebResourceRequest, diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt index b60bc8dc0..b3329e9b7 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/WebViewUtil.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.util.system import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageManager +import android.os.Build import android.webkit.CookieManager import android.webkit.WebSettings import android.webkit.WebView @@ -34,11 +35,15 @@ object WebViewUtil { } fun getVersion(context: Context): String { - val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" - val pm = context.packageManager - val label = webView.applicationInfo.loadLabel(pm) - val version = webView.versionName - return "$label $version" + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val webView = WebView.getCurrentWebViewPackage() ?: return "how did you get here?" + val pm = context.packageManager + val label = webView.applicationInfo.loadLabel(pm) + val version = webView.versionName + "$label $version" + } else { + "Unknown" + } } fun supportsWebView(context: Context): Boolean {