Friday, November 8, 2013

OpenCV: How to get started and index of posts

So, you want to do some cool image processing... so, here is a very basic explanation on how to get started with link/index to the stuff I posted so far.

Where to start

Basically OpenCV is a set of nice libraries that will highly expedite a lot of your work. See more detail here. You will need to call them from your program, say in C/C++ or Java.

To develop the program you will need an IDE (integrated development environment) which takes care of editing (more than a text editor, with nice support features), and allows you to "plug in", compilers, debuggers, etc... so that you can run everything from there. In my case, I am using Eclipse. Notice that you could use a different IDE. During configuration of the IDE, you tell it what compiler to use, etc... So that when you press the compile button, Eclipse calls it to generate the object file... I think you get the point...

So, install Eclipse if you don't have it. Of course, you could choose a different IDE, but sorry, no experience on that, and honestly, I have no complains about Eclipse. Great tool. In my case, I did the installation when I was planning to use it with Qt (a set of widgets for something that I was doing completely unrelated). Still, the initial portion of the installation is the same. You can see my installation experience here.

So, what do I choose, C/C++ or Java?

Not an expert on this but I believe that a lot of the initial stuff on OpenCV was done for C development. Nevertheless, I think that almost everything in OpenCV has a port to Java already. I.e., there are packages in Java equivalent to libraries in C. So, probably depends more on what language you feel comfortable with.

One thing I was thinking (and I was wrong) is that if I want to use OpenCV in Android, I better get a handle of the Java version, as that is the language to develop in that platform (see this overview on Android programming environment). Nevertheless, that it's not that truth. In Android development, there is something called the NDK which allows you to call pieces of C code (native code) from the java code (see more info here on the NDK). The funny part is that in the end, as OpenCV is pretty processing intensive, you may want to use the NDK for the OpenCV routines (native code runs much faster than java code, if you do things properly...). Bottom line, I went down the path of working with OpenCV in Java, but probably I (and you, if you prefer) could have saved part of that work, as I was more familiar with C. But as I went down that path, I end-up with Eclipse supporting both languages (that is done with the "views"). So, to install each of the languages to work with OpenCV in a PC CPU, follow:
  1. Installation to work with C/C++
  2. Installation to work with Java
To develop for an Android machine, follow this.

Note: The 3 links above are in the order of what I historically did on my case. I.e., the 3 steps may not be completely independent of each other. For instance, something got installed in step 2 that is needed for Android, but I never realized and if I had done only the third, it would not have worked. Please let me know if you got any trouble...

Coding examples

So, now that you got it installed, let's do some coding:
  1. As part of the installation of OpenCV in Java (the same link as above) we did a first tutorial where we detect faces in an image file in a PC.
  2. Creating windows in Java and drawing in them. We strip everything to get familiar with the java drawing/workings. There is no OpenCV here. I read an image file from disk and display it. No detection yet.
  3. Next, we create windows and capture webcam, i.e., not from a file, like in #1. Although we do not do any image processing, we do use OpenCV structures to be ready for the next step (processing). 
  4. One of the keys on that post is how to take a Mat structure from OpenCV and pass it to BufferedImage, for display in Java. I created a post just for that.
  5. And into image processing, we now detect the faces on the webcam stream. Notice that this is very similar (a port to Java) of the original C tutorial
  6. Then we move into detecting a ball in the image. Part of the detection is based on color. So, you got to understand the color space. See this.
  7. And then we track the ball with the PC camera/CPU.
  8. Then we start moving into Android with a first app using OpenCV.
  9. Here we track faces with OpenCV in Android, using the smart phone camera. And here I use the Android SDK for the same thing.
  10. Using the face tracking I created a 3D display, which seems to be a similar technique to what Amazon is going to be using on their phone.
  11. And finally, we port the tracking of the ball to Android, i.e., we use the smart phone camera/CPU.
  12. The last final thing that I had in plan but haven't done yet is to actually port it to Android but have the OpenCV CPU intensive routines done in a C library, with the NDK.
