mirror of
https://github.com/jellyfin/jellyfin-android.git
synced 2026-09-03 05:10:27 +03:00
Fix crash caused by fragment transaction on background thread (#296)
This commit is contained in:
@@ -162,7 +162,9 @@ class NativeInterface(private val fragment: WebViewFragment) : KoinComponent {
|
||||
|
||||
@JavascriptInterface
|
||||
fun openClientSettings() {
|
||||
fragment.parentFragmentManager.addFragment<SettingsFragment>()
|
||||
fragment.runOnUiThread {
|
||||
fragment.parentFragmentManager.addFragment<SettingsFragment>()
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
||||
@@ -2,22 +2,18 @@ package org.jellyfin.mobile.bridge
|
||||
|
||||
import android.os.Bundle
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.add
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import org.jellyfin.mobile.AppPreferences
|
||||
import org.jellyfin.mobile.PLAYER_EVENT_CHANNEL
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.player.ExoPlayerFormats
|
||||
import org.jellyfin.mobile.player.PlayerEvent
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.settings.VideoPlayerType
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import org.koin.core.qualifier.named
|
||||
|
||||
class NativePlayer(private val fragmentManager: FragmentManager) : KoinComponent {
|
||||
class NativePlayer(private val host: NativePlayerHost) : KoinComponent {
|
||||
|
||||
private val appPreferences: AppPreferences by inject()
|
||||
private val playerEventChannel: Channel<PlayerEvent> by inject(named(PLAYER_EVENT_CHANNEL))
|
||||
@@ -30,13 +26,10 @@ class NativePlayer(private val fragmentManager: FragmentManager) : KoinComponent
|
||||
|
||||
@JavascriptInterface
|
||||
fun loadPlayer(args: String) {
|
||||
val fragmentArgs = Bundle().apply {
|
||||
val argsBundle = Bundle().apply {
|
||||
putString(Constants.EXTRA_MEDIA_SOURCE_ITEM, args)
|
||||
}
|
||||
fragmentManager.beginTransaction().apply {
|
||||
add<PlayerFragment>(R.id.fragment_container, args = fragmentArgs)
|
||||
addToBackStack(null)
|
||||
}.commit()
|
||||
host.loadNativePlayer(argsBundle)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jellyfin.mobile.bridge
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
interface NativePlayerHost {
|
||||
fun loadNativePlayer(args: Bundle)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import androidx.activity.addCallback
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.add
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.webkit.WebResourceErrorCompat
|
||||
@@ -25,11 +26,14 @@ import androidx.webkit.WebViewFeature
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.apiclient.interaction.ApiClient
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
import org.jellyfin.mobile.bridge.ExternalPlayer
|
||||
import org.jellyfin.mobile.bridge.NativeInterface
|
||||
import org.jellyfin.mobile.bridge.NativePlayer
|
||||
import org.jellyfin.mobile.bridge.NativePlayerHost
|
||||
import org.jellyfin.mobile.controller.ServerController
|
||||
import org.jellyfin.mobile.databinding.FragmentWebviewBinding
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.utils.*
|
||||
import org.jellyfin.mobile.utils.Constants.FRAGMENT_WEB_VIEW_EXTRA_SERVER_ID
|
||||
import org.jellyfin.mobile.utils.Constants.FRAGMENT_WEB_VIEW_EXTRA_URL
|
||||
@@ -44,7 +48,7 @@ import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class WebViewFragment : Fragment() {
|
||||
class WebViewFragment : Fragment(), NativePlayerHost {
|
||||
val apiClient: ApiClient by inject()
|
||||
private val serverController: ServerController by inject()
|
||||
private val webappFunctionChannel: WebappFunctionChannel by inject()
|
||||
@@ -171,15 +175,14 @@ class WebViewFragment : Fragment() {
|
||||
val errorMessage = errorResponse.data?.run { bufferedReader().use(Reader::readText) }
|
||||
Timber.e("Received WebView HTTP %d error: %s", errorResponse.statusCode, errorMessage)
|
||||
|
||||
if (request.url == Uri.parse(instanceUrl))
|
||||
runOnUiThread { onErrorReceived() }
|
||||
if (request.url == Uri.parse(instanceUrl)) onErrorReceived()
|
||||
}
|
||||
|
||||
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceErrorCompat) {
|
||||
val description = if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_RESOURCE_ERROR_GET_DESCRIPTION)) error.description else null
|
||||
Timber.e("Received WebView error at %s: %s", request.url.toString(), description)
|
||||
if (request.url.toString() == instanceUrl)
|
||||
runOnUiThread { onErrorReceived() }
|
||||
|
||||
if (request.url.toString() == instanceUrl) onErrorReceived()
|
||||
}
|
||||
}
|
||||
webChromeClient = WebChromeClient()
|
||||
@@ -188,7 +191,7 @@ class WebViewFragment : Fragment() {
|
||||
domStorageEnabled = true
|
||||
}
|
||||
addJavascriptInterface(NativeInterface(this@WebViewFragment), "NativeInterface")
|
||||
addJavascriptInterface(NativePlayer(parentFragmentManager), "NativePlayer")
|
||||
addJavascriptInterface(NativePlayer(this@WebViewFragment), "NativePlayer")
|
||||
addJavascriptInterface(externalPlayer, "ExternalPlayer")
|
||||
|
||||
loadUrl(instanceUrl)
|
||||
@@ -199,7 +202,7 @@ class WebViewFragment : Fragment() {
|
||||
(activity as? MainActivity)?.requestNoBatteryOptimizations()
|
||||
}
|
||||
|
||||
fun onSelectServer(error: Boolean = false) {
|
||||
fun onSelectServer(error: Boolean = false) = runOnUiThread {
|
||||
val activity = activity
|
||||
if (activity != null && activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||
if (error) {
|
||||
@@ -218,6 +221,13 @@ class WebViewFragment : Fragment() {
|
||||
onSelectServer(error = true)
|
||||
}
|
||||
|
||||
override fun loadNativePlayer(args: Bundle) = runOnUiThread {
|
||||
parentFragmentManager.beginTransaction().apply {
|
||||
add<PlayerFragment>(R.id.fragment_container, args = args)
|
||||
addToBackStack(null)
|
||||
}.commit()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == Constants.HANDLE_EXTERNAL_PLAYER) {
|
||||
|
||||
Reference in New Issue
Block a user