Bolek.N
Bolek.N

Reputation: 81

How to play Youtube Video in a Fragment in ViewPager, Android

Now I am trying to play Youtube video in a fragment of ViewPager using YouTubePlayerSupportFragment. I am using SmartFragmentStatePagerAdapter as a viewpager adapter. But I got this error :

W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.support.v4.view.ViewPager{41a53898 VFED.... ......I. 0,84-480,730 #7f0c00b8 app:id/viewPager}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: 480, top: 0, right: -480, bottom: 376 (these should all be positive).

How can I solve this issue. Regards

This is FragmentPageAdapter code

public class VideoPagerAdapter extends SmartFragmentStatePagerAdapter 

{
    private UserInfo usrInfo;

public VideoPagerAdapter(FragmentManager fragmentManager, UserInfo userInfo){
    super(fragmentManager);
    usrInfo = userInfo;
}

@Override
public Fragment getItem(int position) {
    VideoDetailFragment videoDetailFragment = new VideoDetailFragment();
    videoDetailFragment.video = usrInfo.videoList.get(position);
    return videoDetailFragment;
}

@Override
public int getCount() {
    return usrInfo.videoList.size();
}

}

and I have implemented code in VideoDetailFragment.

private YouTubePlayer mYoutubePlayer;
private YouTubePlayerSupportFragment mYoutubeFragment;

private void initYoutubeVideo(){
    mYoutubeFragment = YouTubePlayerSupportFragment.newInstance();
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    transaction.replace(R.id.youtube_layout, mYoutubeFragment).commit();

    mYoutubeFragment.initialize(DEVELOPER_KEY, this);
}

@Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
    mYoutubePlayer = youTubePlayer;
    if (!b){
        youTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.DEFAULT);
        youTubePlayer.loadVideo(VIDEO_ID);
    }
}



@Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
    Log.d(TAG, "*** Youtube Player error : " + youTubeInitializationResult.toString());
    String errorMessage = String.format(getString(R.string.error_youtube_player), youTubeInitializationResult.toString());

    Utils.showAlert(mActivity, errorMessage);
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (!isVisibleToUser && mYoutubePlayer != null) {
        mYoutubePlayer.release();
    }
    if (isVisibleToUser && mYoutubeFragment != null) {
        mYoutubeFragment.initialize(DEVELOPER_KEY, this);
    }
}

and I have tested it in real device

