Android and Webview

As I found out when I was working with the canvas, graphic are clunky – well about the same as everything else. The stuff I want to do is not so pretty, it is more functional. I want nice looking dial or pretty graph of live data. Why not use the web and access the android data as a service. Good idea. This post outlines the experiments.

Basics – a simple web pages as an app.
1. Create a project with a main activity and webview as about all you see.
2. Update the manifest to include internet access? – even for local?
3. create a folder called html in the assets folder of the project
4. Fill it with a file called index.html
5. Put some stupid stuff in index.html
6. [special bonus for including css file]
7. customize mainactivity to allow javascript and open the local url

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

Experiment 1 – My own

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		WebView myWebView = (WebView) findViewById(R.id.webView1);
		String summary = "<html><body>You scored <b>192</b> points.</body></html>";
		 myWebView.loadData(summary, "text/html", null);
		 		//myWebView.loadUrl("http://www.example.com");	
	}

}

Experiment 2 – With the world

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
                WebView myWebView = (WebView) findViewById(R.id.webView1);
                myWebView.loadUrl("http://www.google.com");
	}

}

Experiment 3 – my own file (with puppy graphic )
{it didn’t work because I used “android_assets/html/index.html” instead of final “android_asset/html/index.html”)
put a sample index.html file in assets/html/index.html
add a sample graphic at assets/html/puppy.jpg

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
        WebView myWebView = (WebView) findViewById(R.id.webView1);
        myWebView.loadUrl("file:///android_asset/html/index.html");

	}

}
<!doctype html>
<html lang=es>
<head>
<title>Title</title>
</head>
<body>
<h1>Hey there</h1>
<div>
  <img src="file:///android_asset/html/puppy.jpg">
</div>
<div>
The time is 
<span id="time">Time</span>
</div>
</body>
</html>

So then I got bold – CSS and jQuery!
1. Add the css file
2. add the jquery.min.js file
3. Change mainactivity to allow javascript run

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		WebView myWebView = (WebView) findViewById(R.id.webView1);
        WebSettings websettings=myWebView.getSettings();
        websettings.setJavaScriptEnabled(true);
        myWebView.loadUrl("file:///android_asset/html/index.html");

	}

}
html {
   background-color: #aa2020;
}
h1 { 
   color: #0000ff;
}
img { 
 width: 90%;
 margin: auto;
}
<!doctype html>
<html lang=en>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="main.css" />
<script src="jquery-2.0.3.min.js"></script>
<script type="text/javascript">
var counter=0;
$( document ).ready(function() { 
    setInterval(tick,1000);
});
function tick(){
	counter++;
    $( "#time" ).text(counter);
}
</script>
</head>
<body>
<h1>Hey there</h1>
<div>
Elapsed Seconds: 
<span id="time">???</span>
</div>
<div>
  <img src="file:///android_asset/html/puppy.jpg">
</div>
</body>
</html>

Extra special awesomeness part 1 – Dynamic graph demo
create the graph.html file (cut and paste from the example)
include Flot and jquery and rember to
include flot’s example.css too so it will show up
Remove the relative links from the example html

Now the fun begins – combine the two
1. Create an interface in the main activity and attache it using the addJavascriptInterface call
2. Add references to that object in the javascript
note: save time by changing manifest versions to max at 16 not 17(where it needs a special annotation syntax)

public class MainActivity extends Activity {
	Random random=new Random();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		WebView myWebView = (WebView) findViewById(R.id.webView1);
        WebSettings websettings=myWebView.getSettings();
        websettings.setJavaScriptEnabled(true);
        myWebView.addJavascriptInterface(new JavaScriptInterface(this), "MyAndroid");
        myWebView.loadUrl("file:///android_asset/html/index.html");

	}
    public class JavaScriptInterface {
        Context mContext;
 
        /** Instantiate the interface and set the context */
        JavaScriptInterface(Context c) {
            mContext = c;
        }
 
        /** Show a toast from the web page */
        public String showToast(String toast) {
            Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
            return toast;
        }
 
        public int randomInt(){
            return random.nextInt(100);
        }
    }

}
<!doctype html>
<html lang=en>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="main.css" />
<script src="jquery-2.0.3.min.js"></script>
<script type="text/javascript">
var counter=0;
$( document ).ready(function() { 
    setInterval(tick,1000);
});
function tick(){
var result=MyAndroid.randomInt();
	counter++;
    $( "#time" ).text(counter);
    $("#time2").text(" uh "+result);
}
</script>
</head>
<body>
<h1>Hey there</h1>
<div>
Elapsed Seconds: 
<span id="time">???</span>
<span id="time2">???</span>
</div>
<div>
<a href="testgraph.html">Test Grapht</a>
</div>
<div>
  <img src="file:///android_asset/html/puppy.jpg">