For the next posts I am going to be concentrating in Android development, not related to OpenCV, but I'll be back :)

Cheers!!

Tuesday, November 5, 2013

Saving to a file in Android

We create the routine apart, as part of a task, but that is irrelevant to the topic. Straight to the code...
async_save_file.java
 package com.example.saveit;  
 import java.io.DataOutputStream;  
 import java.io.File;  
 import java.io.FileOutputStream;  
 import java.text.SimpleDateFormat;  
 import java.util.Date;  
 import java.util.Locale;  
 import android.content.Context;  
 import android.os.AsyncTask;  
 import android.os.Environment;  
 import android.os.Handler;  
 import android.os.Message;  
 import android.util.Log;  
 public class async_save_file extends AsyncTask<Void, Void, Void> {  
   Context mContext;  
   private Handler threadHandler;  
   private int[] audio_buffer;  
   public async_save_file(Context context,Handler threadHandler, int[] buffer) {  
     super();  
     this.threadHandler=threadHandler;  
     this.audio_buffer=buffer;  
     mContext = context;  
       }  
   @Override  
     protected Void doInBackground(Void...params) {   
     String root = Environment.getExternalStorageDirectory().toString();  
     File myDir = new File(root + "/captured_files");    
     if (myDir.exists()) Log.v(saveit.TAG,"S: Diretory exists!");  
     else {  
          myDir.mkdirs();   
          Log.v(saveit.TAG,"S: Diretory created!");  
     }  
     String dateInString = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss",Locale.US).format(  
         new Date()).toString();  
     String fileName = dateInString + "_record.bin";  
     File file = new File (myDir, fileName);  
     Log.v(saveit.TAG,"S: file path: "+file.getPath());  
     if (file.exists ()) file.delete ();   
     try {  
          FileOutputStream out = new FileOutputStream(file);  
       DataOutputStream out_s = new DataOutputStream(out);  
           Log.v(saveit.TAG, "L: Length: "+audio_buffer.length);  
           for (int i=0;i<audio_buffer.length;i++) out_s.writeChar(audio_buffer[i]);  
           //out_s.flush();  
           //out.flush();  
           //out.close();  
           out_s.close();   
              Message.obtain(this.threadHandler, saveit.ACK_SAVED, "SAVED").sendToTarget();   
                return null;  
       } catch (Exception e) {  
            e.printStackTrace();  
                    Message.obtain(this.threadHandler, saveit.ACK_NOT_SAVED, "FAILED SAVING").sendToTarget();   
                    return null;  
       }  
   }  
 }  
Notice also the flushing of the file (most of it commented out as the last instruction takes care of the rest). See flushing the file and Will closing a dataoutputstream close also the fileoutputstream. This is called from saveit.java
 package com.example.saveit;  
 import android.os.Bundle;  
 import android.os.Handler;  
 import android.annotation.SuppressLint;  
 import android.app.Activity;  
 import android.util.Log;  
 import android.view.View;  
 import android.widget.Button;  
 import android.widget.TextView;  
 import android.widget.Toast;  
 public class saveit extends Activity {  
      public static final int ACK_SAVED=1;  
      public static final int ACK_NOT_SAVED=2;  
      public static final String TAG = "MyActivity";  
      private TextView mResult;       
      private Button save_array;                    // To trigger the whole process  
      private int[] audio_buffer={1,2,3,4};  
      @Override  
      protected void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
           setContentView(R.layout.saveit_layout);  
           save_array=(Button)findViewById(R.id.button1);  
           mResult=(TextView)findViewById(R.id.display);  
           save_array.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                     // TODO Auto-generated method stub  
                     new async_save_file(getApplicationContext(),threadHandler,audio_buffer).execute();  
                     Log.v(TAG, "UI: SAVING");  
                     mResult.setText("SAVING");        
                }  
           });  
      }  
      ////////////////////////////////////thread Handler///////////////////////////////////////  
      @SuppressLint("HandlerLeak")  
      private Handler threadHandler = new Handler() {  
           public void handleMessage(android.os.Message msg) {  
           switch(msg.what){  
                case ACK_SAVED:  
                     Toast.makeText(getBaseContext(), (String)msg.obj, Toast.LENGTH_SHORT).show();  
                     mResult.setText("SAVED");   
                     break;  
                case ACK_NOT_SAVED:  
                     Toast.makeText(getBaseContext(), (String)msg.obj, Toast.LENGTH_SHORT).show();  
                     mResult.setText("NOT SAVED");   
                     break;  
                }            
           }  
      };  
 }  
