vídeos videos ver reproducir puedo pantalla móviles google dispositivos completa como chrome activar android android-webview html5-video

videos - Reproducción de video HTML5 en pantalla completa en la vista web de Android



video html5 android (7)

Editar 2014/10: por demanda popular estoy manteniendo y moviendo esto a GitHub. Verifique cprcrack/VideoEnabledWebView para la última versión. Mantendrá esta respuesta solo como referencia.

Edición 2014/01: uso mejorado de ejemplos para incluir las vistas nonVideoLayout, videoLayout y videoLoading, para aquellos usuarios que solicitan más código de ejemplo para una mejor comprensión.

Edición 2013/12: algunas correcciones de errores relacionadas con la compatibilidad de los dispositivos Sony Xperia, pero que de hecho afectaron a todos los dispositivos.

Editar 2013/11: después del lanzamiento de Android 4.4 KitKat (nivel de API 19) con su nueva vista web de Chromium, tuve que trabajar duro nuevamente. Se hicieron varias mejoras. Debes actualizar a esta nueva versión. Libero esta fuente bajo WTFPL . Se aceptan donaciones (encuentre el enlace Donar en la parte inferior).

Editar 2013/04: después de 1 semana de arduo trabajo, finalmente logré todo lo que necesitaba. Creo que estas dos clases genéricas que he creado pueden resolver todos tus problemas.

VideoEnabledWebChromeClient se puede usar solo si no necesita la funcionalidad que VideoEnabledWebView agrega. Pero VideoEnabledWebView siempre debe confiar en VideoEnabledWebChromeClient . Por favor, lea todos los comentarios de las dos clases con cuidado.

Clase VideoEnabledWebChromeClient