06-08 19:02:47.012 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.082 2562-2562/com.videofeed.tickit D/dalvikvm: DexOpt: couldn't find field Landroid/view/accessibility/CaptioningManager$CaptionStyle;.windowColor
06-08 19:02:47.082 2562-2562/com.videofeed.tickit W/dalvikvm: VFY: unable to resolve instance field 10579
06-08 19:02:47.082 2562-2562/com.videofeed.tickit D/dalvikvm: VFY: replacing opcode 0x52 at 0x0019
06-08 19:02:47.082 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@41fd4d28 helper:Lazy@41fd5898 view:null status: ...... {...}
06-08 19:02:47.372 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.442 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@42c9fe20 helper:Lazy@42c9fe98 view:null status: ...... {...}
06-08 19:02:47.462 2562-2562/com.videofeed.tickit I/Choreographer: Skipped 40 frames!  The application may be doing too much work on its main thread.
06-08 19:02:47.602 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Cannot load modern controls UI. Upgrade to the latest version of the Android YouTube API.
06-08 19:02:47.692 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: Forcefully created overlay:vtd@42d8f2a8 helper:Lazy@42d8f320 view:null status: ...... {...}
06-08 19:02:51.912 2562-2604/com.videofeed.tickit D/dalvikvm: GC_FOR_ALLOC freed 15971K, 69% free 7899K/25052K, paused 35ms, total 37ms
06-08 19:02:58.202 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.support.v4.view.ViewPager{42c4a610 VFED.... ......ID 0,84-480,730 #7f0c00b8 app:id/viewPager}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: -480, top: 0, right: 480, bottom: 376 (these should all be positive).
06-08 19:02:58.222 2562-2562/com.videofeed.tickit W/YouTubeAndroidPlayerAPI: YouTube video playback stopped due to unauthorized overlay on top of player. The YouTubePlayerView is not contained inside its ancestor android.support.v4.view.ViewPager{42c4a610 VFED.... ......ID 0,84-480,730 #7f0c00b8 app:id/viewPager}. The distances between the ancestor's edges and that of the YouTubePlayerView is: left: 480, top: 0, right: -480, bottom: 376 (these should all be positive).

this is log in Android studio. I have attached the screenshots. This is the screenshot

Upvotes: 1

Views: 3447

Answers (3)

Amrinder Singh
Amrinder Singh

Reputation: 79

It's not possible. Because YouTubePlayerView requires its activity to extend YoutubeBaseActivity. YouTubePlayerView provides limited functionality.

Upvotes: 1

Ishant Periwal
Ishant Periwal

Reputation: 1

So basically, the problem is that one of your videos is being loaded outside the visible screen causing the error of overlay. In the case of a viewpager, the already loaded pages also load the video but those videos are not on screen causing the error.

SOLUTION (for viewpager): Load one video at a time, i.e. the video to be played. Do this by loading the video whenever the page is visible.

Upvotes: 0

Balder Lai
Balder Lai

Reputation: 11

This answer maybe to late, but I found a possible solution.

I' run into similar problem, I also try to play multiple videos in viewpager. If there's only one youtube fragment in viewpager, and it's ok, but when there's more then one, video won't play, and show that error message

YouTube video playback stopped due to unauthorized overlay on top of player.

First "unauthorized overlay" is not come from my current fragment which is on the visible page of view pager. it come from the page that view pager create "next" to the current fragment.

View pager create pages before they are slide into visible window, so the youtube fragment are create before it is visible, and if you initialize that fragment, then youtube player detect that strange overlay error and stop the video, and the youtube player stop, even stop the video which is showing normally in the visible page.

In your case, you can see the error message

left: 480, top: 0, right: -480, bottom: 376

which the negative number is a window wide, so it's probability same as the issue I got.

So my solution

1. No't initialize the youtube at onCreate(), don't do the initialize before that fragment is the visible of the viewpager.

in my case, I use a interface between adapter and fragment, and in the parent page of the viewpager, add a OnPageChangeListener to viewpager, youtube fragment only initialize after viewpager's page is change to that youtube fragment.

page change > notify adapter > interface > youtubefragment > start initialize

After first step, first video should play normally even if there's 2 or more youtube fragment in viewpager, but when I swipe to 2nd page, video won't play and show the same error, so move to 2nd step

2. release youtube player when youtube fragment is slide to invisible part of view pager

the reason of 2nd video not playing is same, first page has a youtubeplayer and it out side the visible range, and it got an error message, which stop all youtubeplayer for a reason I don'y know why.

I use the same interface, when page is changed. adapter will use the interface to notify the youtube fragment which is slide away, to release youtubeplayer, and the interface implement like this, which mPlayer will be the youtubeplayer return by initialize method.

      mInitializeListener = new InitializeListener() {
        @Override
        public void startVideo() {
            initialize();
        }

        @Override
        public void stopVideo() {
                mPlayer.release();
        }
    };

there's still some questions I can't answer, like why youtubeplayer in one pager will effect others..?

but when I did the changes at my adapter and fragment, youtube video can play normally, hope this helps you

below are codes I use in my app

    MediaFragmentViewPager adapter =
        new MediaFragmentViewPager(getChildFragmentManager(), getActivity(), true);
List<MediaData> mediaDataList = new ArrayList<>();

adapter.setmResources(mediaDataList);

imageViewPager.setAdapter(adapter);

ViewPager.OnPageChangeListener pagerchangeListener = new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }
    @Override
    public void onPageSelected(int position) {
        adapter.onPageChanged(position);
    }
    @Override
    public void onPageScrollStateChanged(int state) {

    }
};

imageViewPager.addOnPageChangeListener(pagerchangeListener);
pagerchangeListener.onPageSelected(0);

circlePageIndicator.setFillColor(getResources().getColor(R.color.colorAccent));
circlePageIndicator.setViewPager(imageViewPager);

Adapter