Along the way, I also used few ways to display results/debug notices... just as example...

The manifest:
 <?xml version="1.0" encoding="utf-8"?>  
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
   package="com.example.saveit"  
   android:versionCode="1"  
   android:versionName="1.0" >  
   <uses-sdk  
     android:minSdkVersion="9"  
     android:targetSdkVersion="17" />  
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
   <application  
     android:allowBackup="true"  
     android:icon="@drawable/ic_launcher"  
     android:label="@string/app_name"  
     android:theme="@style/AppTheme" >  
     <activity  
       android:name="com.example.saveit.saveit"  
       android:label="@string/app_name" >  
       <intent-filter>  
         <action android:name="android.intent.action.MAIN" />  
         <category android:name="android.intent.category.LAUNCHER" />  
       </intent-filter>  
     </activity>  
   </application>  
 </manifest>  
And the layout:
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   android:paddingBottom="@dimen/activity_vertical_margin"  
   android:paddingLeft="@dimen/activity_horizontal_margin"  
   android:paddingRight="@dimen/activity_horizontal_margin"  
   android:paddingTop="@dimen/activity_vertical_margin"  
   tools:context=".MyAdderActivity" >  
   <Button  
     android:id="@+id/button1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_centerHorizontal="true"  
     android:layout_marginTop="81dp"  
     android:text="@string/save_button" />  
   <TextView  
     android:id="@+id/display"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_below="@+id/button1"  
     android:layout_centerHorizontal="true"  
     android:text="@string/display" />  
 </RelativeLayout>  
Cheers!

PS.: Please, click here to see an index of other posts on Android. 

Sunday, October 13, 2013

Tutorial for Drawing in Android - SurfaceView and SurfaceHolder

Right into the water! The next paragraph is my 5 seconds explanation, so, hold on to anything coz is not straightforward (it was not for me, at least)!! But don't worry. Gets broken down below... If you can't learn it here, we will return your money, guaranteed... lol! Also, you can start by checking "simpler but less powerful" approaches here.

Soooo.... Bottom line, within the Activity, we need an ObjectA that has the Surface object (the screen with pixels) of the application, that we want to show at that instant. This ObjectA has an ObjectB inside that implements a bunch of methods that allow access to that surface. The ObjectA launches a separate thread and gives it ObjectB. The thread as such, independent of the UI, gets a hold of the canvas provided by ObjectB (in the background, no display, and no interfering with the main thread/UI thread), draws on it, and releases the hold, for it to get updated by the UI.

The pending questions that I haven't found answer for are:
  1. Why do we need Object B and not implement the methods directly in Object A? Stackoverflow question on the same thing is unanswered.
  2. Do we really update the UI in the thread or in the UI? I thought we were supposed to do this always in the UI.
Anyhow, let's put names to all this. In simple graphics (see this) to update the  screen one uses an object from View class. Nevertheless, in this case, we want something with a bit more control, with more methods, among other things, to do live graphics. An example is shown below. The following app has a menu which allows the selection between two views, a simple one that does nothing, created with a layout, and the 2nd one, with SurfaceView, that keeps adding a random circle every 100ms.


To do the 2nd one (the one we care to explain) we build a class extending SurfaceView class, which is a child of View. This, in the example below, happens in the DotsSurfaceView definition (DotsSurfaceView.java). An instance of this class is what we call ObjectA above. In the code below, this is dots_screen_view (see Dots1.java). Whenever we want the app to switch to this view, we will use setContentView(dots_screen_view);

