Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pause Flash content in an Android WebView when my activity isn't visible?

I am experimenting with using a WebView to display Flash content inside my activity. Everything is working pretty well, but when the user hits the home key to put the activity into the background, the Flash content keeps running (sound keeps playing, etc)

I have noticed that both the stock Android browser and Dolphin Browser seem to avoid this problem, and properly pause the Flash content when the browsing activity is put into the background.

Ideally I would like a solution that kills the WebView completely if the activity is finishing, but pauses it otherwise (basically copying the default behavior of the browser)

Here is a simple test I put together that loads a game on Kongregate which has some background music:

    public class BrowserTest extends Activity {
    private WebView mWebView;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            mWebView = new WebView(this);
            mWebView.getSettings().setJavaScriptEnabled(true);
            mWebView.getSettings().setPluginsEnabled(true);

            mWebView.loadUrl("http://m.kongregate.com/games/Jiggmin/the-game-of-disorientation-mobile");
            setContentView(mWebView);
        }

        @Override
        protected void onPause(){
            super.onPause();

            mWebView.pauseTimers();
            if(isFinishing()){
                mWebView.loadUrl("about:blank");
                setContentView(new FrameLayout(this));
            }
        }

        @Override
        protected void onResume(){
            super.onResume();
            mWebView.resumeTimers();
        }
    }

I took a look at the latest source for the stock browser, and it seems to be doing something similar (calling pauseTimers/resumeTimers), although I fear the code I have been looking at is out of date, because it is calling functions that don't seem to exist anymore.

I did verify that the call to pauseTimers is working by testing with a simple JavaScript setInterval which updates a counter. Is there something else obvious that I should be trying in regard to Window or View management?

The documentation for the mobile Flash player says:

Flash Player will also automatically pause SWF playback it is not in view or the foreground application, for example when a call is received or alarm goes off, to reduce CPU utilization, battery usage and memory usage.

This seems to be working perfectly in both the stock browser and Dolphin Browser, but not in my app. Any ideas/solutions would be greatly appreciated!

Update: Here is the function we ended up adding to our activity to get this to work. We call it with "onPause" in the activity's onPause function and "onResume" in the activity's onResume function:

private void callHiddenWebViewMethod(String name){
    if( mWebView != null ){
        try {
            Method method = WebView.class.getMethod(name);
            method.invoke(mWebView);
        } catch (NoSuchMethodException e) {
            Log.error("No such method: " + name, e);
        } catch (IllegalAccessException e) {
            Log.error("Illegal Access: " + name, e);
        } catch (InvocationTargetException e) {
            Log.error("Invocation Target Exception: " + name, e);
        }
    }
}
like image 585
BenV Avatar asked Aug 07 '10 17:08

BenV


2 Answers

I don't see where you see that BrowserActivity or anything is calling pauseTimers(). I do see where onPause() for BrowserActivity eventually routes to onPause() of WebView. However, onPause() of WebView has the @hide annotation and so is not part of the SDK. Off the cuff, it would seem like onPause() is what you want, given the comment:

Call this to pause any extra processing associated with this view and its associated DOM/plugins/javascript/etc. For example, if the view is taken offscreen, this could be called to reduce unnecessary CPU and/or network traffic. When the view is again "active", call onResume().

Note the reference to "plugins", which is not mentioned in the pauseTimers() documentation.

I'd try using reflection to see if onPause() (and later onResume(), when you want stuff to start up again) does what you need. If it does, please post an issue to b.android.com about this, asking them to add these methods (or equivalents) to the SDK. Your requirement seems like it will be a common one, and a solution that goes past the SDK is not a good solution.

like image 123
CommonsWare Avatar answered Sep 19 '22 13:09

CommonsWare


@Override
protected void onPause() {
    super.onPause();
    this.callHiddenWebViewMethod("onPause");
}

@Override
protected void onResume() {
    super.onResume();
    this.callHiddenWebViewMethod("onResume");
}

This is how you call it in your activity... Works like a charm.

like image 29
Evan Leis Avatar answered Sep 22 '22 13:09

Evan Leis