import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.webkit.WebChromeClient; import android.widget.FrameLayout; /** * This class serves as a WebChromeClient to be set to a WebView, allowing it to play video. * Video will play differently depending on target API level (in-line, fullscreen, or both). * * It has been tested with the following video classes: * - android.widget.VideoView (typically API level <11) * - android.webkit.HTML5VideoFullScreen$VideoSurfaceView/VideoTextureView (typically API level 11-18) * - com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView (typically API level 19+) * * Important notes: * - For API level 11+, android:hardwareAccelerated="true" must be set in the application manifest. * - The invoking activity must call VideoEnabledWebChromeClient''s onBackPressed() inside of its own onBackPressed(). * - Tested in Android API levels 8-19. Only tested on http://m.youtube.com. * * @author Cristian Perez (http://cpr.name) * */ public class VideoEnabledWebChromeClient extends WebChromeClient implements OnPreparedListener, OnCompletionListener, OnErrorListener { public interface ToggledFullscreenCallback { public void toggledFullscreen(boolean fullscreen); } private View activityNonVideoView; private ViewGroup activityVideoView; private View loadingView; private VideoEnabledWebView webView; private boolean isVideoFullscreen; // Indicates if the video is being displayed using a custom view (typically full-screen) private FrameLayout videoViewContainer; private CustomViewCallback videoViewCallback; private ToggledFullscreenCallback toggledFullscreenCallback; /** * Never use this constructor alone. * This constructor allows this class to be defined as an inline inner class in which the user can override methods */ @SuppressWarnings("unused") public VideoEnabledWebChromeClient() { } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity''s layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity''s layout that will display the video. Typically you would like this to fill the whole layout. */ @SuppressWarnings("unused") public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = null; this.webView = null; this.isVideoFullscreen = false; } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity''s layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity''s layout that will display the video. Typically you would like this to fill the whole layout. * @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view. */ @SuppressWarnings("unused") public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = loadingView; this.webView = null; this.isVideoFullscreen = false; } /** * Builds a video enabled WebChromeClient. * @param activityNonVideoView A View in the activity''s layout that contains every other view that should be hidden when the video goes full-screen. * @param activityVideoView A ViewGroup in the activity''s layout that will display the video. Typically you would like this to fill the whole layout. * @param loadingView A View to be shown while the video is loading (typically only used in API level <11). Must be already inflated and without a parent view. * @param webView The owner VideoEnabledWebView. Passing it will enable the VideoEnabledWebChromeClient to detect the HTML5 video ended event and exit full-screen. * Note: The web page must only contain one video tag in order for the HTML5 video ended event to work. This could be improved if needed (see Javascript code). */ public VideoEnabledWebChromeClient(View activityNonVideoView, ViewGroup activityVideoView, View loadingView, VideoEnabledWebView webView) { this.activityNonVideoView = activityNonVideoView; this.activityVideoView = activityVideoView; this.loadingView = loadingView; this.webView = webView; this.isVideoFullscreen = false; } /** * Indicates if the video is being displayed using a custom view (typically full-screen) * @return true it the video is being displayed using a custom view (typically full-screen) */ public boolean isVideoFullscreen() { return isVideoFullscreen; } /** * 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; } @Override public void onShowCustomView(View view, CustomViewCallback callback) { if (view instanceof FrameLayout) { // A video wants to be shown FrameLayout frameLayout = (FrameLayout) view; View focusedChild = frameLayout.getFocusedChild(); // Save video related variables this.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 LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); activityVideoView.setVisibility(View.VISIBLE); if (focusedChild instanceof android.widget.VideoView) { // android.widget.VideoView (typically API level <11) android.widget.VideoView videoView = (android.widget.VideoView) focusedChild; // Handle all the required events videoView.setOnPreparedListener(this); 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); } } } @Override @SuppressWarnings("deprecation") public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) // Available in API level 14+, deprecated in API level 18+ { onShowCustomView(view, callback); } @Override public void onHideCustomView() { // 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); } } } @Override public View getVideoLoadingProgressView() // Video will start loading { if (loadingView != null) { loadingView.setVisibility(View.VISIBLE); return loadingView; } else { return super.getVideoLoadingProgressView(); } } @Override public void onPrepared(MediaPlayer mp) // Video will start playing, only called in the case of android.widget.VideoView (typically API level <11) { if (loadingView != null) { loadingView.setVisibility(View.GONE); } } @Override public void onCompletion(MediaPlayer mp) // Video finished playing, only called in the case of android.widget.VideoView (typically API level <11) { onHideCustomView(); } @Override public boolean onError(MediaPlayer mp, int what, int extra) // Error while playing video, only called in the case of android.widget.VideoView (typically API level <11) { return false; // By returning false, onCompletion() will be called } /** * Notifies the class that the back key has been pressed by the user. * This must be called from the Activity''s onBackPressed(), and if it returns false, the activity itself should handle it. Otherwise don''t do anything. * @return Returns true if the event was handled, and false if was not (video view is not visible) */ public boolean onBackPressed() { if (isVideoFullscreen) { onHideCustomView(); return true; } else { return false; } } }

Clase VideoEnabledWebView

import android.annotation.SuppressLint; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.webkit.WebChromeClient; import android.webkit.WebView; import java.util.Map; /** * This class serves as a WebView to be used in conjunction with a VideoEnabledWebChromeClient. * It makes possible: * - To detect the HTML5 video ended event so that the VideoEnabledWebChromeClient can exit full-screen. * * Important notes: * - Javascript is enabled by default and must not be disabled with getSettings().setJavaScriptEnabled(false). * - setWebChromeClient() must be called before any loadData(), loadDataWithBaseURL() or loadUrl() method. * * @author Cristian Perez (http://cpr.name) * */ public class VideoEnabledWebView extends WebView { public class JavascriptInterface { @android.webkit.JavascriptInterface public void notifyVideoEnd() // Must match Javascript interface method of VideoEnabledWebChromeClient { // This code is not executed in the UI thread, so we must force that to happen new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (videoEnabledWebChromeClient != null) { videoEnabledWebChromeClient.onHideCustomView(); } } }); } } private VideoEnabledWebChromeClient videoEnabledWebChromeClient; private boolean addedJavascriptInterface; public VideoEnabledWebView(Context context) { super(context); addedJavascriptInterface = false; } @SuppressWarnings("unused") public VideoEnabledWebView(Context context, AttributeSet attrs) { super(context, attrs); addedJavascriptInterface = false; } @SuppressWarnings("unused") public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); addedJavascriptInterface = false; } /** * Indicates if the video is being displayed using a custom view (typically full-screen) * @return true it the video is being displayed using a custom view (typically full-screen) */ public boolean isVideoFullscreen() { return videoEnabledWebChromeClient != null && videoEnabledWebChromeClient.isVideoFullscreen(); } /** * Pass only a VideoEnabledWebChromeClient instance. */ @Override @SuppressLint("SetJavaScriptEnabled") public void setWebChromeClient(WebChromeClient client) { getSettings().setJavaScriptEnabled(true); if (client instanceof VideoEnabledWebChromeClient) { this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client; } super.setWebChromeClient(client); } @Override public void loadData(String data, String mimeType, String encoding) { addJavascriptInterface(); super.loadData(data, mimeType, encoding); } @Override public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl) { addJavascriptInterface(); super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl); } @Override public void loadUrl(String url) { addJavascriptInterface(); super.loadUrl(url); } @Override public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { addJavascriptInterface(); super.loadUrl(url, additionalHttpHeaders); } private void addJavascriptInterface() { if (!addedJavascriptInterface) { // Add javascript interface to be called when the video ends (must be done before page load) addJavascriptInterface(new JavascriptInterface(), "_VideoEnabledWebView"); // Must match Javascript interface name of VideoEnabledWebChromeClient addedJavascriptInterface = true; } } }

Ejemplo de uso:

Diseño principal activity_main.xml en el que ponemos VideoEnabledWebView y otras vistas utilizadas:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <!-- View that will be hidden when video goes fullscreen --> <RelativeLayout android:id="@+id/nonVideoLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <your.package.VideoEnabledWebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> <!-- View where the video will be shown when video goes fullscreen --> <RelativeLayout android:id="@+id/videoLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <!-- View that will be shown while the fullscreen video loads (maybe include a spinner and a "Loading..." message) --> <View android:id="@+id/videoLoading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:visibility="invisible" /> </RelativeLayout> </RelativeLayout>

Activity onCreate () , en el que lo inicializamos:

private VideoEnabledWebView webView; private VideoEnabledWebChromeClient webChromeClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set layout setContentView(R.layout.activity_main); // Save the web view webView = (VideoEnabledWebView) findViewById(R.id.webView); // Initialize the VideoEnabledWebChromeClient and set event handlers View nonVideoLayout = findViewById(R.id.nonVideoLayout); // Your own view, read class comments ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout); // Your own view, read class comments View loadingView = getLayoutInflater().inflate(R.layout.view_loading_video, null); // Your own view, read class comments webChromeClient = new VideoEnabledWebChromeClient(nonVideoLayout, videoLayout, loadingView, webView) // See all available constructors... { // Subscribe to standard events, such as onProgressChanged()... @Override public void onProgressChanged(WebView view, int progress) { // Your code... } }; webChromeClient.setOnToggledFullscreen(new VideoEnabledWebChromeClient.ToggledFullscreenCallback() { @Override public void toggledFullscreen(boolean fullscreen) { // Your code to handle the full-screen change, for example showing and hiding the title bar. Example: if (fullscreen) { WindowManager.LayoutParams attrs = getWindow().getAttributes(); attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; getWindow().setAttributes(attrs); if (android.os.Build.VERSION.SDK_INT >= 14) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); } } else { WindowManager.LayoutParams attrs = getWindow().getAttributes(); attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN; attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; getWindow().setAttributes(attrs); if (android.os.Build.VERSION.SDK_INT >= 14) { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } } } }); webView.setWebChromeClient(webChromeClient); // Navigate everywhere you want, this classes have only been tested on YouTube''s mobile site webView.loadUrl("http://m.youtube.com"); }

Y no te olvides de llamar aBackPressed () :

@Override public void onBackPressed() { // Notify the VideoEnabledWebChromeClient, and handle it ourselves if it doesn''t handle it if (!webChromeClient.onBackPressed()) { if (webView.canGoBack()) { webView.goBack(); } else { // Close app (presumably) super.onBackPressed(); } } }

Bueno, he estado buscando hace unos días, cómo mostrar video HTML5 en modo de pantalla completa en Android WebView.

Logré reproducir videos HTML5 en mi vista web. Los problemas surgen cuando se muestra video en modo pantalla completa.

Como descubrí, Android tiene dos formas de manejar la etiqueta <video>:

  1. En las versiones de Android <= 2.3.3 , se dispara el método onShowCustomView, y puedo tener la instancia de VideoView y configurar oyentes cuando finaliza el video, establecer controles, etc. Hasta ahora todo va bien.

  2. En ICS (y probablemente 3.0 y superior) , parece que el <video> se maneja de manera diferente. Cuando se reproduce el video HTML5, no se llama a onShowCustomView en modo normal, parece que hay un negocio interno dentro del WebView que reproduce el video y se muestran todos los controles definidos en la etiqueta <video>. no puede acceder a ella de ninguna manera. En realidad, si el video se reproduce en modo normal, esto está bien porque los controles están ahí y están funcionando.

Eso me llevó al gran problema: cuando se muestra el video en modo de pantalla completa, se llama a onShowCustomView, pero en ICS, el parámetro "ver" no es una instancia de VideoView.

Me las arreglé para descubrir que la instancia es de VideoSurfaceView, una clase interna privada de clase HTML5VideoFullScreen. La única forma en que podemos acceder a esta clase interna es a través de la reflexión.

Después de mirar GrepCode para esta clase, aprendí que a diferencia de VideoView, HTML5VideoFullScreen $ VideoSurfaceView no contiene una instancia de MediaPlayer que puedo escuchar sus eventos o acceder a sus controles. Lo único que puedo hacer es tomar este VideoSurfaceView tal como está y ponerlo dentro de un diseño de pantalla completa sin controlarlo.

En pocas palabras: cuando visualizo video en pantalla completa, no sé cuándo termina el video, no se muestran sus controles, esto es bastante triste. No puedo obtener el disparador para cerrar la pantalla completa.

Intenté algunas soluciones fallidas:

  1. Reflexión: Intenté llegar a la instancia HTML5VideoFullScreen, que contiene un miembro de MediaPlayer, desde la clase interna VideoSurfaceView. No logré obtenerlo, no estoy seguro de que esto sea posible (ViewSurfaceView no contiene la instancia de su propietario).

  2. Regístrese para los eventos de video a través de Javascript (activado, por ejemplo) y maneje lo que necesito en JAVA a través de JavascriptInterface: Encontré que esta solución no es confiable porque al hacer esto me encontré con otro problema: la etiqueta <video> puede anidarse en un La fuente del iframe no es mía y no puedo obtener su contenido (getElementById o getElementsByTagName [i] son ​​nulos), lo que significa que no puedo acceder al elemento <video> dentro del iframe.

Todavía estoy buscando una solución, se escribe muy poco sobre este tema. ¿Alguien logró resolverlo? ¡La ayuda sería muy apreciada!

Clase VideoView : Here (tiene MediaPlayer)

HTML5VideoFullScreen $ VideoSurfaceView class: Here (no tiene MediaPlayer)


Esto es genial. Pero si desea que los enlaces de su sitio web se abran en la propia aplicación, agregue este código en su ExampleActivity.java:

webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (Uri.parse(url).getHost().endsWith("yourwebsite.com")) { return false; } Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); view.getContext().startActivity(intent); return true; } });