Dots1.java
 package com.cell0907.dots1;  
   
 import android.os.Bundle;  
 import android.app.Activity;  
 import android.view.Menu;  
 import android.view.MenuItem;  
 import android.view.View;  
 import android.widget.Button;  
   
 public class Dots1 extends Activity {  
      // USER INTERFACE  
      static int screen_selected=0;  
      private static final int MENU_SIMPLE_UI = 1;     // SIMPLE UI  
      private Button button1;  
      private static final int MENU_DOTS = 2;          // RANDOM CIRCLES "dots"  
      DotsSurfaceView dots_screen_view;  
        
   @Override  
      protected void onCreate(Bundle savedInstanceState) {  
           super.onCreate(savedInstanceState);  
      }  
        
   @Override  
   public void onPause(){  
        if (screen_selected==2){  
             dots_screen_view.surfaceDestroyed(dots_screen_view.getHolder());  
        }  
        super.onPause();  
   }  
        
   @Override  
      protected void onResume(){  
           super.onResume();  
           switch (screen_selected) {  
           case 0:  
                screen_selected=MENU_SIMPLE_UI;  
           case MENU_SIMPLE_UI:  
           screen_selected=1;  
              set_simple_UI();  
       return;  
     case MENU_DOTS:  
           screen_selected=2;  
           set_dots();  
       return;  
     }  
      }  
             
   @Override  
      protected void onStop() {  
           super.onStop();  
   }   
     
       /**  
    * Invoked during init to give the Activity a chance to set up its Menu.  
    *  
    * @param menu the Menu to which entries may be added  
    * @return true  
    */  
   @Override  
   public boolean onCreateOptionsMenu(Menu menu) {  
     super.onCreateOptionsMenu(menu);  
     menu.add(0, MENU_SIMPLE_UI, 0, R.string.menu_simple_ui);  
     menu.add(0, MENU_DOTS, 0, R.string.menu_dots);  
     return true;  
   }       
     
   /**  
    * Invoked when the user selects an item from the Menu.  
    *  
    * @param item the Menu entry which was selected  
    * @return true if the Menu item was legit (and we consumed it), false  
    *     otherwise  
    */  
   @Override  
   public boolean onOptionsItemSelected(MenuItem item) {  
           switch (screen_selected) {  
     case MENU_SIMPLE_UI:  
          break;  
     case MENU_DOTS:  
          dots_screen_view.surfaceDestroyed(dots_screen_view.getHolder());  
          break;  
     }  
     switch (item.getItemId()) {  
       case MENU_SIMPLE_UI:  
            screen_selected=1;  
               set_simple_UI();  
         return true;  
       case MENU_DOTS:  
            screen_selected=2;  
            set_dots();  
         return true;  
       }  
     return false;  
   }  
        
      void set_simple_UI(){  
           setContentView(R.layout.activity_main);  
           button1=(Button)this.findViewById(R.id.button1);       
           button1.setOnClickListener(new View.OnClickListener() {  
                @Override  
                public void onClick(View v) {  
                     //~Activity;  
                }  
           });  
      }  
        
      void set_dots(){  
           dots_screen_view=new DotsSurfaceView(this);  
           setContentView(dots_screen_view);  
      }  
 }  

Ok, so, DotsSurfaceView inherits from SurfaceView class, among other things, few Surface objects (like the one we are using now, and the one we are going to use...) and methods, like callbacks to react to stuff that happens, etc... Also, SurfaceView has an internal (private) object created from an anonymous class (see references below) that implements the SurfaceHolder interface. This is what we call Object B above. This is an object that allows access to the Surfaces. This approach effectively gives body to the methods of the SurfaceHolder interface. See in Google Source (line 694) the creation of the internal object mSurfaceHolder:
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() { methods... }
Still, in our code, we need to implement in the DotsSurfaceView the SurfaceHolder.Callback interface. That is a nested interface to the SurfaceHolder interface. To see this, one can simply look at the SurfaceHolder source. Notice that inside that code (line 69), nested, there is the definition of the Callback interface (i.e., SurfaceHolder.Callback) which defines 3 more methods (see example code). Those are the ones that we need to implement when we extend SurfaceView. If not, we will get a compiler error as we are saying "implement SurfaceHolder.Callback" in the header of the class, but we don't.

