Package com.imaginato.qravedconsumer.widget.player; Import Android.annotation.SuppressLint; Import android.app.Activity; Import Android.content.Context; Import android.content.Intent; Import Android.net.Uri; Import Android.os.Build; Import Android.util.AttributeSet; Import Android.util.DisplayMetrics; Import Android.util.Log; Import Android.view.View; Import Android.webkit.JavascriptInterface; Import android.webkit.WebChromeClient; Import android.webkit.WebSettings; Import Android.webkit.WebView; Import android.webkit.WebViewClient; Import COM.QRAVED.APP.R; Import Java.io.BufferedReader; Import Java.io.InputStream; Import Java.io.InputStreamReader; Import java.lang.ref.WeakReference; Import Java.lang.reflect.Field; public class Youtubeplayerview extends WebView { private static final String TAG = YoutubePlayerView.class.getSimpleName (); Private Qualsonbridge bridge = new Qualsonbridge (); Private Ytparams params = new Ytparams (); Private Youtubelistener Youtubelistener; Private String backgroundcolor = "#000000"; Private state mplaystate = state. unstarted; Public Youtubeplayerview { Super (context); Setwebviewclient (new mywebviewclient); } Public Youtubeplayerview (context context, AttributeSet Attrs) { Super (context, attrs); Setwebviewclient (new mywebviewclient); } @SuppressLint ("Javascriptinterface")
public void Initialize (String videoid, Youtubelistener Youtubelistener, webchromeclient webchromeclient) {
WebSettings set = This.getsettings ();
Set.setjavascriptenabled (TRUE);
Set.setusewideviewport (TRUE);
Set.setloadwithoverviewmode (TRUE);
Set.setlayoutalgorithm (WebSettings.LayoutAlgorithm.NORMAL);
Set.setcachemode (Websettings.load_no_cache);
Set.setpluginstate (WebSettings.PluginState.ON);
Set.setpluginstate (WebSettings.PluginState.ON_DEMAND);
Set.setallowcontentaccess (TRUE);
Set.setallowfileaccess (TRUE); if (webchromeclient!= null) { This.setwebchromeclient (webchromeclient); } This.mplaystate = state. unstarted;
This.youtubelistener = Youtubelistener;
This.setlayertype (View.layer_type_none, NULL);
This.measure (measurespec.unspecified, measurespec.unspecified);
This.addjavascriptinterface (Bridge, "qualsoninterface")//Register JS code to invoke Java code interface
This.loaddatawithbaseurl ("Https://www.youtube.com", getvideohtml (VideoID), "text/html", "Utf-8", null);
This.setlongclickable (TRUE);
This.setonlongclicklistener (New Onlongclicklistener () {
@Override
public boolean Onlongclick (View v) {
return true;
}
}); } public void Initialize (String videoid, ytparams params, Youtubelistener Youtubelistener, webchromeclient Webchromeclient) { if (params!= null) { This.params = params; } Initialize (VideoID, Youtubelistener, webchromeclient); } public void Setwhitebackgroundcolor () { BackgroundColor = "#ffffff"; } public void Setautoplayerheight (context context) { Displaymetrics displaymetrics = new Displaymetrics (); (activity) context. Getwindowmanager (). Getdefaultdisplay (). Getmetrics (Displaymetrics); this.getlayoutparams (). Height = (int) (Displaymetrics.widthpixels * 0.5625); } /** * Let WebView to execute JS code javascript:onvideopause (), to pause the video */ public void Pause () { LOG.D (TAG, "pause"); This.loadurl ("Javascript:onvideopause ()"); } /** * Let WebView to execute JS code, to stop the video */ public void Stop () { LOG.D (TAG, "stop"); This.loadurl ("Javascript:onvideostop ()"); } Public State getplayerstate () { LOG.D (TAG, "getplayerstate"); return mplaystate; } public void Play () { LOG.D (TAG, "play"); This.loadurl ("Javascript:onvideoplay ()"); } private void Notifystatechange (state state) { if (youtubelistener!=null) { Youtubelistener.onstatechange (state); } This.mplaystate = State; } /** * WEB to APP JavaScript's Android interface for deploying JS code on Android, here's a callback of JS to Android, Let JS trigger Java code * need to be in the JS code appropriate place to call this inside the method, in JS has a function as follows: * function Onplayerstatechange (Event) * and such a function * functions Onstatechange (e) { window. Qualsoninterface.onstatechange (e);//For Callback Java code } and this need to use This.addjavascriptinterface (bridge, "Qualsoninterface") in Java code; To register the */ private class Qualsonbridge { @JavascriptInterface public void Onready (String arg) { LOG.D (TAG, "onready (" + arg +) "); if (Youtubelistener!= null) { Youtubelistener.onready (); } } @JavascriptInterface
public void Onstatechange (String arg) {
LOG.D (TAG, "onstatechange (" + arg +) ");
if ("Unstarted". Equalsignorecase (Arg)) {
Notifystatechange (state. unstarted);
else if ("ENDED". Equalsignorecase (Arg)) {
Notifystatechange (state. ENDED);
else if ("PLAYING". Equalsignorecase (Arg)) {
Notifystatechange (state. PLAYING);
else if ("Paused". Equalsignorecase (Arg)) {
Notifystatechange (state. paused);
else if ("buffering". Equalsignorecase (Arg)) {
Notifystatechange (state. Buffering);
else if ("cued". Equalsignorecase (Arg)) {
Notifystatechange (state. cued);
}
} @JavascriptInterface public void Onplaybackqualitychange (String arg) { LOG.D (TAG, "onplaybackqualitychange (" + arg +) "); if (Youtubelistener!= null) { Youtubelistener.onplaybackqualitychange (ARG); } } @JavascriptInterface public void Onplaybackratechange (String arg) { log.d (TAG, "onplaybackratechange (" + arg +) "); if (youtubelistener!= null) { Youtubelistener.onplaybackratechange (ARG); } } @JavascriptInterface public void OnError (String arg) { log.e (TAG, "onError (" + arg + ")"); if (youtubelistener!= null) { Youtubelistener.onerror ( ARG); } } @JavascriptInterface public void Onapichange (String arg) { LOG.D (TAG, "onapichange (" + arg +) "); if (youtubelistener!= null) { Youtubelistener.onapichange (ARG); } } @JavascriptInterface public void Currentseconds (String seconds) { if (Youtubelistener!= null) { Youtubelistener.oncurrentsecond (double.parsedouble (seconds)); } } @JavascriptInterface public void duration (String seconds) { if (Youtubelistener!= null) { youtubelistener.onduration (double.parsedouble (seconds)); } } @JavascriptInterface public void logs (String arg) { LOG.D (TAG, "logs (" + arg +) "); if (Youtubelistener!= null) { Youtubelistener.logs (ARG); } } } /** * Nonleakingwebview */ private static Field Sconfigcallback; static { try { sconfigcallback = Class.forName ("Android.webkit.BrowserFrame"). Getdeclaredfield ("Sconfigcallback"); sconfigcallback.setaccessible (true); } catch (Exception e) { //Ignored } } public void OnDestroy () { Super.ondetachedfromwindow (); //View is now detached, and about to being destroyed & nbsp; youtubelistener = null; This.clearcache (true); this.clearhistory (); try { if (sconfigcallback!= null) sconfigcallback.set (null, NULL); } catch (Exception e) { throw new RuntimeException (e); } } Private class Mywebviewclient extends Webviewclient { protected weakreference<activity> activityref; Public mywebviewclient (activity activity) { This.activityref = new weakreference<activity> (activity); } @Override
public boolean shouldoverrideurlloading (webview view, String URL) {
try {
Final Activity activity = Activityref.get ();
if (activity!= null)
Activity.startactivity (New Intent (Intent.action_view, Uri.parse (URL)));
catch (RuntimeException ignored) {
Ignore any URL parsing exceptions
}
return true;
} @Override public void onpagefinished (webview view, String URL) { super.onpagefinished (view, URL); LOG.D (TAG, "onpagefinished ()"); } } Public interface Youtubelistener { void Onready ()//can display the play button to play void Onstatechange (state),/pause, etc. void Onplaybackqualitychange (String arg);//Clarity Change void Onplaybackratechange (String arg); void OnError (String arg); void Onapichange (String arg); void Oncurrentsecond (double second); void Onduration (double duration); void logs (String log); } public enum State { Unstarted, ENDED, PLAYING, Paused, Buffering, Cued, NONE } /**
* Write a piece of HTML yourself and set up YouTube video ID and put it in webview for display
* @param videoid
* @return
*/
private string getvideohtml (string videoid) {
try {
InputStream in = Getresources (). Openrawresource (R.raw.players);
if (in!= null) {
InputStreamReader stream = new InputStreamReader (in, "utf-8");
BufferedReader buffer = new BufferedReader (stream);
String Read;
StringBuilder sb = new StringBuilder (""); while (read = Buffer.readline ())!= null) { Sb.append (read + "\ n"); } In.close (); String html = sb.tostring (). replace ("[video_id]", videoid). replace ("[Bg_color]", backgroundcolor);
html = Html.replace ("[Auto_play]", String.valueof (Params.getautoplay ())). replace ("[Auto_hide]", string.valueof ( Params.getautohide ())). replace ("[REL]", String.valueof (Params.getrel ())). replace ("[Show_info]", string.valueof ( Params.getshowinfo ())). replace ("[Enable_js_api]", String.valueof (Params.getenablejsapi ())). replace ("[disable_kb ] ", String.valueof (PARAMS.GETDISABLEKB ())). replace (" [Cc_lang_pref] ", String.valueof (Params.getcc_lang_pref ()). Replace ("[CONTROLS]", String.valueof (Params.getcontrols ())). replace ("[FS]", String.valueof (Params.getfs ()));
return HTML;
}
catch (Exception e) {
E.printstacktrace ();
}
Return "";
}
} Code initialized in Fragment View Youtubeview = Layoutinflater.from (journalactivity). Inflate (R.layout.layout_youtube_player, NULL); Youtubeplayerview Youtubeplayerview = (Youtubeplayerview) Youtubeview.findviewbyid (R.id.youtubeplayerview); youtubeplayerview.setautoplayerheight (journalactivity); youtubeplayerview.initialize (videoid, New Youtubeplayercallback ( Youtubeplayerview), mwebchromeclient); Ll_journal.addview (Youtubeview,ll_journal.getchildcount ()-1); The layout files mentioned above are r.layout.layout_youtube_player as follows <?xml version= "1.0" encoding= "Utf-8" <framelayout xmlns:android= "http://schemas.android.com/" Apk/res/android " android:layout_ Width= "Match_parent" android:layout _height= "Match_parent" android:o rientation= "Vertical" <com.xxx.youtubeplayerview android:id= "@+ Id/youtubeplayerview android:layout_width= "Match_parent" android:layout_height= "Wrap_content" android:layout_marginleft= "15DP" android:layout _marginright= "15DP" android:layout_margintop= "10DP"/> <framelayout Android:layout_width= "Match_parent" android:layout_height= "50DP" android:layout_gravity= "Top" Android:clickable= "true" android:layout_marginleft= "15DP" android:layout_marginright= "15DP" android:layout_margintop= "10DP" > </FrameLayout> </FrameLayout> The webchromeclient described above is defined as the following for controlling the full screen playback Private Webchromeclient mwebchromeclient = new Webchromeclient () { @Override Public View Getvideoloadingprogressview () { Layoutinflater Inflater = layoutinflater.from (activity); Mvideoprogressview = inflater.inflate (r.layout.video_layout_loading, NULL);
return mvideoprogressview; } @Override
public void Onshowcustomview (view view,
Webchromeclient.customviewcallback callback) {
If a view already exists then immediately terminate the new one
if (journalactivity==null) {
Return
}
if (Mcustomview!= null) {
Onhidecustomview ();
Return
} 1. Stash the current state Mcustomview = view; Moriginalsystemuivisibility = Journalactivity.getwindow (). Getdecorview (). getsystemuivisibility (); Moriginalorientation = Journalactivity.getrequestedorientation (); 2. Stash the Custom View callback Mcustomviewcallback = callback; 3. Add the custom view to the view hierarchy
Framelayout decor = (framelayout) Journalactivity.getwindow (). Getdecorview ();
Decor.addview (Mcustomview, New Framelayout.layoutparams (
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
if (mvideofullscreenback!=null) {
Mvideofullscreenback.setvisibility (view.visible);
} 4. Change the state of the window
Activity.getwindow (). Getdecorview (). Setsystemuivisibility (
view.system_ui_flag_layout_stable |
view.system_ui_flag_layout_hide_navigation |
View.system_ui_flag_layout_fullscreen |
view.system_ui_flag_hide_navigation |
View.system_ui_flag_fullscreen |
view.system_ui_flag_immersive);
Activity.setrequestedorientation (Activityinfo.screen_orientation_landscape);
} @Override
public void Onhidecustomview () {
if (journalactivity = = null) {
Return
}
1. Remove the Custom View
Framelayout decor = (framelayout) Journalactivity.getwindow (). Getdecorview ();
Decor.removeview (Mcustomview);
Mcustomview = null;
if (mvideofullscreenback!=null) {
Mvideofullscreenback.setvisibility (View.gone);
} 2. Restore the state to it ' s original form Journalactivity.getwindow (). Getdecorview () . setsystemuivisibility (moriginalsystemuivisibility); Journalactivity.setrequestedorientation (moriginalorientation); 3. Call the Custom view callback if (mcustomviewcallback!=null) { Mcustomviewcallback.oncustomviewhidden (); Mcustomviewcallback = null; } } }; The r.layout.view_layout_loading layout file mentioned above is just a progressbar when the placeholder is used <?xml version= "1.0" encoding= "Utf-8" <framelayout xmlns:android= "http://schemas.android.com/" Apk/res/android " android:layout_ Width= "Match_parent" android:layout _height= "Match_parent" android: gravity= "center" Android:o rientation= "Vertical" <progressbar Android:id= "@android: Id/progress" Style= "Android:attr/progressbarstylelarge"? Android:layout_width= "Wrap_content" android:layout_height= "Wrap_content" android:layout_gravity= "Center"/> </FrameLayout> The method for extracting videoid from a URL is as follows
private string Parseidfromvideourl (string videourl) {
int startIndex = Videourl.indexof (Video_id_start);
if (StartIndex!=-1) {
StartIndex = StartIndex + video_id_start.length ();
int endindex = Videourl.indexof ("?");
if (Endindex = = 1) {
Endindex = Videourl.length ();
}
if (StartIndex < Endindex) {
Return videourl.substring (Startindex,endindex);
}
}
Return "";
}
Because this project in the same fragment put a lot of such video playback control, so in order to unify their pause, destroy operations, here using a ArrayList for maintenance When switching to other fragment or when new activity is pressed to the top, pause WebView playback, fragment the total OnPause method:
@Override
public void OnPause () {
if (playerviewlist!=null) {
for (Youtubeplayerview v:playerviewlist) {
if (v.getplayerstate () = = YoutubePlayerView.STATE.PLAYING) {
V.pause ();
}else if (v.getplayerstate () = = YoutubePlayerView.STATE.BUFFERING) {
V.stop ();
}
}
}
Super.onpause ();
There is also a need to allow fragment to release WebView resources at the time of destruction as follows: @Override public void OnDestroy () { Super.ondestroy (); if (playerviewlist!=null) { for (Youtubeplayerview v:playerviewlist) { if (v!=null) { V.ondestroy (); } } } } Turn off full screen code when the return button is pressed @Override public void onbackpressed () { Boolean isclose = Currentjournalfragment.closefullscreen (); if (isclose) { Return } } This fragment Closefullscreen method is as follows public Boolean closefullscreen () { if (mcustomview!=null && mcustomviewcallback!=null) { Mwebchromeclient.onhidecustomview (); return true; } return false; } |