views:

375

answers:

2

Hi All, 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);
        }
    }
}
A: 

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.

CommonsWare
The call to pauseTimers is inside the pauseWebViewTimers method of the Browser activity. I was not familiar with the @hide annotation, so that is why I thought perhaps I was browsing some sort of old/different code. I think your suggestion to attempt to call onPause/onResume using reflection is a great one, I'll let you know how that works out, thanks!
BenV
This works perfectly, thank you so much for filling me in about the @hide annotation, I didn't even realize I could get to those methods using reflection. I'll post an issue to b.android.com as you suggested!
BenV
@BenV: glad to hear it worked! If you think of it, put a comment on here with a link to the issue once you file it. I'd like to keep an eye on this one.
CommonsWare
Not a problem, here is the link to the issue: http://code.google.com/p/android/issues/detail?id=10282
BenV
A: 

Could you post the code that worked for you? I'm having the same problem and I am unsure of how to use reflections properly. Thanks!

JND
Sure, I added some example code to the original post. I hope it is helpful.
BenV