Tweak SDK version check and start activity for result related code

This commit is contained in:
vfsfitvnm 2022-10-23 21:56:14 +02:00
parent 1bdc120430
commit 1221ddf424
10 changed files with 113 additions and 116 deletions

View file

@ -6,7 +6,6 @@ import android.content.Intent
import android.content.ServiceConnection
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.widget.Toast
@ -86,6 +85,8 @@ import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
import it.vfsfitvnm.vimusic.utils.forcePlay
import it.vfsfitvnm.vimusic.utils.getEnum
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid8
import it.vfsfitvnm.vimusic.utils.preferences
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
import it.vfsfitvnm.vimusic.utils.useSystemFontKey
@ -453,12 +454,12 @@ class MainActivity : ComponentActivity() {
isAppearanceLightNavigationBars = !isDark
}
if (Build.VERSION.SDK_INT < 23) {
if (!isAtLeastAndroid6) {
window.statusBarColor =
(if (isDark) Color.Transparent else Color.Black.copy(alpha = 0.2f)).toArgb()
}
if (Build.VERSION.SDK_INT < 26) {
if (!isAtLeastAndroid8) {
window.navigationBarColor =
(if (isDark) Color.Transparent else Color.Black.copy(alpha = 0.2f)).toArgb()
}

View file

@ -24,7 +24,6 @@ import android.media.audiofx.AudioEffect
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.text.format.DateUtils
import androidx.compose.runtime.getValue
@ -93,6 +92,7 @@ import it.vfsfitvnm.vimusic.utils.getEnum
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid13
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid8
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
import it.vfsfitvnm.vimusic.utils.mediaItems
@ -659,7 +659,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
val mediaMetadata = player.mediaMetadata
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val builder = if (isAtLeastAndroid8) {
Notification.Builder(applicationContext, NotificationChannelId)
} else {
Notification.Builder(applicationContext)
@ -706,7 +706,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
private fun createNotificationChannel() {
notificationManager = getSystemService()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
if (!isAtLeastAndroid8) return
notificationManager?.run {
if (getNotificationChannel(NotificationChannelId) == null) {
@ -987,7 +987,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
this@Context,
100,
Intent(value).setPackage(packageName),
PendingIntent.FLAG_UPDATE_CURRENT.or(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
PendingIntent.FLAG_UPDATE_CURRENT.or(if (isAtLeastAndroid6) PendingIntent.FLAG_IMMUTABLE else 0)
)
companion object {

View file

@ -1,8 +1,8 @@
package it.vfsfitvnm.vimusic.ui.screens.player
import android.app.SearchManager
import android.content.ActivityNotFoundException
import android.content.Intent
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@ -45,6 +45,9 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.media3.common.C
import androidx.media3.common.MediaMetadata
import it.vfsfitvnm.innertube.Innertube
import it.vfsfitvnm.innertube.models.bodies.NextBody
import it.vfsfitvnm.innertube.requests.lyrics
import it.vfsfitvnm.kugou.KuGou
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
@ -67,10 +70,8 @@ import it.vfsfitvnm.vimusic.utils.isShowingSynchronizedLyricsKey
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.produceSaveableState
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.toast
import it.vfsfitvnm.vimusic.utils.verticalFadingEdge
import it.vfsfitvnm.innertube.Innertube
import it.vfsfitvnm.innertube.models.bodies.NextBody
import it.vfsfitvnm.innertube.requests.lyrics
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
@ -327,24 +328,17 @@ fun Lyrics(
menuState.hide()
val mediaMetadata = mediaMetadataProvider()
val intent =
Intent(Intent.ACTION_WEB_SEARCH).apply {
putExtra(
SearchManager.QUERY,
"${mediaMetadata.title} ${mediaMetadata.artist} lyrics"
)
}
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
Toast
.makeText(
context,
"No browser app found!",
Toast.LENGTH_SHORT
)
.show()
try {
context.startActivity(
Intent(Intent.ACTION_WEB_SEARCH).apply {
putExtra(
SearchManager.QUERY,
"${mediaMetadata.title} ${mediaMetadata.artist} lyrics"
)
}
)
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find an application to browse the Internet")
}
}
)

View file

@ -1,9 +1,9 @@
package it.vfsfitvnm.vimusic.ui.screens.player
import android.content.ActivityNotFoundException
import android.content.Intent
import android.media.audiofx.AudioEffect
import android.widget.Toast
import androidx.activity.compose.LocalActivityResultRegistryOwner
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.ExperimentalFoundationApi
@ -70,6 +70,7 @@ import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
import it.vfsfitvnm.vimusic.utils.thumbnail
import it.vfsfitvnm.vimusic.utils.toast
import kotlin.math.absoluteValue
@ExperimentalFoundationApi
@ -382,7 +383,9 @@ private fun PlayerMenu(
onDismiss: () -> Unit
) {
val context = LocalContext.current
val resultRegistryOwner = LocalActivityResultRegistryOwner.current
val activityResultLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
BaseMediaItemMenu(
mediaItem = mediaItem,
@ -392,19 +395,16 @@ private fun PlayerMenu(
binder.setupRadio(NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId))
},
onGoToEqualizer = {
val intent = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
putExtra(AudioEffect.EXTRA_AUDIO_SESSION, binder.player.audioSessionId)
putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
}
if (intent.resolveActivity(context.packageManager) != null) {
val contract = ActivityResultContracts.StartActivityForResult()
resultRegistryOwner?.activityResultRegistry
?.register("", contract) {}?.launch(intent)
} else {
Toast.makeText(context, "No equalizer app found!", Toast.LENGTH_SHORT).show()
try {
activityResultLauncher.launch(
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
putExtra(AudioEffect.EXTRA_AUDIO_SESSION, binder.player.audioSessionId)
putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
}
)
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find an application to equalize audio")
}
},
onShowSleepTimer = {},

View file

@ -1,6 +1,7 @@
package it.vfsfitvnm.vimusic.ui.screens.settings
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
@ -28,14 +29,15 @@ import it.vfsfitvnm.vimusic.ui.components.themed.Header
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.produceSaveableState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import it.vfsfitvnm.vimusic.utils.toast
import java.io.FileInputStream
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.Date
import kotlin.system.exitProcess
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
@ExperimentalAnimationApi
@Composable
@ -124,7 +126,12 @@ fun DatabaseSettings() {
onClick = {
@SuppressLint("SimpleDateFormat")
val dateFormat = SimpleDateFormat("yyyyMMddHHmmss")
backupLauncher.launch("vimusic_${dateFormat.format(Date())}.db")
try {
backupLauncher.launch("vimusic_${dateFormat.format(Date())}.db")
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find an application to create documents")
}
}
)
@ -138,13 +145,11 @@ fun DatabaseSettings() {
title = "Restore",
text = "Import the database from the external storage",
onClick = {
restoreLauncher.launch(
arrayOf(
"application/x-sqlite3",
"application/vnd.sqlite3",
"application/octet-stream"
)
)
try {
restoreLauncher.launch(arrayOf("application/vnd.sqlite3"))
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find an application to open documents")
}
}
)
}

View file

@ -1,49 +1,52 @@
package it.vfsfitvnm.vimusic.ui.screens.settings
import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SnapshotMutationPolicy
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.autoSaver
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.only
import androidx.compose.runtime.SnapshotMutationPolicy
import androidx.compose.runtime.saveable.autoSaver
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
import it.vfsfitvnm.vimusic.query
import it.vfsfitvnm.vimusic.service.PlayerMediaBrowserService
import it.vfsfitvnm.vimusic.ui.components.themed.Header
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid12
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
import it.vfsfitvnm.vimusic.utils.pauseSearchHistoryKey
import it.vfsfitvnm.vimusic.utils.produceSaveableState
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.toast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
@SuppressLint("BatteryLife")
@ExperimentalAnimationApi
@Composable
fun OtherSettings() {
@ -142,7 +145,7 @@ fun OtherSettings() {
ImportantSettingsDescription(text = "If battery optimizations are applied, the playback notification can suddenly disappear when paused.")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (isAtLeastAndroid12) {
SettingsDescription(text = "Since Android 12, disabling battery optimizations is required for the \"Invincible service\" option to take effect.")
}
@ -155,28 +158,21 @@ fun OtherSettings() {
"Disable background restrictions"
},
onClick = {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return@SettingsEntry
if (!isAtLeastAndroid6) return@SettingsEntry
@SuppressLint("BatteryLife")
val intent =
Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
data = Uri.parse("package:${context.packageName}")
}
if (intent.resolveActivity(context.packageManager) != null) {
activityResultLauncher.launch(intent)
} else {
val fallbackIntent =
Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
if (fallbackIntent.resolveActivity(context.packageManager) != null) {
activityResultLauncher.launch(fallbackIntent)
} else {
Toast.makeText(
context,
"Couldn't find battery optimization settings, please whitelist ViMusic manually",
Toast.LENGTH_SHORT
).show()
try {
activityResultLauncher.launch(
Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
data = Uri.parse("package:${context.packageName}")
}
)
} catch (e: ActivityNotFoundException) {
try {
activityResultLauncher.launch(
Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
)
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find battery optimization settings, please whitelist ViMusic manually")
}
}
}

View file

@ -1,14 +1,17 @@
package it.vfsfitvnm.vimusic.ui.screens.settings
import android.content.ActivityNotFoundException
import android.content.Intent
import android.media.audiofx.AudioEffect
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
@ -18,18 +21,15 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.only
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.ui.components.themed.Header
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid13
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.resumePlaybackWhenDeviceConnectedKey
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
import it.vfsfitvnm.vimusic.utils.toast
import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
@ExperimentalAnimationApi
@ -40,13 +40,15 @@ fun PlayerSettings() {
val binder = LocalPlayerServiceBinder.current
var persistentQueue by rememberPreference(persistentQueueKey, false)
var resumePlaybackWhenDeviceConnected by rememberPreference(resumePlaybackWhenDeviceConnectedKey, false)
var resumePlaybackWhenDeviceConnected by rememberPreference(
resumePlaybackWhenDeviceConnectedKey,
false
)
var skipSilence by rememberPreference(skipSilenceKey, false)
var volumeNormalization by rememberPreference(volumeNormalizationKey, false)
val activityResultLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
}
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
Column(
modifier = Modifier
@ -109,24 +111,16 @@ fun PlayerSettings() {
title = "Equalizer",
text = "Interact with the system equalizer",
onClick = {
val intent =
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
putExtra(
AudioEffect.EXTRA_AUDIO_SESSION,
binder?.player?.audioSessionId
)
putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
putExtra(
AudioEffect.EXTRA_CONTENT_TYPE,
AudioEffect.CONTENT_TYPE_MUSIC
)
}
val intent = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
putExtra(AudioEffect.EXTRA_AUDIO_SESSION, binder?.player?.audioSessionId)
putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
}
if (intent.resolveActivity(context.packageManager) != null) {
try {
activityResultLauncher.launch(intent)
} else {
Toast.makeText(context, "No equalizer app found!", Toast.LENGTH_SHORT)
.show()
} catch (e: ActivityNotFoundException) {
context.toast("Couldn't find an application to equalize audio")
}
}
)

View file

@ -5,8 +5,8 @@ import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.PowerManager
import android.widget.Toast
import androidx.core.content.getSystemService
inline fun <reified T> Context.intent(): Intent =
@ -14,7 +14,7 @@ inline fun <reified T> Context.intent(): Intent =
inline fun <reified T : BroadcastReceiver> Context.broadCastPendingIntent(
requestCode: Int = 0,
flags: Int = if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0,
flags: Int = if (isAtLeastAndroid6) PendingIntent.FLAG_IMMUTABLE else 0,
): PendingIntent =
PendingIntent.getBroadcast(this, requestCode, intent<T>(), flags)
@ -27,12 +27,14 @@ inline fun <reified T : Activity> Context.activityPendingIntent(
this,
requestCode,
intent<T>().apply(block),
(if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_IMMUTABLE else 0) or flags
(if (isAtLeastAndroid6) PendingIntent.FLAG_IMMUTABLE else 0) or flags
)
val Context.isIgnoringBatteryOptimizations: Boolean
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
get() = if (isAtLeastAndroid6) {
getSystemService<PowerManager>()?.isIgnoringBatteryOptimizations(packageName) ?: true
} else {
true
}
fun Context.toast(message: String) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()

View file

@ -7,7 +7,6 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Binder
import android.os.Build
import android.os.Handler
import android.os.Looper
@ -28,7 +27,7 @@ abstract class InvincibleService : Service() {
private var invincibility: Invincibility? = null
private val isAllowedToStartForegroundServices: Boolean
get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.S || isIgnoringBatteryOptimizations
get() = !isAtLeastAndroid12 || isIgnoringBatteryOptimizations
override fun onBind(intent: Intent?): Binder? {
invincibility?.stop()

View file

@ -116,5 +116,11 @@ suspend fun Result<Innertube.PlaylistOrAlbumPage>.completed(): Result<Innertube.
inline val isAtLeastAndroid6
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
inline val isAtLeastAndroid8
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
inline val isAtLeastAndroid12
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
inline val isAtLeastAndroid13
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU