diff --git a/core-sample-app/src/main/AndroidManifest.xml b/core-sample-app/src/main/AndroidManifest.xml index f21c670f..c0e1f76b 100644 --- a/core-sample-app/src/main/AndroidManifest.xml +++ b/core-sample-app/src/main/AndroidManifest.xml @@ -85,6 +85,11 @@ android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout" android:hardwareAccelerated="true" android:label="@string/simple_example" /> + exitFullScreen) { + // the video will continue playing in fullScreenView + youTubePlayerView.setVisibility(View.GONE); + fullScreenViewContainer.setVisibility(View.VISIBLE); + fullScreenViewContainer.addView(fullScreenView); + + // optionally request landscape orientation + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + + @Override + public void onExitFullScreen() { + // the video will continue playing in the player + youTubePlayerView.setVisibility(View.VISIBLE); + fullScreenViewContainer.setVisibility(View.GONE); + fullScreenViewContainer.removeAllViews(); + + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); + } + }); + + youTubePlayerView.initialize(new AbstractYouTubePlayerListener() { + @Override + public void onReady(@NonNull YouTubePlayer youTubePlayer) { + super.onReady(youTubePlayer); + youTubePlayer.loadVideo("S0Q4gqBUs7c", 0F); + } + }, iFramePlayerOptions); + + getLifecycle().addObserver(youTubePlayerView); + } +} diff --git a/core-sample-app/src/main/res/layout/activity_fullscreen_example.xml b/core-sample-app/src/main/res/layout/activity_fullscreen_example.xml new file mode 100644 index 00000000..3f799e5b --- /dev/null +++ b/core-sample-app/src/main/res/layout/activity_fullscreen_example.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/core-sample-app/src/main/res/values/strings.xml b/core-sample-app/src/main/res/values/strings.xml index 3ebc216b..249433fe 100644 --- a/core-sample-app/src/main/res/values/strings.xml +++ b/core-sample-app/src/main/res/values/strings.xml @@ -1,6 +1,7 @@ ayp API Simple example + Fullscreen example Complete example RecyclerView example Custom UI example diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/AbstractYouTubePlayerListener.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/AbstractYouTubePlayerListener.kt index 6f6624db..6bd9daaa 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/AbstractYouTubePlayerListener.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/AbstractYouTubePlayerListener.kt @@ -1,5 +1,7 @@ package com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners +import android.view.View +import android.webkit.WebChromeClient import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/FullScreenListener.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/FullScreenListener.kt new file mode 100644 index 00000000..6b75b7de --- /dev/null +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/FullScreenListener.kt @@ -0,0 +1,31 @@ +package com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners + +import android.view.View + +/** + * Interface used to keep track of full screen events + */ +interface FullScreenListener { + /** + * Notify the host application that the player has entered full screen mode + * (the full screen button in the player UI has been clicked). + * After this call, the video will no longer be rendered in the [YouTubePlayerView], + * but will instead be rendered in [fullScreenView]. + * The host application should add this View to a container that fills the screen + * in order to actually display the video full screen. + * + * The application can explicitly exit fullscreen mode by invoking [exitFullScreen] + * (for example when the user presses the back button). + * However, the player will show its own UI to exist fullscreen. + * Regardless of how the player exits fullscreen mode, [onEnterFullScreen] will be invoked, + * signaling for the application to remove the custom View. + */ + fun onEnterFullScreen(fullScreenView: View, exitFullScreen: () -> Unit) + + /** + * Notify the host application that the player has exited full screen mode. + * The host application must hide the custom View (the View which was previously passed to + * [onEnterFullScreen]). After this call, the video will render in the player again. + */ + fun onExitFullScreen() +} \ No newline at end of file diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/YouTubePlayerListener.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/YouTubePlayerListener.kt index 1fdd7eb0..0ed37f2b 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/YouTubePlayerListener.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/listeners/YouTubePlayerListener.kt @@ -1,5 +1,7 @@ package com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners +import android.view.View +import android.webkit.WebChromeClient import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/options/IFramePlayerOptions.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/options/IFramePlayerOptions.kt index a4ee1b05..e948e9f7 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/options/IFramePlayerOptions.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/options/IFramePlayerOptions.kt @@ -161,6 +161,16 @@ class IFramePlayerOptions private constructor(private val playerOptions: JSONObj return this } + /** + * Setting this parameter to 0 prevents the fullscreen button from displaying in the player. + * See original documentation for more info: https://developers.google.com/youtube/player_parameters#Parameters + * @param fs if set to 1: the player fullscreen button will be show. If set to 0: the player fullscreen button will not be shown. + */ + fun fullscreen(fs: Int): Builder { + addInt(FS, fs) + return this + } + private fun addString(key: String, value: String) { try { builderOptions.put(key, value) diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/LegacyYouTubePlayerView.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/LegacyYouTubePlayerView.kt index a2f05729..065cdb8e 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/LegacyYouTubePlayerView.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/LegacyYouTubePlayerView.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.OnLifecycleEvent import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.FullScreenListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerCallback import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions @@ -23,13 +24,16 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.Playbac * Legacy internal implementation of YouTubePlayerView. The user facing YouTubePlayerView delegates * most of its actions to this one. */ -internal class LegacyYouTubePlayerView(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): - SixteenByNineFrameLayout(context, attrs, defStyleAttr), LifecycleObserver { +internal class LegacyYouTubePlayerView( + context: Context, + listener: FullScreenListener, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +): SixteenByNineFrameLayout(context, attrs, defStyleAttr), LifecycleObserver { - constructor(context: Context): this(context, null, 0) - constructor(context: Context, attrs: AttributeSet? = null): this(context, attrs, 0) + constructor(context: Context): this(context, FakeWebViewYouTubeListener,null, 0) - internal val youTubePlayer: WebViewYouTubePlayer = WebViewYouTubePlayer(context) + internal val youTubePlayer: WebViewYouTubePlayer = WebViewYouTubePlayer(context, listener) private val networkListener = NetworkListener() private val playbackResumer = PlaybackResumer() diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/WebViewYouTubePlayer.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/WebViewYouTubePlayer.kt index 205b9d25..a2d683a2 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/WebViewYouTubePlayer.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/WebViewYouTubePlayer.kt @@ -14,17 +14,33 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.R import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayerBridge +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.FullScreenListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.toFloat import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.Utils import java.util.* + +internal object FakeWebViewYouTubeListener : FullScreenListener { + override fun onEnterFullScreen(fullScreenView: View, exitFullScreen: () -> Unit) { } + override fun onExitFullScreen() { } +} + /** * WebView implementation of [YouTubePlayer]. The player runs inside the WebView, using the IFrame Player API. */ -internal class WebViewYouTubePlayer constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) - : WebView(context, attrs, defStyleAttr), YouTubePlayer, YouTubePlayerBridge.YouTubePlayerBridgeCallbacks { +internal class WebViewYouTubePlayer constructor( + context: Context, + private val listener: FullScreenListener, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : WebView(context, attrs, defStyleAttr), + YouTubePlayer, + YouTubePlayerBridge.YouTubePlayerBridgeCallbacks { + + /** Constructor used by tools */ + constructor(context: Context) : this(context, FakeWebViewYouTubeListener) private lateinit var youTubePlayerInitListener: (YouTubePlayer) -> Unit @@ -114,6 +130,17 @@ internal class WebViewYouTubePlayer constructor(context: Context, attrs: Attribu // if the video's thumbnail is not in memory, show a black screen webChromeClient = object : WebChromeClient() { + + override fun onShowCustomView(view: View, callback: CustomViewCallback) { + super.onShowCustomView(view, callback) + listener.onEnterFullScreen(view) { callback.onCustomViewHidden() } + } + + override fun onHideCustomView() { + super.onHideCustomView() + listener.onExitFullScreen() + } + override fun getDefaultVideoPoster(): Bitmap? { val result = super.getDefaultVideoPoster() diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/YouTubePlayerView.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/YouTubePlayerView.kt index 3f66919d..468cd07c 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/YouTubePlayerView.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/player/views/YouTubePlayerView.kt @@ -4,6 +4,8 @@ import android.content.Context import android.util.AttributeSet import android.view.View import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams +import android.widget.FrameLayout import androidx.annotation.LayoutRes import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver @@ -13,22 +15,50 @@ import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerCallback import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener +import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.* import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.options.IFramePlayerOptions import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.loadOrCueVideo -class YouTubePlayerView(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): - SixteenByNineFrameLayout(context, attrs, defStyleAttr), LifecycleObserver { +private val matchParent get() = FrameLayout.LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT +) + +class YouTubePlayerView( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : SixteenByNineFrameLayout(context, attrs, defStyleAttr), LifecycleObserver { constructor(context: Context): this(context, null, 0) constructor(context: Context, attrs: AttributeSet? = null): this(context, attrs, 0) - private val legacyTubePlayerView: LegacyYouTubePlayerView = LegacyYouTubePlayerView(context) + private val fullScreenListeners = mutableListOf() + + /** + * A single [FullScreenListener] that is always added to the WebView, + * responsible for calling all optional listeners added from clients of the library. + */ + private val webViewFullScreenListener = object : FullScreenListener { + override fun onEnterFullScreen(fullScreenView: View, exitFullScreen: () -> Unit) { + fullScreenListeners.forEach { it.onEnterFullScreen(fullScreenView, exitFullScreen) } + } + + override fun onExitFullScreen() { + fullScreenListeners.forEach { it.onExitFullScreen() } + } + } + + private val legacyTubePlayerView = LegacyYouTubePlayerView( + context, + webViewFullScreenListener + ) // this is a publicly accessible API var enableAutomaticInitialization: Boolean init { - addView(legacyTubePlayerView, LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) + addView(legacyTubePlayerView, matchParent) val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.YouTubePlayerView, 0, 0) @@ -145,6 +175,10 @@ class YouTubePlayerView(context: Context, attrs: AttributeSet? = null, defStyleA fun removeYouTubePlayerListener(youTubePlayerListener: YouTubePlayerListener) = legacyTubePlayerView.youTubePlayer.removeListener(youTubePlayerListener) + fun addFullScreenListener(fullScreenListener: FullScreenListener) = fullScreenListeners.add(fullScreenListener) + + fun removeFullScreenListener(fullScreenListener: FullScreenListener) = fullScreenListeners.remove(fullScreenListener) + /** * Convenience method to set the [YouTubePlayerView] width and height to match parent. */ diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/utils/FadeViewHelper.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/utils/FadeViewHelper.kt index 943c6c28..af98bbc5 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/utils/FadeViewHelper.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/utils/FadeViewHelper.kt @@ -2,6 +2,7 @@ package com.pierfrancescosoffritti.androidyoutubeplayer.core.ui.utils import android.animation.Animator import android.view.View +import android.webkit.WebChromeClient import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener diff --git a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/views/YouTubePlayerSeekBar.kt b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/views/YouTubePlayerSeekBar.kt index 12362607..1ad56bea 100644 --- a/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/views/YouTubePlayerSeekBar.kt +++ b/core/src/main/java/com/pierfrancescosoffritti/androidyoutubeplayer/core/ui/views/YouTubePlayerSeekBar.kt @@ -4,6 +4,8 @@ import android.content.Context import android.util.AttributeSet import android.util.TypedValue import android.view.Gravity +import android.view.View +import android.webkit.WebChromeClient import android.widget.LinearLayout import android.widget.SeekBar import android.widget.TextView