</div>
</body>
</html>

NOW TIE IT ALL TOGHETHER


public class MainActivity extends Activity {
	Random random=new Random();
	int lastRandom=50;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		WebView myWebView = (WebView) findViewById(R.id.webView1);
        WebSettings websettings=myWebView.getSettings();
        websettings.setJavaScriptEnabled(true);
        myWebView.addJavascriptInterface(new JavaScriptInterface(this), "MyAndroid");
        myWebView.loadUrl("file:///android_asset/html/index.html");

	}
    public class JavaScriptInterface {
        Context mContext;
 
        /** Instantiate the interface and set the context */
        JavaScriptInterface(Context c) {
            mContext = c;
        }
 
        /** Show a toast from the web page */
        public String showToast(String toast) {
            Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
            return toast;
        }
 
        public int randomInt(){
        	lastRandom+=random.nextInt(5)-2;
            return lastRandom;
        }
    }

}

<!doctype html>
<html lang=en>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>Flot Examples: Real-time updates</title>
	<link href="examples.css" rel="stylesheet" type="text/css">
	<script language="javascript" type="text/javascript" src="jquery-2.0.3.min.js"></script>
	<script language="javascript" type="text/javascript" src="jquery.flot.min.js"></script>
	<script type="text/javascript">
	$(function() {

		// We use an inline data source in the example, usually data would
		// be fetched from a server

		var data = [],
			totalPoints = 300;

		function getRandomData() {
			if (data.length > 0)
				data = data.slice(1);

			// Do a random walk

			while (data.length < totalPoints) {
				data.push(MyAndroid.randomInt());
			}

			// Zip the generated y values with the x values
			var res = [];
			for (var i = 0; i < data.length; ++i) {
				res.push([i, data[i]])
			}

			return res;
		}

		// Set up the control widget

		var updateInterval = 500;
		$("#updateInterval").val(updateInterval).change(function () {
			var v = $(this).val();
			if (v && !isNaN(+v)) {
				updateInterval = +v;
				if (updateInterval < 1) {
					updateInterval = 1;
				} else if (updateInterval > 2000) {
					updateInterval = 2000;
				}
				$(this).val("" + updateInterval);
			}
		});

		var plot = $.plot("#placeholder", [ getRandomData() ], {
			series: {
				shadowSize: 0	// Drawing is faster without shadows
			},
			yaxis: {
				min: 0,
				max: 100
			},
			xaxis: {
				show: false
			}
		});

		function update() {

			plot.setData([getRandomData()]);

			// Since the axes don't change, we don't need to call plot.setupGrid()

			plot.draw();
			setTimeout(update, updateInterval);
		}

		update();

		// Add the Flot version string to the footer

		$("#footer").prepend("Flot " + $.plot.version + " – ");
	});

	</script>
</head>
<body>

	<div id="header">
		<h2>Real-time updates</h2>
	</div>

	<div id="content">

		<div class="demo-container">
			<div id="placeholder" class="demo-placeholder"></div>
		</div>

		<p>You can update a chart periodically to get a real-time effect by using a timer to insert the new data in the plot and redraw it.</p>

		<p>Time between updates: <input id="updateInterval" type="text" value="" style="text-align: right; width:5em"> milliseconds</p>

	</div>

	<div id="footer">
		Copyright © 2007 - 2013 IOLA and Ole Laursen
	</div>

</body>
</html>

HEE HEE. Not a bad afternoons expermimentation. Now to combine it with the Bluetooth Experiments of early October and a nifty bit of hardware called HH ODB Advanced – to use CAN Open to read realtime information.
Stay Tuned.