Saturday, October 27, 2012

Add Native Support to JS in Android HTML5 Apps

Running HTML 5 apps in Android , is not effective as you loss a lot of native power , Android provides the ability to expose native power to JS so you can use the powerful native support in your app.

Here is the simple steps:


1. Create any class and name it any thing like JavaScriptInterface
Example:


public class JavaScriptInterface {
        Context mContext;

        JavaScriptInterface(Context c) {
            mContext = c;
        }

        public void doSomething() {
         System.err.println("inside do something");
        }
}

2. The class should have constructor that take Context as parameter

3. During instatiation send the activity object in the constructor and add nick(prefix) name to be used inside JS to call this class methods:

     webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");


Example:

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_crazy);
    WebView webView=(WebView)findViewById(R.id.webView);
    webView.setWebChromeClient(new WebChromeClient());
    webView.getSettings().setJavaScriptEnabled(true); 
    webView.getSettings().setDatabaseEnabled(true);
    webView.getSettings().setDatabasePath("/data/data/osa.ora.test/databases/");
    webView.getSettings().setDomStorageEnabled(true);
    //remove this line for emulator bug in Android 2.3
    webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
       //the following line to prevent the backlight from going during application running.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    webView.loadUrl("file:///android_asset/www/index.html");    
    }


4. In the JS call this methods

Example:
Android.doSomething();

You can see in the console the outcome of the sys err statement.
(Android is the prefix we have specified during creating instance of this JS interface)

5. Of course we can have many interfaces each for specific purpose.

Simple and straightforward but there is a bug in android emulator in 2.3 so better to test it on mobile devices direct in case you need to test it on such platform.

Monday, October 22, 2012

"Hit The Ball" .. Android Game

I have published 1st version of my game "Hit The Ball" over Android platform.


Links:

Here is the link for the demo version :
https://play.google.com/store/apps/details?id=hit.ball.game.demo

And this is the link to commercial version :
https://play.google.com/store/apps/details?id=hit.ball.game

Description:
The game is based on HTML 5 technology and use Java Script Interface for some native work.
It uses Box2D implementation as physics engine for the game.

The idea behind this game is you play with a ball and you need to hit the other ball in the scene.
If you hit the other ball , you go to next level, where it get complicated little bit.
You can select the destination of the shoot by your click/finger.
If you didn't shoot the ball , the ball will be automatically shoot to a default location.
If you pick small ball you get extra trial.
Pay attention to the speed bar during shooting.
You can resume the game from the last successful level which is auto-saved.

Game screen shots:




Saturday, October 6, 2012

Java Fork Join & Parallel Programming

After emerging of multi-cores programs , a major shift to the application development to utilize these cores by forking many threads/process for the applications esp. in the intensive processing procedure.

Java came lately to the paradigm shift with concurrency APIs in Java 7  (JSR 166) (which was initially planned in Java 5), the framework will go under another improvement to facilitate the current complex way in Java 8.

Best fit algorithms for paralization is divide-and-conquer algorithms.
In this post we will go through example of using the fork-join to develop quick sort enhancement..

1) Framework important parts:
-ForkJoinTask : this is a task to be forked and joined after processing.
It has lifecycle methods as doJoin , doInvoke , doExecute plus status.

- RecursiveAction extends ForkJoinTask: represent a recursive action..
It has important method which is compute..
We will extend this class and override compute method to do what we need.

-ForkJoinPool : represents the pool for fork and join framework , you can initialize it by the number of cores or by fixed magic number ...
Note: To get the number of processors/cores:
int processors = Runtime.getRuntime().availableProcessors();

2) Non-parallel Quick sort:
Static method that process the numbers[] to sort them...


//non-parallellll...
private static int[] numbers;
private static void quicksort(int low, int high) {
int i = low, j = high;
// Get the pivot element from the middle of the list
int pivot = numbers[low + (high-low)/2];

// Divide into two lists
while (i <= j) {
// If the current value from the left list is smaller then the pivot
// element then get the next element from the left list
while (numbers[i] < pivot) {
i++;
}
// If the current value from the right list is larger then the pivot
// element then get the next element from the right list
while (numbers[j] > pivot) {
j--;
}

// If we have found a values in the left list which is larger then
// the pivot element and if we have found a value in the right list
// which is smaller then the pivot element then we exchange the
// values.
// As we are done we can increase i and j
if (i <= j) {
exchange(i, j);
i++;
j--;
}
}
// Recursion
if (low < j)
quicksort(low, j);
if (i < high)
quicksort(i, high);
}

private static void exchange(int i, int j) {
int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}



3) Using Fork-Join:


public class ParallelQuickSort extends RecursiveAction {
    Phaser phaser;
    int[] arr = null;
    int left;
    int right;

    ParallelQuickSort(Phaser phaser, int[] arr) {
        this(phaser, arr, 0, arr.length - 1);
    }

    ParallelQuickSort(Phaser phaser, int[] arr, int left, int right) {
        this.phaser = phaser;
        this.arr = arr;
        this.left = left;
        this.right = right;
        phaser.register();  //important
    }