La respuesta de Cprcrack funciona muy bien para los niveles API de 19 y menos. Solo una pequeña adición a cprcrack''s onShowCustomView hará funcionar en el nivel API 21+

if (Build.VERSION.SDK_INT >= 21) { videoViewContainer.setBackgroundColor(Color.BLACK); ((ViewGroup) webView.getParent()).addView(videoViewContainer); webView.scrollTo(0,0); // centers full screen view } else { activityNonVideoView.setVisibility(View.INVISIBLE); ViewGroup.LayoutParams vg = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); activityVideoView.addView(videoViewContainer,vg); activityVideoView.setVisibility(View.VISIBLE); }

También deberá reflejar los cambios en onHideCustomView


Muchas gracias por esa clase, Cristian.

Hice un pequeño ajuste para que la vista de carga personalizada sea opcional, así:

@Override public View getVideoLoadingProgressView() // Video will start loading, only called in the case of VideoView (typically API level 10-) { if (loadingView == null) { return super.getVideoLoadingProgressView(); } else { loadingView.setVisibility(View.VISIBLE); return loadingView; } }

También agregué un nuevo constructor que solo toma dos parámetros. De todos modos, solo una pequeña simplificación si no necesitas la vista de carga. Gracias de nuevo por proporcionar esto.


Parece que en lollipop y hasta (o tal vez solo una versión diferente de WebView) que llamar al cprcrack''s onHideCustomView() no funciona. Funciona si se llama desde el botón de pantalla completa de salida, pero cuando se llama específicamente al método, solo saldrá de pantalla completa, pero la vista webView queda en blanco. Una forma de onHideCustomView() es simplemente agregar estas líneas de código a onHideCustomView() :

String js = "javascript:"; js += "var _ytrp_html5_video = document.getElementsByTagName(''video'')[0];"; js += "_ytrp_html5_video.webkitExitFullscreen();"; webView.loadUrl(js);

Esto notificará a la vista web que se ha cerrado la pantalla completa.


Solo establece
mWebView.setWebChromeClient(new WebChromeClient());

y el video se reproduce como normalmente no necesita ninguna vista personalizada.


Editar: vea mi otra respuesta , ya que probablemente no la necesite ahora.

Como dijiste, en los niveles API 11+ se pasa HTML5VideoFullScreen $ VideoSurfaceView. Pero no creo que tengas razón cuando dices que "no tiene un MediaPlayer".

Esta es la forma de llegar a la instancia de MediaPlayer desde la instancia de HTML5VideoFullScreen $ VideoSurfaceView utilizando la reflexión :

@SuppressWarnings("rawtypes") Class c1 = Class.forName("android.webkit.HTML5VideoFullScreen$VideoSurfaceView"); Field f1 = c1.getDeclaredField("this$0"); f1.setAccessible(true); @SuppressWarnings("rawtypes") Class c2 = f1.getType().getSuperclass(); Field f2 = c2.getDeclaredField("mPlayer"); f2.setAccessible(true); Object ___html5VideoViewInstance = f1.get(focusedChild); // Look at the code in my other answer to this same question to see whats focusedChild Object ___mpInstance = f2.get(___html5VideoViewInstance); // This is the MediaPlayer instance.

Entonces, ahora puede configurar el oyente onCompletion de la instancia de MediaPlayer de esta manera:

OnCompletionListener ocl = new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // Do stuff } }; Method m1 = f2.getType().getMethod("setOnCompletionListener", new Class[] { Class.forName("android.media.MediaPlayer$OnCompletionListener") }); m1.invoke(___mpInstance, ocl);

El código no falla, pero no estoy completamente seguro de si realmente se llamará al oyente onCompletion o si podría ser útil para su situación. Pero solo en caso de que alguien quiera probarlo.