DotsSurfaceView.java
 package com.cell0907.dots1;  
   
 import android.content.Context;  
 import android.view.SurfaceHolder;  
 import android.view.SurfaceView;  
   
 // We extend SurfaceView. Internally (private) SurfaceView creates an object SurfaceHolder  
 // effectively defining the methods of the SurfaceHolder interface. Notice that it does  
 // not create a new class or anything, it just defines it right there. When we extend  
 // the SurfaceView with the SurfaceHolder.Callback interface, we need to add in that extension  
 // the methods of that interface.  
   
 public class DotsSurfaceView extends SurfaceView implements SurfaceHolder.Callback {  
      private SurfaceHolder holder;     // This is no instantiation. Just saying that the holder  
                                              // will be of a class implementing SurfaceHolder  
      private DotsThread DotsThread;// The thread that displays the dots  
             
      public DotsSurfaceView(Context context) {  
           super(context);  
           holder = getHolder();          // Holder is now the internal/private mSurfaceHolder inherit   
                                              // from the SurfaceView class, which is from an anonymous  
                                              // class implementing SurfaceHolder interface.  
           holder.addCallback(this);  
      }  
        
      @Override  
      public void surfaceCreated(SurfaceHolder holder) {  
      }  
        
      @Override  
      // This is always called at least once, after surfaceCreated  
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
           if (DotsThread==null){  
                DotsThread = new DotsThread(holder);  
                DotsThread.setRunning(true);  
                DotsThread.setSurfaceSize(width, height);  
                DotsThread.start();  
           }  
      }  
   
      @Override  
      public void surfaceDestroyed(SurfaceHolder holder) {  
           boolean retry = true;  
           DotsThread.setRunning(false);  
           while (retry) {  
                try {  
                     DotsThread.join();  
                     retry = false;  
                } catch (InterruptedException e) {}  
           }  
   }  
        
   public Thread getThread() {  
     return DotsThread;  
   }  
 }  

But still, where do we draw anything? All that happens on a separate object thread. We want to have that running on its own pace, faster or slower, without interfering with the UI. We define this object class in DotsThread.java. And we create the instance of the object in one of the callbacks of the SurfaceHolder.Callback interface (surfaceChanged). Whenever the view is created, it goes through surfaceCreated and then this call. So, within surfaceChanged, we will lunch the thread that will do the actual drawing. We will give that process a Holder to our view, so, that it can manipulate it.

The main magic here happens within the run method. Basically there is a loop running continuously as long as the variable running is truth. One can make that variable truth or false from outside, through the method setRunning, which effectively will allow the loop to run or stop it. See how we stop it in surfaceDestroyed, the 3rd callback of the SurfaceHolder.Callback interface. Basically, we turn the variable off and wait for the thread to disappear.

Within the thread loop, we wait for certain time and then we create a dot. This gets added to the list and then we lock the canvas. Now we can draw on it. That routine basically goes through the list drawing all the dots. Notice that we write them all, not only the last one. Basically, making sure that even if something changed the canvas while it was out of our control (lock), we get it back as we like it. After we are done, we unlock it, which effectively will refresh it in the screen.

