Thursday, November 24, 2011

PHP Plug-in Update

My cross compiled version of the PHP CGI was not working so well and I didn't manage to fix it.

Fortunately Klaas Biker informed me that Iulian Virtejanu has cross compiled a PHP CGI version that seems to work significantly better.
Here is Iulian's blog entry: PHP and Lighttpd for Android

Iulian gave me the permission to use it in PAW, so I have updated the PHP Plug-in to version 0.3.

There is one known issue:

system(...) does not work.
It is because system('pwd') actually invokes a hardcoded /bin/sh -c 'pwd' - and /bin/sh is not available on Android.
Iulian has submitted a bug report to PHP: https://bugs.php.net/bug.php?id=60081

If you find more bugs, please let me know. I will forward them.

Monday, October 31, 2011

Building PHP from Scratch

This post by Rahul Amaram describes how to build PHP for Android from scratch and how it can later be used within PAW.
I've added links to the needed files at the end of the post.

Thanks to Rahul for putting this together!

Here is Rahul's documentation...



It is suggested to use a VM for compilation so that you can take snapshots at regular intervals. Also as per google recommendation, it is suggested to use a VM with at least 8 GB RAM/swap and 12 GB of free hard disk.

Install Ubuntu 10.04 64-bit (select username as "joschi") on a VM.

After booting ubuntu, login as joschi.

Download and extract android-php

$ cd
$ wget -c "http://paw-android.fun2code.de/download/android-php.zip"
$ sudo apt-get install unzip
$ unzip android-php.zip

First initialize build environment. For donut, java 5 is needed. Also compiling with gcc/g++ 4.4 was throwing errors during compilation. Therefore we use gcc/g++ 4.3 for compilation.

$ sudo apt-get install python-software-properties
$ sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu hardy main multiverse"
$ sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu hardy-updates main multiverse"
$ sudo apt-get update
$ sudo apt-get install sun-java5-jdk


$ sudo apt-get install git-core gnupg flex bison gperf build-essential \
zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev \
libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
libxml2-utils


$ sudo apt-get install g++-4.3-multilib

Download Android source
This will be about 3 GB.

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo


$ mkdir ~/android-donut-src
$ cd ~/android-donut-src
$ repo init -u https://android.googlesource.com/platform/manifest -b android-1.6_r2
$ repo sync

It is a good idea to take snapshot of the VM here.

Build Android

$ cd /usr/bin
$ sudo ln -sf cpp-4.3 cpp
$ sudo ln -sf g++-4.3 g++
$ sudo ln -sf gcc-4.3 gcc
$ sudo ln -sf gcov-4.3 gcov
$ sudo ln -sf cpp-4.3 x86_64-linux-gnu-cpp
$ sudo ln -sf g++-4.3 x86_64-linux-gnu-g++
$ sudo ln -sf gcc-4.3 x86_64-linux-gnu-gcc


$ cd ~/android-donut-src
$ source build/envsetup.sh
$ lunch generic-eng
$ make -j4

It is a good idea to take another snapshot of the VM here.

Next build android-php. The patch is applied in order to avoid the error "undefined reference to `__sync_fetch_and_add_4'" during compilation.

$ cd ~/android-php
$ rm -rf ~/android-donut-src/bionic/libc/include/
$ unzip -d ~/android-donut-src/bionic/libc/ bionic_libc_include.zip
$ patch php-5.3.6/ext/standard/php_crypt_r.c < ~/sync_fetch_and_add.patch
$ ./build_php_5.3.sh

Finally copy php-5.3.6/sapi/cgi/php-cgi to /mnt/sdcard/paw/html/app/plugins/php_plugin/bin/ on your android phone (be sure to backup the existing php-cgi file), and install PHP using the PAW Web App.

References:



Files:
android-php.zip
sync_fetch_and_add.patch

Wednesday, October 19, 2011

Setting up a Cloud Print Printer using the Cloud-X API

The Cloud-X Java API makes it easy to set up a Google Cloud Print aware printer. In the latest API version Cloud Print push notifications are supported.


The below sample code shows the registration of a new printer (if not already present) and how to listen to push notifications.
For the sake of simplicity this is straight forward code, so there might be cleaner ways to do is ;)

Here is the sample code with comments:

