tag:blogger.com,1999:blog-83712215440340780322024-02-20T01:37:26.652-08:00Fun2CodeJochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.comBlogger61125tag:blogger.com,1999:blog-8371221544034078032.post-21248540022057583232020-07-06T09:44:00.001-07:002020-07-16T13:29:25.543-07:00Evercade - Flashing Firmware on Linux<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjCRYAdkVSN1TC04rYimvPFxHC_ieREe-GsA5CtXJsAc_WZuSToSwYwZmYyVsSboGQOJvPJaMsmy2YI5lBgyjs6jQ-FcysvpZzpATlgtaikgVqJa54xMSYdgxUDUcmsenxckpasM1vQEM/s1600/evercade.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="72" data-original-width="72" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjCRYAdkVSN1TC04rYimvPFxHC_ieREe-GsA5CtXJsAc_WZuSToSwYwZmYyVsSboGQOJvPJaMsmy2YI5lBgyjs6jQ-FcysvpZzpATlgtaikgVqJa54xMSYdgxUDUcmsenxckpasM1vQEM/s1600/evercade.png" /></a></div>
This article describes how to flash a new Evercade firmware using Linux.<br />
<br />
<h3>
Download Rockchip upgrad_tool</h3>
<pre class="brush:bash">wget https://raw.githubusercontent.com/rockchip-linux/tools/master/linux/Linux_Upgrade_Tool/Linux_Upgrade_Tool/upgrade_tool
chmod 755 upgrade_tool</pre>
<pre class="brush:bash"></pre>
<h3>
Download Evercade Firmware</h3>
<pre class="brush:bash">wget http://evercade-support.co.uk/support/EVERCADE_FW_UPDATE.zip
unzip EVERCADE_FW_UPDATE.zip</pre>
<pre class="brush:bash"></pre>
<h3>
Flash Evercade Firmware</h3>
In this example we will firmware 1.1a.<br />
Connect the Evercade to USB, hold down the MENU button and turn on the console.<br />
Now run the following command:<br />
<br />
<pre class="brush:bash">./upgrade_tool UF "EVERCADE_FW_UPDATE/EVERCADE FW FILE/EVERCADE FW 1.1a.img"
</pre>
<pre class="brush:bash"></pre>
The output should look something like this:<br />
<pre class="brush:bash">Not found config.ini
Program Data in /tmp
Loading firmware...
Support Type:RK312A<span style="white-space: pre;"> </span>FW Ver:8.1.276<span style="white-space: pre;"> </span>FW Time:2020-05-13 18:02:21
Loader ver:2.52<span style="white-space: pre;"> </span>Loader Time:2020-05-13 18:01:00
Upgrade firmware ok.
</pre>
After flashing, the Evercade will restart.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-73550697477335210792016-07-22T04:25:00.000-07:002016-07-30T04:29:25.233-07:00RM mini 3 Workaround<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvD7T7wrZhTKpsm-PMgp3tCR8XQeQZFLk0dcl5Kr5smTTjCePQ1nxlUtjlNsewmVqG33ygkE1TTmBu2Qa-_crMCTueDHG0cp2gFIWkr45jRIFvOQTtX0oVhjr2hRbZMpFi5pXuvf-y0dk/s1600/ic_launcher.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvD7T7wrZhTKpsm-PMgp3tCR8XQeQZFLk0dcl5Kr5smTTjCePQ1nxlUtjlNsewmVqG33ygkE1TTmBu2Qa-_crMCTueDHG0cp2gFIWkr45jRIFvOQTtX0oVhjr2hRbZMpFi5pXuvf-y0dk/s1600/ic_launcher.png" /></a></div>
The <i>RM mini 3</i> is an inexpensive BroadLink device.
Unfortunately the <i>RM mini 3</i> is not supported by the BroadLink API and thus not working with <a href="https://play.google.com/store/apps/details?id=de.fun2code.android.rmbridge" target="_blank">RM Bridge</a> out of the box.<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHVzfH48mvTf5elEWfBiJl_4FvyH3rNh5EcmCt35XM8oZtK_LEiuPSgeDkAZEZeVFz4pllCV7mjVLRCqtEp5Ji9W1ij6Y28FezKJrXCY0iOqbOVasmn4YierimIQk8Wcq6iNO5JLUfvh4/s1600/vitrin+resmi.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHVzfH48mvTf5elEWfBiJl_4FvyH3rNh5EcmCt35XM8oZtK_LEiuPSgeDkAZEZeVFz4pllCV7mjVLRCqtEp5Ji9W1ij6Y28FezKJrXCY0iOqbOVasmn4YierimIQk8Wcq6iNO5JLUfvh4/s200/vitrin+resmi.jpg" width="102" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">BroadLink RM mini 3</td></tr>
</tbody></table>
<br />
Nevertheless the new RM Bridge version 1.3.0 offers a workaround to get <i>RM mini 3</i> devices working.<br />
<br />
RM Bridge in its version 1.3.0 persists all found and manually registered devices. So it is possible to permanently register a <i>RM mini 3</i> manually.<br />
The <i>RM mini 3</i> seems to support the same IR command set as the RM2 which makes it possible to register a <i>RM mini 3</i> as RM2 devices.<br />
<br />
The setup is simply done by using the RM Bridge web interface <a href="http://rm-bridge.fun2code.de/rm_manage/code_learning.html" target="_blank">Code Learning</a> page.<br />
On that page there is a new entry to register a device manually.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8H46k0O5GJb0-ICXv1ozqMVWhZ8kbKDd3_u1GXvH9CrM2FwOebJPSv8ERmt_tWhDLsBXHTlpmtbFcJVqqqPDXLsoQwzq0crYAMnqK8dfKArP9_sp0DWtnFxQdpTwybdQLw5yvpTdSdkE/s1600/rm_bridge_manually_register.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8H46k0O5GJb0-ICXv1ozqMVWhZ8kbKDd3_u1GXvH9CrM2FwOebJPSv8ERmt_tWhDLsBXHTlpmtbFcJVqqqPDXLsoQwzq0crYAMnqK8dfKArP9_sp0DWtnFxQdpTwybdQLw5yvpTdSdkE/s640/rm_bridge_manually_register.png" width="640" /></a></div>
<br />
Fill in a name, the MAC address of the <i>RM mini 3</i>, specify <b>RM2</b> as type and press the <b>Add Manually</b> button.<br />
<br />
After that the <i>RM mini 3</i> should show of in the list of devices.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY6aga4BNqJLFf-3N-JmSkM75FguA2dZUpO67-ItbB81Yt3DCqAEeEPey-xGFFW5T2gWawHiUF0bTodjU2nA-pCDDlxyoIkDpTE5Nt0F1hFRj2Ve4Abku3R6X3Buhz-QPdLCN9Pef43gI/s1600/rm_bridge_devices.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY6aga4BNqJLFf-3N-JmSkM75FguA2dZUpO67-ItbB81Yt3DCqAEeEPey-xGFFW5T2gWawHiUF0bTodjU2nA-pCDDlxyoIkDpTE5Nt0F1hFRj2Ve4Abku3R6X3Buhz-QPdLCN9Pef43gI/s1600/rm_bridge_devices.png" /></a></div>
<br />
Now IR code learning should work the same way as with RM2 devices.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com54tag:blogger.com,1999:blog-8371221544034078032.post-44252495778647683242015-12-19T00:25:00.000-08:002015-12-20T22:21:37.965-08:00Chatting with Binary Web Sockets<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a>This is a follow up article to <a href="http://fun2code-blog.blogspot.de/2013/09/chatting-with-web-sockets.html">Chatting with Web Sockets</a>.<br />
Since version 0.97 beta, PAW Server supports binary Web Sockets. Before that only text base Web Sockets were supported.<br />
<br />
Binary Web Sockets have the benefit (as the name implies) that binary Blobs (Binary Large Objects) can be exchanged. That offers the possibility to exchange binary data. This blog post shows how to use binary Web Sockets to build a simple (multi-) media chat client by using these new capabilities.<br />
<br />
Bellow is a screenshot of the new chat window which also allows to drag and drop (media) files to send them to connected clients. There are two drop areas, the button titled <i>Drop / Select</i> and the message output area. In addition files can be selected by pressing the <i>Drop / Select</i> button.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijKabiKj1H0gmawtUL_NOj36Er_5CD3Zll1fcstVWiZOobwH7EcOK26NSH5zEMUP9ti8KvVqAnYkrJyMIi62oq8iySRh1-yHDqgwgVR0j2rtPasYTwqDZnFhLTr_4rkXErIplUFcGmgR0/s1600/chat2_screenshot.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijKabiKj1H0gmawtUL_NOj36Er_5CD3Zll1fcstVWiZOobwH7EcOK26NSH5zEMUP9ti8KvVqAnYkrJyMIi62oq8iySRh1-yHDqgwgVR0j2rtPasYTwqDZnFhLTr_4rkXErIplUFcGmgR0/s640/chat2_screenshot.png" width="250" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Chat Window</td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: center;"></div>
Supported file types depend on the used browser, but normally audio, video, text and html files should work.<br />
<br />
The setup is almost identical to the one described inside the former post <a href="http://fun2code-blog.blogspot.de/2013/09/chatting-with-web-sockets.html">Chatting with Web Sockets</a>.<br />
Only the ZIP file including HTML/CSS and JavaScript files are different. You'll find a link to the ZIP file below that post.<br />
<br />
So to make sure Web Sockets are setup correctly follow the following steps from the post <a href="http://fun2code-blog.blogspot.de/2013/09/chatting-with-web-sockets.html">Chatting with Web Sockets</a>:<br />
<ol>
<li>Configuring the Web Socket Handler</li>
<li>Web Socket Config File</li>
<li>The BeanShell Script</li>
</ol>
<div>
After the configuration is finished, the only thing left is to extract the ZIP file into a folder (e.g. <span style="font-family: "courier new" , "courier" , monospace;">chat2</span>) of your choice inside the <span style="font-family: "courier new" , "courier" , monospace;">[PAW_HOME]/html</span> folder (usually <span style="font-family: "courier new" , "courier" , monospace;">/sdcard/paw</span>) and to call that page from a browser.</div>
<div>
<br /></div>
<div>
You can now try to connect to the web page (e.g. <span style="font-family: "courier new" , "courier" , monospace;">http://<ip>:8080/chat2/</span>) with multiple browsers and see if the chat is working.</div>
<div>
<br /></div>
<div>
Have fun and merry Xmas :)</div>
<div>
<br /></div>
<h3>
Links</h3>
<div>
ZIP file: <a href="http://paw-android.fun2code.de/blog/web_sockets_chat2.zip" target="_blank">web_sockets_chat2.zip</a></div>
<div>
<br /></div>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com5tag:blogger.com,1999:blog-8371221544034078032.post-83367824877718332192015-12-06T01:40:00.002-08:002016-09-02T09:28:21.430-07:00Extending Handlers with BeanShell<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
This post will show how to extend an existing handler by using BeanShell.<br />
Since PAW 0.96 BeanShell can be used to write handlers (and filters). In earlier versions of PAW handlers and filters had to be provided as Java class file, so a Java development environment was needed. By the use of BeanShell handlers and filters can now be developed directly on an Android device. This is especially handy when developing handler and filters for testing.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ7BbVpMOhB4fH88FGZ3VBzhCnSERV7sGR1hXvNkj3fpLPSJuFijTmxPOFNvEVcke-CCCw3RUTUKKqHYgiVdHOIeO8qqVN-hoENOwUfxwE_G7lLxrMeSXBt_6LgUxctyyKsF_eMWVjvf4/s1600/native_mapper.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ7BbVpMOhB4fH88FGZ3VBzhCnSERV7sGR1hXvNkj3fpLPSJuFijTmxPOFNvEVcke-CCCw3RUTUKKqHYgiVdHOIeO8qqVN-hoENOwUfxwE_G7lLxrMeSXBt_6LgUxctyyKsF_eMWVjvf4/s320/native_mapper.png" width="281" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PAW Standard Handler Chain</td></tr>
</tbody></table>
<br />
I’ll briefly recap what handlers are good for.<br />
Handlers form the processing chain on HTTP requests. Handler are organized in a list that is processed until a handler processing the request is found. If a handler signals that it can handle the request, the handler will process the request and the list of handlers is no longer processed.<br />
<br />
In the example we will extend the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> which handles the basic authentication to protect a web resource (most often a directory).<br />
The handler will be extended in the way, that it will only request credentials if pages are called from external, localhost request should not need to authenticate.<br />
<br />
The standard <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> does not provide this functionality. It always asks for credentials, regardless where the request came from.<br />
<br />
Since PAW 0.96 there is a new handler called <span style="font-family: "courier new" , "courier" , monospace;">CallBshHandler</span> which accepts a BeanShell file to act as a handler.<br />
<br />
The BeanShell file has the following base structure:<br />
<br />
<pre class="brush:java">/*
Variables: server, prefix, handler
*/
init() {
}
/*
Variables: server, prefix, handler, request
*/
respond() {
}
</pre>
<br />
There are the two methods <span style="font-family: "courier new" , "courier" , monospace;">init() </span>and <span style="font-family: "courier new" , "courier" , monospace;">respond()</span>. Both methods return <span style="font-family: "courier new" , "courier" , monospace;">true</span> on success and <span style="font-family: "courier new" , "courier" , monospace;">false</span> on failure. The <span style="font-family: "courier new" , "courier" , monospace;">init()</span> method receives the <span style="font-family: "courier new" , "courier" , monospace;">server</span>, <span style="font-family: "courier new" , "courier" , monospace;">prefix</span> and <span style="font-family: "courier new" , "courier" , monospace;">handler</span> variables. The server and prefix variables are needed to get configuration parameters specified inside the <span style="font-family: "courier new" , "courier" , monospace;">conf/handler.xml </span>file. The handler variable holds a reference to the calling <span style="font-family: "courier new" , "courier" , monospace;">CallBshHandler</span> instance. This instance is needed to persist settings (between <span style="font-family: "courier new" , "courier" , monospace;">init()</span> and <span style="font-family: "courier new" , "courier" , monospace;">response()</span>) methods. This is necessary, because <span style="font-family: "courier new" , "courier" , monospace;">init()</span> and <span style="font-family: "courier new" , "courier" , monospace;">response()</span> are not called within the same BeanShell interpreter instance (to make the handler thread safe). To persists objects within the handler, the methods <span style="font-family: "courier new" , "courier" , monospace;">save() </span>and <span style="font-family: "courier new" , "courier" , monospace;">load()</span> are provided. The example will show how these methods are used.<br />
<br />
Extending the current <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> will be done in three steps:<br />
<ol>
<li>Disable the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span></li>
<li>Create the new handler</li>
<li>Configure the new handler</li>
</ol>
<h3>
</h3>
<h3>
Disable the BasicAuthHandler</h3>
To disabling the current <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span>, find the following handler in the <span style="font-family: "courier new" , "courier" , monospace;">conf/handler.xml</span> file and change the status property to inactive<br />
<pre class="brush:xml"><handler status="inactive">
<name>Basic Auth Handler</name>
…
</hadler></pre>
<h3>
</h3>
<h3>
Create the New Handler</h3>
We will now build a handler that calls the standard <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> only on external requests. Local requests, which have the IP number <span style="font-family: "courier new" , "courier" , monospace;">127.0.0.1</span> or <span style="font-family: "courier new" , "courier" , monospace;">::1</span> will not be processed and so no credentials will be requested.<br />
<br />
To build the new handler, create a directory <span style="font-family: "courier new" , "courier" , monospace;">handler</span> inside the PAW installation folder (<span style="font-family: "courier new" , "courier" , monospace;">paw/handler</span>). Inside that folder create a file called authHandler.bsh with the following content:<br />
<br />
<pre class="brush:java">import org.paw.handler.BasicAuthHandler;
LOCALHOST = "127.0.0.1";
LOCALHOST_V6 = "::1";
/*
Variables: server, prefix, handler
*/
init() {
authHandler = new BasicAuthHandler();
handler.save("authHandler", authHandler);
return authHandler.init(server, prefix);
}
/*
Variables: server, prefix, handler, request
*/
respond() {
ip = request.sock.getInetAddress().getHostAddress();
if(ip.equals(LOCALHOST) || ip.equals(LOCALHOST_V6)) {
return false;
}
authHandler = handler.load("authHandler");
return authHandler.respond(request);
}
</pre>
<br />
The code is straightforward. Inside the <span style="font-family: "courier new" , "courier" , monospace;">init() </span>method the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> is instantiated. That instance is saved within the calling handler by calling <span style="font-family: "courier new" , "courier" , monospace;">handler.save()</span>.<br />
The last line of the <span style="font-family: "courier new" , "courier" , monospace;">init()</span> method returns the result of the call to i<span style="font-family: "courier new" , "courier" , monospace;">nit() </span>of the instantiated <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> class.<br />
<br />
If the <span style="font-family: "courier new" , "courier" , monospace;">init()</span> method returns true, the handler will be added to the list of handlers and the <span style="font-family: "courier new" , "courier" , monospace;">respond()</span>method will be called on each request.<br />
<br />
When the <span style="font-family: "courier new" , "courier" , monospace;">respond()</span> method is called it first gets the requestor’s IP number and assigns it to the variable <span style="font-family: "courier new" , "courier" , monospace;">ip</span>. If the variable contains a localhost IP (<span style="font-family: "courier new" , "courier" , monospace;">127.0.0.1</span> or <span style="font-family: "courier new" , "courier" , monospace;">::1</span>) the method returns <span style="font-family: "courier new" , "courier" , monospace;">false</span>, which indicates that the handler will not handle the request.<br />
In that case no credentials are requested and the handler chain is further processed.<br />
<br />
If the request is not initiated by a localhost address, the <span style="font-family: "courier new" , "courier" , monospace;">respond()</span> method of the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> instance is called and the return value of that method is returned.<br />
<br />
<br />
<h3>
Configure the New Handler</h3>
To configure the new handler, just place the following handler definition below or above the original <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span> definition of the c<span style="font-family: "courier new" , "courier" , monospace;">onf/hander.xml</span> file:<br />
<br />
<pre class="brush:xml"><handler status="active">
<name>BeanShell auth handler</name>
<description>Auth handler that allows local access</description>
<removable>true</removable>
<id>bshAuth</id>
<files/>
<params>
<param name="bshAuth.class" value="org.paw.handler.CallBshHandler" />
<param name="bshAuth.script" value="[PAW_HOME]/handler/authHandler.bsh" />
<param name="bshAuth.confdir" value="[PAW_HOME]/webconf/auth" />
</params>
</handler>
</pre>
<br />
The parameters describe the <span style="font-family: "courier new" , "courier" , monospace;">class</span> (<span style="font-family: "courier new" , "courier" , monospace;">org.paw.handler.CallBshHandler</span>) and <span style="font-family: "courier new" , "courier" , monospace;">script</span> (<span style="font-family: "courier new" , "courier" , monospace;">[PAW_HOME]/handler/authHandler.bsh</span>) to use. The third parameter called <span style="font-family: "courier new" , "courier" , monospace;">confdir</span> is the standard configuration parameter used by the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHandler</span>. The BeanShell handler passes this parameter when calling the <span style="font-family: "courier new" , "courier" , monospace;">BasicAuthHander.init()</span> method from its i<span style="font-family: "courier new" , "courier" , monospace;">nit()</span> method.<br />
<br />
Because the new handler calls the standard handler, the Directory Protection settings from within PAW’s web interface also apply to the new handler.<br />
<br />
On next startup of the server the new handler should be active. If the startup fails, increase the log level, restart the server and have a look at the log file.<br />
<br />
<h3>
Testing the Handler</h3>
To test the handler, I’ve created a directory <span style="font-family: "courier new" , "courier" , monospace;">test</span> within the <span style="font-family: "courier new" , "courier" , monospace;">html</span> folder (<span style="font-family: "courier new" , "courier" , monospace;">html/test</span>). For the at folder, directory protection has been setup using the Directory Protection page of the web interface.<br />
The <span style="font-family: "courier new" , "courier" , monospace;">localhost</span> connection was tested by using ADB’s TCP forward parameter (<span style="font-family: "courier new" , "courier" , monospace;">adb forward tcp:8080 tcp:8080</span>).<br />
<br />
When testing with an IP number, authentication is required:<br />
<br />
<pre class="brush:bash">$ telnet 192.168.178.79 8080
Trying 192.168.178.79...
Connected to 192.168.178.79.
Escape character is '^]'.
GET /test/ HTTP/1.0
HTTP/1.0 401 Unauthorized
WWW-Authenticate: basic realm="Bsh Auth Test"
Date: Sun, 06 Dec 2015 09:05:38 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 34
Content-Type: text/html
Missing http header: AuthorizationConnection closed by foreign host.
</pre>
<br />
On a localhost request, no authentication is needed and the directory listing is displayed:<br />
<br />
<pre class="brush:bash">$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /test/ HTTP/1.0
HTTP/1.0 200 OK
Set-Cookie: cookie=7th5kto9f4nrf1a5r8pdse; PATH=/
Date: Sun, 06 Dec 2015 09:08:32 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 99
Content-Type: text/html
<title>Directory Listing</title>
<h1>Directory Listing</h1>
<a href=..><b>parent directory</b></a>
Connection closed by foreign host.
</pre>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-70775159272915000192015-11-25T07:18:00.000-08:002015-12-19T00:28:06.434-08:00WSMirror - Web Screen Mirror<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfgA5bfh7Rq0VQjEArKJ5A-5q-mIXu1A0xEFYUl3B8o1peSwtUQGpfZsu79WF24W-CGWkSt_A_j0lgtMwg0OhTgY9UPIktOLsE90h-3NxIwBffTvjrEOwt6XevP0NYLU01rAWfbohWiV8/s1600/ic_launcher.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfgA5bfh7Rq0VQjEArKJ5A-5q-mIXu1A0xEFYUl3B8o1peSwtUQGpfZsu79WF24W-CGWkSt_A_j0lgtMwg0OhTgY9UPIktOLsE90h-3NxIwBffTvjrEOwt6XevP0NYLU01rAWfbohWiV8/s1600/ic_launcher.png" /></a></div>
WSMirror is a small app that mirrors the device screen and displays it within a web browser.<br />
This can be handy for presentations or talks to present the device screen to a larger audience. The app uses the <i>MediaProjection API</i> available since Android Lollipop (5.x). So the app will only work on Devices running Lollipop or higher.<br />
Due to the use of the <i>MideaProjection API </i><b>no root</b> is required.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEgY4_EChszhN7KGpdn2Ft5LdEK_07vNGRee3jE-ss1JoxRecHNd_UawyLav6PdW9b1lkuWP17tN_3EQXnUt9dscqgLQfZTNUSJwdqGi_-owp_PEJ9FsQLMoQUQpIfm8kaiDdZ3OKXnxI/s1600/screen1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEgY4_EChszhN7KGpdn2Ft5LdEK_07vNGRee3jE-ss1JoxRecHNd_UawyLav6PdW9b1lkuWP17tN_3EQXnUt9dscqgLQfZTNUSJwdqGi_-owp_PEJ9FsQLMoQUQpIfm8kaiDdZ3OKXnxI/s320/screen1.jpg" width="184" /></a></div>
<br />
<br />
<screenshot></screenshot>
After pressing the start button a URL will be displayed. This URL can be inserted into the address bar of a mordern browser (WebSockets are required). The page will display the mirrored screen. Multiple connections are possible and device rotation is supported.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_4vuQrIEh-L-3oSrhKoJz0mwGvohKYjP8Io3H1G_2NutiXGki8S4Ygs4suX83h1p8N322LhGAsk3BOtUWJ25hzrvNnane7gHutNN5OUVjfA32U_RuvHrXkVyaEX-WKUrN0jaitXT8zNU/s1600/screenshot_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_4vuQrIEh-L-3oSrhKoJz0mwGvohKYjP8Io3H1G_2NutiXGki8S4Ygs4suX83h1p8N322LhGAsk3BOtUWJ25hzrvNnane7gHutNN5OUVjfA32U_RuvHrXkVyaEX-WKUrN0jaitXT8zNU/s320/screenshot_2.png" width="320" /></a></div>
<br />
<screenshots></screenshots><br />
If the screen refresh is too slow, scaling and quality can be adjusted to make the mirroring more responsive.<br />
To stop WSMirror, just press the stop button.<br />
<br />
WSMirror is available on Google Play.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://play.google.com/store/apps/details?id=de.fun2code.android.wsmirror" target="_blank"><img border="0" height="58" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGYrqGeoIcl8Mp639-1nPQlAdbVUtBStvWRMiLIgEBcjsAonyPznZcUZNMvJpYGix2hVduoOXaZhiRZKVMo7KNRWC6Mt9jnfN27vpNEfjGDsahmXv5RIfpmOhoTV7TKDRtl28vXEuQy8o/s200/en-play-badge.png" width="200" /></a></div>
<br />Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com2tag:blogger.com,1999:blog-8371221544034078032.post-43085129095838221802015-10-03T23:15:00.002-07:002015-10-03T23:45:15.078-07:00PAW - New Tags<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
Since PAW Server 0.96 BeanShell tag handling in XHTML files has been improved. In addition PHP like tags are now supported.<br />
In older PAW versions it was a bit cumbersome to write XHTML pages because BeanSHell and HTML could not be mixed. The following code would not have worked:<br />
<br />
<div style="text-align: right;">
</div>
<pre class="brush:xml" style="width: 50%;"><bsh>if(i > 0) {</bsh>
<h3>TEST</h3>
<bsh>}</bsh>
</pre>
<br />
This code now works in the new PAW version, because PAW does no longer execute BeanShell blocks separately but does build complete BeanShell script representing the page that is executed as a whole.<br />
<br />
The old <span style="font-family: Courier New, Courier, monospace;"><bsh></bsh></span> tags <span style="font-family: "Courier New",Courier,monospace;"><bsh> ... </bsh></span> still do work, but in addition PHP like <span style="font-family: "Courier New",Courier,monospace;"><?bsh ... ?> </span>tags <span style="font-family: Courier New, Courier, monospace;"> </span>are available.<br />
Here is a short example:<br />
<br />
<pre class="brush:xml"><?bsh if(i > 0) { ?>
<h3>TEST</h3>
<?bsh } ?>
</pre>
<br />
To make it easier to output BeanShell variables inside HTML code easier the short print tag <span style="font-family: "Courier New",Courier,monospace;"><?= ... ?> </span> is now available:<br />
<br />
<pre class="brush:xml"><?bsh i = 7; { ?>
<b>Value of i = </b> <?=i ?>
<?bsh } ?>
</pre>
<br />
<h3>
Debugging</h3>
Sometimes BeanShell error output in XHTML pages might be hard to read and it sometimes makes development more complicated than it should be.<br />
<br />
A BeanShell error output that is visible inside the HTML source looks like this:<br />
<br />
<pre class="brush:xml"><!--
BeanShell Error:
bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( )
-->
</pre>
<br />
Now that the whole page is executed as one entity there is the possibility to show the generated code inside the HTML page source when an error occurred.<br />
By default this feature is disabled (not everyone should see your code), but while developing it's a good idea to turn it on.<br />
<br />
To enable the enhanced debug output, change the the value of the <span style="font-family: Courier New, Courier, monospace;">bsh.debug</span> property inside the <span style="font-family: Courier New, Courier, monospace;">paw/con/handler.xml</span> from <span style="font-family: Courier New, Courier, monospace;">false</span> to <span style="font-family: Courier New, Courier, monospace;">true </span>and restart the server.<br />
<br />
<pre class="brush:xml"><param name="bsh.debug" value="true" />
</pre>
<br />
The above sample error message is now enhanced with the generated BeanShell code.<br />
<br />
<pre class="brush:xml"><!--
BeanShell Error:
bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( )
-->
<!--
Generated BeanShell Code:
1 $$.print("<html>\n<body>\n");
2 // Imports
3 import de.fun2code.android.pawserver.AndroidInterface;
4 import android.content.Context;
5 import android.hardware.Sensor;
6 sensorListener = AndroidInterface.getSensorListener();
* 7 proximity = sensorListene.getProximity();
-->
</pre>
<br />
If possible the erroneous line is marked with an asterisk (*). This should make finding the error much easier.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-87253834530143967092015-09-22T09:03:00.000-07:002015-10-03T23:16:33.215-07:00Digest Authentication<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
Although the PAW Server configuration does not include Digest Authentication by default, this authentication scheme is available and can be configured inside the <span style="font-family: Courier New, Courier, monospace;">paw/conf/handler.xml </span>configuration file.<br />
<br />
To enable Digest Authentication, add the following lines to the <span style="font-family: Courier New, Courier, monospace;">paw/conf/handler.xml</span> file just after the opening <span style="font-family: Courier New, Courier, monospace;"><handlers></span> tag:<br />
<br />
<pre class="brush:xml"> <handler status="active">
<name>Digest Handler</name>
<description>Digest authentication handler.</description>
<removable>true</removable>
<id>authDigest</id>
<files/>
<params>
<param name="authDigest.class" value="sunlabs.brazil.handler.DigestAuthHandler" />
<param name="authDigest.prefix" value="/" />
<param name="authDigest.realm" value="Protected" />
<param name="authDigest.credentials" value="[PAW_HOME]/webconf/auth/digest.conf" />
</params>
</handler>
</pre>
<br />
This configuration protects the whole web site, if you would only like to protect a single directory, you can change the <span style="font-family: Courier New, Courier, monospace;">prefix</span> parameter.<br />
<br />
Now create a file called <span style="font-family: Courier New, Courier, monospace;">paw/webconf/auth/digest.conf </span>with the following content:<br />
<br />
<pre class="brush:bash">#---------------------------------------------------------
# Digest Authenticatin configuration
#---------------------------------------------------------
# Format:
# username=plain password
#
# Instead of the plain password, HA1 can be used:
# md5(user:realm:pass)
#
# username=HA1
#---------------------------------------------------------
user=test
</pre>
<br />
The sample user is called <span style="font-family: Courier New, Courier, monospace;">user</span>, with the password <span style="font-family: Courier New, Courier, monospace;">test</span>.<br />
It is recommended to build the HA1 hash for security reasons.<br />
<br />
For the changes to take effect, restart the server.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com4tag:blogger.com,1999:blog-8371221544034078032.post-17522568976461505602015-08-15T03:24:00.000-07:002015-10-03T23:16:50.355-07:00Advanced PAW Server - Pre-Release 1<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
PAW's documentation is far from perfect and I often get questions from users how things work. To make life for users and me easier I decided to write an eBook how to use PAW's API to write dynamic web applications.<br />
<br />
This is the first pre-release of <b>Advanced PAW Server</b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikdrGOH8mHFRK9TZS5BH8aCxl0E00M3GIfHt5XEmVRkmeIu2a5RqB7NqCyxeTeVd5u5fzXoshZWM5iph0jSuAVw8SRpGu0ORE58MwHJgWqTp-YdVAHt1lYi33wK-aGVcRp25oDod3EJGE/s1600/cover_advanced_paw_server.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikdrGOH8mHFRK9TZS5BH8aCxl0E00M3GIfHt5XEmVRkmeIu2a5RqB7NqCyxeTeVd5u5fzXoshZWM5iph0jSuAVw8SRpGu0ORE58MwHJgWqTp-YdVAHt1lYi33wK-aGVcRp25oDod3EJGE/s320/cover_advanced_paw_server.png" width="225" /></a></div>
<br />
<br />
<br />
It is not complete and surely contains a lot of bugs and typos.<br />
Nevertheless I hope it is already useful at this point.<br />
<br />
Have fun :)<br />
<br />
The eBook is available in PDF format.<br />
<br />
Here is the download Link:<br />
<a href="https://goo.gl/6BDgno" target="_blank">https://goo.gl/6BDgno</a>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com9tag:blogger.com,1999:blog-8371221544034078032.post-37362189095626359822014-12-10T06:17:00.002-08:002018-02-21T04:41:09.277-08:00PAW - Using JavaMail<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
I got a question (hello Guy) regarding sending mails via PAW Server.<br />
In this use case an Arduio Uno sends HTTP request to PAW which then sends a mail via SMTP to a mail relay.<br />
<br />
<pre> --------- ---------------
| Arduino | ---- HTTP --> | Android / PAW | ---- SMTP -->
--------- ---------------
</pre>
So far for the setup seems quite easy.<br />
Unfortunately (as so often) this is not as easy as it seems. The Android API does not include means to send mails via SMTP. Something like JavaMail is not included.<br />
This post will show how to use JavaMail together with PAW to implement the above use case.<br />
You'll find a <i>Short</i> and a <i>Long Version</i>. The <i>Short Version</i> contains only the necessary downloads and scripts to get things running.<br />
For those interested in technical detail there is the Long Version which will explain things in more detail.<br />
There is a pitfall when using Gmail. So in case you are a Gmail user, please read <i>Using Gmail</i> in addition.<br />
<br />
<h3>
Short Version</h3>
Download this <a href="http://goo.gl/Pkd5Gs" target="_blank">paw_javamail.zip</a> ZIP file from Google Drive and extract it to your PAW installation folder (normally <span style="font-family: "courier new" , "courier" , monospace;">/sdcard/paw</span>) inside the <span style="font-family: "courier new" , "courier" , monospace;">webconf/dex</span> folder.<br />
The ZIP file contains the JavaMail libraries from the <a href="http://code.google.com/p/javamail-android/" target="_blank">javamail-android</a> project together with an utility library to make sending of mails via PAW easier.<br />
<br />
After a restart of PAW Server everything should be setup to send mails from the BeanShell console.<br />
<br />
Here is a test script:<br />
<br />
<pre class="brush:java">useDexClasses();
import de.fun2code.paw.mail.*;
// Construct a mail class that holds all the server settings
mail = new Mail("smtp.gmail.com", 587, "user@gmail.com",
"password", Mail.TransportType.TLS);
// Send an SMTP message including attachments
mail.sendSmtp("sender@gmail.com", "recipient@whatever.com",
"Test subject", "Test message ...", new File[] { new File("/sdcard/image1.jpg"), new File("/sdcard/image2.jpg") });
</pre>
<br />
First we create a mail object that holds the SMTP server, authentication and connection settings.<br />
The connection are in this example set to <span style="font-family: "courier new" , "courier" , monospace;">TLS</span>, but could also be <span style="font-family: "courier new" , "courier" , monospace;">SSL</span> or <span style="font-family: "courier new" , "courier" , monospace;">PLAIN</span>.<br />
In this case Gmail ist used but could be any other provider.<br />
<br />
The <span style="font-family: "courier new" , "courier" , monospace;">sendSmtp</span> method implements the sending of the mail message and takes sender, recipient, subject, body message and an attachment <span style="font-family: "courier new" , "courier" , monospace;">File</span> array as parameter.<br />
If no attachments should be added, just pass <span style="font-family: "courier new" , "courier" , monospace;">null</span> as parameter.<br />
<br />
In case of Gmail you'll have to take additional steps to get this working, please read <i>Using Gmail</i> below.<br />
<br />
<h3>
Using Gmail</h3>
When using Gmail, the following <span style="font-family: "courier new" , "courier" , monospace;">Exception</span> is likely to occur:<br />
<br />
<pre>javax.mail.AuthenticationFailedException
</pre>
<br />
The reason for this is that Google does not allow third party apps to access Gmail by default.<br />
In my case I got a mail from Google which included the following link to lower my Gmail security:<br />
<br />
<a href="https://www.google.com/settings/security/lesssecureapps" target="_blank">https://www.google.com/settings/security/lesssecureapps</a><br />
<br />
After lowering security, everything worked as expected.<br />
<br />
<h3>
Long Version</h3>
Let's get a bit into detail ...<br />
<br />
Why is it necessary to use the files form the <a href="http://code.google.com/p/javamail-android/" target="_blank">javamail-android</a> project and why is a separate utility class needed for sending mails?<br />
<br />
My first take on JavaMail was to download the JavaMail JAR file from the official Oracle web site and use it within PAW. For JAR files to work on Android devices they have to be converted into Dalvic Executable (DEXed) format. For more info about DEXing, you can have a look at the following blog post: <a href="http://fun2code-blog.blogspot.de/2011/07/paw-dynamic-dex-class-loading.html" target="_blank">PAW - Dynamic DEX Class Loading</a><br />
<br />
Not all classes can bed converted into DEX format, some just don't work. That's the case with the <i>Activation</i> classes needed by JavaMail. That's why the official libraries cannot be used.<br />
Here comes the <a href="http://code.google.com/p/javamail-android/" target="_blank">javamail-android</a> project to the rescue which provides DEXable JavaMail libraries.<br />
These are the library included inside the <a href="http://goo.gl/Pkd5Gs" target="_blank">paw_javamail.zip</a> ZIP file.<br />
<br />
Inside the ZIP file as well comes a DEXed version of the <span style="font-family: "courier new" , "courier" , monospace;">de.fun2code.paw.mail.Mail </span>class which implements the sending of SMTP messages. Why do we need that class, couldn't we have just put all that code insde a BeanShell script?<br />
<br />
In principle yes, but BeanShell on Android does not have the possibility to compile all (inner) classes. That's just not working for the authentication part of JavaMail. So that's why there is this precompiled additional class, which in addition also has the advantage of being faster than the equivalent BeanShell code.<br />
<br />
Below is the complete <span style="font-family: "courier new" , "courier" , monospace;">de.fun2code.paw.mail.Mail </span>class which uses plain JavaMail.<br />
<br />
<br />
<pre class="brush:java">package de.fun2code.paw.mail;
import java.io.File;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
* Class that contains methods to send SMTP messages via JavaMail
*/
public class Mail {
public static enum TransportType {
PLAIN, TLS, SSL
};
private TransportType transport;
private String smtpServer;
private int smtpPort;
private String username;
private String password;
/**
* The constructor takes the basic connection parameters
*
* @param smtpServer SMTP server name
* @param smtpPort SMTP server name
* @param username authentication user name
* @param password authentication password
* @param transport transport type: PLAIN, TLS or SSL
*/
public Mail(String smtpServer, int smtpPort, String username,
String password, TransportType transport) {
this.smtpServer = smtpServer;
this.smtpPort = smtpPort;
this.username = username;
this.password = password;
this.transport = transport;
}
/**
* Sends a SMTP mail message
*
* @param from sender name
* @param to recipient name
* @param subject mail subject
* @param messageText body text
* @param attachments attachments to attach
* @throws MessagingException
*/
public void sendSmtp(String from, String to,
String subject, String messageText, File[] attachments) throws MessagingException {
String strPort = String.valueOf(smtpPort);
// Fill basic properties
Properties props = new Properties();
props.put("mail.smtp.host", smtpServer);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", strPort);
// Add connection properties
switch(transport) {
case TLS:
props.put("mail.smtp.starttls.enable", "true");
break;
case SSL:
System.out.println("Using SSL ...");
props.put("mail.smtp.socketFactory.port", strPort);
props.put("mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
break;
case PLAIN:
break;
}
// Create the session
Session session = Session.getInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
try {
// Create MimeMessage
Message message = new MimeMessage(session);
// Set from header
message.setFrom(new InternetAddress(from));
// Set to header
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to));
// Add subject
message.setSubject(subject);
// Add attachments if available
if(attachments != null) {
Multipart multipart = new MimeMultipart();
// The body message
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText(messageText, "utf-8");
multipart.addBodyPart(textPart);
for(File file : attachments) {
MimeBodyPart messageBodyPart = new MimeBodyPart();
DataSource source = new FileDataSource(file.getAbsoluteFile());
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(file.getName());
multipart.addBodyPart(messageBodyPart);
}
message.setContent(multipart);
}
else {
// Add the body message
message.setText(messageText);
}
// Send the message
Transport.send(message);
} catch(MessagingException e) {
throw e;
}
}
}
</pre>
<br />
<br />Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-83629541544894899342014-11-08T09:47:00.000-08:002014-11-14T05:39:43.433-08:00Microbes - Fast Paced Casual Game<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIxkK0gAnZZq4eR98ubk_GgV8jf4gnCASLrk8ZDHSKPbjbyQbK3t5OQ4FOYPtxuZjpcHi-4qLOPSVVMB6pMyuPG1r4ks-WVGjwARVSdqMl5IIQgLfWYSekPHDjeT8tSWpP2cZlSBDY8Lc/s1600/microbes.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIxkK0gAnZZq4eR98ubk_GgV8jf4gnCASLrk8ZDHSKPbjbyQbK3t5OQ4FOYPtxuZjpcHi-4qLOPSVVMB6pMyuPG1r4ks-WVGjwARVSdqMl5IIQgLfWYSekPHDjeT8tSWpP2cZlSBDY8Lc/s1600/microbes.png" /></a></div>
This is a guest post by Michaela presenting her first game <i><a href="http://goo.gl/Hr1PSX" target="_blank">Microbes</a></i> available now on Google Play.<br />
<br />
The original post in German can be found <a href="http://morgaine1976.blogspot.de/2014/10/microbes-das-actionreiche-spiel-fur.html" target="_blank">here</a> ...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/9efy9dyqD4c?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<div style="text-align: center;">
<span style="font-size: x-small;"><i>Microbes Promo Video</i></span></div>
<hr />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXjxxbbbYL6PMeo6rLYU-fjEc9tKGN8ITy52g6QHuEa0S1dUKAiqwl2nHwyn1g0LjhZK2RZxUjmCOjPhQnsLwtSpQ4nPD_cfn3mEW6oEkotYoEmWlVVHozQQkOBDFwNPEw_cBMj2PpfhXa/s1600/dumpSpider.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXjxxbbbYL6PMeo6rLYU-fjEc9tKGN8ITy52g6QHuEa0S1dUKAiqwl2nHwyn1g0LjhZK2RZxUjmCOjPhQnsLwtSpQ4nPD_cfn3mEW6oEkotYoEmWlVVHozQQkOBDFwNPEw_cBMj2PpfhXa/s1600/dumpSpider.gif" height="162" width="320" /></a></div>
<br />
<div style="text-align: center;">
Yeah, it is finished :) </div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
moreGainE1976's first Android Game is released to play!</div>
<div style="text-align: center;">
Now you can visit the small and cute <b>Microbes</b> on their garbage dump!</div>
<span id="goog_2080788981"></span><span id="goog_2080788982"></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHRh8JXZ8nkZ5dUNaNoDWL7Hw3A2EgFYYYFHy9d34ELIMuMOsrQICZs-IVwIqi-bTphHalIeB2Fh0LuMHCEPXwNnqAppc_q3n0Cn6Fd6wUonCkh2kdxntgc2_m3ridZp_hqHtWLFbZjgFP/s1600/qrcode.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHRh8JXZ8nkZ5dUNaNoDWL7Hw3A2EgFYYYFHy9d34ELIMuMOsrQICZs-IVwIqi-bTphHalIeB2Fh0LuMHCEPXwNnqAppc_q3n0Cn6Fd6wUonCkh2kdxntgc2_m3ridZp_hqHtWLFbZjgFP/s1600/qrcode.png" height="200" width="200" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">Link to Google Play Store: <a href="http://goo.gl/Hr1PSX" target="_blank">http://goo.gl/Hr1PSX</a></span></div>
<h2>
</h2>
<h3>
The Main Characters</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKPgCiFSzpfUB0bH7aEywashlrTc0xTmmr_80PHn0LIjNqGk1C4pxefoCVHSW5hwE-zrLVN6BZiXaXVe2isasCGv9XSeIHWqouvxVx56Z166reOTlOFp6RpnRX29ZtDPb3uRVtz8SiJ9_G/s1600/SBase.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKPgCiFSzpfUB0bH7aEywashlrTc0xTmmr_80PHn0LIjNqGk1C4pxefoCVHSW5hwE-zrLVN6BZiXaXVe2isasCGv9XSeIHWqouvxVx56Z166reOTlOFp6RpnRX29ZtDPb3uRVtz8SiJ9_G/s1600/SBase.gif" /></a></div>
<br />
<br />
This small and <b>green scaredy cat</b> is the smallest Microbe, that is allowed to play on the garbage dump. Its only job is to be afraid and to be eaten.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGLBB7phD0Vw6E8d7snrQTGBfGdy0gffCy_8B-DMscDS5Ce7zbErfnYiU-OKZrtgaQrNNAOuCRbg2Ik6OivpmgKVJEcl2FNhQM62NVeBIrOgw5s6IJr26XusPEUsn_a71hjYAZ7bWUkP6o/s1600/MBase.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGLBB7phD0Vw6E8d7snrQTGBfGdy0gffCy_8B-DMscDS5Ce7zbErfnYiU-OKZrtgaQrNNAOuCRbg2Ik6OivpmgKVJEcl2FNhQM62NVeBIrOgw5s6IJr26XusPEUsn_a71hjYAZ7bWUkP6o/s1600/MBase.gif" /></a></div>
<br />
<br />
The next bigger one is the <b>yellow Microbe with the funny snouts</b> as ears. It eats smaller green Microbes and prefers many at once. Nevertheless, it must have to worry if the larger Microbe is near:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg83l5Oynm-mjpiX_UgJ4XOP8BbN3XxBEKVek2J_n_ME-AwIHTAxbuhJhD-6fG5myZuoHY8JRP9c34j2Q2F-i1yRrDmAPNBZkaW14s9pSPKeZeOopoeVCRRNMq1N7MGvq_SyqKi_BVuBQg8/s1600/LBase.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg83l5Oynm-mjpiX_UgJ4XOP8BbN3XxBEKVek2J_n_ME-AwIHTAxbuhJhD-6fG5myZuoHY8JRP9c34j2Q2F-i1yRrDmAPNBZkaW14s9pSPKeZeOopoeVCRRNMq1N7MGvq_SyqKi_BVuBQg8/s1600/LBase.gif" /></a></div>
<br />
<br />
These <b>lovely purple lady</b> is the third Microbe. As harmless as she may strum with her eyes, so greedy she is! No yellow Microbe is safe from her!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmfWA05_UoJRIumA7iA7Q_eGgRqjneXo-mzOAbvuS_L4obcXeBKBOw5KEacUwxB6R_KixSSOg-ZdrASBE7m3ttl0OIZ_-JqmoUxlhbv-pDmC63IZTLMGZ5TTPnajnxoXTgtjKiHTUcJaG/s1600/XLBase.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivmfWA05_UoJRIumA7iA7Q_eGgRqjneXo-mzOAbvuS_L4obcXeBKBOw5KEacUwxB6R_KixSSOg-ZdrASBE7m3ttl0OIZ_-JqmoUxlhbv-pDmC63IZTLMGZ5TTPnajnxoXTgtjKiHTUcJaG/s1600/XLBase.gif" /></a></div>
<br />
<br />
The <b>red Microbe is the hungriest of the four</b>. It hits its teeth in the purple ladies, as it was just starving! There is no escape! And when it ate too much, then it bursts!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDl-mz8RydTQf-AxM9wXnLpBqgIlMI2z21_kaiep85ZYr37ndJSRP84Oc6w2FifS0uSNzHSs9HVmYIpAHAH50TMcV8shZI9b5reL5Gc_2PZKIy1IBbgPhDH13wQiewT7oLOGif5d7atQR8/s1600/bottle.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDl-mz8RydTQf-AxM9wXnLpBqgIlMI2z21_kaiep85ZYr37ndJSRP84Oc6w2FifS0uSNzHSs9HVmYIpAHAH50TMcV8shZI9b5reL5Gc_2PZKIy1IBbgPhDH13wQiewT7oLOGif5d7atQR8/s1600/bottle.gif" /></a></div>
<br />
<br />
To clean up the garbage dump, there is from time to time – as a reward – a <b>small poison bottle</b>. Sometimes – but not always! - the shattered poison bottle lets explode some Microbes, too, and so generates extra points.<br />
<br />
And yes, the skull is a cross over to the <i>PirateBox</i> :)Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-398195328935346382014-10-11T09:34:00.000-07:002014-11-14T05:40:26.519-08:00Wear Shell - Exploring Android Wear<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjET2PJibwbGgNo8XiPMMB5qtYSbCRfdHH2DKnYgvTJd9PTjGi5WXsg1lIxmDpSc6Qk_XQQBRmoEBX5Zt0XiHse75pUcl82ePYSBDwIfvI5500MmGuUABBKCwELZcfjwIqC-DmR_8wFSyA/s1600/wear_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjET2PJibwbGgNo8XiPMMB5qtYSbCRfdHH2DKnYgvTJd9PTjGi5WXsg1lIxmDpSc6Qk_XQQBRmoEBX5Zt0XiHse75pUcl82ePYSBDwIfvI5500MmGuUABBKCwELZcfjwIqC-DmR_8wFSyA/s1600/wear_icon.png" /></a></div>
Having a LG G Watch for a while I thought that it would be interesting to run code directly on the watch without having to create an APK. Sometimes I just wanted to run some code snippets on the watch and view the result instantly.<br />
Creating a complete project, compiling and deploying the APK on the Wear device is quite time consuming and somewhat annoying.<br />
<br />
I tried to write an app to execute <i>BeanShell</i> code directly on the Wear device. This is all experimental and the possibilities are quite limited compared to an regular app, but for an execution of some code snippets that seemed to be a good idea.<br />
<br />
The result is Wear Shell, an app that consists of a mobile and a Wear part. The mobile part moves the code for execution to the smart watch, collects the result and passes it to the calling application.<br />
<br />
So I hope owners of an Android Wear smart watch have fun with the app and find it as interesting as I did to explore things from the perspective of a watch.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieatRpsvl1EUUxo1ioF5oCD68YfwIK2_w8N6OrpDVvlo4qI1lAqn-2DvsldW2KYOk6ir4jUhu8Bx5FTojZHEwrUoGJ35GRk3l31IEKZp8PQUNTOpCzzRbX0wM7029nw6kd6k4Zm1ZElQk/s1600/wear_shell_app.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieatRpsvl1EUUxo1ioF5oCD68YfwIK2_w8N6OrpDVvlo4qI1lAqn-2DvsldW2KYOk6ir4jUhu8Bx5FTojZHEwrUoGJ35GRk3l31IEKZp8PQUNTOpCzzRbX0wM7029nw6kd6k4Zm1ZElQk/s1600/wear_shell_app.png" height="320" width="180" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">WearShell App</td></tr>
</tbody></table>
<br />
<br />
<h3>
Web Interface</h3>
To make tests easier, the app contains a small (PAW based) web server with a web interface. Inside this interface you can type the code inside a text area, press the Execute button and wait for the result to be displayed.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFYTUdr58tI7yA5ZsKxeadgPNX10c0LOMMv64MtZ7nS0kThG-3FzrSb8ct237gnV55CbMtXtTIGti-XTSys6gijPUqtyswrlPpzMnYRKpg3G-ENwm-aFPkk6VonZJqe6wj6nMz4YTU2k0/s1600/wear_shell_console.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFYTUdr58tI7yA5ZsKxeadgPNX10c0LOMMv64MtZ7nS0kThG-3FzrSb8ct237gnV55CbMtXtTIGti-XTSys6gijPUqtyswrlPpzMnYRKpg3G-ENwm-aFPkk6VonZJqe6wj6nMz4YTU2k0/s1600/wear_shell_console.png" height="400" width="371" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Web Interface with Wear System Information</td></tr>
</tbody></table>
<br />
<br />
The web interface also contains a page containing code snippets for you to try out. These snippets include code for database, Bluetooth and system info access and should provide a good starting point for further explorations.<br />
<br />
<h3>
Developers</h3>
Developers have the possibility to use the functionality of the app within their own applications by using a <i>Result Intent</i>.<br />
<br />
Action: <span style="font-family: Courier New, Courier, monospace;">de.fun2code.android.wear.shell.EXEC</span><br />
Request String Extra: <span style="font-family: Courier New, Courier, monospace;">bsh</span><br />
Response String Extra: <span style="font-family: Courier New, Courier, monospace;">result</span><br />
<br />
Just pass the <i>BeanShell</i> code to execute to the <span style="font-family: Courier New, Courier, monospace;">bsh</span> parameter and read the <span style="font-family: Courier New, Courier, monospace;">result</span> from the resulting <i>Intent</i>.<br />
<br />
<h3>
Links </h3>
Download: <a href="http://goo.gl/qakzDO" target="_blank">WearShell APK</a><br />
Discussion: <a href="http://goo.gl/aGQLhO" target="_blank">XDA Developers</a>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com8tag:blogger.com,1999:blog-8371221544034078032.post-85092462169328869732014-08-26T10:08:00.000-07:002014-08-26T10:47:14.238-07:00PirateBox for Android - Android Wear<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
Starting with version 0.53 PirateBox for Android supports Android Wear notifications for uploads and shout messages.<br />
<br />
Android Wear support is disabled by default but can be enabled inside the PirateBox preferences. There is a new Android Wear section which currently only has one <i>Wear Notification</i> check-box preference.<br />
As soon as this option is ticked upload and shout notifications will be sent to a connect Wear device.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU_4oimRIwNGe0iW0aGQAje7nKohydqNV-V2IprOJH7b0F96r6CXgNScWrpVdp2WPLHZiLzQ2zR-VQHv9lENEVdWC2V976YrVl7C3Y6qyAEiOwFl2W69YhebAUkWNWORA9UQxMdJZVxCw/s1600/wear_preferences.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU_4oimRIwNGe0iW0aGQAje7nKohydqNV-V2IprOJH7b0F96r6CXgNScWrpVdp2WPLHZiLzQ2zR-VQHv9lENEVdWC2V976YrVl7C3Y6qyAEiOwFl2W69YhebAUkWNWORA9UQxMdJZVxCw/s1600/wear_preferences.png" height="89" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Android Wear Preference</td></tr>
</tbody></table>
<br />
Whenever a new upload or shout has been processed and sent to the Wear device a notification is displayed on the Android device (the phone) to indicate that new notifications have been transferred to the Wear device. If that notification gets dismissed, all notifications on the smart-watch will also be deleted.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwTIUKPL95lDKCnf-Q_HuEhxhE-Lp_YIzUTeNq-KOK6ZwENXdjMSIsbAOTK7QKNrJiqYQp1uTO4xCJan7aCRXQzZOyIG3UnKhHOd9cPws3tTAMZhAbrSqktxoUS77b11Raa4MFz6uc97Y/s1600/notification_device.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwTIUKPL95lDKCnf-Q_HuEhxhE-Lp_YIzUTeNq-KOK6ZwENXdjMSIsbAOTK7QKNrJiqYQp1uTO4xCJan7aCRXQzZOyIG3UnKhHOd9cPws3tTAMZhAbrSqktxoUS77b11Raa4MFz6uc97Y/s1600/notification_device.png" height="59" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Wear Notification on Phone</td></tr>
</tbody></table>
<br />
On the smart-watch notifications are summarized and presented in chronological order (newer first). The following image describes the flow on the Wear device.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM47ohh7UasS-XzPzrEte7NwqoeBISrbZmldOHQo3F2VQlM1eTw_ADSuGhwifIQMJWn_p-Q0ZAl5i2o0vwAa1TidX6JLzn_p2pSuO27JWI8eNLsE6KYMXgLEOWYFWP1hFbcMPaJdw1Lw8/s1600/wear_flow.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM47ohh7UasS-XzPzrEte7NwqoeBISrbZmldOHQo3F2VQlM1eTw_ADSuGhwifIQMJWn_p-Q0ZAl5i2o0vwAa1TidX6JLzn_p2pSuO27JWI8eNLsE6KYMXgLEOWYFWP1hFbcMPaJdw1Lw8/s1600/wear_flow.png" height="320" width="236" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Flow on Wear Device</td></tr>
</tbody></table>
<br />
After the messages have been expanded options are available to open the PirateBox app on the phone and in the case of a file upload to open that file on your phone for display.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-50036689224832764382014-08-07T08:04:00.000-07:002015-08-23T08:33:19.407-07:00PirateBox for Android - I18N<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
The latest PirateBox for Android version 0.5.2 adds i18n support to the web interface. It is now possible to change the language of the web interface independent of the phone's langue settings.<br />
This post will show how to add your own translations in a few easy steps ...<br />
<br />
The language files are stored inside the <span style="font-family: Courier New, Courier, monospace;">piratebox/html/i18n</span><span style="font-family: inherit;">*</span> folder. The file names have the following format: <span style="font-family: Courier New, Courier, monospace;">i18n_<i><b>ISO</b></i>.properties</span><br />
<span style="font-family: inherit;">The <b><i>ISO</i></b> part specified the <i>ISO 639-1</i> code which defines the language. Here is a list of available ISO language codes: </span><a href="http://www.mathguide.de/info/tools/languagecode.html" target="_blank">Language Codes according to ISO 639-1</a><br />
<br />
To add your own translation copy the English translation <span style="font-family: Courier New, Courier, monospace;">i18n_en.properties</span> file and rename it to your desired language. To take French as an example, the file would be named <span style="font-family: Courier New, Courier, monospace;">i18n_fr.properties</span><span style="font-family: inherit;">.</span><br />
<br />
It is important to note that the file encoding has to be <b>ISO-8859-1</b>, otherwise you might have issues displaying the characters correctly inside the web interface.<br />
<br />
Now you can start editing the file. The file contains key value pairs separated by an equals (<span style="font-family: Courier New, Courier, monospace;">=</span>) sign. All you have to do is to translate the right hand side of the euqation.<br />
Here is an example, the original in English on the left and the French translation on the right:<br />
<span style="font-family: Courier New, Courier, monospace;">button.thanks=Thanks </span> <span style="font-family: Courier New, Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">button.thanks</span><span style="font-family: Courier New, Courier, monospace;">=Merci</span><br />
<br />
If all lines have been translated, copy the new file to the <span style="font-family: 'Courier New', Courier, monospace;">piratebox/html/i18n</span><span style="font-family: inherit;"> </span>folder and you are almost done.<br />
<br />
To select the new language simply go to the preferences of the PirateBox app and select <i><b>Web Interface Language</b></i>. If everything worked well the language should be available for selection.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiushX3btLPuHffnmGlGnLLJ0ZesPex5y-6opL2VlxoZiaWRerGfk4n0pRjI1Lbtn2tsdvNtaZ6tH17cRz1c4mUz64vyDIJEApCl_kvhanisdUt1aDjCaEARjIhp1eqnm64uSzhhsUczKk/s1600/device-2014-08-06-183845.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiushX3btLPuHffnmGlGnLLJ0ZesPex5y-6opL2VlxoZiaWRerGfk4n0pRjI1Lbtn2tsdvNtaZ6tH17cRz1c4mUz64vyDIJEApCl_kvhanisdUt1aDjCaEARjIhp1eqnm64uSzhhsUczKk/s1600/device-2014-08-06-183845.png" width="200" /></a></div>
<br />
<br />
After a restart of the server the web interface should show the new translation.<br />
Besides English the web interface is already translation into German. If you have made your own translation, you can send it to me** and I'll include it in the next release***.<br />
<br />
Have fun and I hope everything is working as it should ...<br />
<br />
<br />
<span style="font-size: x-small;">* </span><span style="font-size: x-small;">Base directory: </span><span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: xx-small;">/data/data/de.fun2code.android.piratebox/files/</span></span><br />
<span style="font-size: x-small;">** </span><span style="font-size: x-small;">Mail: jochen[at]fun2code.de</span><br />
<span style="font-size: x-small;">*** If there are multiple for the same language, I'll pick one...</span>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com2tag:blogger.com,1999:blog-8371221544034078032.post-47493336883286251752014-07-19T06:37:00.000-07:002014-07-19T06:51:51.757-07:00PirateBox for Android - Modding<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
Here are the workshop slides I prepared for the PirateBox Camp #2 in Lille. Because they were not used at the camp I'll post them here, so they are not lost.<br />
The slides show the range of possible modifications to the PirateBox for Android, ranging form simple preference changes to the more advanced use of the Android API.<br />
<br />
Here are the slides, more details and download links are available below the presentation.<br />
<iframe allowfullscreen="true" frameborder="0" height="500px" id="presentFrame" mozallowfullscreen="true" src="https://docs.google.com/presentation/d/1gvsxKx8zcBkp-HyKU0WfT9mcBSfKTw7jApo3YTVd4sk/embed?start=true&loop=true&delayms=8000" webkitallowfullscreen="true" width="100%"></iframe><br />
The first slide shows the <i>Basic Settings</i> that can be changed inside the preferences of the PirateBox app.<br />
These basic settings allow to change things like the SSID name, storage directory etc. without deeper knowledge of the PirateBox.<br />
<br />
The next slide <i>Content Modifications</i> shows the settings needed to make basic changes to the HTML, CSS and JavaScript files. After ticking the <i>Content to SD</i> option, the app has to be restarted for the change to take effect. After the restart you should find a folder named <span style="font-family: Courier New, Courier, monospace;">piratebox</span> on your SD card (or wherever your external storage file system is located).<br />
<br />
Inside the <span style="font-family: Courier New, Courier, monospace;">piratebox</span> folder you'll find a directory named <span style="font-family: Courier New, Courier, monospace;">html</span> which contains all the HTML, CSS and JavaScript files. If you are making changes to files located inside the <span style="font-family: Courier New, Courier, monospace;">html</span> directory, make sure that the option <i>Enable Updates</i> is not ticked to prevent the next update of the app to overwrite your changes.<br />
You will also notice that the <span style="font-family: Courier New, Courier, monospace;">html</span> directory contains files with the extension <span style="font-family: Courier New, Courier, monospace;">xhtml</span>. These files are html files that, in addition to standard HTML, include dynamic content. Dynamic content is covered in the slides that follow.<br />
<br />
The next five slide (<i>Dynamic Pages</i>, <i>Using BeanShell</i>, <i>XHTML Example</i>, <i>XHTML Errors</i> and <i>BeanShell DIY</i>) cover the use of dynamic pages by using BeanShell. The slide named <i>BeanShell DIY</i> contains a download link (available below) that offers you the possibility to execute BeanShell code directly on your device.<br />
<br />
The last two slides (<i>Using the Android API </i>and <i>Android API DIY</i>) are targeted at developers that already know the Android API. The Adroid API DIY links to a ZIP file (download below) that contains an example that shows the use of the Android API to access the music stored on the Android device. After unzipping the files to the <span style="font-family: Courier New, Courier, monospace;">html</span> directory you should have an additional menu entry named <i>Media</i> inside the menu of your PirateBox start page.<br />
<br />
If you are interested in how that works you can inspect the <span style="font-family: Courier New, Courier, monospace;">xhtml</span> files included inside the ZIP file. But event if you are not into development the sample might be a nice addition to your PirateBox.<br />
<br />
<h3>
Downloads</h3>
The files referred to inside the presentation are available on Google Drive:<br />
<a href="https://drive.google.com/uc?export=download&id=0B8T86cdxxvu-T2dKN1JPaEswVGc">camp#2/beanshell.zip</a><br />
<a href="https://drive.google.com/uc?export=download&id=0B8T86cdxxvu-eG1XSkdNZW9ZNUk">camp#2/android_media.zip</a><br />
<br />Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-54927919075092125292014-07-15T02:56:00.001-07:002014-07-15T02:58:10.041-07:00PirateShare<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
PirateShare is an app that tries to simplify file upload to a PirateBox by using Android's share functionality.<br />
On the PirateBox Camp #2 we tried the app and it seems to work quite well.<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtMAbx2N4I9tGigarGjN9FmFqDIxZXKyPpkeMAglGmG0YeSPrR6-9MsfHVTwimNT7zhP-O5JIcPGU-InyotsCEBwD5FhzXb2sjSJhOhI_XF198yoIMYISInvK6tbMp8HAqrceGQ5NbbH0/s1600/PirateShare_Android-PirateBox.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtMAbx2N4I9tGigarGjN9FmFqDIxZXKyPpkeMAglGmG0YeSPrR6-9MsfHVTwimNT7zhP-O5JIcPGU-InyotsCEBwD5FhzXb2sjSJhOhI_XF198yoIMYISInvK6tbMp8HAqrceGQ5NbbH0/s1600/PirateShare_Android-PirateBox.png" height="200" width="171" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Android Share Dialog (image by <a href="https://twitter.com/Biblio_Box" target="_blank">#BiblioBox</a>)</td></tr>
</tbody></table>
<br />
PirateShare was inspired by the <i>PirateFox</i> a PirateBox file sharing app for FireFox OS:<br />
<br />
<a href="http://ruk.ca/content/piratebox-firefox-os-piratefox" target="_blank">http://ruk.ca/content/piratebox-firefox-os-piratefox</a><br />
<a href="https://github.com/reinvented/piratefox" target="_blank">https://github.com/reinvented/piratefox</a><br />
<br />
The PirateShare app is available for download on Google Drive:<br />
<a href="http://t.co/j7oiLJdZuT" target="_blank">http://t.co/j7oiLJdZuT</a><br />
<br />
<br />
The app works like this:<br />
<br />
<ol>
<li>Select one or multiple photos from the Gallery or select file(s) inside a file management app</li>
<li>Select PirateShare from share menu</li>
<li>PirateShare checks if connected to a PirateBox by requesting the <span style="font-family: Courier New, Courier, monospace;">ncsi.txt</span> file</li>
<li>If connected PirateShare will upload the file(s)</li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL7lD6Tc36RyS2pwvFYVZDBvHlyQDUgH95Sf6xNwvfqRfnDj5j4gIF_a85kVacwJDrLRky33L3Grml7uDg0NHbTM6CK3oBBU2gfbUa8va32eiBIz8Tt9D2vlmGwvcyAL9wmXvlhlZsMI0/s1600/ps_dialog.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL7lD6Tc36RyS2pwvFYVZDBvHlyQDUgH95Sf6xNwvfqRfnDj5j4gIF_a85kVacwJDrLRky33L3Grml7uDg0NHbTM6CK3oBBU2gfbUa8va32eiBIz8Tt9D2vlmGwvcyAL9wmXvlhlZsMI0/s1600/ps_dialog.png" height="115" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Upload Dialog</td></tr>
</tbody></table>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com1tag:blogger.com,1999:blog-8371221544034078032.post-35844565176776513282014-05-21T09:19:00.000-07:002014-05-21T10:16:16.266-07:00PirateBox at Google Play<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
After quite some testing PirateBox for Android is now available at <a href="https://play.google.com/store/apps/details?id=de.fun2code.android.piratebox" target="_blank">Google Play</a>.<br />
Thanks a lot to all of you for testing. Special thanks goes to <i>Skyworth S8</i> for testing and sending in lots of screen shots (see gallery below).<br />
<br />
The APKs will also be published to <a href="https://drive.google.com/folderview?id=0B8T86cdxxvu-UnhTdUw2U3pLUjQ&usp=sharing" target="_blank">Google Drive</a>, so installation will be possible for devices without Goggle Apps.<br />
<br />
In case of errors or if you would like to provide feedback, please send a mail to <i>piratebox[at]fun2code.de</i> or leave a comment below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwV0hA2jhyphenhyphenTiO6oI0BMpeCxYovdYDP5ML_VHlisDGR6MiYMzd6_48mOGjae26ymYBYWopiz4efEKZbh2WTKN6INIpOytpMbIajjHrImHccEHgx1hSuaouyt-4StMTv5P5txaBiKk8tYxY/s1600/IMG_20140520_192916.jpg" imageanchor="1" style="float: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwV0hA2jhyphenhyphenTiO6oI0BMpeCxYovdYDP5ML_VHlisDGR6MiYMzd6_48mOGjae26ymYBYWopiz4efEKZbh2WTKN6INIpOytpMbIajjHrImHccEHgx1hSuaouyt-4StMTv5P5txaBiKk8tYxY/s1600/IMG_20140520_192916.jpg" height="150" width="200" /></a></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibCAIZEhTpIS6RiErkK3i-qIGOvcTGq74UJ3KhLkWtvEW07dO2ldJek1_pQRais4oeIg0Y4u2mm8SN-N60d3uS_L90vmbbcYskEgKtDmNFOZv7fhdlTbojn1rf3WI8txkX9xUXT6IHT-w/s1600/Screenshot_2014-05-21-20-52-35.png" imageanchor="1" style="float: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibCAIZEhTpIS6RiErkK3i-qIGOvcTGq74UJ3KhLkWtvEW07dO2ldJek1_pQRais4oeIg0Y4u2mm8SN-N60d3uS_L90vmbbcYskEgKtDmNFOZv7fhdlTbojn1rf3WI8txkX9xUXT6IHT-w/s1600/Screenshot_2014-05-21-20-52-35.png" height="150" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqV9LfWqrKm6e8HjQSVqfrAUbqqLpNmQBGa_KdQBz_9rzUq_i2zGVwLcW6xJhwVVKFdn0_2Mwdalul1anidfe04U-G4glCEqbtmZGCGlc7UrF8nLGdOwN6pA64oWZUF_o_7Re5SrjqW7Q/s1600/Screenshot_2014-05-21-20-52-53.png" imageanchor="1" style="clear: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqV9LfWqrKm6e8HjQSVqfrAUbqqLpNmQBGa_KdQBz_9rzUq_i2zGVwLcW6xJhwVVKFdn0_2Mwdalul1anidfe04U-G4glCEqbtmZGCGlc7UrF8nLGdOwN6pA64oWZUF_o_7Re5SrjqW7Q/s1600/Screenshot_2014-05-21-20-52-53.png" height="150" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZjPKFXBGQ7Ag50r1In8py-jBtxYAFi00FKZjPHufB7L9ptej9bTYdq0Lg-eXnmhA8HUFUCGkvvYFREEFt1AjvX6LuGViBSxau1-Xi8mESYuoldP4xWCrkJT__Vn-3QBYPyF4yK8yeAQ/s1600/Screenshot_2014-05-21-20-53-04.png" imageanchor="1" style="clear: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZjPKFXBGQ7Ag50r1In8py-jBtxYAFi00FKZjPHufB7L9ptej9bTYdq0Lg-eXnmhA8HUFUCGkvvYFREEFt1AjvX6LuGViBSxau1-Xi8mESYuoldP4xWCrkJT__Vn-3QBYPyF4yK8yeAQ/s1600/Screenshot_2014-05-21-20-53-04.png" height="150" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDOzoT_P6hK4ao_XbN2Qrm5hELHM2SJLDQOH1LG3H-Xou56LOXP11U8Ifbb8YNkCQAzDlhyphenhyphen-yikDXfMg_JodtlYTeuS4ol6YDH53HSBBcjAPRLqagEUClRbgqnDqXczjq_cUzFMHsYj0/s1600/Screenshot_2014-05-21-20-53-20.png" imageanchor="1" style="clear: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKDOzoT_P6hK4ao_XbN2Qrm5hELHM2SJLDQOH1LG3H-Xou56LOXP11U8Ifbb8YNkCQAzDlhyphenhyphen-yikDXfMg_JodtlYTeuS4ol6YDH53HSBBcjAPRLqagEUClRbgqnDqXczjq_cUzFMHsYj0/s1600/Screenshot_2014-05-21-20-53-20.png" height="150" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPYc74HXIE4qBrAgcgeAv9SvQbF1_bGGEsABME7cD6BF1yfz8mYnOYf70YoM36vvE8ZZwZiLqDQnrVhpUXJHbKwPNqFJ49RJioTprDgHlTTL-yMY7sSHhyphenhyphenl3TaGgfD9X-xN4gGwveZQAI/s1600/Screenshot_2014-05-21-20-53-32.png" imageanchor="1" style="clear: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPYc74HXIE4qBrAgcgeAv9SvQbF1_bGGEsABME7cD6BF1yfz8mYnOYf70YoM36vvE8ZZwZiLqDQnrVhpUXJHbKwPNqFJ49RJioTprDgHlTTL-yMY7sSHhyphenhyphenl3TaGgfD9X-xN4gGwveZQAI/s1600/Screenshot_2014-05-21-20-53-32.png" height="150" width="200" /></a>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRwlObTnx-vTyJHheQklmvBQo0mWRukx4XRaHHvxzjJ4pBrJovKRSHt9a431CVb_2zTECNKCGhfN3OWZRO_D-n2U4ZX2UFBuuULFu7-ivy2SyYLn23i_oouLWoFXneXd8UZDL2lOMH_vY/s1600/Screenshot_2014-05-21-20-54-16.png" imageanchor="1" style="clear: left;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRwlObTnx-vTyJHheQklmvBQo0mWRukx4XRaHHvxzjJ4pBrJovKRSHt9a431CVb_2zTECNKCGhfN3OWZRO_D-n2U4ZX2UFBuuULFu7-ivy2SyYLn23i_oouLWoFXneXd8UZDL2lOMH_vY/s1600/Screenshot_2014-05-21-20-54-16.png" height="150" width="200" /></a>
<br />
<br />
<br />
<h3>
Links</h3>
<a href="https://play.google.com/store/apps/details?id=de.fun2code.android.piratebox" target="_blank">PirateBox at Google Play</a><br />
<a href="https://drive.google.com/folderview?id=0B8T86cdxxvu-UnhTdUw2U3pLUjQ&usp=sharing" target="_blank">APKs on Google Drive</a>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com14tag:blogger.com,1999:blog-8371221544034078032.post-81795226669635227172014-05-17T09:08:00.000-07:002014-05-17T09:08:17.556-07:00PirateBox Reloaded - Episode III<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
Version 0.4.4 of PirateBox for Android is now available. This post is about the new and noteworthy features of that version.<br />
<br />
If tests go well and I have enough feedback I will make PirateBox for Android available at Google Play. So please fill out the <a href="https://docs.google.com/forms/d/1w033bw4pTc0BtU9-vA-XpQJADAVts33zFJigbK4pcRY/viewform?embedded=false" target="_blank">questionnaire</a> ... feedback has been very sparse lately.<br />
<br />
<h3>
Droopy Support</h3>
The original PirateBox uses Droopy for file upload. PirateBox for Android uses his own mechanism for file uploads. To be compatible Droopy emulation has been introduced. If the <i>Emulate Droopy</i> option is enabled (which it is by default) files can be uploaded by using port 8080.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH5QRqtIwVnGSPku-VPrNtGLyrtBwfs2XHRxO-uxN_FN8LWGjlEzqmTnzcNXkpOlcuWrAhmbCdwONpgi_YIC7MV5d5nzcl-Q6H-C5hNpjxCkDLSYVOpLy4rTcaumhQ_DMXcacGjExuM1U/s1600/piratebox_piratefox.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH5QRqtIwVnGSPku-VPrNtGLyrtBwfs2XHRxO-uxN_FN8LWGjlEzqmTnzcNXkpOlcuWrAhmbCdwONpgi_YIC7MV5d5nzcl-Q6H-C5hNpjxCkDLSYVOpLy4rTcaumhQ_DMXcacGjExuM1U/s1600/piratebox_piratefox.png" height="320" width="290" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox and PirateFox</td></tr>
</tbody></table>
<br />
This makes it possible to use existing file upload tools. For testing the FireFox OS app <a href="http://ruk.ca/content/piratebox-firefox-os-piratefox" target="_blank">PirateFox</a> has been used (see image).<br />
<br />
In addition to the file upload feature, a number is added to the uploaded file name if the file already exists. In earlier versions files with the same name were silently overwritten.<br />
<br />
<br />
<h3>
Info Widget</h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBoU9VqU4SxucBgwMKIF7eLzhSzmFjQViNakkhbrfQl8o1U7fqyYWcFEyvvDHPk0sQ2X38DnfkyhyF69hf4Z9XG5n1789K2hMQnrOxxOBPP-U0ShZoWEZIXWoc5mZ1n8vrqfduOV_CvgQ/s1600/info_widget.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBoU9VqU4SxucBgwMKIF7eLzhSzmFjQViNakkhbrfQl8o1U7fqyYWcFEyvvDHPk0sQ2X38DnfkyhyF69hf4Z9XG5n1789K2hMQnrOxxOBPP-U0ShZoWEZIXWoc5mZ1n8vrqfduOV_CvgQ/s1600/info_widget.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Info Widget</td></tr>
</tbody></table>
To make it easier to see if files were uploaded or new messages are available the new version contains a new widget which displays this information.<br />
<br />
The counters should update automatically. If that does not work, you can force an update by tapping the widget.<br />
<br />
<h3>
Tasker/Locale Plugin</h3>
To make automation easier the latest version contains a <i>Tasker</i>/<i>Locale</i> plugin.<br />
With this plugin it is possible to define tasks to switch the PirateBox on/off automatically.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizSmwaNYw_ldXtpETTPKbYO9TqTriFwLwA2t136ntEB5fsUsfejxIiQlEmntlpJPMWLsuKl-BOX9rbKzUAiCEsBgwSghXIDN94n4F9-PmL17jaaj87HuILzNOcXwCfx4-2gIROil6SPfc/s1600/tasker.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizSmwaNYw_ldXtpETTPKbYO9TqTriFwLwA2t136ntEB5fsUsfejxIiQlEmntlpJPMWLsuKl-BOX9rbKzUAiCEsBgwSghXIDN94n4F9-PmL17jaaj87HuILzNOcXwCfx4-2gIROil6SPfc/s1600/tasker.png" height="80" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Tasker</td></tr>
</tbody></table>
It has to be noted, that there are problems when using WiFi on/off as trigger. This is likely to not work as expected. I hope I'll be able to fix that in upcoming versions.<br />
<br />
<br />
<br />
<br />
<br />
<h3>
Status Broadcasts</h3>
This might only be interesting for developers but it is now possible to request the status of the PirateBox externally via broadcast. The new Info Widget uses this functionality and might serve as example.<br />
<br />
The broadcast action used for the status request is <span style="font-family: Courier New, Courier, monospace;">de.fun2code.android.piratebox.broadcast.intent.STATUS_REQUEST</span> and the PirateBox app will respond with a <span style="font-family: Courier New, Courier, monospace;">de.fun2code.android.piratebox.broadcast.intent.STATUS_RESULT broadcast</span> which contains the following extras:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SERVER_STATE</span><br />
<span style="font-family: Courier New, Courier, monospace;">boolean</span> value: <span style="font-family: Courier New, Courier, monospace;">true</span> if the server is running, otherwise <span style="font-family: Courier New, Courier, monospace;">false</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">UPLOAD_NUMBER</span><br />
<span style="font-family: Courier New, Courier, monospace;">int</span> value: number of uploaded files<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SHOUT_NUMBER</span><br />
int value: number of shout/chat messages<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">UPLOAD_DIR</span><br />
<span style="font-family: Courier New, Courier, monospace;">String</span> value: upload directory location<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">SHOUT_DIR</span><br />
<span style="font-family: Courier New, Courier, monospace;">String</span> value: shout/chat directory location<br />
<br />
<br />
That's it for the new version ... looking forward to receiving more feedback :)<br />
<br />Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com1tag:blogger.com,1999:blog-8371221544034078032.post-70741142115946530852014-05-09T10:15:00.000-07:002014-05-12T20:35:21.691-07:00PirateBox Reloaded - Episode II<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
First of all thanks to all of you who gave feedback regarding the PirateBox for Android. The feedback was very useful and showed that there are problems when running the app on Android 4.x.<br />
Meanwhile I've rooted my Galaxy Nexus (still on stock ROM) running 4.3, so I had the change for in depth testing. The result is version 0.4.0 of the app which includes a different handling of the <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span> process. I'll go a little into detail to describe the changes that have been made.<br />
<br />
Those of you not interested can jump directly to the end of this post where the download link is located. I've also added the questionnaire again. It would be really nice if you could provide feedback, it's really useful.<br />
<br />
<h3>
Wrapping Dnsmasq</h3>
In previous version of the app the dnsmasq process was killed and restarted with the <span style="font-family: Courier New, Courier, monospace;">--address=/#/<access ip="" point=""></access></span>. This worked fine on Android 2.x devices but lead to a continuous restart of the AP (Access Point) on Android 4.x devices.<br />
The new approach is different in the way that it does not kill the dnsmasq process but installs a wrapper script that is created before the AP stars and removed afterwards.<br />
For this to work the app saves a copy of the file <span style="font-family: Courier New, Courier, monospace;">/system/bin/dnsmasq</span> to <span style="font-family: Courier New, Courier, monospace;">/system/bin/dansmasq.pb.real</span>. On start of the PirateBox service the wrapper script is created which overwrites the <span style="font-family: 'Courier New', Courier, monospace;">/system/bin/dnsmasq </span>command. After the AP is started the original <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span> binary is restored.<br />
The wrapper script looks like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#!/system/bin/sh</span><br />
<span style="font-family: Courier New, Courier, monospace;">exec /system/bin/dnsmasq.pb.real --address=/#/192.168.43.1 $*</span><br />
<br />
The wrapper calls the original <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span> binary which is now located at <span style="font-family: 'Courier New', Courier, monospace;">/system/bin/dnsmasq.pb.real</span> with the <span style="font-family: 'Courier New', Courier, monospace;">--address </span>and all other other parameters (<span style="font-family: Courier New, Courier, monospace;">$*</span>) the system used to start <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span>.<br />
<br />
If you look at the process list after starting the AP you should see that the backed up <span style="font-family: 'Courier New', Courier, monospace;">dnsmasq.pb.real </span>is running instead of the real one (<span style="font-family: 'Courier New', Courier, monospace;">dnsmasq</span>).<br />
Here is the result of the <span style="font-family: Courier New, Courier, monospace;">ps | grep dnsmasq</span> command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">shell@maguro:/ $ ps | grep dnsmasq</span><br />
<span style="font-family: Courier New, Courier, monospace;">nobody 5088 121 928 496 ffffffff 00000000 S <b>/system/bin/dnsmasq.pb.backup</b></span><br />
<div>
<br /></div>
<h3>
New Preferences</h3>
<div>
The preference screen has two new additions. One is the IP address of the AP and the other is the option to restore the original <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span> binary.</div>
<div>
<br /></div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUUReTW90k8zEW5ZolvSUdhsNnScqd9FB7b5FxNcRxN2M00rCOJqKhTm-SJ12mtwlTrraSSgLWYuK_Ju7TXzbJZCxBh5V543k_5DcMQMvKq-Kip9RsgTSfeFakTi0ZayFkyBh8wEFtrHI/s1600/pb_0.4.0_new_options.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUUReTW90k8zEW5ZolvSUdhsNnScqd9FB7b5FxNcRxN2M00rCOJqKhTm-SJ12mtwlTrraSSgLWYuK_Ju7TXzbJZCxBh5V543k_5DcMQMvKq-Kip9RsgTSfeFakTi0ZayFkyBh8wEFtrHI/s1600/pb_0.4.0_new_options.png" height="153" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">New Preference Options</td></tr>
</tbody></table>
In previous versions the IP of the AP could determined after the AP was started and used to restart <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span>. This is no longer possible, because the wrapper script has to be created before the AP starts.<br />
<br /></div>
<div>
On Android most of the devices have the IP address <span style="font-family: 'Courier New', Courier, monospace;">192.168.43.1 </span>hard coded and I don't believe that there are a lot ROMs with different addresses. Should your AP start with a different IP address, you can still change this by using the new preference setting <i>AP IP Number</i>.</div>
<div>
<br /></div>
<div>
The second new preferences option is called <i>Restore "dnsmasq" Binary</i>. This will, as the name implies, try to restore the original <span style="font-family: Courier New, Courier, monospace;">dnsmasq</span> binary. This should not be necessary to used, because the wrapper is removed and replaced by the original binary after the AP has been started. But in case thing do not work as desired when the device is used for standard tethering, this is the option to restore the binary.</div>
<div>
<br /></div>
<h3>
Simple Widget</h3>
<div>
The new version also comes with a simple widget. It is not pretty ... but hey, I'm a developer not an artist ;)<br />
Meanwhile I've updated the widget images in version 0.4.1, hope the widget is looking a bit better.</div>
<div>
<br /></div>
<div>
Below are the links to the app, the questionnaire and to the source code located at GitHub.</div>
<div>
So I hope the new version is working better as the previous version and I'm looking forward for your feedback.</div>
<div>
<br /></div>
<div>
<br />
<hr />
<h3>
Source Code</h3>
The source code is now available on <a href="https://github.com/joschi70/AndroidPirateBox" target="_blank">GitHub</a>.<br />
<br />
<h3>
Download Links</h3>
Google Drive: <a href="https://drive.google.com/folderview?id=0B8T86cdxxvu-UnhTdUw2U3pLUjQ&usp=sharing" target="_blank">PirateBox APKs</a><br />
<br />
<h3>
Questionnaire</h3>
</div>
<div>
The results can be viewed <a href="https://docs.google.com/spreadsheet/lv?key=0AsT86cdxxvu-dGZkRWpFT1ZYSDZCWVpRaDlFSFdNQUE" target="_blank">here</a>, so you know on which configurations PirateBox is running.</div>
<div>
<br /></div>
<iframe frameborder="0" height="800" marginheight="0" marginwidth="0" src="https://docs.google.com/forms/d/1w033bw4pTc0BtU9-vA-XpQJADAVts33zFJigbK4pcRY/viewform?embedded=true" width="100%">Loading...</iframe>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com2tag:blogger.com,1999:blog-8371221544034078032.post-20359975572268417822014-03-27T11:14:00.000-07:002014-03-27T14:05:33.484-07:00A Look at Android Wear<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjILcYDgjzVRs9cR1ZZOFeCTGoJzaGJcbidV5RGBz6hglsaSpdjd8-ucu3fCtikFlgZR0f4g3Z7CxadEjzQDxJyDXpLLFFgmeyBkL0HEje27H2b0LWOrDbOozndTlE1QVXbHkm8lMc8G8c/s1600/android_wear_icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjILcYDgjzVRs9cR1ZZOFeCTGoJzaGJcbidV5RGBz6hglsaSpdjd8-ucu3fCtikFlgZR0f4g3Z7CxadEjzQDxJyDXpLLFFgmeyBkL0HEje27H2b0LWOrDbOozndTlE1QVXbHkm8lMc8G8c/s1600/android_wear_icon.png" /></a></div>
Google released Android Wear a version of the Android OS specifically designed for wearable device like smart watches and the like.<br />
Actual devices should follow shortly by the middle of this year starting with smart watches from Motorola and LG.<br />
<br />
Along with the announcement of Android Wear Google released a preview version of the Android Wear SDK for developers to test and try the new OS.<br />
Looking at the SDKs emulator and docs thing might look a little bit disappointing at first glance, if the expectation is that reals apps can be installed on an Android Wear device.<br />
The Wear API is designed that the wearable device is showing notifications from an Android phone by using the since Android 4.3 Jelly Bean available <i>Notification Access</i> service. This service allows apps to receive information about notifications displayed on device notification bar. In earlier versions of Android this was only available by using the Accessibility feature of Android.<br />
<br />
To connect a device to an Android Wear emulator, Google has provided an <i>Android Wear Preview</i> app for registered developers. Because using the above mentioned “Notification Access” service, this app only runs on devices with Android 4.3 or higher.<br />
When the app is enabled all (non ongoing) notifications will be displayed on the Android Wear device with the ability to use rich notifications which allow to use action buttons for sending Intents back to the smart phone.<br />
This design has the advantage that without any change current apps will work with Android Wear out of box.<br />
<br />
The possibilities currently available with that notification approach are quite limited and can be viewed on the <a href="http://developer.android.com/wear/preview/start.html" target="_blank">Android Wear developer page</a>.<br />
<br />
In summary developers can use the following notification types:<br />
<br />
<ul>
<li>Rich notifications including images and action buttons</li>
<li>Grouped notifications</li>
<li>Notifications with multiple pages</li>
<li>Receive voice input from a notification</li>
</ul>
<br />
<br />
That seems to be it as far as the official API concerned. But the question arises (at least from a hacker’s perspective) … Can the Android Wear OS run regular apps?<br />
<br />
If we have a look at the above linked developer page, it states:<br />
<br />
<i>“Caution: Do not install apps on the Android Wear emulator. The system does not support traditional Android apps and the result of running such apps is unpredictable.”</i><br />
<br />
It is indeed possible to run apps with some exceptions. Network access is not possible and in the case of most apps will lead to a crash of the app. Web Views are also not supported. Apart from that, apps seem to work fine, but the small display size might be a problem.<br />
Because this is a block for developers and hackers, let’s have a look how to run apps on the Android Device emulator.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZUykAayB73P8zHkpyhLlAEcD6JTWXeRSDVZ1t7QodsOufL8RDTo4iFo99zmr6O3DrMEeiOlnrgfIK4vBF4k-aNeBglvzhn3V49TiE1pE_jvJAifeY71OkG3UohWEDhP4YCmS6UeWE0Y/s1600/stopwatch_round_transp.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZUykAayB73P8zHkpyhLlAEcD6JTWXeRSDVZ1t7QodsOufL8RDTo4iFo99zmr6O3DrMEeiOlnrgfIK4vBF4k-aNeBglvzhn3V49TiE1pE_jvJAifeY71OkG3UohWEDhP4YCmS6UeWE0Y/s1600/stopwatch_round_transp.png" height="200" width="195" /></a>First of all an APK of an app is needed that does not require network access. An example of such an app is the <i><a href="https://play.google.com/store/apps/details?id=com.sportstracklive.stopwatch" target="_blank">StopWatch & Timer</a></i> app from Google Play.<br />
The APK can be extracted from another Android device with a backup app. Using APK Backup of the PAW web interface is also an option.<br />
The APK can be simply installed onto an emulator running Android Wear with the following command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">adb install <path apk="" to=""></path></span><br />
<br />
When the APK has been installed, the app StopWatch & Timer app can be started like this:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">adb shell am start -n com.sportstracklive.stopwatch/com.sportstracklive.stopwatch.BigStopWatchActivity</span><br />
<br />
After startup the app will show up on the emulator’s screen. Apart from the small screen estate, the app seems to be working fine. Event the preference screen is working.<br />
<br />
All in all Android Wear seems to be a nice addition to the Android family and summer seems to be getting interesting with new devices popping up.Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com2tag:blogger.com,1999:blog-8371221544034078032.post-77859783206069399302014-03-16T02:57:00.000-07:002014-03-16T02:58:29.142-07:00Writing/Deleting Data with KitKat<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi05-WsC4kQDuOzH7hAQqTapVZk4bPDEzC-VezokPEKYlAeMfxNUCHR3VqoI-z02gXiozzYeI4OGXhG29ZdbqC4LuolTa99vp4DeiXGhDwse91c8L5jMSGmk8FfyLpzBWHqB0xQZnGgusY/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi05-WsC4kQDuOzH7hAQqTapVZk4bPDEzC-VezokPEKYlAeMfxNUCHR3VqoI-z02gXiozzYeI4OGXhG29ZdbqC4LuolTa99vp4DeiXGhDwse91c8L5jMSGmk8FfyLpzBWHqB0xQZnGgusY/s1600/icon.png" /></a></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;">Unfortunately Android 4.4 KitKat does restrict file access to the secondary SD card when it comes to writing and deleting files.</span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;">This restriction was actually introduced in Android 3.2 HoneyComb but was not enforced by device manufacturers.</span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;">With KitKat this seems to have changed (e.g. for Samsung devices) and so File-Managers including DavDrive can not write or delete files on the secondary SD card on some devices.</span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;">There is nothing that can be done from a software perspective, the only chance to change this is to root the device.</span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial;"><span style="font-size: 15px; line-height: 17.25px; white-space: pre-wrap;">A detailed description can be found here:</span></span></div>
<h4>
<span style="font-family: Arial; font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><a href="http://www.androidpolice.com/2014/02/17/external-blues-google-has-brought-big-changes-to-sd-cards-in-kitkat-and-even-samsung-may-be-implementing-them/" target="_blank">External Blues: Google Has Brought Big Changes To SD Cards In KitKat, And Even Samsung Is Implementing Them</a></span></h4>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><i><br /></i></span></div>
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; line-height: 17.25px; white-space: pre-wrap;"><i>Thanks to Stefan for letting me know about this issue!</i></span></div>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-32818263115120872532013-10-10T11:24:00.001-07:002014-01-14T11:24:39.496-08:00PirateBox Reloaded<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNe9KC8rVqeLS5Fo-Szso3X7ifIB2FenNWB_lVaf1pY7N-JJOEy1y5IILochjR_3ZxmLR6dwYpw4EY80WObvhDFvS1L4OKiC4IMB5FQKzz_NHHdtsD_6BOGxZ6a9KGq3tE6caPRM_Ks4g/s1600/icon_no_alpha.png" /></a></div>
It's been a while since the last PirateBox update. The <a href="http://fun2code-blog.blogspot.de/2011/12/piratebox-on-android.html">last version</a> was based on a PAW server plug-in that didn't work well for all users.<br />
Meanwhile I developed a stand alone PirateBox Android app that hopefully will work better.<br />
<br />
The new app is based on CyanogenMod 7 and was tested on a Nexus One.<br />
I have no other devices running CyanogenMod but I hope that the app will run too on different versions of that ROM.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOo3pmeSU_c_Miahd98h-h9bvp60wYZT02ehH6vBgR4wef4WbLqshAjc5wHmJK1z2J29fkAW0_b1PROGtnhjZlkYqW9W3hFySbdvRBhyOO9dwP9fdkY03NqNWJAkB_NUQEcQEKLmAWDqs/s1600/cyanogen_nexusone.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOo3pmeSU_c_Miahd98h-h9bvp60wYZT02ehH6vBgR4wef4WbLqshAjc5wHmJK1z2J29fkAW0_b1PROGtnhjZlkYqW9W3hFySbdvRBhyOO9dwP9fdkY03NqNWJAkB_NUQEcQEKLmAWDqs/s320/cyanogen_nexusone.png" width="163" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">CyanogenMod 7 and Nexus One</td></tr>
</tbody></table>
<br />
<br />
This post will describe the app in some detail. Technical details about the networking part will not be covered, because these were described in the <a href="http://fun2code-blog.blogspot.de/2011/12/piratebox-on-android.html">earlier post</a>. The techniques are the same, so there is no need to go through all of that again.<br />
For those of you not interested, don't worry, here is the download link to the app straight away. Just download the APK and install it. A rooted device is necessary and it has only be tested with CyanogenMod 7.<br />
<br />
So here is the Google Drive download link: <a href="https://drive.google.com/folderview?id=0B8T86cdxxvu-UnhTdUw2U3pLUjQ&usp=sharing" target="_blank">PirateBox APKs</a><br />
<br />
<br />
<h3>
Running the App</h3>
For those still reading here is the more detailed part...<br />
When you start the app you will see the (not so spectacular) main screen which basically consists of an image and a start button. If your device is not rooted or the device is missing some prerequisites there will be a message telling so and you will not be able to proceed.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhueQEcRmi3po9OUVsSbrXwe0PgWE7i0cVppOj9oCDboACWCiyWSr-LfwhQ178G5VyQLK7BSV6YKm4nNIpuKT-knF6i8ejFpu9hLZTXBhz_p_ID92sgSr4yTWjWpzC6t9REVsR-snQcyjc/s1600/device-piratebox-off.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhueQEcRmi3po9OUVsSbrXwe0PgWE7i0cVppOj9oCDboACWCiyWSr-LfwhQ178G5VyQLK7BSV6YKm4nNIpuKT-knF6i8ejFpu9hLZTXBhz_p_ID92sgSr4yTWjWpzC6t9REVsR-snQcyjc/s320/device-piratebox-off.png" width="192" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox - Switched off</td></tr>
</tbody></table>
<br />
<br />
After pressing the start button the app will start to setup the network. There is no need to start the hotspot beforehand, that will be done automatically. The app also take care to create an open hotspot and to name it appropriately.<br />
After all is set up, you should see three icons underneath the start button and a notification in form of a scull.<br />
<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI1NXLQfyj3Tq_AZMLe8I3tEV5w2hqui3B3h32OfS2EfBYkh4MxMF2SftMmDCF5IlPxObuMYUK_EuU4bmLZ-mKdg8-E3K-TG0pLD8h1EijW1kplW4y8yAqqot_cpBf0G75jTwnhZYSeZg/s1600/device-piratebox-on.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiI1NXLQfyj3Tq_AZMLe8I3tEV5w2hqui3B3h32OfS2EfBYkh4MxMF2SftMmDCF5IlPxObuMYUK_EuU4bmLZ-mKdg8-E3K-TG0pLD8h1EijW1kplW4y8yAqqot_cpBf0G75jTwnhZYSeZg/s320/device-piratebox-on.png" width="192" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox - Running</td></tr>
</tbody></table>
<br />
<br />
The icons show the active components that are configured during start up. These are, from left to right, the <i>web server</i>, the <i>access point</i> and the <i>network configuration</i>.<br />
<br />
<h3>
Connecting via Browser</h3>
The PirateBox should show up as access point with the default SSID named <i>PirateBox - Share Freely</i>. The name can be changed inside the setting, but we'll come to that in the next section.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2i4PWQbm8ABHDJZ0oW2KxMrzZqp2xu7l4YN-4ATwZDpZR9PbE8Cw8eR4cjp7O7Le-jwtXbCQFgqKP5M2DZejki6a4C5dnnS5oye9ezEkD4epLBziAAUdABHn29T49n_KXFdTb7rfUCsc/s1600/device-piratebox-wifi.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="64" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2i4PWQbm8ABHDJZ0oW2KxMrzZqp2xu7l4YN-4ATwZDpZR9PbE8Cw8eR4cjp7O7Le-jwtXbCQFgqKP5M2DZejki6a4C5dnnS5oye9ezEkD4epLBziAAUdABHn29T49n_KXFdTb7rfUCsc/s320/device-piratebox-wifi.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox - Wi-Fi Access Point</td></tr>
</tbody></table>
<br />
<br />
After connecting to the access point you should be able to enter any HTTP URL inside your browser's address bar to get to the index page of the PirateBox.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0zRGAIlOLIc5A6uvb3XQDCMtnqCxflgyC8JTV7ESP9Jej1puSrcCXmIlYDvz6AEeW2q9-LCfqdsf0s1vU4rsAOH7Jdr-wPcdtZVxh1D0Pwv-2xAbIdFCSpiqqco73XtocWwuuctd8UbY/s1600/device-piratebox-index-page.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0zRGAIlOLIc5A6uvb3XQDCMtnqCxflgyC8JTV7ESP9Jej1puSrcCXmIlYDvz6AEeW2q9-LCfqdsf0s1vU4rsAOH7Jdr-wPcdtZVxh1D0Pwv-2xAbIdFCSpiqqco73XtocWwuuctd8UbY/s320/device-piratebox-index-page.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox - Index page</td></tr>
</tbody></table>
<br />
<br />
<h3>
App Settings</h3>
The app has a few settings. We will discuss them briefly.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDTrQNymhs-IbYN-ygPWIaikQ4-TXhsNvpF_e_2N6lMVrZzaTEEvfNU2I2-ORaiVpGHCJKO7-5Fq00GQ9OK-HcSKI6YO3a50RA-VKWvDG_pJWEMCKrxvhCF19WsblS_ey7T0NT2-TFo7g/s1600/device-piratebox-settings.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDTrQNymhs-IbYN-ygPWIaikQ4-TXhsNvpF_e_2N6lMVrZzaTEEvfNU2I2-ORaiVpGHCJKO7-5Fq00GQ9OK-HcSKI6YO3a50RA-VKWvDG_pJWEMCKrxvhCF19WsblS_ey7T0NT2-TFo7g/s320/device-piratebox-settings.png" width="192" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">PirateBox - Settings</td></tr>
</tbody></table>
<br />
<br />
<b>Start On Boot</b>: If you check that option, the PirateBox will start up after the device has been booted and the SD card is ready.<br />
<br />
<b>SSID Name</b>: You can change the SSID name here. The app will try to change the name immediately. A restart should not be necessary. The default name is <i>PirateBox - Share Freely </i><span style="font-family: inherit;">as mentioned above</span><span style="font-family: inherit;">.</span><br />
<br />
<b>Storage Directory</b>: The directory which contains the uploaded files and the messages inside the shoutbox. You can locate the directory wherever you like. The directory <i>/sdcard/pb_store</i> is the default.<br />
<br />
<b>Enable Updates</b>: On default the configuration and HTML files are updated with each new version of the app. If you don not want to do that, because you want to use your own configuration, un-check that option and no updates will be done.<br />
<br />
<b>iOS WISPr Support</b>: iOS devices use WISPr request to detect if the device is indeed online. If not the device will not permanently connect to the hotspot. If that option is enabled the iOS device assumes it's online.<br />
<br />
<b>WP NCSI Support</b>: Basically the same as for iOS devices. Windows Phone request a NCSI file to check if it's online.<br />
<br />
<h3>
App Broadcasts</h3>
This is a more advances topic and directed to developers which would like to interface with the app.<br />
You do not need to read this section to use the app.<br />
The app broadcast Intents to make indications about the state of the PirateBox , of file uploads and shout messages.<br />
Here are the broadcasts and the extra values provided.<br />
<br />
<b>Intent</b>: de.fun2code.android.piratebox.broadcast.intent.server<br />
<b>Extras</b>: state (boolean)<br />
<b>Description</b>: Indicates the state of the web server. <br />
<br />
<b>Intent</b>: de.fun2code.android.piratebox.broadcast.intent.ap<br />
<b>Extras</b>: state (boolean)<br />
<b>Description</b>: Indicates if the access point is running or not.<br />
<br />
<b>Intent</b>: de.fun2code.android.piratebox.broadcast.intent.network<br />
<b>Extras</b>: state (boolean)<br />
<b>Description</b>: If the state is true, the networking (dnsmasq and iptables) are configured.<br />
<br />
<b>Intent</b>: de.fun2code.android.piratebox.broadcast.intent.shout<br />
<b>Extras</b>: name (String), text (String)<br />
<b>Description</b>: If a message is entered into the shoutbox, the name and text will be included inside the extras of this Intent.<br />
<br />
<b>Intent</b>: de.fun2code.android.piratebox.broadcast.intent.upload<br />
<b>Extras</b>: file (String)<br />
<b>Description</b>: Upon file upload the extra will contain the FQN of the file. <br />
<br />
<hr />
<h3>
Current State</h3>
The app is in an very early state. I've tested as good as I could. There are surely bugs and in some cases the app might not work at all.<br />
<br />
New updates of the APK will show up in the Google Drive folder linked below.<br />
So if you are interested, check the folder from time to time. <br />
<br />
Feedback is always welcome!<br />
<br />
<h3>
Source Code</h3>
The source code is now available on <a href="https://github.com/joschi70/AndroidPirateBox" target="_blank">GitHub</a>.<br />
<br />
<h3>
In Case of Errors</h3>
If the PirateBox does not work as expected, please send me a mail describing your setup and include the LogCat output ... thanks<br />
<br />
Mail address: jochen [at] fun2code.de<br />
<br />
<h3>
Download Links</h3>
Google Drive: <a href="https://drive.google.com/folderview?id=0B8T86cdxxvu-UnhTdUw2U3pLUjQ&usp=sharing" target="_blank">PirateBox APKs</a>
<br />
<br />
<h3>
Questionnaire</h3>
<div>
If you tried the app, please provide feedback by filling out the following questionnaire ... thanks!<br />
The results can be viewed <a href="https://docs.google.com/spreadsheet/lv?key=0AsT86cdxxvu-dGZkRWpFT1ZYSDZCWVpRaDlFSFdNQUE" target="_blank">here</a>, so you know on which configurations PirateBox is running.</div>
<div>
<br /></div>
<iframe frameborder="0" height="800" marginheight="0" marginwidth="0" src="https://docs.google.com/forms/d/1w033bw4pTc0BtU9-vA-XpQJADAVts33zFJigbK4pcRY/viewform?embedded=true" width="100%">Loading...</iframe>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com29tag:blogger.com,1999:blog-8371221544034078032.post-40508120649254639922013-09-18T11:06:00.000-07:002015-12-18T23:31:47.665-08:00Chatting with Web Sockets<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
Web Sockets enable direct socket connections between a web browser and a web server.<br />
Newer versions of PAW support text based Web Sockets. This post shows how to build a small Web Sockets based chat server.<br />
<br />
If you have ever tried coding a web based chat server you have surely noticed that the task is not as easy as it might seem at the first look. You have to deal with sessions and have to synchronize clients and so forth. That’s one of the reasons why I never did that ;).<br />
We will see that with Web Sockets there are only a few lines of code necessary on the server side.<br />
<br />
I will not go into much detail when it comes to the HTML part, this is standard and everybody can google that.<br />
What I will explain in detail is the PAW setup and the server side BeanShell script included in implementing the chat server.<br />
<br />
<h3>
Configuring the Web Socket Handler</h3>
To enable Web Socket support for your PAW server, we have to insert and configure the Web Socket handler inside the <span style="font-family: "courier new" , "courier" , monospace;">handler.xml</span> file. The file is located inside the <span style="font-family: "courier new" , "courier" , monospace;">conf</span> folder of your PAW installation directory . The installation directory is normally <span style="font-family: "courier new" , "courier" , monospace;">/sdcard/paw</span>. Inside the <span style="font-family: "courier new" , "courier" , monospace;">handler.xml</span> file the installation directory is referenced as <span style="font-family: "courier new" , "courier" , monospace;">[PAW_HOME]</span>.<br />
<br />
The handler can be places right in front of the configuration file inside the <span style="font-family: "courier new" , "courier" , monospace;"><handlers>...</handlers></span><br />
tag:<br />
<br />
<pre class="brush:xml"><handler status="active">
<name>WebSocket Handler</name>
<description>WebSocket Handler</description>
<removable>true</removable>
<id>websocket</id>
<files/>
<params>
<param name="websocket.class" value="org.paw.handler.android.websocket.WebSocketHandler" />
<param name="websocket.basedir" value="[PAW_HOME]" />
<param name="websocket.config" value="[PAW_HOME]/webconf/websocket.conf" />
</params>
</handler>
</pre>
<br />
There are two important parameters in that handler definition… <span style="font-family: "courier new" , "courier" , monospace;">basedir</span> and <span style="font-family: "courier new" , "courier" , monospace;">config</span>.<br />
<br />
Let’s start with <span style="font-family: "courier new" , "courier" , monospace;">config</span>. The parameter <span style="font-family: "courier new" , "courier" , monospace;">config</span> specifies the location of the Web Socket definition file. This file defines rules that describe which BeanShell script (or Java class) to call if a Web Socket connection requesting a specific protocol comes along.<br />
<br />
A Web Socket communication can specify a protocol to use, which makes it possible for the server to react differently even if listening to the same port.<br />
A common protocol type is <span style="font-family: "courier new" , "courier" , monospace;">chat</span> which the client sends to the server within the header when the connection is established. You can also define your own protocol, it’s just a text.<br />
<br />
In our example the web browser will send a different protocol for each chat room which makes it possible for the server to distinguish them. So if a chat room is called <span style="font-family: "courier new" , "courier" , monospace;">talk</span>, the protocol will be <span style="font-family: "courier new" , "courier" , monospace;">chat.talk</span>.<br />
<br />
The other parameter <span style="font-family: "courier new" , "courier" , monospace;">basedir</span> defines the base directory of the BeanShell scripts which are defined inside the Web Socket configuration file.<br />
<br />
In the next step, we’ll create the Web Socket config file.<br />
<br />
<h3>
Web Socket Config File</h3>
As defined in the handler definition, create a file called <span style="font-family: "courier new" , "courier" , monospace;">[PAW_HOME]/webconf/websocket.conf</span> with the following content:<br />
<br />
<pre class="brush:shell"># Format:
# Protocol:Bsh script (.bsh extension) or class name
#
chat.*:html/websocket/websocket_chat.bsh
</pre>
<br />
That’s it, actually quite simple. I’ll quickly explain the syntax.<br />
The parameters are devided by colons.<br />
<br />
First parameter is the protocol which is defined as a regular expression. So in our case the server will call the script <span style="font-family: "courier new" , "courier" , monospace;">html/websocket/websocket_chat.bsh </span>for all protocols starting with <span style="font-family: "courier new" , "courier" , monospace;">chat</span>. Now you already know the second parameter which is the BeanShell script to call.<br />
<br />
Actually you can also use a Java class (or performance reasons) but this will not be handled inside this post. More about how to get this working with Java classes can be found inside the PAW Functions section of the PAW web interface.<br />
<br />
The next step is to create the BeanShell script.<br />
<br />
<h3>
The BeanShell Script</h3>
Before creating the script, some infos in advance.<br />
The handler sets some variables before it calls the script. These variables are <span style="font-family: "courier new" , "courier" , monospace;">action</span>, <span style="font-family: "courier new" , "courier" , monospace;">message</span>, <span style="font-family: "courier new" , "courier" , monospace;">sockets</span> and <span style="font-family: "courier new" , "courier" , monospace;">socket</span>.<br />
The <span style="font-family: "courier new" , "courier" , monospace;">action</span> variable tells us something about the state of the communication. Possible values are <span style="font-family: "courier new" , "courier" , monospace;">connect</span>, <span style="font-family: "courier new" , "courier" , monospace;">disconnect</span> or <span style="font-family: "courier new" , "courier" , monospace;">text</span>. The state important for us is <span style="font-family: "courier new" , "courier" , monospace;">text</span> because it indicated that a text message has been sent by a client.<br />
<br />
If <span style="font-family: "courier new" , "courier" , monospace;">text</span> is set, there is also a variable called <span style="font-family: "courier new" , "courier" , monospace;">message</span> which contains the message itself.<br />
<br />
Let’s now have a look at the code, because I think will make things clearer.<br />
Create a file called<span style="font-family: "courier new" , "courier" , monospace;"> [PAW_HOME]/html/websocket/websocket_chat.bsh</span><br />
with the following content:
<br />
<br />
<pre class="brush:java">import de.fun2code.android.pawserver.websocket.WebSocketMessage;
if(action.equals("text")) {
for(sock : sockets) {
try {
WebSocketMessage.sendMessage(message, sock);
}
catch(e) {
sock.close();
}
}
}
</pre>
<br />
That’s the complete server side code. First thing that is checked is if the <span style="font-family: "courier new" , "courier" , monospace;">action</span> variable is set to <span style="font-family: "courier new" , "courier" , monospace;">text</span> which indicates that a message text is available inside the <span style="font-family: "courier new" , "courier" , monospace;">message</span> variable.<br />
<br />
If a message is present the code iterates over the <span style="font-family: "courier new" , "courier" , monospace;">sockets</span> collection. The <span style="font-family: "courier new" , "courier" , monospace;">sockets</span> collection contains all client socket connections that have the same protocol.<br />
The socket collections are grouped by Web Socket protocol names, so we are sure that all sockets inside the collection belong to the same chat room.<br />
As mentioned above, the web browser sends different Web Socket protocol names for each chat room (<span style="font-family: "courier new" , "courier" , monospace;">chat.>chatroom></span>).<br />
<br />
So all that is left is to send the incoming message to all connected client. This is done by the following line:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> WebSocketMessage.sendMessage(message, sock);</span><br />
<br />
The try/catch block is there to close a socket if something goes wrong.<br />
<br />
One variable that is not present in the code and therefore was not handled until now is the <span style="font-family: "courier new" , "courier" , monospace;">socket</span> variable. This variable contains the socket of the client that delivered the message.<br />
<br />
<h3>
The HTML File</h3>
The only thing that is missing is now the HTML file that is responsible for opening the Web Socket connection from the web browser. This is actually a XHTML file because it contains some additional BeanShell code.<br />
<br />
The file can be downloaded from the link below. Just copy it into the <span style="font-family: "courier new" , "courier" , monospace;">[PAW_HOME]/html/websocket/</span> directory.<br />
Now you can start your browser and call the XHTML file by inserting the following address into your browser’s address bar:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">http://<ip>:<port>/websocket/chat.xhtml</span><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRN0so4gVmruRb_EL1XI1NvkE9kpowRvQSDkb-ji9V2iv1Be9PfPN-K1XXLK7jCLfuJ14BXHPKexcV2UJQ5-diu9gvCbvLEF8lgJOUu2wJeeGt-R2RuNb3R18CAxl5yCyD97cXN79Xy54/s1600/websocket_chat_screenshot.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="351" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRN0so4gVmruRb_EL1XI1NvkE9kpowRvQSDkb-ji9V2iv1Be9PfPN-K1XXLK7jCLfuJ14BXHPKexcV2UJQ5-diu9gvCbvLEF8lgJOUu2wJeeGt-R2RuNb3R18CAxl5yCyD97cXN79Xy54/s640/websocket_chat_screenshot.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Web Socket Chat</td></tr>
</tbody></table>
<br />
If everything goes well, the Web Socket chat server should be up and running.<br />
In case of questions, write a comment or send me a mail.<br />
<br />
Happy coding :)<br />
<br />
<h3>
Links</h3>
XHTML File: <a href="http://paw-android.fun2code.de/blog/websocket_chat_xhtml.zip">websocket_chat_xhtml.zip</a>Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com0tag:blogger.com,1999:blog-8371221544034078032.post-52914989123173869782013-09-16T11:22:00.000-07:002013-09-22T08:21:12.016-07:00PAW - Build Your Own Server<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
A lot of people have been asking about the PAW source code.<br />
PAW is not Open Source, so (for the time being) you cannot get the source.<br />
<br />
Nevertheless … it is now possible for developers to build their own PAW based apps for private and educational purposes. If you plan to use PAW in a commercial product, please drop me a line.<br />
<br />
To make this easy, the PAW source code has been restructured.<br />
A sample project along with documentation and a sample APK can be downloaded form the links listed below.<br />
The process of creating a PAW based app should quite easy. Please read the linked documentation for detailed instructions.<br />
<br />
… happy coding! :)<br />
<br />
<h3>
<span style="font-size: large;">Links:</span></h3>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
Documentation: <a href="http://paw-android.fun2code.de/download/own_paw_server/Build_Own_PAW_Server.pdf" target="_blank">Build_Own_PAW_Server.pdf</a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
Eclipse Project: <a href="http://paw-android.fun2code.de/download/own_paw_server/BuildOwnPawServer.zip" target="_blank">BuildOwnPawServer.zip</a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
Sample APK: <a href="http://paw-android.fun2code.de/download/own_paw_server/BuildOwnPawServer.apk">BuildOwnPawServer.apk</a></div>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com1tag:blogger.com,1999:blog-8371221544034078032.post-16936438476602082232012-12-30T03:32:00.000-08:002014-06-16T04:39:01.515-07:00PAW - Using other Languages with CGI<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xVUCc3JO2ZoUZNgDFyhaRhX05toXN7VWo4GWnhEfe9XZjpeeIyp9FD1kM3FZ-qJVJRqzwrNRb3cK1b3jw1e08zQ6BPdAahuLRYZFkGrc9qO8b20SqHXUxx4hTStWQYmKzZFGFV5GGD4/s1600/icon.png" /></a></div>
This post is about using other languages apart from BeanShell and PHP.
PAW includes a CGI Handler to execute scripts by using the Common Gateway Protocol (CGI).
This handler is also used by the PHP plugin to call the CGI version of PHP.
The handler is defined inside the file <tt>PAW_HOME/conf/handler.XML</tt>. Instead of using PHP we will use Perl to create a simple web page.
<br />
<h3>
Finding the Executable Path</h3>
First thing to do is to install the SL4A and Perl APK from the <i>Android Scripting Project</i>:
<a href="http://code.google.com/p/android-scripting/downloads/list">http://code.google.com/p/android-scripting/downloads/list</a>
After installing the APKs and extracting Perl it's time to find out where the Perl executable is located.
One way to do it is to execute the Perl interpreter and to use a terminal emulator and run the <tt>ps</tt> command.
In the case of Perl the executable is located here: <tt> /data/data/com.googlecode.perlforandroid/files/perl/perl</tt>
<br />
<h3>
CGI Configuration</h3>
Now it's time to edit the PAW handler configuration.
Open the file <tt>PAW_HOME/conf/handler.XML</tt> and add the following lines below the <tt>Basic Auth Handler</tt> configuration:
<br />
<pre class="brush:xml"> <handler status="active">
<name>Perl CGI Handler</name>
<description>Perl CGI Handler</description>
<removable>true</removable>
<id>perlCgiHandler</id>
<files />
<params>
<param name="perlCgiHandler.class" value="org.paw.handler.AndroidCgiHandler" />
<param name="perlCgiHandler.root" value="[PAW_HOME]/html" />
<param name="perlCgiHandler.suffix" value=".pl" />
<param name="perlCgiHandler.runwith" value="/data/data/com.googlecode.perlforandroid/files/perl/perl" />
<param name="perlCgiHandler.sl4a" value="true" />
<param name="perlCgiHandler.ENV_TMPDIR" value="[PAW_HOME]/tmp" />
</params>
</handler>
</pre>
Let's have a look at the parameters.
The <tt>class</tt> parameter defines the handler to use. In our case this is the CGI Handler. The next parameter is the <tt>root</tt> parameter which specifies the directory the scripts are located. Subdirectories are also included.
The <tt>suffix</tt> parameter defines the filename extension for the scripts. The <tt>runwith</tt> parameter is the most important one, it defines the location of the CGI binary.
If the <tt>sl4a</tt> is set to <tt>true</tt> the environment variables <tt>AP_HOST</tt> and <tt>AP_PORT</tt> are set. Because this information is read from logcat entries, SL4A should be started right before the startup of PAW. Otherwise it might not possible for the handler to extract the SL4A configuration.
The last parameter sets the <tt>TMPDIR</tt> environment variable. All parameters starting with <tt>ENV_</tt> are used to set environment variables.
Now the PAW configuration is complete and we can start to write a test CGI script.
<br />
<h3>
The CGI Script</h3>
We will create a test CGI script inside the <tt>PAW_HOME/html</tt> directory called <tt>test.pl</tt>.
The test script looks like this:
<br />
<pre class="brush:perl">print "Content-type: text/html\n\n";
print "Hello world!\n";
</pre>
After starting PAW and entering the URL <tt>http://<ip-address>:8080/test.pl</tt> into the address bar of the browser the following text should be displayed:
<br />
<pre>Hello world!
</pre>
<h3>
Conclusion</h3>
The Android Scripting Project offers many more interpreters. It should be possible use many of them together with PAW, as long as you can get them to work from the command line.
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com10tag:blogger.com,1999:blog-8371221544034078032.post-77495444321028684302012-08-06T04:35:00.001-07:002014-11-08T01:28:38.215-08:00Cache Beacon (beta) - Introduction<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO7d_NiB097tn-Yo2Kp8__P5mXJmkmr_JWjn2CgFmXBFwC79XoWRARnzNU34SicqVOjXEUKx21vADQJjXS0-tAtids5T7G1_r5ieb-qVJjoMPxgJ80Xf45dNMr9QOs44ntFhT84qKsUHc/s1600/icon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO7d_NiB097tn-Yo2Kp8__P5mXJmkmr_JWjn2CgFmXBFwC79XoWRARnzNU34SicqVOjXEUKx21vADQJjXS0-tAtids5T7G1_r5ieb-qVJjoMPxgJ80Xf45dNMr9QOs44ntFhT84qKsUHc/s1600/icon.png" /></a></div>
This is a post about the Android app <b><i><a href="https://play.google.com/store/apps/details?id=de.fun2code.android.cachebeacon" target="_blank">Cache Beacon</a></i></b> that supports Wireless Cache Beacons on Android.<br />
Garmin® introduced Wireless Beacons in the form of their Chirp™ device almost two years ago.<br />
<br />
<blockquote class="tr_bq">
<span style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;"><i>Cache Beacon is no longer available at Google Play.</i></span><br />
<span style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;"><i>The reason is that there is now an official ANT+ Plugin Sampler that includes the functionality of Cache Beacon.</i></span><br />
<span style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;"><i>It also allows to write Chirps which was not possible with Cache Beacon and is more stable.</i></span><br />
<span style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;"><i>Cache Beacon was ok as long as there was no other implementation of the protocol.</i></span><br />
<i><br style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;" /></i>
<span style="background-color: #141414; color: white; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2000007629395px; text-align: justify;"><i>The ANT+ Plugin Sampler can be found here: <a href="https://play.google.com/store/apps/details?id=com.dsi.ant.antplus.pluginsampler" target="_blank">https://play.google.com/store/apps/details?id=com.dsi.ant.antplus.pluginsampler</a></i></span></blockquote>
<br />
A Wireless Beacon can contain cache information like cache name, coordinates and hints.<br />
These information is transmitted via the ANT+ protocol. Some of the Garmin GPS devices support these beacons.<br />
Accessing the information from other devices is complicated, because most devices lack an integrated ANT+ chip.<br />
<br />
There are solutions for iPhones and iPads by purchasing a separate BlueTooth ANT+ adapter.<br />
Unfortunately these adapters are quite expensive.<br />
<br />
Although the ANT+ Geocaching Device Profile is open there didn't exist a solution for Android devices to access Wireless Beacon until now.<br />
Cache Beacon is an Android app that makes it possible to read the beacon information.<br />
<br />
<b>Note:</b> The app is still in beta, so there might be bugs.<br />
<br />
To use this app a Sonx Xperia device or an Android device with USB host support is needed.<br />
<br />
The maximal distance varies from device to device. When testing, the max. distance with the Xperia device was approx. 2 meters. With an USB adapter it was possible to stay up to 4 meters away.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/CBAJ-Gorq00?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<h3>
Sony Xperia Devices</h3>
There are some Sony Xperia devices that have an integrated ANT+ chip.<br />
The app should work with these devices without any modification.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgESZBlNZTYnVwrgg_Aha9FEY_LJHPBK0Z37Et9u6cHmz-yRbPvhXpCwbVyc8JeWwcZn7RYnKWCioBp1SLeCZjT82FQpfx-oa0cDSRqZEEFrZfH1TVL5JIsVVHff-dtCppctsLV827WY2M/s1600/Sony-Ericsson-Xperia-X10-mini.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgESZBlNZTYnVwrgg_Aha9FEY_LJHPBK0Z37Et9u6cHmz-yRbPvhXpCwbVyc8JeWwcZn7RYnKWCioBp1SLeCZjT82FQpfx-oa0cDSRqZEEFrZfH1TVL5JIsVVHff-dtCppctsLV827WY2M/s1600/Sony-Ericsson-Xperia-X10-mini.jpg" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Sony Xperia pro</td></tr>
</tbody></table>
<br />
<br />
<b>Here is the list of supported Sony devices:</b><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia arco S</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia S </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia ion </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Live with Walkman </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony active</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">Sony Xperia arc </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia arc S </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia mini</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia mini pro</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia neo</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony neo V </span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia pro</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia ray</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia X8</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia X10 mini</span><br />
<span style="font-family: Courier New, Courier, monospace;">Sony Xperia X10 Mini pro</span><br />
<br />
The app has been tested with a <b>Sony Sony Xperia pro (Android 2.1)</b>.<br />
<br />
<h3>
USB Host Mode</h3>
In addition Android since version 3.1 supports USB Host mode together with an <i>USB OTG adapter</i>.<br />
If USB host mode is supported by the Andrdoid device an USB2 compatble ANT+ USB adapter can be used to add ANT+ support.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizWcI4bHR0nwERif_mtlQhhExiQo9SurxHEEUCu1bgtkQ-Tzp13AyNKc5BUj1n2O_SXPUt4CEqsnKoLCQZMqSX5nPzKWENSlW0Z2EBq8a2gD4xnHqFcv2itwqhstw4E_R9g4MveuTO7ZU/s1600/otg_suunto.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizWcI4bHR0nwERif_mtlQhhExiQo9SurxHEEUCu1bgtkQ-Tzp13AyNKc5BUj1n2O_SXPUt4CEqsnKoLCQZMqSX5nPzKWENSlW0Z2EBq8a2gD4xnHqFcv2itwqhstw4E_R9g4MveuTO7ZU/s320/otg_suunto.png" height="132" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">USB OTG Apter and SUUNTO Movestick Mini</td></tr>
</tbody></table>
<br />
<br />
This has been tested with the following configuration:<br />
<b>Galaxy Nexus, SUUNTO Movestick Mini</b><br />
<br />
After starting the app, the app will tell you if USB host is supported or not.<br />
<br />
<h3>
Result Intent</h3>
The app can be also called from another app by using a Result Intent.<br />
The Intent Action to use is: <b><i>de.fun2code.android.cachebeacon.SEARCH</i></b><br />
<br />
The resulting Intent contains some Intent Extras.<br />
Here is the list:<br />
<br />
<table border="1">
<tbody>
<tr><th>Name</th><th>Type</th><th>Description</th><th>Example</th></tr>
<tr><td>BEACON_NAME</td><td>String</td><td>Cache Name</td><td>GC123456</td></tr>
<tr><td>BEACON_HINT</td><td>String</td><td>Hint</td><td>follow the white rabbit</td></tr>
<tr><td>BEACON_LATITUDE</td><td>Double</td><td>Latitude</td><td>49.02056660503149</td></tr>
<tr><td>BEACON_LONGITUDE</td><td>Double</td><td>Longitude</td><td>8.355349972844124</td></tr>
<tr><td>BEACON_VISITS</td><td>Integer</td><td>Visit Count</td><td>4</td></tr>
<tr><td>BEACON_LAST_VISIT_DATE</td><td>Long</td><td>Ms since 1.1.1970</td><td>1344249202000</td></tr>
<tr><td>BEACON_BATTERY</td><td>String</td><td>Battery Status</td><td>Ok</td></tr>
</tbody></table>
<h3>
<span style="font-weight: normal;"><br /></span></h3>
<h3>
<span style="font-weight: normal;">
Links</span></h3>
<div>
Google Drive: <a href="http://goo.gl/YhZ6cu" target="_blank">Cache Beacon</a></div>
Jochenhttp://www.blogger.com/profile/00094449484000593959noreply@blogger.com9