SL4A + Python 4 Android : Bluetooth and Webviews example

Most of the other non-native frameworks that I’ve used so far are often very good, but lack low-level connectivity modules such as bluetooth (though they pretty much do anything else…). So while hunting around for what I might be able to use for developing a bluetooth app, I ran across SL4A – scripting language for android, and it’s corresponding python module: Py4A – python for android. It’s quite an underrated environment – for something that can do so much, there is less “buzz” around it than I expected. It really can do wonders. Probably the main reason that it hasnt gone mainstream is the inability to package the resulting scripts you write into standalone apps. However, in some situations it is extremely useful – like when you are building a personal app, or, as is my case, your distribution platform is a controlled one and you can pre-install and setup the SL4A environment.

sl4a

Installation is a breeze: you simply each link in turn and download the .APK (make sure your device allows installation of apps from unknown sources). On installation, the installer creates a “scripts” folder located at “/mnt/sdcard/sl4a/scripts“. Any python script you place there can be launched via the SL4A app. I recommend downloading an FTP server for your android device for easy transferring of files to and from your development machine. Then it’s playtime…

For a developer coming from a python and web development background, getting up and running is easy. However, you should still have a once-over the API, which can be found here:

https://code.google.com/p/android-scripting/wiki/ApiReference

In this article, i’ll post basically an amalgamation of two concepts: the bluetooth chat and webviews. We should end up with the following:

1. A bluetooth “client” device that will display the data sent to it over bluetooth in a webview.

2. The bluetooth server can be anything really, but in my case it will be another android device, so i’ll provide the code for the server too.

3. We’ll show off some SL4A UI capabilites…

Note the bluetooth communication is one-way (from server -> client). For two way communication, have a look at the bluetooth_chat.py script that comes included with python for android (and include a little fix I posted about here). Before continuing, if you’d like to know the details of what i’m doing in webviews (especially when it comes to communication between webview and python script) I suggest you have a once over the following excellent article, since I’ll skim over details already posted elsewhere:

http://www.pythoncentral.io/python-for-android-using-webviews-sl4a/

Ok, so let’s start with the setup. As I mentioned before, I used a FTP server and client to create a new folder “daveTest”, inside /mnt/sdcard/sl4a/scripts into which I placed “css” and “js” subfolders. In here, I placed bootstrap + jquery css and javascript files. I’ll be using these within my webview. Then place the main .py script into /mnt/sdcard/sl4a/scripts (i called it daveDemo.py in my case). Looking at the contents of daveDemo.py we see:

from android import Android
import time,sys
# Prepare the python for android API
droid = Android()
# Instruct Py4A which HTML file to use for the webview (we’ll explore this later)
droid.webViewShow('file:///sdcard/sl4a/scripts/daveTest/index.html')
# SL4A uses the concept of events, like javascript does.
# To use them, you need to “register” to events, and take action whenever you detect an event.
# Events are passed with various attributes to your script.
# So for example the “name” attribute allows you to distinguish between different events, while the “data” attribute contains the # data passed by the event
# You create your own event names and data via the webview as we’ll soon see
while True:
# Wait for an event
event = droid.eventWait().result
#If / else statement to determine what action to take depending on the event name
if event['name'] == 'kill':
#exit if webview sends and event named “kill”
sys.exit()
elif event['name'] == 'bluetooth':
#switch bluetooth on
droid.toggleBluetoothState(True)
# this is a bluetooth client, so we just need to ask the user
# which bluetooth server to connect to, and connect
droid.bluetoothConnect()
# wait for a bluetooth message
while True:
# We got a bluetooth message, so emit an event to the webview (using eventPost)
# named “bluetoothOut” and pass the message along with the #event.
message = droid.bluetoothReadLine().result
droid.eventPost('bluetoothOut', message)
#If the message is “quit”, display a native android alert (not a web one) and #exit
if message =='quit':
title = 'dvas0004'
text = 'Server told me to turn bluetooth off'
droid.dialogCreateAlert(title, text)
droid.dialogSetNeutralButtonText('Ok')
droid.dialogShow()
droid.dialogGetResponse().result
droid.dialogDismiss()
break
elif event['name'] == 'sayHi':
# If the event the script receives is called “sayHi” vibrate, create a notification
# in the notification bar, and an alert to boot…
droid.notify('dvas0004',event['data'])
droid.vibrate()
title = 'dvas0004'
text = 'Look at your notifications bar!'
droid.dialogCreateAlert(title, text)
droid.dialogSetNeutralButtonText('Ok')
droid.dialogShow()
droid.dialogGetResponse().result
droid.dialogDismiss()