DotsThread.java
 package com.cell0907.dots1;  
   
 import java.util.ArrayList;  
   
 import android.graphics.Canvas;  
 import android.graphics.Color;  
 import android.graphics.Paint;  
 import android.graphics.Paint.Style;  
 import android.view.SurfaceHolder;  
   
 public class DotsThread extends Thread {       
      private int mCanvasWidth;  
   private int mCanvasHeight;  
      private ArrayList<dot> Dots= new ArrayList<dot>(); // Dynamic array with dots  
      private SurfaceHolder holder;  
   private boolean running = false;  
   private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
   private final int refresh_rate=100;      // How often we update the screen, in ms  
   
   public DotsThread(SurfaceHolder holder) {  
     this.holder = holder;  
   }  
   
   @Override  
   public void run() {  
        int x,y,radius;  
        float[] color=new float[3]; // HSV (0..360,0..1,0..1)  
     long previousTime, currentTime;  
        previousTime = System.currentTimeMillis();  
     Canvas canvas = null;  
     while(running) {  
          // Look if time has past  
       currentTime=System.currentTimeMillis();  
       while ((currentTime-previousTime)<refresh_rate){  
            currentTime=System.currentTimeMillis();  
       }  
       previousTime=currentTime;  
       // ADD ONE MORE DOT TO THE SCREEN  
       x=100 + (int)(Math.random() * (mCanvasWidth-200));  
       y=100 + (int)(Math.random() * (mCanvasHeight-200));  
       radius=1 + (int)(Math.random() * 99);  
       color[0]=(float)(Math.random()*360);  
       color[1]=1;  
       color[2]=1;  
       dot mdot=new dot(x,y,radius,Color.HSVToColor(128,color));  
       Dots.add(mdot);  
       // PAINT  
       try {  
         canvas = holder.lockCanvas();  
         synchronized (holder) {  
               draw(canvas);           
         }  
       }  
       finally {  
            if (canvas != null) {  
                 holder.unlockCanvasAndPost(canvas);  
                 }  
       }  
       // WAIT  
                try {  
                     Thread.sleep(refresh_rate-5); // Wait some time till I need to display again  
                } catch (InterruptedException e) {  
                     // TODO Auto-generated catch block  
                     e.printStackTrace();  
                }       
     }  
   }  
   
   // The actual drawing in the Canvas (not the update to the screen).  
   private void draw(Canvas canvas)  
   {  
        dot temp_dot;  
        canvas.drawColor(Color.BLACK);  
        paint.setStyle(Style.FILL_AND_STROKE);  
        for (int i=0;i<Dots.size();i++){  
             temp_dot=Dots.get(i);  
             paint.setColor(temp_dot.get_color());  
             canvas.drawCircle((float)temp_dot.get_x(),  
                       (float)temp_dot.get_y(),   
                       (float)temp_dot.get_radius(),  
                       paint);  
        }  
    }  
     
   public void setRunning(boolean b) {  
     running = b;  
   }  
     
   public void setSurfaceSize(int width, int height) {  
        synchronized (holder){  
          mCanvasWidth = width;  
          mCanvasHeight = height;  
        }  
   }  
     
   private class dot{  
           private int x,y,radius,color;  
             
           dot(int x, int y, int radius, int color){  
                this.x=x;  
                this.y=y;  
                this.radius=radius;  
                this.color=color;  
           }  
             
           public int get_x(){  
                return this.x;  
           }  
   
           public int get_y(){  
                return this.y;  
           }  
   
           public int get_radius(){  
                return this.radius;  
           }  
   
           public int get_color(){  
                return this.color;  
           }  
      }  
 }  

And just for Richard (my first commenter below) :), the layout file activity_main.xml:
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   android:paddingBottom="@dimen/activity_vertical_margin"  
   android:paddingLeft="@dimen/activity_horizontal_margin"  
   android:paddingRight="@dimen/activity_horizontal_margin"  
   android:paddingTop="@dimen/activity_vertical_margin"  
   tools:context=".Dots1" >  
   <TextView  
     android:id="@+id/textView1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="@string/hello_world" />  
   <Button  
     android:id="@+id/button1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_alignLeft="@+id/textView1"  
     android:layout_below="@+id/textView1"  
     android:layout_marginLeft="32dp"  
     android:layout_marginTop="146dp"  
     android:text="@string/button1" />  
 </RelativeLayout>  

