On some devices like the Nexus 7 or Samsung Galaxy Nexus (possibly others), I noticed this issue (See picture). This is running on Hardware Acceleration Mode in a WebView. However, when I turn it to Software Rendering Mode, it displays fine but slows down performance a little. I would love to learn how to fix this issue and only use Hardware Acceleration on the WebViews and not Software Mode.
Bad rendering (running on Samsung Galaxy Nexus):
Correct rendering (running on Motorola Bionic):
Android Manifest:
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<supports-screens
android:resizeable="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"
android:anyDensity="true" />
<application
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
....
</application>
</manifest>
Java code:
....
@TargetApi(VERSION_CODES.HONEYCOMB)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
db = new DatabaseHandler(this);
tts = new TextToSpeech(this, this);
handler = new Handler();
frame = new FrameLayout(this);
frame.setBackgroundColor(Color.GRAY);
wv = new WebView(this);
wv.setScrollBarStyle(WebView.SCROLLBARS_INSIDE_OVERLAY);
frame.addView(wv);
wv.setVisibility(WebView.INVISIBLE);
iv = new ImageView(this);
Drawable d = Drawable.createFromStream(getAssets().open("www/img/loading.jpg"), null);
iv.setImageDrawable(d);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
iv.setLayoutParams(params);
frame.addView(iv);
WebSettings ws = wv.getSettings();
ws.setRenderPriority(RenderPriority.HIGH);
ws.setJavaScriptEnabled(true);
ws.setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN)
ws.setAllowUniversalAccessFromFileURLs(true);
ws.setCacheMode(WebSettings.LOAD_NO_CACHE);
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
if(Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB && !pref.getBoolean("prefHardware", true)){
wv.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
wv.setWebChromeClient(new WebChromeClient(){
//int id = 0;
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
// TODO Auto-generated method stub
// Log.d("JS Console", consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber());
//Toast.makeText(TaskRunner.this, consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber(), Toast.LENGTH_LONG).show();
// NotificationCompat.Builder mBuilder =
// new NotificationCompat.Builder(TaskRunner.this)
// .setSmallIcon(R.drawable.ic_launcher)
// .setContentTitle("Console Message")
// .setContentText(consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber());
//// mBuilder.setContentIntent(null);
// NotificationManager mNotificationManager =
// (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// // mId allows you to update the notification later on.
// mNotificationManager.notify(id++, mBuilder.build());
return super.onConsoleMessage(consoleMessage);
}
});
wv.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
//Log.i("TEST", "TEST");
//hideLoading();
super.onPageFinished(view, url);
}
@Override
public void onPageStarted(WebView view, String url,
Bitmap favicon) {
// TODO Auto-generated method stub
if(frame.getChildAt(frame.getChildCount()-1) != iv){
frame.addView(iv);
wv.setVisibility(WebView.INVISIBLE);
}
super.onPageStarted(view, url, favicon);
}
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
// TODO Auto-generated method stub
Log.e("ERROR", description);
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
MyJavascriptInterface ji = new MyJavascriptInterface();
wv.addJavascriptInterface(ji, "ji");
setOrientation();
wv.loadUrl("file:///android_asset/www/index.html");
setContentView(frame);
}
catch(Exception e){
}
}
....
HTML file:
<!DOCTYPE html>
<html>
<head>
<title>Task Player</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="format-detection" content="telephone=no" />
......
</head>
<body>
<div id="gamespacer">
<div id="instructions-block">
<div id="explaination">
</div>
<div id="instructions-close">
<br /><br />
<div class="btn btn-large btn-info" id="speak-tts">Speak</div>
<br /><br />
<input type='checkbox' id='auto-speak' value="yes" checked="checked" />Auto speak
</div>
<div id="drag-container">
<div id='drag'>
<span id='au'><img src="img/arrow-up.png" alt="" width="45" /></span>
<span id='ad'><img src="img/arrow-down.png" alt="" width="45"/></span>
</div>
</div>
</div>
</div>
<div id="play-container">
<canvas>
</canvas>
</div>
<div class="centerMe" id="rotate" style="display: none;"><p style="font-size: 24px; margin-top: 20px">Rotate the device to play the game.</p></div>
<div id="winScreen">
<div id="points">
You Got<br/>
<div id="mypoints">0</div>
Points
</div>
<a href="#" id='done' class="btn btn-large btn-inverse">Done</a>
</div>
....
</body>
</html>
css:
#winScreen{
display: none;
width: 100%;
height: 100%;
text-align: center;
background-color: green;
font-size: 24px;
margin: 0 auto;
position: absolute;
left: 0px;
top: 0px;
}
#points {
padding-top: 110px;
color: yellow;
margin-bottom: 10px;
}
#mypoints{
margin: 10px;
}
.button{
margin: 0 auto;
margin-top: 50px;
}
#play-container{
width: 100%;
height: 100%;
margin: 0 auto;
text-align: center;
}
canvas {
background-color: white;
position: absolute;
top: 0px;
left: 0px;
}
#gamespacer {
}
#instructions-block {
position: absolute;
left: 0px;
top: -144px;
width: 100%;
background-color: white;
z-index: 1;
}
#instructions-content {
margin-top: 5px;
}
#instructions-close {
text-align: center;
margin-bottom: 10px;
}
#explaination {
margin: 5px;
font-size: 24px;
line-height: 1;
position: relative;
width: 100%
height: 100%
}
#drag-container{
width: 100%;
}
#drag {
position: absolute;
left: 92%;
margin-top: 5px;
}
#au{
display: none;
pointer-events: none;
}
#ad {
pointer-events: none;
}
body{
-webkit-user-select: none;
user-select: none;
-webkit-touch-callout: none;
touch-callout: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
tap-highlight-color: rgba(0,0,0,0);
}
UPDATE 1
So I tried the following code and that did not work as well.
wv.setLayerType(View.LAYER_TYPE_HARDWARE, null);
UPDATE 2
It looks like so far to my knowledge that this only happens on Google made devices (like the Nexus). So, could there be a bug in their kernel or video driver? Or, it could be something wrong with Android 4.2.2.
If you have any ideas on how to fix this, please let me know.
UPDATE 3
I have made a test project for you to try. Play around with the zoom level and moving the window around. Let me know if it does anything weird. It so far does this with Android 4.2.2
http://jsbin.com/equtoq/2
Thanks!
See Question&Answers more detail:
os