2023-01-22 16:48:14 +01:00
package app.fedilab.android.peertube.webview ;
2023-01-24 15:09:21 +01:00
/ * Copyright 2023 Thomas Schneider
2023-01-22 16:48:14 +01:00
*
2023-01-24 15:09:21 +01:00
* This file is a part of Fedilab
2023-01-22 16:48:14 +01:00
*
* This program is free software ; you can redistribute it and / or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation ; either version 3 of the
* License , or ( at your option ) any later version .
*
2023-01-24 15:09:21 +01:00
* Fedilab is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even
2023-01-22 16:48:14 +01:00
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General
* Public License for more details .
*
2023-01-24 15:09:21 +01:00
* You should have received a copy of the GNU General Public License along with Fedilab ; if not ,
2023-01-22 16:48:14 +01:00
* see < http : //www.gnu.org/licenses>. */
import android.app.Activity ;
import android.graphics.Bitmap ;
import android.media.MediaPlayer ;
import android.view.LayoutInflater ;
import android.view.SurfaceView ;
import android.view.View ;
import android.view.ViewGroup ;
import android.webkit.WebChromeClient ;
import android.webkit.WebView ;
import android.widget.FrameLayout ;
import android.widget.ImageView ;
import android.widget.LinearLayout ;
import android.widget.ProgressBar ;
import android.widget.TextView ;
import androidx.appcompat.app.ActionBar ;
import androidx.appcompat.app.AppCompatActivity ;
2023-01-23 09:31:32 +01:00
import app.fedilab.android.R ;
2023-01-22 16:48:14 +01:00
public class MastalabWebChromeClient extends WebChromeClient implements MediaPlayer . OnCompletionListener , MediaPlayer . OnErrorListener {
2023-01-23 18:06:25 +01:00
private final WebView webView ;
2023-01-22 16:48:14 +01:00
private final View activityNonVideoView ;
private final ViewGroup activityVideoView ;
private final ProgressBar pbar ;
private final Activity activity ;
private FrameLayout videoViewContainer ;
private CustomViewCallback videoViewCallback ;
private ToggledFullscreenCallback toggledFullscreenCallback ;
private boolean isVideoFullscreen ;
2023-01-23 18:06:25 +01:00
public MastalabWebChromeClient ( Activity activity , WebView webView , FrameLayout activityNonVideoView , ViewGroup activityVideoView ) {
2023-01-22 16:48:14 +01:00
this . activity = activity ;
this . isVideoFullscreen = false ;
this . webView = webView ;
this . pbar = activity . findViewById ( R . id . progress_bar ) ;
this . activityNonVideoView = activityNonVideoView ;
this . activityVideoView = activityVideoView ;
}
@Override
public void onProgressChanged ( WebView view , int progress ) {
if ( pbar ! = null ) {
if ( progress < 100 & & pbar . getVisibility ( ) = = ProgressBar . GONE ) {
pbar . setVisibility ( ProgressBar . VISIBLE ) ;
}
pbar . setProgress ( progress ) ;
if ( progress = = 100 ) {
pbar . setVisibility ( ProgressBar . GONE ) ;
}
}
}
@Override
public Bitmap getDefaultVideoPoster ( ) {
return Bitmap . createBitmap ( 50 , 50 , Bitmap . Config . ARGB_8888 ) ;
}
@Override
public void onReceivedIcon ( WebView view , Bitmap icon ) {
super . onReceivedIcon ( view , icon ) ;
LayoutInflater mInflater = LayoutInflater . from ( activity ) ;
ActionBar actionBar = ( ( AppCompatActivity ) activity ) . getSupportActionBar ( ) ;
if ( actionBar ! = null ) {
View webview_actionbar = mInflater . inflate ( R . layout . webview_actionbar , new LinearLayout ( activity ) , false ) ;
TextView webview_title = webview_actionbar . findViewById ( R . id . webview_title ) ;
webview_title . setText ( view . getTitle ( ) ) ;
ImageView webview_favicon = webview_actionbar . findViewById ( R . id . webview_favicon ) ;
if ( icon ! = null )
webview_favicon . setImageBitmap ( icon ) ;
actionBar . setCustomView ( webview_actionbar ) ;
actionBar . setDisplayShowCustomEnabled ( true ) ;
} else {
activity . setTitle ( view . getTitle ( ) ) ;
}
}
/ * *
* Set a callback that will be fired when the video starts or finishes displaying using a custom view ( typically full - screen )
*
* @param callback A VideoEnabledWebChromeClient . ToggledFullscreenCallback callback
* /
public void setOnToggledFullscreen ( ToggledFullscreenCallback callback ) {
this . toggledFullscreenCallback = callback ;
}
//FULLSCREEN VIDEO
//Code from https://stackoverflow.com/a/16179544/3197259
@Override
public void onShowCustomView ( View view , CustomViewCallback callback ) {
2024-01-09 16:00:35 +01:00
if ( view instanceof FrameLayout frameLayout ) {
2023-01-22 16:48:14 +01:00
if ( ( ( AppCompatActivity ) activity ) . getSupportActionBar ( ) ! = null )
( ( AppCompatActivity ) activity ) . getSupportActionBar ( ) . hide ( ) ;
// A video wants to be shown
View focusedChild = frameLayout . getFocusedChild ( ) ;
// Save video related variables
isVideoFullscreen = true ;
this . videoViewContainer = frameLayout ;
this . videoViewCallback = callback ;
// Hide the non-video view, add the video view, and show it
activityNonVideoView . setVisibility ( View . INVISIBLE ) ;
activityVideoView . addView ( videoViewContainer , new ViewGroup . LayoutParams ( ViewGroup . LayoutParams . MATCH_PARENT , ViewGroup . LayoutParams . MATCH_PARENT ) ) ;
activityVideoView . setVisibility ( View . VISIBLE ) ;
2024-01-09 16:00:35 +01:00
if ( focusedChild instanceof android . widget . VideoView videoView ) {
2023-01-22 16:48:14 +01:00
// android.widget.VideoView (typically API level <11)
// Handle all the required events
videoView . setOnCompletionListener ( this ) ;
videoView . setOnErrorListener ( this ) ;
} else {
// Other classes, including:
// - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 11-18)
// - android.webkit.HTML5VideoFullScreen$VideoTextureView, which inherits from android.view.TextureView (typically API level 11-18)
// - com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView, which inherits from android.view.SurfaceView (typically API level 19+)
// Handle HTML5 video ended event only if the class is a SurfaceView
// Test case: TextureView of Sony Xperia T API level 16 doesn't work fullscreen when loading the javascript below
if ( webView ! = null & & webView . getSettings ( ) . getJavaScriptEnabled ( ) & & focusedChild instanceof SurfaceView ) {
// Run javascript code that detects the video end and notifies the Javascript interface
String js = " javascript: " ;
js + = " var _ytrp_html5_video_last; " ;
js + = " var _ytrp_html5_video = document.getElementsByTagName('video')[0]; " ;
js + = " if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) { " ;
{
js + = " _ytrp_html5_video_last = _ytrp_html5_video; " ;
js + = " function _ytrp_html5_video_ended() { " ;
{
js + = " _VideoEnabledWebView.notifyVideoEnd(); " ; // Must match Javascript interface name and method of VideoEnableWebView
}
js + = " } " ;
js + = " _ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended); " ;
}
js + = " } " ;
webView . loadUrl ( js ) ;
}
}
// Notify full-screen change
if ( toggledFullscreenCallback ! = null ) {
toggledFullscreenCallback . toggledFullscreen ( true ) ;
}
}
}
// Available in API level 14+, deprecated in API level 18+
@Override
@SuppressWarnings ( " deprecation " )
public void onShowCustomView ( View view , int requestedOrientation , CustomViewCallback callback ) {
onShowCustomView ( view , callback ) ;
}
@Override
public void onHideCustomView ( ) {
if ( ( ( AppCompatActivity ) activity ) . getSupportActionBar ( ) ! = null )
( ( AppCompatActivity ) activity ) . getSupportActionBar ( ) . show ( ) ;
// This method should be manually called on video end in all cases because it's not always called automatically.
// This method must be manually called on back key press (from this class' onBackPressed() method).
if ( isVideoFullscreen ) {
// Hide the video view, remove it, and show the non-video view
activityVideoView . setVisibility ( View . INVISIBLE ) ;
activityVideoView . removeView ( videoViewContainer ) ;
activityNonVideoView . setVisibility ( View . VISIBLE ) ;
// Call back (only in API level <19, because in API level 19+ with chromium webview it crashes)
if ( videoViewCallback ! = null & & ! videoViewCallback . getClass ( ) . getName ( ) . contains ( " .chromium. " ) ) {
videoViewCallback . onCustomViewHidden ( ) ;
}
// Reset video related variables
isVideoFullscreen = false ;
videoViewContainer = null ;
videoViewCallback = null ;
// Notify full-screen change
if ( toggledFullscreenCallback ! = null ) {
toggledFullscreenCallback . toggledFullscreen ( false ) ;
}
}
}
// Video will start loading
@Override
public View getVideoLoadingProgressView ( ) {
return super . getVideoLoadingProgressView ( ) ;
}
// Video finished playing, only called in the case of android.widget.VideoView (typically API level <11)
@Override
public void onCompletion ( MediaPlayer mp ) {
onHideCustomView ( ) ;
}
// Error while playing video, only called in the case of android.widget.VideoView (typically API level <11)
@Override
public boolean onError ( MediaPlayer mp , int what , int extra ) {
return false ; // By returning false, onCompletion() will be called
}
public interface ToggledFullscreenCallback {
void toggledFullscreen ( boolean fullscreen ) ;
}
}