And as we are on it, let me add the AndroidManifest.xml:
 <?xml version="1.0" encoding="utf-8"?>  
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
   package="com.cell0907.dots1"  
   android:versionCode="1"  
   android:versionName="1.0" >  
   <uses-sdk  
     android:minSdkVersion="9"  
     android:targetSdkVersion="17" />  
   <application  
     android:allowBackup="true"  
     android:icon="@drawable/ic_launcher"  
     android:label="@string/app_name"  
     android:theme="@style/AppTheme" android:debuggable="true">  
     <activity  
       android:name="com.cell0907.dots1.Dots1"  
       android:label="@string/app_name" >  
       <intent-filter>  
         <action android:name="android.intent.action.MAIN" />  
         <category android:name="android.intent.category.LAUNCHER" />  
       </intent-filter>  
     </activity>  
   </application>  
 </manifest>  

So, that's it. Other things to learn from the example:
  1. Notice that the app may have different "screens or views" objects and at a given moment an app will pick one. 
  2. Also notice the HSV use to create the color of the dots. That helps us to avoid "grey" dots by only manipulating the Hue. If questions about that, check my other post here.
  3. Do not use the width and height of a view inside its constructor. When a view’s constructor is called, Android doesn’t know yet how big the view will be, so the sizes are set to zero. The real sizes are calculated during the layout stage, which occurs after construction but before anything is drawn. You can use the onSizeChanged() method to be notified of the values when they are known, or you can use the getWidth( ) and getHeight() methods later, such as in the onDraw( ) method.
  4. What do we do when the surface is destroyed? See closing surfaceView properly
  5. I don't want to ignore the line Holder.addCallback(this). Maybe the best explanation I have seen on this is here
  6. The whole painting in the canvas it can be pretty straightforward but it can also get advanced. I list here a bunch of links. Eventually may write a tutorial on this:
    1. Clearing canvas with Canvas.drawColor()
    2. Android Bitmap Blending - Color Channels 
    3. How to paint with alpha
    4. PorterDuff.Mode
    5. Wikipedia Alpha Compositing 
    6. Stackoverflow question
Finally, as summary, let me try to describe the different players on this approach. The best attempt to this is here. Worth reading. Also thanks to Android Student here and Sajan and Lawrence D'Oliveiro for trying to do the same:
  1. SurfaceView is a subclass of View. "Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen."
  2. SurfaceHolder is an object which provide us with the canvas we can draw on. Allows you to control the surface size and format, edit the pixels in the surface, and monitor changes to the surface. All this methods are part of the SurfaceHolder interface definition.
  3. SurfaceHolder.Callback is just an interface, a list of method headers, not the implementation, but just a description of how those methods interface with the external world. It is a nested class of SurfaceHolder and it is actually what we implement in the SurfaceView class. For "implement" we mean that when we define the a class extending SurfaceView we have to implement (program, create) the methods defined by SurfaceHolder.Callback interface. We tell the compiler that we are going to do so by writing in the class definition the word "implement", like class Panel extends SurfaceView implements SurfaceHolder.Callback. Therefore if we fail to create the methods defined by the SurfaceHolder.Callback interface, the compiler will throw an error. As SurfaceHolder.Callback is a nested class of SurfaceHolder, the other methods of the SurfaceHolder interface can be also implemented, but do not have to.
Just for completeness, I list here two parent classes that we actually do not use directly (you can skip):
  1. View class, direct descendent from Object, and parent of SurfaceView, "this class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.)."
  2. Surface class.  Handle onto a raw buffer that is being managed by the screen compositor. I believe the SurfaceHolder actually can provide access directly to this, but I have seldom seen do that.
Finally, please, click here to see an index of other posts on Android.

References:
  1. Probably the best tutorial I found on this is here and although it doesn't completely explain it either it gives plenty to work with. 
  2. Anonymous class examples here and here.
  3. A whole series of  tutorials from less to more complicated.  
  4. Create a circle at the touch point of surfaceview
  5. Example without launching a separate thread
  6. tic tac toe example
  7. http://blog.infrared5.com/2011/07/android-graphics-and-animation-part-ii-animation/  
  8. One tutorial that covers SurfaceView with and without the thread. The issue with this one is that the code is not completely proven so it won't run if you just cut and paste.
  9. Can we create an instance of an interface?
  10. Note that there are other methods to do advanced graphics, like OpenGL...

