Edit: I made a demo apk, so you can understand what I mean: http://cl.ly/3g0s1p030j243y0p3m2F
For my application, I want a kind of "Super Power Point", or a keynote (the commercial team will present the product to their customers) using all the Android goodness, gestures, etc... on an Android tablet. As Honeycomb is not yet ready and because we need it before march, we choose some random Froyo Tablet (Archos 101), but my issue is for every tablet/phone I tried.
I made a really great application, but for some animations during the presentation, the customer wanted to use flash animations. Because I couldn't code animations (sort of little movies/ animated graphics) that easily in Android and the lack of time, that seemed to be a good idea.
So, after some search on the Web, I used webview and this code:
WebView mWebView1 = (WebView) findViewById(R.id.webview1);
mWebView1.getSettings().setJavaScriptEnabled(true);
mWebView1.getSettings().setPluginsEnabled(true);
mWebView1.loadUrl("file:///android_asset/graph_01.swf");
This work pretty well, but on every device I tried (Archos 101, Nexus One, Nexus S, Galaxy S, Xperia, Desire, HTC Hero, and really more) every activity with a webview blink, a few milliseconds of black screen, then the animation finally appear.
PS: My layout is quite simple too:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView android:id="@+id/webview1" android:layout_height="fill_parent"
android:layout_width="fill_parent"></WebView>
</LinearLayout>
Please help me, I cannot imagine I am the only one to face this issue.
Thank a lot for any help. You have all my code and the demo apk.
THIS ANSWER ADDED LATER:
So the problem is that Adobe's Flash Player creates a SurfaceView
inside the WebView
and there is a delay between the SurfaceView
appearing and the Flash engine bothering to draw anything. In that small gap the SurfaceView appears totally black.
The solution I've found is to subclass WebView and add a customized SurfaceView to the view tree. Secondly it is also important to suppress the first draw() call to the Adobe view. The code for my subclassed WebView is as follows:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.webkit.WebView;
import android.widget.AbsoluteLayout;
public class FixAdobeWebView extends WebView {
View whiteView;
private boolean eatenFirstFlashDraw;
public FixAdobeWebView(Context context, AttributeSet attrs) {
super(context, attrs);
whiteView = new WhiteSurfaceView(context);
whiteView.setLayoutParams(new AbsoluteLayout.LayoutParams(800, 480, 0, 0));
addView(whiteView);
}
private class WhiteSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
public WhiteSurfaceView(Context context) {
super(context);
getHolder().addCallback(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
holder.unlockCanvasAndPost(canvas);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) { }
@Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}
//
// Override drawChild to eat the first draw of the FlashPaintSurface
//
@Override
protected boolean drawChild (Canvas canvas, View child, long drawingTime) {
if (!eatenFirstFlashDraw && child.getClass().getName().equals("com.adobe.flashplayer.FlashPaintSurface")) {
eatenFirstFlashDraw = true;
return true;
}
return super.drawChild(canvas, child, drawingTime);
}
}
The layout XML should declare an instance of this class, i.e. :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"
>
<org.test.FixAdobeWebView android:id="@+id/webview1"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
/>
</LinearLayout>
On my Nexus One running CM6.1 this works perfectly in that the WebView appears as solid white until the Flash SurfaceView starts drawing. You will probably need to adapt it a bit, e.g. get rid of the hardcoded 800x480 dimensions, and also destroy the white SurfaceView once it's no longer needed.
ORIGINAL (WRONG) ANSWER:
Looks like Adobe are to blame for this one.
The least awful workaround I've found so far is to :
- Make the background of the WebView's parent a compatible colour (i.e. white).
- Hide the WebView initially.
- Wait until you get the page loaded event, and then queue a runnable to show the WebView after a one second delay.
It means you get a guaranteed one second delay before you can see anything, but it's less jarring than that horrible black flash afaik.
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/white"
>
<WebView android:id="@+id/webview1"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:visibility="invisible"
/>
</LinearLayout>
Code:
final Handler handler = new Handler();
...
final WebView mWebView1 = (WebView) findViewById(R.id.webview1);
mWebView1.getSettings().setJavaScriptEnabled(true);
mWebView1.getSettings().setPluginsEnabled(true);
mWebView1.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
mWebView1.setVisibility(View.VISIBLE);
}
}, 1000);
}
});
mWebView1.loadUrl("file:///android_asset/graph_01.swf");
There might be a better way though that would remove the need for a fixed delay...
It's been a while since I did anything with Flash but I seem to recall there is a way for the Flash control to use the browser's Javascript engine (a quick Google turns up the Flex Ajax Bridge which seems likely).
What you could do is, with the aforementioned bridge, use ActionScript to call a Javascript function which does an alert(). In your Java code you'd hook your mWebView1 up to a WebChromeClient
which implements onJsAlert()
. In that function you'd make the WebView visible.