fix: краш «Свой звук» на FragmentActivity (0.5.5)

Ringtone picker через startActivityForResult вместо Activity Result API с большим requestCode.
This commit is contained in:
PTah
2026-06-14 18:32:44 +10:00
parent 902e47880d
commit 37c8357a87
5 changed files with 79 additions and 43 deletions
@@ -59,6 +59,7 @@ import ru.kalinamall.seaca.ui.screens.HostDetailScreen
import ru.kalinamall.seaca.ui.screens.HostsScreen
import ru.kalinamall.seaca.ui.screens.ProblemDetailScreen
import ru.kalinamall.seaca.ui.screens.ProblemsScreen
import ru.kalinamall.seaca.ui.RingtonePicker
import ru.kalinamall.seaca.ui.screens.ReportsScreen
import ru.kalinamall.seaca.ui.theme.SeacaTheme
@@ -94,6 +95,13 @@ class MainActivity : FragmentActivity() {
deepLinkState.value = extractDeepLink(intent)
}
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@Suppress("DEPRECATION")
super.onActivityResult(requestCode, resultCode, data)
RingtonePicker.handleActivityResult(requestCode, resultCode, data)
}
override fun onStop() {
super.onStop()
if (shouldRequireBiometric()) {
@@ -20,7 +20,11 @@ object NotificationSoundResolver {
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
fun displayName(context: Context, settings: NotificationSoundSettings): String {
val uri = resolve(context, settings)
return RingtoneManager.getRingtone(context, uri)?.getTitle(context) ?: ""
return try {
val uri = resolve(context, settings)
RingtoneManager.getRingtone(context, uri)?.getTitle(context) ?: ""
} catch (_: Exception) {
""
}
}
}
@@ -0,0 +1,52 @@
package ru.kalinamall.seaca.ui
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import androidx.fragment.app.FragmentActivity
import ru.kalinamall.seaca.push.NotificationSoundResolver
object RingtonePicker {
private const val REQUEST_CODE = 9001
private var callback: ((Uri?) -> Unit)? = null
fun launch(activity: FragmentActivity, currentUri: Uri, onResult: (Uri?) -> Unit) {
callback = onResult
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, NotificationSoundResolver.defaultNotificationUri())
putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentUri)
}
try {
@Suppress("DEPRECATION")
activity.startActivityForResult(intent, REQUEST_CODE)
} catch (_: ActivityNotFoundException) {
callback = null
throw ActivityNotFoundException()
}
}
fun handleActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode != REQUEST_CODE) return
val onResult = callback ?: return
callback = null
val uri = if (resultCode == Activity.RESULT_OK) readResult(data) else null
onResult(uri)
}
private fun readResult(data: Intent?): Uri? {
if (data == null) return null
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, Uri::class.java)
} else {
@Suppress("DEPRECATION")
data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
}
}
}
@@ -1,16 +1,10 @@
package ru.kalinamall.seaca.ui.screens
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.widget.Toast
import androidx.compose.runtime.rememberUpdatedState
import androidx.fragment.app.FragmentActivity
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -64,6 +58,7 @@ import ru.kalinamall.seaca.data.ProblemDetail
import ru.kalinamall.seaca.data.SacRepository
import ru.kalinamall.seaca.push.NotificationHelper
import ru.kalinamall.seaca.push.NotificationSoundResolver
import ru.kalinamall.seaca.ui.RingtonePicker
import ru.kalinamall.seaca.ui.components.BackArrowButton
import ru.kalinamall.seaca.ui.components.ForwardArrowButton
import ru.kalinamall.seaca.ui.util.SacDateTimes
@@ -459,36 +454,23 @@ fun DeviceScreen(repo: SacRepository, onLogout: () -> Unit) {
}
}
val ringtonePickerLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.StartActivityForResult(),
) { result ->
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
val uri = readRingtonePickerResult(result.data)
scope.launch {
if (uri == null) {
repo.session.setNotificationSound(NotificationSoundSource.SYSTEM, null)
} else {
repo.session.setNotificationSound(NotificationSoundSource.CUSTOM, uri.toString())
}
applySoundChannels(repo.session.getNotificationSoundSettings())
}
}
fun openRingtonePicker() {
if (activity == null) {
Toast.makeText(context, "Не удалось открыть выбор звука", Toast.LENGTH_SHORT).show()
return
}
val currentUri = NotificationSoundResolver.resolve(context, latestSoundSettings)
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION)
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, NotificationSoundResolver.defaultNotificationUri())
putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentUri)
}
try {
ringtonePickerLauncher.launch(intent)
RingtonePicker.launch(activity, currentUri) { uri ->
scope.launch {
if (uri == null) {
repo.session.setNotificationSound(NotificationSoundSource.SYSTEM, null)
} else {
repo.session.setNotificationSound(NotificationSoundSource.CUSTOM, uri.toString())
}
applySoundChannels(repo.session.getNotificationSoundSettings())
}
}
} catch (_: ActivityNotFoundException) {
Toast.makeText(context, "На устройстве нет выбора звука уведомлений", Toast.LENGTH_LONG).show()
}
@@ -730,14 +712,4 @@ private fun Field(label: String, value: String) {
}
}
private fun readRingtonePickerResult(data: Intent?): Uri? {
if (data == null) return null
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, Uri::class.java)
} else {
@Suppress("DEPRECATION")
data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
}
}
private fun JsonElement.toPrettyString(): String = toString()