/*
  * Process print job
  */
 public static void processJobs(CloudPrintConnection gcp, Printer printer) {
  try {
   List<Job> jobs = gcp.fetch(printer);
   if (jobs != null) {
    for (Job job : jobs) {
     System.out.println("Processing job " + job.getId() + " ("
       + job.getTitle() + ")");
     gcp.deletJob(job);
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static void main(String[] args) {
  try {
   String printProxy = "testprinter-" + NetworkUtil.getMacAddress();

   /*
    * Our printer
    */
   final Printer printer = new Printer();
   printer.setProxy(printProxy);
   printer.setName("Test Printer");
   printer.setStatus("Online");

   final CloudPrintConnection gcp = new CloudPrintConnection();
   gcp.connect(username, password, "cloudprint",
     "Cloud Print Test Client", null);

   /*
    * Register printer if not already present
    */
   List<Printer> printers = gcp.list(printProxy);
   if (printers.size() == 0) {
    System.out.println("Registering Printer with Proxy "
      + printProxy);
    gcp.register(printer, null);
   } else {
    printer.setId(printers.get(0).getId());
   }

   /*
    * Refetch all printer info
    */
   gcp.printer(printer);

   System.out.println("Printer Name: " + printer.getName());
   System.out.println("Printer ID: " + printer.getId());
   System.out.println("---------------------------------------------");

   processJobs(gcp, printer);

   /*
    * Wait for push notifications
    */
   PushReceiver pr = new PushReceiver("Cloud-X API - Push Receiver");
   pr.addListener(new PushListener() {

    @Override
    public void onReceive(String printerId) {
     if (printerId.equals(printer.getId())) {
      processJobs(gcp, printer);
     }
    }

    @Override
    public void onConnect() {
      System.out.println("Connected to Google Talk!");
    }

    @Override
    public void onDisconnect() {
      // Do nothing
    }
   });

   pr.connectPlain(username, password);

  } catch (Exception e) {
   e.printStackTrace();
  }

 }

Thursday, October 13, 2011

Cloud-X - Sharing Files through the Cloud

We just released the first alpha version of Cloud-X.
Cloud-X uses Google Cloud Print to share files between different users and devices. Along with the PC and Android app the Java API to access Google Cloud Print is also released.

This is a very early version, so there might be bugs.
The Android app and an online and stand alone PC version can be found at the following site:
http://cloud-x.fun2code.de

Comments welcome!

Update

The website is no longer online.
API with included sources can be downloaded from http://fun2code.de/downloads/GoogleCloudPrint.jar.

Monday, September 19, 2011

PAW and DynDNS

From time to time I get requests from users who would like to have a DynDNS integration into PAW.
I thought about it ... but it just doesn't make much sense, because there are enough apps in the Android Market that do exactly this.
So I will not provide a plug-in or another means of DynDNS integration, but for those of you who would like to experiment here is a basic BeanShell implementation of the DynDNS API:

import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.*;
import org.apache.http.client.methods.*;
import org.apache.http.util.*;
import org.apache.http.auth.*;

/*
    Host, username and password settings
*/
hostname = "";
user = "";
password = "";

/*
    Get IP number
*/
client = new DefaultHttpClient();  
getURL = "http://checkip.dyndns.com/";
get = new HttpGet(getURL);
responseGet = client.execute(get);  
resEntityGet = responseGet.getEntity();

if (resEntityGet != null) {
  // Extract IP number
  ip = EntityUtils.toString(resEntityGet).replaceAll(".*?([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}).*", "$1").replaceAll("[\n\r]", "");
  print("IP: " + ip);
 
 /*
    Send DynDNS update request
 */
  updateURL= "https://members.dyndns.org/nic/update?hostname=" + hostname + "&myip=" + ip + "&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG";
  get = new HttpGet(updateURL);
  client.getCredentialsProvider().setCredentials(new AuthScope(null, -1),
new UsernamePasswordCredentials(user, password));
  responseGet = client.execute(get);  
  resEntityGet = responseGet.getEntity();
  
  response = EntityUtils.toString(resEntityGet);
  success = response.startsWith("good");
  
  // Print result
  print("Response: " + response);
}


Hostname, username and password have to be inserted into the script.

This implementation is not complete but should be a good start for further development.
To start the script automatically when PAW starts, put it in the paw/autostart or paw/etc/rc.* folder.

The API is quite easy and it should not take too long to get a complete implementation up and running ...

Thursday, September 15, 2011

PAW and DavDrive on Google TV

So now that the Google TV emulator is out and my Linux box supports KVM I tried PAW and DavDrive.

The only problem I had was that /sdcard was mounted read only and thus PAW could not extract its content and DavDrive could not write files.
To solve this issue I opened an ADB Shell and remounted the root file system via mount -o remount,rw /.

Apart from that everything worked fine. Compared to the Honeycomb emulation the Google TV emulation was quite fast.

Below are screen-shots of the two apps running on Google TV.

PAW running on Goolge TV

DavDrive running on Google TV

Wednesday, August 31, 2011

PAW - I18N & Native Mapper

It might seem that there is no process concerning PAW, but actually I'm quite busy :)
My plans are to release a 1.0 version this year. In October PAW will be two years under development and I think it's time to leave beta.

Things I'm currently working on are internationalization and what I call Native Mapping.

Internationalization
Currently I'm translating the web interface into German. This will result in a Java properties file with key and value pairs.
After this is finished it should be quite easy to make a translation for any language.
Translation takes much longer than I thought and I'm sure there will be a lot of mistakes in the first version.

Native Mapper
The PAW BeanShell approach has the advantage of being very flexible but when it comes to performance it's really slow.
As I showed in a previous blog post BeanShell is considerably slower than the same native code.
The Native Mapper is an approach to solve this dilemma.

The Mapper is comparable to a Servlet mapping in a JEE environment. The Native Mapper is implemented as Brazil Handler that sits in front of the BeanShell Handler and redirects URLs to native code (DEXed classes).

Handler Chain

The next version of PAW will use the mapper to speed up the generation of graphics inside the web application. This includes the generation of icons, contact images, album covers and the load graph.
Because some versions of HoneyComb have the problem that the DEX classloader is not working the original BeanShell code is also available. So if the Native Mapper fails to initialize (because the DEX classes are not available), the old BeanShell code is used.

A good example to show the possible speed-up when the Native Mapper is used is the Installed Apps page of the web application. On my Nexus One it shows 131 icons. Without Native Mapper this takes 90 seconds, with Native Mapper only 10.

Speed Test (time in seconds)

I hope to release the new version in the next couple of weeks ... stay tuned :)