6

From what I have been able to find out, this seems to be specific to recent Samsung devices. The S4 will do this. The Nexus 7 will not.

If a WebView with a WebChromeClient begins to play an HTML5 video, it creates a MediaPlayer instance. Once the video is over, there doesn't seem to be a way to kill the MediaPlayer short of System.exit(0).

This is my entire MainActivity.java

package com.test.webviewtest;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

public class MainActivity extends Activity {
    WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        webView = new WebView(this);
        webView.setWebChromeClient(new WebChromeClient());
        String html = "<video width=\"320\" height=\"240\" controls autoplay>" +
                "<source src=\"http://www.w3schools.com/html/movie.mp4\" " +
                "type=\"video/mp4\"></video>";
        webView.loadData(html, "text/html", null);
        setContentView(webView);
    }

    @Override
    protected void onPause(){
        super.onPause();
        // attempt to kill the MediaPlayer here...
    }

}

And naturally this is required in the manifest

<uses-permission android:name="android.permission.INTERNET"/>

As soon as you click the video, logcat starts spitting out MediaPlayer messages and it NEVER STOPS. There are useful ones while the video is playing but after that, it just logs

02-25 17:13:19.395     220-8584/? V/MediaPlayerService﹕ [470] notify (0x51b7aa00, 3, 100, 0)
02-25 17:13:19.395    8532-8610/? V/MediaPlayer﹕ message received msg=3, ext1=100, ext2=0
02-25 17:13:19.395    8532-8610/? V/MediaPlayer﹕ buffering 100
02-25 17:13:19.395    8532-8610/? V/MediaPlayer﹕ callback application
02-25 17:13:19.405    8532-8610/? V/MediaPlayer﹕ back from callback
02-25 17:13:20.406     220-8584/? V/MediaPlayerService﹕ [470] notify (0x51b7aa00, 3, 100, 0)
02-25 17:13:20.406    8532-8544/? V/MediaPlayer﹕ message received msg=3, ext1=100, ext2=0
02-25 17:13:20.406    8532-8544/? V/MediaPlayer﹕ buffering 100
02-25 17:13:20.406    8532-8544/? V/MediaPlayer﹕ callback application
02-25 17:13:20.406    8532-8544/? V/MediaPlayer﹕ back from callback
02-25 17:13:21.407     220-8584/? V/MediaPlayerService﹕ [470] notify (0x51b7aa00, 3, 100, 0)
02-25 17:13:21.407    8532-8611/? V/MediaPlayer﹕ message received msg=3, ext1=100, ext2=0
02-25 17:13:21.407    8532-8611/? V/MediaPlayer﹕ buffering 100
02-25 17:13:21.407    8532-8611/? V/MediaPlayer﹕ callback application
02-25 17:13:21.417    8532-8611/? V/MediaPlayer﹕ back from callback

And this repetition never ends until you force close or uninstall or something else drastic. I have already tried:

  • webView.onPause(); This pauses the video so it stops playing in the background, but does not kill the MediaPlayer.
  • webView.destroy(); Still doesn't stop that zombie MediaPlayer
  • webView = null; nope
  • webView = new WebView(this); still nope
  • finish();
  • I've also tried various ways of getting a hold of the WebChromeClient and destroying it, but nothing works.

I'll update this list as I try more things. Appreciate the help.

  • I've now also tried redirecting the webView to non video content with webView.loadData("hi", "text/html", null); still alive...

HACKED ANSWER

Well this is the best I can find. If someone has a better solution, please still let me know.

In order to get the MediaPlayer to stop, I told it to go to page with a <video> tag that pointed to something other than a video.

String html = "<video width=\"320\" height=\"240\" controls>" +
    "<source src=\"http://www.w3schools.com/html/NOT_A_MOVIE.mp4\" " +
    "type=\"video/mp4\"></video>";
webView.loadData(html, "text/html", null); 

When I do this, I see a video player on screen and when I click the play button, it logs

02-26 12:26:37.112    220-11354/? V/MediaPlayerService﹕ [576] notify (0x47fa92b8, 100, 1, -1004)
02-26 12:26:37.112  11264-11325/com.test.webviewtest V/MediaPlayer﹕ message received msg=100, ext1=1, ext2=-1004
02-26 12:26:37.112  11264-11325/com.test.webviewtest E/MediaPlayer﹕ error (1, -1004)
02-26 12:26:37.112  11264-11325/com.test.webviewtest V/MediaPlayer﹕ callback application
02-26 12:26:37.112  11264-11325/com.test.webviewtest V/MediaPlayer﹕ back from callback
02-26 12:26:37.122  11264-11264/com.test.webviewtest E/MediaPlayer﹕ Error (1,-1004)

From this point on, the MediaPlayer seems to be mostly dead (only slightly alive). It ceases all logging activity, which is the desired result. The only trace of it remaining is when you force close the app, you will still see this.

02-26 12:29:35.826      220-738/? V/MediaPlayerService﹕ Client(576) destructor pid = 11264
02-26 12:29:35.836      220-738/? V/MediaPlayerService﹕ disconnect(576) from pid 11264
02-26 12:29:35.836      220-738/? W/MediaPlayerService﹕ native_window_api_disconnect returned an error: Broken pipe (-32)

I'm ok with that but a real solution would be nice. I'll obviously wire up the bad video with autoplay so the crash can happen in the background, but that's the framework.


UPDATE 2-27-14 While this 'fixes' the issue on Samsung devices, it does breaks other devices, so this is not a good solution. On other devices (Nexus 7 tested), this code will render the WebView useless to any future calls. I'll update this when I find more information. If you never need to render another WebView for the rest of the app's lifespan, I guess that's ok, but I need it to be able to load another page later.

ADDruid
  • 196
  • 1
  • 6
  • 3
    given that this looks like something that will need an AOSP fix, I've opened https://code.google.com/p/android/issues/detail?id=67605 referencing this issue – Offbeatmammal Mar 25 '14 at 05:49

2 Answers2

1

For me no other solution worked other than:

android.os.Process.killProcess(android.os.Process.myPid());

This comes with the hassle that you can't actually create the activity from inside, but I've overcome that with a second process.

-1
((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)).requestAudioFocus(
                    new AudioManager.OnAudioFocusChangeListener() {
                        @Override
                        public void onAudioFocusChange(int focusChange) {
                        }
                    }, AudioManager.STREAM_MUSIC,
                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
jie
  • 1
  • 1