Skip to content

Commit

Permalink
Add fullscreen option to IFramePlayerOptions (#926)
Browse files Browse the repository at this point in the history
This change exposes the fs option in the IFramePlayerOptions. When set to 1 this option causes the full screen button to show up in the IFrame Player.

This change also introduces a `FullScreenListener` that can be added to `YouTubePlayerView` in order to react to full screen event (when the user clicks the full screen button in the IFrame Player).
---------

Co-authored-by: Pierfrancesco Soffritti <soffritti.pierfrancesco@gmail.com>
  • Loading branch information
Praveen-Pable and PierfrancescoSoffritti authored Mar 14, 2023
1 parent c79f7ee commit 70dc609
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 11 deletions.
5 changes: 5 additions & 0 deletions core-sample-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:hardwareAccelerated="true"
android:label="@string/simple_example" />
<activity
android:name="com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.fullscreenExample.FullscreenExampleActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:hardwareAccelerated="true"
android:label="@string/fullscreen_example" />
<activity
android:name="com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.noLifecycleObserverExample.NoLifecycleObserverExampleActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.playlistExample.PlaylistExampleActivity;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.recyclerViewExample.RecyclerViewActivity;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.simpleExample.SimpleExampleActivity;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.fullscreenExample.FullscreenExampleActivity;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.viewPagerExample.ViewPagerActivity;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.defaultCustomUiExample.DefaultCustomUiExampleActivity;
import com.pierfrancescosoffritti.aytplayersample.R;
Expand All @@ -38,6 +39,7 @@ protected void onCreate(Bundle savedInstanceState) {

ExampleActivityDetails[] examples = new ExampleActivityDetails[]{
new ExampleActivityDetails(R.string.simple_example,null, SimpleExampleActivity.class),
new ExampleActivityDetails(R.string.fullscreen_example,null, FullscreenExampleActivity.class),
new ExampleActivityDetails(R.string.complete_example,null, CompleteExampleActivity.class),
new ExampleActivityDetails(R.string.default_custom_ui_example,null, DefaultCustomUiExampleActivity.class),
new ExampleActivityDetails(R.string.custom_ui_example,null, CustomUiActivity.class),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.pierfrancescosoffritti.androidyoutubeplayer.core.sampleapp.examples.fullscreenExample;

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

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.options.IFramePlayerOptions;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView;
import com.pierfrancescosoffritti.aytplayersample.R;

import kotlin.Unit;
import kotlin.jvm.functions.Function0;

public class FullscreenExampleActivity extends AppCompatActivity {

private YouTubePlayerView youTubePlayerView;
private FrameLayout fullScreenViewContainer;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen_example);

youTubePlayerView = findViewById(R.id.youtube_player_view);
fullScreenViewContainer = findViewById(R.id.full_screen_view_container);

IFramePlayerOptions iFramePlayerOptions = new IFramePlayerOptions.Builder()
.controls(1)
// enable full screen button
.fullscreen(1)
.build();

// we need to initialize manually in order to pass IFramePlayerOptions to the player
youTubePlayerView.setEnableAutomaticInitialization(false);

youTubePlayerView.addFullScreenListener(new FullScreenListener() {
@Override
public void onEnterFullScreen(@NonNull View fullScreenView, @NonNull Function0<Unit> 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
android:id="@+id/youtube_player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<FrameLayout
android:id="@+id/full_screen_view_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
1 change: 1 addition & 0 deletions core-sample-app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<resources>
<string name="app_name">ayp API</string>
<string name="simple_example">Simple example</string>
<string name="fullscreen_example">Fullscreen example</string>
<string name="complete_example">Complete example</string>
<string name="recycler_view_example">RecyclerView example</string>
<string name="custom_ui_example">Custom UI example</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
Original file line number Diff line number Diff line change
@@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<FullScreenListener>()

/**
* 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)

Expand Down Expand Up @@ -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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 70dc609

Please sign in to comment.