Chore/rework fullscreen configuration (#4142)

* feat(android): handle navigation bar status in full-screen mode
* chore: update default value of prop
* chore(android): rework fullscreen configuration

---------

Co-authored-by: mostafahasani <seyedmostafahassani@gmail.com>
This commit is contained in:
Olivier Bouillet
2024-09-04 09:53:30 +02:00
committed by GitHub
parent d6bae3cd07
commit 9707081ab9
9 changed files with 141 additions and 23 deletions

View File

@@ -6,11 +6,16 @@ import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageButton
import androidx.activity.OnBackPressedCallback
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.media3.ui.LegacyPlayerControlView
import com.brentvatne.common.api.ControlsConfig
import com.brentvatne.common.toolbox.DebugLog
import java.lang.ref.WeakReference
@@ -20,14 +25,22 @@ class FullScreenPlayerView(
private val exoPlayerView: ExoPlayerView,
private val reactExoplayerView: ReactExoplayerView,
private val playerControlView: LegacyPlayerControlView?,
private val onBackPressedCallback: OnBackPressedCallback
) : Dialog(context, android.R.style.Theme_Black_NoTitleBar_Fullscreen) {
private val onBackPressedCallback: OnBackPressedCallback,
private val controlsConfig: ControlsConfig
) : Dialog(context, android.R.style.Theme_Black_NoTitleBar) {
private var parent: ViewGroup? = null
private val containerView = FrameLayout(context)
private val mKeepScreenOnHandler = Handler(Looper.getMainLooper())
private val mKeepScreenOnUpdater = KeepScreenOnUpdater(this)
// As this view is fullscreen we need to save initial state and restore it afterward
// Following variables save UI state when open the view
// restoreUIState, will reapply these values
private var initialSystemBarsBehavior: Int? = null
private var initialNavigationBarIsVisible: Boolean? = null
private var initialNotificationBarIsVisible: Boolean? = null
private class KeepScreenOnUpdater(fullScreenPlayerView: FullScreenPlayerView) : Runnable {
private val mFullscreenPlayer = WeakReference(fullScreenPlayerView)
@@ -59,6 +72,15 @@ class FullScreenPlayerView(
init {
setContentView(containerView, generateDefaultLayoutParams())
window?.let {
val inset = WindowInsetsControllerCompat(it, it.decorView)
initialSystemBarsBehavior = inset.systemBarsBehavior
initialNavigationBarIsVisible = ViewCompat.getRootWindowInsets(it.decorView)
?.isVisible(WindowInsetsCompat.Type.navigationBars()) == true
initialNotificationBarIsVisible = ViewCompat.getRootWindowInsets(it.decorView)
?.isVisible(WindowInsetsCompat.Type.statusBars()) == true
}
}
override fun onBackPressed() {
super.onBackPressed()
@@ -75,6 +97,7 @@ class FullScreenPlayerView(
parent?.removeView(it)
containerView.addView(it, generateDefaultLayoutParams())
}
updateNavigationBarVisibility()
}
override fun onStop() {
@@ -89,6 +112,19 @@ class FullScreenPlayerView(
}
parent?.requestLayout()
parent = null
restoreSystemUI()
}
// restore system UI state
private fun restoreSystemUI() {
window?.let {
updateNavigationBarVisibility(
it,
initialNavigationBarIsVisible,
initialNotificationBarIsVisible,
initialSystemBarsBehavior
)
}
}
private fun getFullscreenIconResource(isFullscreen: Boolean): Int =
@@ -127,4 +163,61 @@ class FullScreenPlayerView(
layoutParams.setMargins(0, 0, 0, 0)
return layoutParams
}
private fun updateBarVisibility(
inset: WindowInsetsControllerCompat,
type: Int,
shouldHide: Boolean?,
initialVisibility: Boolean?,
systemBarsBehavior: Int? = null
) {
shouldHide?.takeIf { it != initialVisibility }?.let {
if (it) {
inset.hide(type)
systemBarsBehavior?.let { behavior -> inset.systemBarsBehavior = behavior }
} else {
inset.show(type)
}
}
}
// Move the UI to fullscreen.
// if you change this code, remember to check that the UI is well restored in restoreUIState
private fun updateNavigationBarVisibility(
window: Window,
hideNavigationBarOnFullScreenMode: Boolean?,
hideNotificationBarOnFullScreenMode: Boolean?,
systemBarsBehavior: Int?
) {
// Configure the behavior of the hidden system bars.
val inset = WindowInsetsControllerCompat(window, window.decorView)
// Update navigation bar visibility and apply systemBarsBehavior if hiding
updateBarVisibility(
inset,
WindowInsetsCompat.Type.navigationBars(),
hideNavigationBarOnFullScreenMode,
initialNavigationBarIsVisible,
systemBarsBehavior
)
// Update notification bar visibility (no need for systemBarsBehavior here)
updateBarVisibility(
inset,
WindowInsetsCompat.Type.statusBars(),
hideNotificationBarOnFullScreenMode,
initialNotificationBarIsVisible
)
}
private fun updateNavigationBarVisibility() {
window?.let {
updateNavigationBarVisibility(
it,
controlsConfig.hideNavigationBarOnFullScreenMode,
controlsConfig.hideNotificationBarOnFullScreenMode,
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
)
}
}
}

View File

@@ -427,15 +427,6 @@ public class ReactExoplayerView extends FrameLayout implements
});
}
if (fullScreenPlayerView == null) {
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, this, playerControlView, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setFullscreen(false);
}
});
}
// Setting the player for the playerControlView
playerControlView.setPlayer(player);
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
@@ -2261,6 +2252,12 @@ public class ReactExoplayerView extends FrameLayout implements
}
if (isFullscreen) {
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, this, playerControlView, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setFullscreen(false);
}
}, controlsConfig);
eventEmitter.onVideoFullscreenPlayerWillPresent.invoke();
if (fullScreenPlayerView != null) {
fullScreenPlayerView.show();
@@ -2383,4 +2380,4 @@ public class ReactExoplayerView extends FrameLayout implements
controlsConfig = controlsStyles;
refreshProgressBarVisibility();
}
}
}