    private ParallelQuickSort leftSorter(int pivotI) {
        return new ParallelQuickSort(phaser, arr, left, --pivotI);
    }

    private ParallelQuickSort rightSorter(int pivotI) {
        return new ParallelQuickSort(phaser, arr, pivotI, right);
    }

    private void recurSort(int leftI, int rightI) {
        if (rightI - leftI > 7) {
            int pIdx = partition(leftI, rightI, getPivot(arr, leftI, rightI));
            recurSort(leftI, pIdx - 1);
            recurSort(pIdx, rightI);
        } else if (rightI - leftI > 0) {
            insertionSort(leftI, rightI);
        }
    }


    @Override
    protected void compute() {
        if (right - left > 1000) {   // if more than 1000 (totally arbitrary number i chose) try doing it parallelly
            int pIdx = partition(left, right, getPivot(arr, left, right));
            leftSorter(pIdx).fork();
            rightSorter(pIdx).fork();

        } else if (right - left > 7) {  // less than 1000 sort recursively in this thread
            recurSort(left, right);

        } else if (right - left > 0) {  //if less than 7 try simple insertion sort
            insertionSort(left, right);
        }

        if (isRoot()) { //if this instance is the root one (the one that started the sort process), wait for others
                        // to complete.
            phaser.arriveAndAwaitAdvance();
        } else {  // all not root one just arrive and de register not waiting for others.
            phaser.arriveAndDeregister();
        }
    }

    /** Patition the array segment based on the pivot   **/
    private int partition(int startI, int endI, int pivot) {
        for (int si = startI - 1, ei = endI + 1; ; ) {
            for (; arr[++si] < pivot;) ;
            for (; ei > startI && arr[--ei] > pivot ; ) ;
            if (si >= ei) {
                return si;
            }
            swap(si, ei);
        }
    }

    private void insertionSort(int leftI, int rightI) {
        for (int i = leftI; i < rightI + 1; i++)
            for (int j = i; j > leftI && arr[j - 1] > arr[j]; j--)
                swap(j, j - 1);

    }

    private void swap(int startI, int endI) {
        int temp = arr[startI];
        arr[startI] = arr[endI];
        arr[endI] = temp;
    }

    /**
     * Check to see if this instance is the root, i.e the first one used to sort the array.
     * @return
     */
    private boolean isRoot() {
        return arr.length == (right - left) + 1;
    }

    /**
     * copied from java.util.Arrays
     */
    private int getPivot(int[] arr, int startI, int endI) {
        int len = (endI - startI) + 1;
        // Choose a partition element, v
        int m = startI + (len >> 1);       // Small arrays, middle element
        if (len > 7) {
            int l = startI;
            int n = startI + len - 1;
            if (len > 40) {        // Big arrays, pseudomedian of 9
                int s = len / 8;
                l = med3(arr, l, l + s, l + 2 * s);
                m = med3(arr, m - s, m, m + s);
                n = med3(arr, n - 2 * s, n - s, n);
            }
            m = med3(arr, l, m, n); // Mid-size, med of 3
        }
        int v = arr[m];
        return v;
    }

    /**
     * copied from java.util.Arrays
     */
    private static int med3(int x[], int a, int b, int c) {
        return (x[a] < x[b] ?
                (x[b] < x[c] ? b : x[a] < x[c] ? c : a) :
                (x[b] > x[c] ? b : x[a] > x[c] ? c : a));
    }


4) Testing :
Generate big random array then sort it using both and see the results:

       private static int[] getRandom(int i) {
        Random randomGenerator = new Random(i);
        int[] array = new int[i];
        for (int n = 0; n < i; n++) {
            array[n] = randomGenerator.nextInt();
        }
        return array;
    }

    public static void main(String[] args) throws InterruptedException {
        int[] arr = getRandom(1000000);
        numbers=Arrays.copyOf(arr, arr.length);
        int[] arr2=Arrays.copyOf(arr, arr.length);
        System.out.println("show: " + arr.length+" "+numbers.length);
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);
        ForkJoinPool pool = new ForkJoinPool();
        StopWatch  stopWatch=new StopWatch();
        Phaser phaser = new Phaser();
        pool.invoke(new ParallelQuickSort(phaser, arr));
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);
        numbers=getRandom(1000000);
        stopWatch=new StopWatch();        
        quicksort(0,numbers.length-1);
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
        System.out.println("show: " + arr[0]+" "+arr[arr.length-1]);
        System.out.println("show: " + numbers[0]+" "+numbers[numbers.length-1]);     
        stopWatch=new StopWatch();        
        Arrays.sort(arr2);
        stopWatch.stop();
        System.out.println("Elapsed Time: " + stopWatch.getElapsedTime());
    }



5) Output :

Example of output of this code:


show: 1000000 1000000
show: 1608240105 -356486679
show: 1608240105 -356486679
Elapsed Time: 68
show: -2147481329 2147476538
show: 1608240105 -356486679
Elapsed Time: 114
show: -2147481329 2147476538
show: -2147481329 2147476538
Elapsed Time: 92



So sorting 1 million element in the array toke 65 milliseconds using fork-join and 113 milliseconds using single threaded mode, and using java optimized quick sort it takes 92 milliseconds.