public class MediaFragmentViewPager  extends FragmentStatePagerAdapter
        implements MediaYoutubeFragment.MediaFullScreenListener {

    protected List<MediaData> mResources;
    private String apiKey = "your apiKey";
    protected Map<Integer, MediaYoutubeFragment.InitializeListener> listenerMap = new HashMap<>();
    private Context context;

    private boolean isFullScreen;

    public MediaFragmentViewPager(FragmentManager fm, Context context, boolean isFullScreen) {
        super(fm);
        this.context = context;
        this.isFullScreen = isFullScreen;
    }

    public int currentPosition = -1;


    @Override
    public void startFullScreen() {
        if (!isFullScreen){
            MediaViewPagerActivity.startActivity(context, itemID, companyId, currentPosition);
        }
    }

    @Override
    public Fragment getItem(int position) {

        if(mResources.get(position).isImage == true){
            Log.i("tag3", "getItem image" + String.valueOf(position));
            MediaImageFragment imageFragment = new MediaImageFragment();
            imageFragment.setImageUrl(mResources.get(position).getImageResource().getImage1080p());
            return  imageFragment;
        } else {
            Log.i("tag3", "getItem video" + String.valueOf(position));
            MediaYoutubeFragment youTubePlayerSupportFragment =
                    MediaYoutubeFragment.newInstance(mResources.get(position).getYoutubeUrl(), this);
            listenerMap.put(position, youTubePlayerSupportFragment.getmInitializeListener());
            return youTubePlayerSupportFragment;
        }
    }

    public void onPageChanged(int position){
        // current page it not null, realse youtubeplayer.
        if(currentPosition != -1){
            if(listenerMap.get(currentPosition) != null){
                listenerMap.get(currentPosition).stopVideo();
            }
        }
        // update current position
        currentPosition = position;
        Log.i("tag3", "onPageSelected " + String.valueOf(position));

        //start loading video
        MediaYoutubeFragment.InitializeListener listener = listenerMap.get(position);
        if(listener != null){
            Log.i("tag3", "startVideo " + String.valueOf(position));
            listener.startVideo();
        } else {
            Log.i("tag3", "startVideo listener is null " + String.valueOf(position));
        }
    }

    @Override
    public int getCount() {
        return mResources.size();
    }

    public List<MediaData> getmResources() {
        return mResources;
    }

    public void setmResources(List<MediaData> mResources) {
        this.mResources = mResources;
    }


}

Youtube Fragment

public class MediaYoutubeFragment extends YouTubePlayerSupportFragment
        implements YouTubePlayer.OnInitializedListener, YouTubePlayer.OnFullscreenListener {
    private static final String KEY_VIDEO_ID = "VIDEO_ID";

    public String apiKey = "yor apiKey";
    private String mVideoId;
    private YouTubePlayer mPlayer;
    boolean mIsFullScreen;
    private InitializeListener mInitializeListener;
    private MediaFullScreenListener fullScreenListener;

    public InitializeListener getmInitializeListener() {
        return mInitializeListener;
    }

    public void setmInitializeListener(InitializeListener mInitializeListener) {
        this.mInitializeListener = mInitializeListener;
    }

    public void setFullScreenListener(MediaFullScreenListener fullScreenListener) {
        this.fullScreenListener = fullScreenListener;
    }

    public interface MediaFullScreenListener{
        void startFullScreen();
    }

    public interface InitializeListener{
        void startVideo();
        void stopVideo();
    }

    public MediaYoutubeFragment(){
        super();
        mInitializeListener = new InitializeListener() {
            @Override
            public void startVideo() {
                initialize();
            }

            @Override
            public void stopVideo() {
                if (mPlayer != null){
                    mPlayer.release();
                }
            }
        };
    }

    private void initialize() {
        initialize(apiKey, this);
    }

    public static MediaYoutubeFragment newInstance(String videoId, MediaFullScreenListener listener) {
        MediaYoutubeFragment frag = new MediaYoutubeFragment();

        Bundle args = new Bundle();
        args.putString(KEY_VIDEO_ID, videoId);

        frag.setArguments(args);
        frag.setFullScreenListener(listener);
        return frag;
    }

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        if (getArguments() != null) {
            mVideoId = getArguments().getString(KEY_VIDEO_ID);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
     }

    @Override
    public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
        mPlayer = youTubePlayer;

        mPlayer.setFullscreenControlFlags(FULLSCREEN_FLAG_CUSTOM_LAYOUT);
        mPlayer.setOnFullscreenListener(this);
        mPlayer.setFullscreen(false);
        mPlayer.setShowFullscreenButton(true);

        if (!wasRestored) {
            // load your video
            mPlayer.loadVideo(mVideoId);
        }
        else
        {
            mPlayer.play();
        }
    }

    @Override
    public void onInitializationFailure(YouTubePlayer.Provider provider,
                                        YouTubeInitializationResult youTubeInitializationResult) {

    }

    @Override
    public void onFullscreen(boolean fullscreen) {
        Log.i("tag3", "onFullscreen" + String.valueOf(fullscreen));
        mPlayer.setFullscreen(false);
        fullScreenListener.startFullScreen();
    }

}

I also handle full screen event with my own activity, and this viewpager contents not only youtube video, but also picture, so please ignore those part.

because I use view pager in fragment, so I use getChildFragmentManger, and I also use this adapter in Activity, but It creates another problem, that first video won't play at the first time viewpager isload , because the listener is call before getItem() in the adapter, So I made some changes that if adapter is first load(first youtube page is load at first time), listener will be call right after getItem return the fragment, other's are all the same.

Upvotes: 0

Related Questions