Tutorial for Drawing in Android - Views/layouts

This is a quick explanation to give context to my other post in SurfaceView and SurfaceHolder, which is really what I wanted to talk about :)

The fundamental way to set what we present in our Activity, in its surface, on what you see, is to call the Activity method setContentView(something) on the onCreate method of the activity. The "something" can change depending of the complexity/capabilities of what we want to do:
For simple stuff on the background, like buttons, horizontal or vertical lines, etc... the "something" will be a reference to a layout, like: R.layout.activity_main, which is created in xml. This is the typical way explained in many "hello world" tutorials to setup your Activity, more than to really "draw". 

For more advanced static views, the "something" is an object from a View class. We can then do calls to the View methods (like setbackground...) or in the onDraw method of the object use calls of the type canvas.drawsomething... The View class has callback methods for a bunch of things. onDraw is one of them, but others take care of window resizing (onSizeChanged), finger interactions with the window (onTouch), etc...

See the post here by Janusz or MuhammadAamirALi for simple layout examples, or from  DonGru, Hema or Vinay for a bit more advanced static views.

Anyhow, as I said, this is just an intro for the SurfaceView approach...

Cheers!

PS.: Please, click here to see an index of other posts on Android.

Saturday, September 28, 2013

Add Google Analytics to Blogger

  1. First you have to create an account on Google Analytics if you don't have one, check here. They'll give you an ID that you need to use there. If you have the account already, you can get the info on how to get the ID here
  2. Follow this link on adding Google Analytics.
Note: when you setup Google Analytics, they also give you a piece of code that you need to paste on every page to help track it. Nevertheless, this is NOT needed if you are using blogger (that is automatic when you do #2). You should start seeing stats about a day after you set it up...

The other thing that I got to set up is how to exclude my own views... I found a link explaining this but I have not done it yet.

Monday, September 2, 2013

A friend asked me to invest on his idea

I had friends asked me for money because they simply needed it... more like a loan... but this is the first time somebody asked me to invest on their idea. We are talking here about a serious enterprise, with good professionals behind, which easily pass the simple questions covered by a full business plan, they got full law documents, 2 rounds of funding, small bank loans, potential very serious customers (with backing letters of intent), and big upside.

At the time of writing this I am not thinking to invest on the company. The following is just a list of thoughts that went through my mind and my reactions:
  • I don't understand the idea well. It is in the Internet field, where valuations are difficult to comprehend and many times myself asks "why Facebook paid $1B for Instagram..."?
  • I have never done such a thing. I would like to invest but this may be too risky to be the first and if it fails, it will kill my appetite to invest again, which would be counterproductive.
  • I am afraid that this could be the first round, but may need further investments later to keep things going...
  • This is the 2nd round of an old idea. Completely remodeled though, has little to do with the initial one... but I tried to use that one and I did not like it. Now  I still remember that feeling... although I know that this person has learn a lot for 2 years since the other idea was launched and also that they can fully reuse all that technology, which is a huge advantage.
Also, I am documenting myself on how to go about this kind of thing, when a friend or relative asks you for an investment. Searched the web and found this. Gives you some view on how other people treats these...

I also tried to become more of an expert on the idea, to try to evaluate it better. But can I really get anywhere meaningful? I think I came up with good feedback to turn it down, but certainly something could still get me if I had decided to invest. I.e., I can't become the expert in 2 days, but this is the reaction typical of an engineer, try to wrap your brain around to understand everything and get to the best possible conclusion.

Anyhow, I still hope he succeeds, but at this time, I will just pass...
Cheers!

PS.: And a view from the other side... what if you want to ask for people to invest on your idea? I think those are good suggestions...