view raw
daveDemo.py
hosted with ❤ by GitHub

I included some comments in bold and red to illustrate what’s going on… Now, onto the webview. One thing to note, is that unlike normal HTML, webviews do not allow you to use relative filenames. So when linking to external scripts, make sure to use the absolute file name. The index.html file I’ve used for the webview is quite simple:

<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="file:///sdcard/sl4a/scripts/daveTest/css/bootstrap.min.css" />
<script src="file:///sdcard/sl4a/scripts/daveTest/js/bootstrap.min.js"></script>
<script>
/* load the android api in javascipt. This is going to be used mainly to emit and receive events to / from the python script */
var droid = new Android();
/* Just like in the python script, we again need to listen for and take action on events. In this case below,
we are listening for (via the registerCallback) an event called “bluetoothOut” and using the data passed by
the event (in the “e.data” attribute) to fill out an html div. Note how the event name bluetoothOut is exactly
the same as the one I’ve defined in the python script above. Here we are communicating FROM python TO webview */
droid.registerCallback('bluetoothOut', function(e) {
document.getElementById('output').innerHTML = e.data;
});
</script>
</head>
<body>
<h1>Hello World</h1>
with SL4a Webviews<hr>
<!– Here we’ll define a button which emits and event (via “eventPost”) that’s called ‘sayHi’ and contains the data ‘Hi dude!’.
Again note that the event name is exactly the same as the one used in the python script. Here we are communicating FROM webview TO python–>
<btn class="btn btn-primary" onclick="droid.eventPost('sayHi', 'Hi dude!')">Say Hi!</btn>
<hr>
<!– Another event emission, this time to turn on bluetooth and start using it –>
<btn class="btn btn-primary" onclick="droid.eventPost('bluetooth', '')">Enable Bluetooth</btn>
<hr>
<!– Last event to switch off our SL4A program –>
<btn class="btn btn-primary" onclick="droid.eventPost('kill', '')">BYE</btn>
<hr>
<h3>Here be bluetooth output (if enabled)</h3>
<div id="output"></div>
</body>
</html>

view raw
index.html
hosted with ❤ by GitHub

Again, comments in bold / red font color. That’s all there is to it – you can’t get much easier than that i’m sure!!! Think of the possibilities this opens up – you can use your already well-known HTML / Javascript constructs and techniques, to get really low level communication to your android device….

Here’s a video of it in action 🙂

PS, here’s the code for the bluetooth “server” – though again this can be any bluetooth device that emits messages. It’s basically a modified version of the bluetooth_chat.py program that comes bundled with python for android…

import android
import time
droid = android.Android()
droid.toggleBluetoothState(True)
droid.dialogCreateAlert('Be a server?')
droid.dialogSetPositiveButtonText('Yes')
droid.dialogSetNegativeButtonText('No')
droid.dialogShow()
result = droid.dialogGetResponse()
is_server = result.result['which'] == 'positive'
if is_server:
droid.bluetoothMakeDiscoverable()
droid.bluetoothAccept()
else:
droid.bluetoothConnect()
if is_server:
result = droid.dialogGetInput('Chat', 'Enter a message').result
if result is None:
droid.exit()
droid.bluetoothWrite(result + '\n')
while True:
result = droid.dialogGetInput('Chat', 'Enter a message').result
if result is None:
break
droid.bluetoothWrite(result + '\n')
droid.exit()

One thought on “SL4A + Python 4 Android : Bluetooth and Webviews example

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.