Wednesday, February 2, 2011

Go Sling!



Go Sling! is a slingshot shooter, its aim is to shot ducks, hedgehogs and other creatures with a sling. They can hide behind various obstacles like stones, trees, barrels, etc. You have to get a certain number of points to pass through the next level.


Currently three levels are available:
  1. Rocky Lakes
  2. Fairway
  3. Apple Madness

Here you can see a several game screenshots



Go Sling! is free and available in Android Market


AsciiCamera



AsciiCamera allows you to take a picture in ASCII style. In other words it converts your snapshot into a sequence of letters, digits and other symbols.







The application has the following set of features:
  •  Switching between color and grayscale modes
  •  Inverting. When you select it, the background turns white, the letters turn black. It's useful if you want to see how can the text result look in a text editor.
  •  Scaling
  •  Importing existing images for processing
  •  Saving the result either as png image or as HTML-page (example)

You can choose one of two ways to process images. Let's take a closer look at the algorithms.

First one takes a bunch of pixels (2x2 or 4x4) and calculates their average brightness (that means "value" in HSV color model). Then we replace these pixels with a relevant symbol. The brighter the pixels - the more "colorful" symbol we use. For instance, "@" is equivalent to white and dot is equivalent to dark gray.

The second approach is a bit more interesting. It takes every 4 pixels (2x2) and find a symbol that seems similar to these pixels (visually). So we build a matching table (16 rows in this case) that looks like this:



Here you can see a few examples of how it works.

You can find it in Android Market. QR-code:


Tuesday, February 1, 2011

Android: using unix pipes for tracking progress of native code execution

One of my projects required tracking of how much code is executed at the moment. The situation was complicated by the fact that for a number of reasons some pieces of code were being executed in a few separate processes in turn.

There was three options to choose from:

  • IPC-calls from native code
  • logcat parsing
  • passing data through pipes

The last choice seemed best. Pipe is a common communication channel that may be used for one-way interprocess communication. Pipe has a file interface so we can handle it as it was an usual file. The main point of pipes is that we cannot write into it until someone start to read from this pipe and conversely, reading call blocks if no one writes into it. Another benefit is that several processes can write into a single pipe simultaneously (no synchronization mechanism needed).

Here you can find a demo project. It starts a service that writes into a pipe from native code. Also there is a reading thread that can read data from the pipe and display it.


Writing thread. It emulates a long running piece of code publishing its own progress. Below you can see the native implementation of "process" method.


    final String pipename = intent.getStringExtra("fn");
    new Thread(new Runnable() {
      
      @Override
      public void run() {
        process(pipename);
      }
    }).start();


JNIEXPORT jint JNICALL Java_ru_jecklandin_cats_ProcessingService_process
 (JNIEnv * env, jobject, jstring path) {
  
  const char* cpath = env->GetStringUTFChars(path, NULL);
  struct stat buf;
  
  if ( stat(cpath, &buf) < 0 || ! (buf.st_mode | S_IFIFO)) {
    LOGD("The file isn't a pipe");
    return -1;
  } 
  
  int fp = open(cpath, O_WRONLY);
  if(fp == -1) {
    LOGD("Could not open the pipe");
    return -1;
  }
   
  for (int i=0; i<10; ++i) {
    sleep(1);
    write(fp, &i, 1);
  }
  close(fp);
  env->ReleaseStringUTFChars(path, cpath);
  return 0;
}


Reading thread. Creates a new pipe and starts to read from it as if it was a simple file. "read" call blocks until someone on the other side of the pipe starts to write data into it.

 


    final TextView disp = new TextView(this);
    disp.setText("0");
    setContentView(disp);
    
    final String pipename = getDir("pipedemo", Context.MODE_WORLD_WRITEABLE)
     .getAbsolutePath() + "/pipe";
    final File pipe = new File(pipename);
    
    new AsyncTask<Void, Integer, Integer>() {

     @Override
     protected void onProgressUpdate(Integer... values) {
      disp.setText(""+values[0]);
     };
     
     protected Integer doInBackground(Void... params) {
      
      //create a pipe
      if (mkfifo(pipename) == -1) {
       Log.d(TAG, "Pipe error");
       return -1;
      }
      
      FileInputStream fis;
      try {
       fis = new FileInputStream(pipe);
       int res = 0;
       while (res != -1) { //blocks until someone writes to this pipe
        res = fis.read();
        publishProgress(res);
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
      return 0;
     }
    }.execute();


* This source code was highlighted with Source Code Highlighter.

Warning 1: Despite our code might be run into a separate process, always launch long-running pieces of code in separate threads. Otherwise, the system can kill the hosting process without notice.

Warning 2. Don't create pipes on sdcard - FAT32 doesn't support them.





Add "process" attribute to our service in AndroidManifest.xml to make sure it works in a separate process.

<service android:name=".ProcessingService"
      android:process=":remote">
    </service>


DDMS displays both processes
image

When you compile and run the project, there will be an increasing number on the screen (not very eye-catching, I know).

If you need a duplex channel, just create one more pipe. Sure, this solution isn't a silver bullet. If there is a need to pass complicated objects between processes, you should consider using standard Android IPC tools (I mean aidl).

Useful references:
developers.sun.com/solaris/articles/named_pipes.html
developer.android.com/guide/developing/tools/aidl.html