Friday, February 28, 2014

Example of using Lock/ReentrantLock

java.util.concurrent.locks.Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements.
java.util.concurrent.locks.ReentrantLock is a reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.

This example have the same function of the More example of Synchronized Statements with separate objects for locking (the 2nd example), implement with Lock.


package com.example.androidthread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB, textInfoC, textInfoD;
 TextView textDuration1, textDuration2;
 TextView textDuration3, textDuration4;

 String infoMsgA;
 String infoMsgB;
 String infoMsgC;
 String infoMsgD;

 ShareClass shareObj = new ShareClass(10);
 long startingTime;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);
  textInfoC = (TextView) findViewById(R.id.infoc);
  textInfoD = (TextView) findViewById(R.id.infod);
  textDuration1 = (TextView) findViewById(R.id.duration1);
  textDuration2 = (TextView) findViewById(R.id.duration2);
  textDuration3 = (TextView) findViewById(R.id.duration3);
  textDuration4 = (TextView) findViewById(R.id.duration4);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    infoMsgC = "Thread C\n";
    infoMsgD = "Thread D\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);
    textInfoC.setText(infoMsgC);
    textInfoD.setText(infoMsgD);

    Thread thread1 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgA += "A 1: "
          + shareObj.delayDecCounter1(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
        final long endTime1 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration1.setText("Duration 1 (reference only): " 
            + (endTime1 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread2 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgB += "B 2: "
          + shareObj.delayDecCounter2(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
        final long endTime2 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration2.setText("Duration 2 (reference only): " 
            + (endTime2 - startingTime));
         }

        });
       }
      }
     }
    });
    
    //
    Thread thread3 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgC += "C 1: "
          + shareObj.delayDecCounter1(200) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoC.setText(infoMsgC);
         }

        });

       } else {
        stop = true;
        final long endTime3 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration3.setText("Duration 3 (reference only): " 
            + (endTime3 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread4 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgD += "D 2: "
          + shareObj.delayDecCounter2(1100) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoD.setText(infoMsgD);
         }

        });

       } else {
        stop = true;
        final long endTime4 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration4.setText("Duration 4 (reference only): " 
            + (endTime4 - startingTime));
         }

        });
       }
      }
     }
    });
    //
    
    startingTime = System.currentTimeMillis();
    thread1.start();
    thread2.start();
    thread3.start();
    thread4.start();
   }
  });

 }

 public class ShareClass {

  int counter1;
  int counter2;
  
  //Object lock1;
  //Object lock2;
  Lock lock1;
  Lock lock2;

  ShareClass(int c) {
   counter1 = c;
   counter2 = c;
   lock1 = new ReentrantLock();
   lock2 = new ReentrantLock();
  }

  public int getCounter1() {
   return counter1;
  }
  
  public int getCounter2() {
   return counter2;
  }

  public int delayDecCounter1(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   int tmpCounter;
   lock1.lock();
   try{
    tmpCounter = counter1;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter1 = tmpCounter;
   }finally{
    lock1.unlock();
   }
   
   return tmpCounter;
   
  }
  
  public int delayDecCounter2(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   int tmpCounter;
   lock2.lock();
   try{
    tmpCounter = counter2;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter2 = tmpCounter;
   }finally{
    lock2.unlock();
   }
   
   return counter2;
   
  }
 }

}

The layout XML, refer to the former exercise of More example of Synchronized Statements with separate objects for locking.


- More example about Thread

HTC Power To Give

There are one billion smartphones in use today. The combined processing power of all these devices can truly revolutionize scientific research, and make an enormous contribution to humanity - if we all work together.

With HTC Power To Give, the potential to research cures for cancer, Alzheimer’s disease, AIDS – to help understand climate change, or venture into space – is all at our fingertips.

By downloading HTC Power To Give, plugging in your phone and connecting to Wi-Fi, your spare computing power will become part of an enormous grid, providing processing power to a project you’ve selected from a range across the world.
Medical, environmental, scientific and many other projects will benefit. Projects that could otherwise take hundreds of years could be executed in a drastically shorter time.

Download HTC Power To Give, plug in, and be a part of the future.


Thursday, February 27, 2014

Developing AR Games for iOS and Android


Develop and deploy augmented reality apps using Vuforia SDK and Unity 3D
Overview
  • Deploy full augmented reality experiences on iOS and Android
  • Build a fully-functional augmented reality game and deploy it on iOS and Android
  • Achieve better trackable performance for a robust experience
  • Understand the prefabs and components that make up Vuforia SDK
  • Explore the Unity environment to maximize your game development experience
In Detail
While augmented reality has been around for years, it has never reached its full potential. Now, the vast majority of people are walking around with powerful smartphones that are perfectly suited to house the AR experience. This is the reason why the technology has become as popular as it is now. Augmented reality can deliver a level of immersion that is unrivalled by any other method of development, as it blends our reality with overlaid computer generated data.
Developing AR Games for iOS and Android is a well-structured guide that introduces you to the augmented reality world using a step-by-step approach. It will help you understand how to create powerful AR apps using Unity as well as how to create immersive experiences for users.
Developing AR Games for iOS and Android examines the structures of Vuforia and Unity and how they work together to create augmented reality. The book will introduce you to the structure of the Unity environment and how Vuforia facilitates creating AR apps.You will also see how easy it is to build a whole world in Unity's Editor. You will go through the process of using Vuforia prefabs like the AR camera and Image Target in Unity, where you can build the AR experience in a what-you-see-is-what-you-get fashion.
In Developing AR Games for iOS and Android, you will learn both basic and advanced techniques that can be applied to achieve truly immersive AR apps and then how to deploy them on iOS and Android devices.
What you will learn from this book
  • Import your assets and packages in a Unity environment
  • Create perfect Image Targets for AR tracking
  • Understand how to deploy to iOS and Android from Unity
  • Add colliders to a scene and learn how to respond to events on them
  • Add forces to objects in a scene in a seamless physics-based environment
  • Learn about transformation and positioning in Unity
  • Listen to Vuforia events and respond to them
Approach
A practical and fast-paced guide that gives you all the information you need to start developing augmented reality games for iOS and Android.
Who this book is written for
This book is great for people who are either new to Vuforia and/or new to Unity. It is a great introductory guide for anyone with a very basic knowledge of xCode and iOS as well as a very basic knowledge of deploying to Android to start developing 3D-powered augmented reality apps.

More example of Synchronized Statements with separate objects for locking

Last example compare between Synchronization with single lock object and separate lock objects, one-on-one; one thread access one object and another object access another object. This example demonstrate a more complicated case, two threads access one object, and other two thread access another object.

Synchronized Statements with single object, this.
package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB, textInfoC, textInfoD;
 TextView textDuration1, textDuration2;
 TextView textDuration3, textDuration4;

 String infoMsgA;
 String infoMsgB;
 String infoMsgC;
 String infoMsgD;

 ShareClass shareObj = new ShareClass(10);
 long startingTime;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);
  textInfoC = (TextView) findViewById(R.id.infoc);
  textInfoD = (TextView) findViewById(R.id.infod);
  textDuration1 = (TextView) findViewById(R.id.duration1);
  textDuration2 = (TextView) findViewById(R.id.duration2);
  textDuration3 = (TextView) findViewById(R.id.duration3);
  textDuration4 = (TextView) findViewById(R.id.duration4);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    infoMsgC = "Thread C\n";
    infoMsgD = "Thread D\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);
    textInfoC.setText(infoMsgC);
    textInfoD.setText(infoMsgD);

    Thread thread1 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgA += "A 1: "
          + shareObj.delayDecCounter1(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
        final long endTime1 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration1.setText("Duration 1 (reference only): " 
            + (endTime1 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread2 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgB += "B 2: "
          + shareObj.delayDecCounter2(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
        final long endTime2 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration2.setText("Duration 2 (reference only): " 
            + (endTime2 - startingTime));
         }

        });
       }
      }
     }
    });
    
    //
    Thread thread3 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgC += "C 1: "
          + shareObj.delayDecCounter1(200) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoC.setText(infoMsgC);
         }

        });

       } else {
        stop = true;
        final long endTime3 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration3.setText("Duration 3 (reference only): " 
            + (endTime3 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread4 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgD += "D 2: "
          + shareObj.delayDecCounter2(1100) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoD.setText(infoMsgD);
         }

        });

       } else {
        stop = true;
        final long endTime4 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration4.setText("Duration 4 (reference only): " 
            + (endTime4 - startingTime));
         }

        });
       }
      }
     }
    });
    //
    
    startingTime = System.currentTimeMillis();
    thread1.start();
    thread2.start();
    thread3.start();
    thread4.start();
   }
  });

 }

 public class ShareClass {

  int counter1;
  int counter2;
  
  Object lock1;
  Object lock2;

  ShareClass(int c) {
   counter1 = c;
   counter2 = c;
   lock1 = new Object();
   lock2 = new Object();
  }

  public int getCounter1() {
   return counter1;
  }
  
  public int getCounter2() {
   return counter2;
  }

  public int delayDecCounter1(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (this) {
    int tmpCounter = counter1;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter1 = tmpCounter;
    
    return counter1;
   }
   
  }
  
  public int delayDecCounter2(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (this) {
    int tmpCounter = counter2;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter2 = tmpCounter;
    
    return counter2;
   }
   
  }
 }

}



Synchronized Statements with separate objects, lock1 and lock2.
package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB, textInfoC, textInfoD;
 TextView textDuration1, textDuration2;
 TextView textDuration3, textDuration4;

 String infoMsgA;
 String infoMsgB;
 String infoMsgC;
 String infoMsgD;

 ShareClass shareObj = new ShareClass(10);
 long startingTime;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);
  textInfoC = (TextView) findViewById(R.id.infoc);
  textInfoD = (TextView) findViewById(R.id.infod);
  textDuration1 = (TextView) findViewById(R.id.duration1);
  textDuration2 = (TextView) findViewById(R.id.duration2);
  textDuration3 = (TextView) findViewById(R.id.duration3);
  textDuration4 = (TextView) findViewById(R.id.duration4);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    infoMsgC = "Thread C\n";
    infoMsgD = "Thread D\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);
    textInfoC.setText(infoMsgC);
    textInfoD.setText(infoMsgD);

    Thread thread1 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgA += "A 1: "
          + shareObj.delayDecCounter1(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
        final long endTime1 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration1.setText("Duration 1 (reference only): " 
            + (endTime1 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread2 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgB += "B 2: "
          + shareObj.delayDecCounter2(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
        final long endTime2 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration2.setText("Duration 2 (reference only): " 
            + (endTime2 - startingTime));
         }

        });
       }
      }
     }
    });
    
    //
    Thread thread3 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {
        
        //caution:
        //shareObj.counter1 may change here

        infoMsgC += "C 1: "
          + shareObj.delayDecCounter1(200) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoC.setText(infoMsgC);
         }

        });

       } else {
        stop = true;
        final long endTime3 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration3.setText("Duration 3 (reference only): " 
            + (endTime3 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread4 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {
        
        //caution:
        //shareObj.counter2 may change here

        infoMsgD += "D 2: "
          + shareObj.delayDecCounter2(1100) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoD.setText(infoMsgD);
         }

        });

       } else {
        stop = true;
        final long endTime4 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration4.setText("Duration 4 (reference only): " 
            + (endTime4 - startingTime));
         }

        });
       }
      }
     }
    });
    //
    
    startingTime = System.currentTimeMillis();
    thread1.start();
    thread2.start();
    thread3.start();
    thread4.start();
   }
  });

 }

 public class ShareClass {

  int counter1;
  int counter2;
  
  Object lock1;
  Object lock2;

  ShareClass(int c) {
   counter1 = c;
   counter2 = c;
   lock1 = new Object();
   lock2 = new Object();
  }

  public int getCounter1() {
   return counter1;
  }
  
  public int getCounter2() {
   return counter2;
  }

  public int delayDecCounter1(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (lock1) {
    int tmpCounter = counter1;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter1 = tmpCounter;
    
    return counter1;
   }
   
  }
  
  public int delayDecCounter2(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (lock2) {
    int tmpCounter = counter2;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter2 = tmpCounter;
    
    return counter2;
   }
   
  }
 }

}


<LinearLayout 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:orientation="vertical"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/buttonstart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start()" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/infoa"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/infob"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
        
        <TextView
            android:id="@+id/infoc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/infod"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    </LinearLayout>
    
    <TextView
        android:id="@+id/duration1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>




- More example about Thread

Synchronized Statements with separate objects for locking

This example compare how Synchronized Statements with single object vs separate objects.

Synchronized Statements with single object, this.
package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB;
 TextView textDuration1, textDuration2;

 String infoMsgA;
 String infoMsgB;

 ShareClass shareObj = new ShareClass(10);
 long startingTime;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);
  textDuration1 = (TextView) findViewById(R.id.duration1);
  textDuration2 = (TextView) findViewById(R.id.duration2);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);

    Thread thread1 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {

        infoMsgA += "A 1: "
          + shareObj.delayDecCounter1(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
        final long endTime1 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration1.setText("Duration 1 (reference only): " 
            + (endTime1 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread2 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {

        infoMsgB += "B 2: "
          + shareObj.delayDecCounter2(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
        final long endTime2 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration2.setText("Duration 2 (reference only): " 
            + (endTime2 - startingTime));
         }

        });
       }
      }
     }
    });
    
    startingTime = System.currentTimeMillis();
    thread1.start();
    thread2.start();
   }
  });

 }

 public class ShareClass {

  int counter1;
  int counter2;

  ShareClass(int c) {
   counter1 = c;
   counter2 = c;
  }

  public int getCounter1() {
   return counter1;
  }
  
  public int getCounter2() {
   return counter2;
  }

  public int delayDecCounter1(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (this) {
    int tmpCounter = counter1;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter1 = tmpCounter;
    
    return counter1;
   }
   
  }
  
  public int delayDecCounter2(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (this) {
    int tmpCounter = counter2;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter2 = tmpCounter;
    
    return counter2;
   }
   
  }
 }

}



Synchronized Statements with separate objects, lock1 and lock2.
package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB;
 TextView textDuration1, textDuration2;

 String infoMsgA;
 String infoMsgB;

 ShareClass shareObj = new ShareClass(10);
 long startingTime;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);
  textDuration1 = (TextView) findViewById(R.id.duration1);
  textDuration2 = (TextView) findViewById(R.id.duration2);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);

    Thread thread1 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter1() > 0) {

        infoMsgA += "A 1: "
          + shareObj.delayDecCounter1(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
        final long endTime1 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration1.setText("Duration 1 (reference only): " 
            + (endTime1 - startingTime));
         }

        });
       }
      }
     }
    });

    Thread thread2 = new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter2() > 0) {

        infoMsgB += "B 2: "
          + shareObj.delayDecCounter2(500) + "\n";

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
        final long endTime2 = System.currentTimeMillis();
        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textDuration2.setText("Duration 2 (reference only): " 
            + (endTime2 - startingTime));
         }

        });
       }
      }
     }
    });
    
    startingTime = System.currentTimeMillis();
    thread1.start();
    thread2.start();
   }
  });

 }

 public class ShareClass {

  int counter1;
  int counter2;
  
  Object lock1;
  Object lock2;

  ShareClass(int c) {
   counter1 = c;
   counter2 = c;
   lock1 = new Object();
   lock2 = new Object();
  }

  public int getCounter1() {
   return counter1;
  }
  
  public int getCounter2() {
   return counter2;
  }

  public int delayDecCounter1(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (lock1) {
    int tmpCounter = counter1;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter1 = tmpCounter;
    
    return counter1;
   }
   
  }
  
  public int delayDecCounter2(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (lock2) {
    int tmpCounter = counter2;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter2 = tmpCounter;
    
    return counter2;
   }
   
  }
 }

}


<LinearLayout 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:orientation="vertical"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/buttonstart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start()" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/infoa"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/infob"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    </LinearLayout>
    
    <TextView
        android:id="@+id/duration1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/duration2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

This example compare between Synchronization with single lock object and separate lock objects, one-on-one; one thread access one object and another object access another object. Next example demonstrate a more complicated case, two threads access one object, and other two thread access another object.


- More example about Thread

OpenGL ES 2 for Android: A Quick-Start Guide



Android is booming like never before, with millions of devices shipping every day. It's never been a better time to learn how to create your own 3D games and live wallpaper for Android. You'll find out all about shaders and the OpenGL pipeline, and discover the power of OpenGL ES 2.0, which is much more feature-rich than its predecessor. If you can program in Java and you have a creative vision that you'd like to share with the world, then this is the book for you.

This book will teach you everything you need to know to create compelling graphics on Android. You'll learn the basics of OpenGL by building a simple game of air hockey, and along the way, you'll see how to initialize OpenGL and program the graphics pipeline using shaders. Each lesson builds upon the one before it, as you add colors, shading, 3D projections, touch interaction, and more.

Then, you'll find out how to turn your idea into a live wallpaper that can run on the home screen. You'll learn about more advanced effects involving particles, lighting models, and the depth buffer. You'll understand what to look for when debugging your program, and what to watch out for when deploying to the market.

OpenGL can be somewhat of a dark art to the uninitiated. As you read this book, you'll learn each new concept from first principles. You won't just learn about a feature; you'll also understand how it works, and why it works the way it does. Everything you learn is forward-compatible with the just-released OpenGL ES 3, and you can even apply these techniques to other platforms, such as iOS or HTML5 WebGL.

Wednesday, February 26, 2014

Share object between threads with Synchronized Statements

Last post show how to create synchronized code with Synchronized Method. Alternatively, we can synchronize block of code with Synchronized Statements.


Example code:
package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB;

 String infoMsgA;
 String infoMsgB;

 ShareClass shareObj = new ShareClass(10);

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);

    new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter() > 0) {

        infoMsgA += "A: "
          + shareObj.delayDecCounter(2500) + "\n";
        
        try {
         Thread.sleep(3000);
        } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
       }
      }
     }
    }).start();

    new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter() > 0) {

        infoMsgB += "B: "
          + shareObj.delayDecCounter(500) + "\n";
        
        try {
         Thread.sleep(500);
        } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
       }
      }
     }
    }).start();

   }
  });

 }

 public class ShareClass {

  int counter;

  ShareClass(int c) {
   counter = c;
  }

  public int getCounter() {
   return counter;
  }

  public int delayDecCounter(int delay) {
   
   //do something not access the share obj
   try {
    Thread.sleep(100);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   synchronized (this) {
    int tmpCounter = counter;

    try {
     Thread.sleep(delay);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }

    tmpCounter--;
    counter = tmpCounter;
    
    return counter;
   }
   
  }
 }

}


The layout XML, refer to last post.


- More example about Thread

Share object between threads with synchronized methods

This example show how to synchronize share object between threads with synchronized methods.

Share object between threads WITH synchronized method


Share object between threads WITHOUT synchronized method


package com.example.androidthread;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 Button buttonStart;
 TextView textInfoA, textInfoB;

 String infoMsgA;
 String infoMsgB;

 ShareClass shareObj = new ShareClass(10);

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button) findViewById(R.id.buttonstart);
  textInfoA = (TextView) findViewById(R.id.infoa);
  textInfoB = (TextView) findViewById(R.id.infob);

  buttonStart.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {

    infoMsgA = "Thread A\n";
    infoMsgB = "Thread B\n";
    textInfoA.setText(infoMsgA);
    textInfoB.setText(infoMsgB);

    new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter() > 0) {

        infoMsgA += "A: "
          + shareObj.delayDecCounter(2500) + "\n";
        
        try {
         Thread.sleep(3000);
        } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoA.setText(infoMsgA);
         }

        });

       } else {
        stop = true;
       }
      }
     }
    }).start();

    new Thread(new Runnable() {

     boolean stop = false;

     @Override
     public void run() {

      while (!stop) {
       if (shareObj.getCounter() > 0) {

        infoMsgB += "B: "
          + shareObj.delayDecCounter(500) + "\n";
        
        try {
         Thread.sleep(500);
        } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }

        MainActivity.this.runOnUiThread(new Runnable() {

         @Override
         public void run() {
          textInfoB.setText(infoMsgB);
         }

        });

       } else {
        stop = true;
       }
      }
     }
    }).start();

   }
  });

 }

 public class ShareClass {

  int counter;

  ShareClass(int c) {
   counter = c;
  }

  public int getCounter() {
   return counter;
  }

  public synchronized int delayDecCounter(int delay) {

   int tmpCounter = counter;

   try {
    Thread.sleep(delay);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

   tmpCounter--;
   counter = tmpCounter;
   return counter;
  }
 }

}

<LinearLayout 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:orientation="vertical"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/buttonstart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start()" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="with synchronized" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/infoa"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <TextView
            android:id="@+id/infob"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    </LinearLayout>

</LinearLayout>

Next: Share object between threads with Synchronized Statements


- More example about Thread

PhoneGap 3, Beginner's Guide, 2nd Edition


A guide to building cross-platform apps using the W3C standards-based Cordova/PhoneGap framework Overview Understand the fundamentals of cross-platform mobile application development from build to distribution Learn to implement the most common features of modern mobile applications Take advantage of native mobile device capabilities including the camera, geolocation, and local storage using HTML, CSS, and JavaScript In Detail You don't have to know complex languages like Objective C to compete in the ever-growing mobile market place. The PhoneGap framework lets you use your web development skills to build HTML and JavaScript-based mobile applications with native wrappers that run on all the major mobile platforms, including Android, iOS, and Windows Phone 8. "PhoneGap Beginner's Guide" will help you break into the world of mobile application development. You will learn how to set up and configure your mobile development environment, implement the most common features of modern mobile apps, and build rich, native-style applications. The examples in this book deal with real use case scenarios, which will help you develop your own apps, and then publish them on the most popular app stores. Dive deep into PhoneGap and refine your skills by learning how to build the main features of a real world app. "PhoneGap Beginner's Guide" will guide you through the building blocks of a mobile application that lets users plan a trip and share their trip information. With the help of this app, you will learn how to work with key PhoneGap tools and APIs, extend the framework's functionality with plug-ins, and integrate device features such as the camera, contacts, storage, and more. By the time you're finished, you will have a solid understanding of the common challenges mobile app developers face, and you will know how to solve them. What you will learn from this book Set up and configure your development environment Manage cross-platform code bases Build well-performing modular apps Interact with the device sensors, file system, and camera Use key PhoneGap APIs Integrate native code in your mobile app Write a PhoneGap plugin Localize a mobile app Approach Written in a friendly, example-driven Beginner's Guide format, there are plenty of step-by-step instructions to help you get started with PhoneGap. Who this book is written for If you are a web developer or mobile application developer interested in an examples-based approach to learning mobile application development basics with PhoneGap, then this book is for you.

Mobile First Design with HTML5 and CSS3

Roll out rock-solid, responsive, mobile first designs quickly and reliably
Overview
  • Make websites that will look great and be usable on almost any device that displays web pages.
  • Learn best practices for responsive design
  • Discover how to make designs that will be lean and fast on small screens without sacrificing a tablet or desktop experience
In Detail
The mobile first design philosophy aims to develop websites that will be lean and fast on small screens without sacrificing a tablet or desktop experience. Using HTML5, CSS3, and simple, standardized modern web tools you can make one site to rule them all.
Mobile First Design with HTML5 and CSS3 will teach you the tools you need to make a modern, standards-based web page that displays beautifully on nearly any web browser—essential knowledge for anyone who makes websites!
In this book, you will learn how to set up a project from scratch and quickly get up and running with a full portfolio website that will form the base for making almost any kind of web page. Learn to develop web pages that fit the web conventions we all have to conform to. You will learn how to make responsive image slideshows; image galleries with detail pages; and bold, eye-catching banners and forms. Best of all, you will learn how to make these things fast without compromising quality.
This book will walk you through the process step by step with all the code required, as well as the thinking that goes behind planning a mobile first responsive website.
What you will learn from this book
  • Develop web pages that change their layout and respond to different sized screens, so that they display well on mobiles, tablets, and desktops
  • Utilize HTML5 and CSS3 to make responsive web pages quickly and effectively
  • Use current technologies like LESS and SASS to work fast
  • Build web page components that will function well on both small and large screens
  • Create and plan designs that work for small and large screens without having to sacrifice content
Approach
A user friendly tutorial to develop websites that work for both small and large screens using HTML5 and CSS3.
Who this book is written for
This book is for beginner to intermediate developers and designers, as well as for those in management who want to understand what is possible with modern tools and strategies on the Web.

Monday, February 24, 2014

Set name of Thread

We can assign a name to a thread by calling its setName(String threadName) method. Inside the thread, we can get the name with: Thread.currentThread().getName().

name of Thread



package com.example.androidthread;

import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {
 
 Button buttonStartA, buttonStart, buttonRun;
 TextView textInfo;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStartA = (Button)findViewById(R.id.buttonstarta);
  buttonStart = (Button)findViewById(R.id.buttonstart);
  buttonRun = (Button)findViewById(R.id.buttonrun);
  textInfo = (TextView)findViewById(R.id.info);
  
  buttonStartA.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    //start a thread with name
    Thread thread = new Thread(new MyRunnable());
    thread.setName("Thread A");
    thread.start(); //in background thread
   }});
  
  buttonStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    Thread thread = new Thread(new MyRunnable());
    thread.start(); //in background thread
   }});
  
  buttonRun.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    Thread thread = new Thread(new MyRunnable());
    thread.setName("another main");
    thread.run(); //in current thread
   }});
 }

 private class MyRunnable implements Runnable {

  @Override
  public void run() {
   
   final String myThreadName = Thread.currentThread().getName();
   
   // check if it's run in main thread, or background thread
   if(Looper.getMainLooper().getThread()==Thread.currentThread()){
    //in main thread
    textInfo.setText("in main thread: " + myThreadName);
   }else{
    //in background thread

    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textInfo.setText("in background thread: " + myThreadName);
     }
     
    });
   }
  }
  
 }

}

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <Button
        android:id="@+id/buttonstarta"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start() with name" />
    <Button
        android:id="@+id/buttonstart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start()" />
    <Button
        android:id="@+id/buttonrun"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="run()" />
    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>


- When button "start() with name" pressed, it show thread name of "Thread A".
- When button "start()" pressed, without name assigned, it show something like "Thread-10807".
- When button "run()" pressed, even a name is assigned to the thread, but the run() method is called in main thread actually. So it show name of "main"



- More example about Thread

Online document: The Java Language Specification

The Java Language Specification for Java SE 7 Edition is available here: http://docs.oracle.com/javase/specs/jls/se7/html/index.html

Online document: The Java Language Specification

The Nokia X, X+ and XL

Nokia X products X, X+ and XL announced running Android OS, Visit Nokia X Products web site: http://nokia.com/nokiaXrange


See it in action:

Sunday, February 23, 2014

Android for Programmers: An App-Driven Approach (2nd Edition)

The professional programmer’s Deitel® guide to smartphone and tablet app development using Android 4.3 and 4.4, the Eclipse-based Android Development Tools and the new Android Studio

Billions of apps have been downloaded from Google Play™! This book gives you everything you’ll need to start developing great Android apps quickly and getting them published on Google Play™. The book uses an app-driven approach–each new technology is discussed in the context of seven fully tested Android apps, complete with syntax coloring, code highlighting, code walkthroughs and sample outputs. Apps you’ll develop include:

  • Welcome App
  • Cannon Game
  • Tip Calculator
  • Doodlz
  • Twitter® Searches
  • Address Book
  • Flag Quiz

The first-generation Android phones were released in October 2008. By October 2013, a Strategy Analytics report showed that Android had 81.3% of the global smartphone market share, compared to 13.4% for Apple, 4.1% for Microsoft and 1% for Blackberry (bit.ly/1aqIZXf). Billions of apps have been downloaded from Google Play. There are now more than one billion activated Android devices worldwide and more than 1.5 million Android devices are being activated daily (venturebeat.com/2013/09/03/android-hits-1bactivations-and-will-be-called-kitkat-in-nextversion). The opportunities for Android app developers are enormous.

This book presents leading-edge computing technologies for professional software developers. At the heart of the book is the Deitel “app-driven approach”–concepts are presented in the context of complete working Android apps, rather than using code snippets. The introduction and app test drives at the beginning of each chapter show one or more sample executions. The book’s source code is available at www.deitel.com/books/androidfp2.

The apps in this book were carefully designed to introduce you to key Android features and APIs. You’ll quickly learn everything you need to start building Android apps–beginning with a testdrive of the Doodlz app in Chapter 1, then building your first app in Chapter 2. By the time you reach Chapter 9, you’ll be ready to create your own apps for submission to Google Play and other app marketplaces. You’ll master the Google Play submission process, including uploading your apps, deciding whether to sell your apps or offer them for free, and marketing them using in-app advertising, social media, Internet public relations and more.

Practical, example-rich coverage of:

  • Android 4.3 and 4.4
  • Android Development Tools, Android Studio
  • Supporting Various Screen Sizes/Resolutions
  • Accessibility, Internationalization, Graphics
  • Activities, Fragments, Intents, Preferences
  • GUIs, Layouts, Menus, Resource Files, Lists, Adapters, Events, Touch/Gesture Processing
  • Immersive Mode, Printing Framework, PrintHelper
  • Assets (Images, Audio), View Animation
  • Threading, Collections, SQLite Database
  • Social sharing via implicit intents
  • Google Play™, App Publishing, Pricing, Monetization, Marketing, In-App Advertising, In-App Billing and more.


Runnable in background thread

This exercise show how to run a Runnable in background.
Runnable in background thread
Runnable in background thread

In this exercise, we need to check if the current thread is the main thread, or called UI thread. Using the code:

Looper.getMainLooper().getThread()==Thread.currentThread()

If it's true, means it's in main thread, otherwise it's in background thread.

The example show how to implement a Thread with Runnable object. And call its start() method to starts the new Thread of execution. Also notice that if you call its run() method, it will calls the run() method of the Runnable object directly, in current thread.

package com.example.androidthread;

import android.os.Bundle;
import android.os.Looper;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {
 
 Button buttonStart, buttonRun;
 TextView textInfo;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  buttonStart = (Button)findViewById(R.id.buttonstart);
  buttonRun = (Button)findViewById(R.id.buttonrun);
  textInfo = (TextView)findViewById(R.id.info);
  
  buttonStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    Thread thread = new Thread(new MyRunnable());
    thread.start(); //in background thread
   }});
  
  buttonRun.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {
    Thread thread = new Thread(new MyRunnable());
    thread.run(); //in current thread
   }});
 }

 private class MyRunnable implements Runnable {

  @Override
  public void run() {
   // check if it's run in main thread, or background thread
   if(Looper.getMainLooper().getThread()==Thread.currentThread()){
    //in main thread
    textInfo.setText("in main thread");
   }else{
    //in background thread

    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textInfo.setText("in background thread");
     }
     
    });
   }
  }
  
 }

}

<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <Button
        android:id="@+id/buttonstart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="start()" />
    <Button
        android:id="@+id/buttonrun"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="run()" />
    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>


More example about Thread:
Set name of Thread
Share object between threads with synchronized methods
Share object between threads with synchronized Statements
Synchronized Statements with separate lock object, I
Synchronized Statements with separate lock object, II
Example of using Lock/ReentrantLock
Solve Producer–consumer problem with wait() and notifyAll()

Saturday, February 22, 2014

Show/Hide Menu Item dynamically

This example demonstrate how to show/hide menu items dynamically using Java code, by calling setVisible() method. Even if a menu item is not visible, it may still be invoked via its shortcut. To completely disable an item, set it to invisible and disabled.

Show/Hide Menu Item dynamically
Show/Hide Menu Item dynamically

MainActivity.java
package com.example.androiddynamicmenu;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;

public class MainActivity extends Activity {
 
 ToggleButton btn1, btn2, btn3;
 Menu myMenu;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  btn1 = (ToggleButton)findViewById(R.id.option1);
  btn2 = (ToggleButton)findViewById(R.id.option2);
  btn3 = (ToggleButton)findViewById(R.id.option3);
  
  btn1.setOnCheckedChangeListener(btnOnCheckedChangeListener);
  btn2.setOnCheckedChangeListener(btnOnCheckedChangeListener);
  btn3.setOnCheckedChangeListener(btnOnCheckedChangeListener);
 }
 
 OnCheckedChangeListener btnOnCheckedChangeListener =
  new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView, 
     boolean isChecked) {
    if(myMenu != null){
     if(buttonView==btn1){
      
      myMenu.findItem(R.id.menuopt1)
       .setVisible(isChecked);
      myMenu.findItem(R.id.menuopt1)
       .setEnabled(isChecked);
     }else if(buttonView==btn2){
      myMenu.findItem(R.id.menuopt2)
       .setVisible(isChecked);
      myMenu.findItem(R.id.menuopt2)
       .setEnabled(isChecked);
     }else if(buttonView==btn3){
      myMenu.findItem(R.id.menuopt3)
       .setVisible(isChecked);
      myMenu.findItem(R.id.menuopt3)
       .setEnabled(isChecked);
     }
    }
    
   }};

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  myMenu = menu;
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch(item.getItemId()){
  case R.id.menuopt1:
   Toast.makeText(MainActivity.this, 
    "menuopt1", 
    Toast.LENGTH_SHORT).show();
   break;
  case R.id.menuopt2:
   Toast.makeText(MainActivity.this, 
    "menuopt2", 
    Toast.LENGTH_SHORT).show();
   break;
  case R.id.menuopt3:
   Toast.makeText(MainActivity.this, 
    "menuopt3", 
    Toast.LENGTH_SHORT).show();
   break;
  }
  return super.onOptionsItemSelected(item);
 }

}

/res/menu/main.xml and /res/layout/activity_main.xml, refer last exercise "Enable/Disable menu item dynamically".


Enable/Disable menu item dynamically

This example show how to enable/disable menu item dynamically using Java code, set with ToggleButton.

Dynamic enable/disable Menu Item
Dynamic enable/disable Menu Item

MainActivity.java
package com.example.androiddynamicmenu;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;

public class MainActivity extends Activity {
 
 ToggleButton btn1, btn2, btn3;
 Menu myMenu;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  btn1 = (ToggleButton)findViewById(R.id.option1);
  btn2 = (ToggleButton)findViewById(R.id.option2);
  btn3 = (ToggleButton)findViewById(R.id.option3);
  
  btn1.setOnCheckedChangeListener(btnOnCheckedChangeListener);
  btn2.setOnCheckedChangeListener(btnOnCheckedChangeListener);
  btn3.setOnCheckedChangeListener(btnOnCheckedChangeListener);
 }
 
 OnCheckedChangeListener btnOnCheckedChangeListener =
  new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView, 
     boolean isChecked) {
    if(myMenu != null){
     if(buttonView==btn1){
      myMenu.findItem(R.id.menuopt1)
      .setEnabled(isChecked);
     }else if(buttonView==btn2){
      myMenu.findItem(R.id.menuopt2)
      .setEnabled(isChecked);
     }else if(buttonView==btn3){
      myMenu.findItem(R.id.menuopt3)
      .setEnabled(isChecked);
     }
    }
    
   }};

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  myMenu = menu;
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch(item.getItemId()){
  case R.id.menuopt1:
   Toast.makeText(MainActivity.this, 
    "menuopt1", 
    Toast.LENGTH_SHORT).show();
   break;
  case R.id.menuopt2:
   Toast.makeText(MainActivity.this, 
    "menuopt2", 
    Toast.LENGTH_SHORT).show();
   break;
  case R.id.menuopt3:
   Toast.makeText(MainActivity.this, 
    "menuopt3", 
    Toast.LENGTH_SHORT).show();
   break;
  }
  return super.onOptionsItemSelected(item);
 }

}

/res/menu/main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menuopt1"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="Menu Option 1"/>
    <item
        android:id="@+id/menuopt2"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="Menu Option 2"/>
    <item
        android:id="@+id/menuopt3"
        android:orderInCategory="100"
        android:showAsAction="ifRoom"
        android:title="Menu Option 3"/>

</menu>

/res/layout/activity_main.xml
<LinearLayout 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:orientation="vertical"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <ToggleButton
        android:id="@+id/option1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="Option 1" />
    <ToggleButton
        android:id="@+id/option2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="Option 2" />
    <ToggleButton
        android:id="@+id/option3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="Option 3" />

</LinearLayout>



Next: Show/Hide Menu Item dynamically

Thursday, February 20, 2014

Send Hello to Arduino from Android in USB Host Mode

This example send bytes of "Hello..." to Arduino Esplora board from Android in USB Host Mode. Please notice that it's just a middle stage in my exercise in USB Host Mode, not a final and mature example.


In Android Side:

MainActivity.java
package com.example.androidusbhost;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;

import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

public class MainActivity extends Activity {

 TextView textInfo;
 TextView textSearchedEndpoint;
 
 TextView textDeviceName;
 TextView textStatus;
 
 private static final int targetVendorID= 9025;
 private static final int targetProductID = 32828;
 UsbDevice deviceFound = null;
 UsbInterface usbInterfaceFound = null;
 UsbEndpoint endpointIn = null;
 UsbEndpoint endpointOut = null;

 private static final String ACTION_USB_PERMISSION = 
   "com.android.example.USB_PERMISSION";
 PendingIntent mPermissionIntent;
 
 UsbInterface usbInterface;
 UsbDeviceConnection usbDeviceConnection;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textStatus = (TextView)findViewById(R.id.textstatus);
  
  textDeviceName = (TextView)findViewById(R.id.textdevicename);
  textInfo = (TextView) findViewById(R.id.info);
  textSearchedEndpoint = (TextView)findViewById(R.id.searchedendpoint);
  
  //register the broadcast receiver
  mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
  IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
  registerReceiver(mUsbReceiver, filter);
  
  registerReceiver(mUsbDeviceReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
  registerReceiver(mUsbDeviceReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
  
  connectUsb();
 }

 @Override
 protected void onDestroy() {
  releaseUsb();
  unregisterReceiver(mUsbReceiver);
  unregisterReceiver(mUsbDeviceReceiver);
  super.onDestroy();
 }
 
 private void connectUsb(){
  
  Toast.makeText(MainActivity.this, 
    "connectUsb()", 
    Toast.LENGTH_LONG).show();
  textStatus.setText("connectUsb()");

  searchEndPoint();

  if(usbInterfaceFound != null){
   setupUsbComm();
  }
  
 }

 private void releaseUsb(){
  
  Toast.makeText(MainActivity.this, 
    "releaseUsb()", 
    Toast.LENGTH_LONG).show();
  textStatus.setText("releaseUsb()");
  
  if(usbDeviceConnection != null){
   if(usbInterface != null){
    usbDeviceConnection.releaseInterface(usbInterface);
    usbInterface = null;
   }
   usbDeviceConnection.close();
   usbDeviceConnection = null;
  }
  
  deviceFound = null;
  usbInterfaceFound = null;
  endpointIn = null;
  endpointOut = null;
 }
 
 private void searchEndPoint(){
  
  textInfo.setText("");
  textSearchedEndpoint.setText("");
  
  usbInterfaceFound = null;
  endpointOut = null;
  endpointIn = null;
  
  //Search device for targetVendorID and targetProductID
  if(deviceFound == null){
   UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
   HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
   Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();

   while (deviceIterator.hasNext()) {
    UsbDevice device = deviceIterator.next();

    if(device.getVendorId()==targetVendorID){
     if(device.getProductId()==targetProductID){
      deviceFound = device;
     }
    }
   }
  }

  if(deviceFound==null){
   Toast.makeText(MainActivity.this, 
     "device not found", 
     Toast.LENGTH_LONG).show();
   textStatus.setText("device not found");
  }else{
   String s = deviceFound.toString() + "\n" + 
     "DeviceID: " + deviceFound.getDeviceId() + "\n" +
     "DeviceName: " + deviceFound.getDeviceName() + "\n" +
     "DeviceClass: " + deviceFound.getDeviceClass() + "\n" +
     "DeviceSubClass: " + deviceFound.getDeviceSubclass() + "\n" +
     "VendorID: " + deviceFound.getVendorId() + "\n" +
     "ProductID: " + deviceFound.getProductId() + "\n" +
     "InterfaceCount: " + deviceFound.getInterfaceCount();
   textInfo.setText(s);
      
   //Search for UsbInterface with Endpoint of USB_ENDPOINT_XFER_BULK,
   //and direction USB_DIR_OUT and USB_DIR_IN
   
   for(int i=0; i<deviceFound.getInterfaceCount(); i++){
    UsbInterface usbif = deviceFound.getInterface(i);
    
    UsbEndpoint tOut = null;
    UsbEndpoint tIn = null;
    
    int tEndpointCnt = usbif.getEndpointCount();
    if(tEndpointCnt>=2){
     for(int j=0; j<tEndpointCnt; j++){
      if(usbif.getEndpoint(j).getType() ==
        UsbConstants.USB_ENDPOINT_XFER_BULK){
       if(usbif.getEndpoint(j).getDirection() ==
         UsbConstants.USB_DIR_OUT){
        tOut = usbif.getEndpoint(j);
       }else if(usbif.getEndpoint(j).getDirection() ==
         UsbConstants.USB_DIR_IN){
        tIn = usbif.getEndpoint(j);
       }
      }
     }
     
     if(tOut!=null && tIn!=null){
      //This interface have both USB_DIR_OUT
      //and USB_DIR_IN of USB_ENDPOINT_XFER_BULK
      usbInterfaceFound = usbif;
      endpointOut = tOut;
      endpointIn = tIn;
     }
    }

   }
   
   if(usbInterfaceFound==null){
    textSearchedEndpoint.setText("No suitable interface found!");
   }else{
    textSearchedEndpoint.setText(
     "UsbInterface found: " + usbInterfaceFound.toString() + "\n\n" +
     "Endpoint OUT: " + endpointOut.toString() + "\n\n" +
     "Endpoint IN: " + endpointIn.toString());
   }
  }
 }
 
 private boolean setupUsbComm(){
  
  //for more info, search SET_LINE_CODING and 
  //SET_CONTROL_LINE_STATE in the document:
  //"Universal Serial Bus Class Definitions for Communication Devices"
  //at http://adf.ly/dppFt
  final int RQSID_SET_LINE_CODING = 0x20;
  final int RQSID_SET_CONTROL_LINE_STATE = 0x22;
  
  boolean success = false;

  UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
  Boolean permitToRead = manager.hasPermission(deviceFound);
  
  if(permitToRead){
   usbDeviceConnection = manager.openDevice(deviceFound);
   if(usbDeviceConnection != null){
    usbDeviceConnection.claimInterface(usbInterfaceFound, true);
    
    showRawDescriptors(); //skip it if you no need show RawDescriptors
    
    int usbResult;
    usbResult = usbDeviceConnection.controlTransfer(
      0x21,        //requestType
      RQSID_SET_CONTROL_LINE_STATE, //SET_CONTROL_LINE_STATE 
      0,     //value
      0,     //index
      null,    //buffer
      0,     //length
      0);    //timeout
    
    Toast.makeText(MainActivity.this, 
      "controlTransfer(SET_CONTROL_LINE_STATE): " + usbResult, 
      Toast.LENGTH_LONG).show();
    
    //baud rate = 9600
    //8 data bit
    //1 stop bit
    byte[] encodingSetting = 
      new byte[] {(byte)0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08 };
    usbResult = usbDeviceConnection.controlTransfer(
      0x21,       //requestType
      RQSID_SET_LINE_CODING,   //SET_LINE_CODING
      0,      //value
      0,      //index
      encodingSetting,  //buffer
      7,      //length
      0);     //timeout
    Toast.makeText(MainActivity.this, 
      "controlTransfer(RQSID_SET_LINE_CODING): " + usbResult, 
      Toast.LENGTH_LONG).show();
    
    byte[] bytesHello = 
      new byte[] {(byte)'H', 'e', 'l', 'l', 'o', ' ', 
      'f', 'r', 'o', 'm', ' ', 
      'A', 'n', 'd', 'r', 'o', 'i', 'd'};
    usbResult = usbDeviceConnection.bulkTransfer(
      endpointOut, 
      bytesHello, 
      bytesHello.length, 
      0);
    Toast.makeText(MainActivity.this, 
      "bulkTransfer: " + usbResult, 
      Toast.LENGTH_LONG).show();
   }

  }else{
   manager.requestPermission(deviceFound, mPermissionIntent);
   Toast.makeText(MainActivity.this, 
     "Permission: " + permitToRead, 
     Toast.LENGTH_LONG).show();
   textStatus.setText("Permission: " + permitToRead);
  }
  
  
  
  return success;
 }
 
 private void showRawDescriptors(){
  final int STD_USB_REQUEST_GET_DESCRIPTOR = 0x06;
  final int LIBUSB_DT_STRING = 0x03;
  
  byte[] buffer = new byte[255];
        int indexManufacturer = 14;
        int indexProduct = 15;
        String stringManufacturer = "";
        String stringProduct = "";
  
        byte[] rawDescriptors = usbDeviceConnection.getRawDescriptors();
   
        int lengthManufacturer = usbDeviceConnection.controlTransfer(
          UsbConstants.USB_DIR_IN|UsbConstants.USB_TYPE_STANDARD,   //requestType
          STD_USB_REQUEST_GET_DESCRIPTOR,         //request ID for this transaction
          (LIBUSB_DT_STRING << 8) | rawDescriptors[indexManufacturer], //value
          0,   //index
          buffer,  //buffer
          0xFF,  //length
          0);   //timeout
        try {
         stringManufacturer = new String(buffer, 2, lengthManufacturer-2, "UTF-16LE");
        } catch (UnsupportedEncodingException e) {
         Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
         textStatus.setText(e.toString()); 
        }
   
        int lengthProduct = usbDeviceConnection.controlTransfer(
          UsbConstants.USB_DIR_IN|UsbConstants.USB_TYPE_STANDARD,
          STD_USB_REQUEST_GET_DESCRIPTOR,
          (LIBUSB_DT_STRING << 8) | rawDescriptors[indexProduct],
          0,
          buffer,
          0xFF,
          0);
        try {
         stringProduct = new String(buffer, 2, lengthProduct-2, "UTF-16LE"); 
        } catch (UnsupportedEncodingException e) {
         // TODO Auto-generated catch block
         e.printStackTrace(); 
        }
   
        textStatus.setText("Manufacturer: " + stringManufacturer + "\n" +
          "Product: " + stringProduct);
 }

 private final BroadcastReceiver mUsbReceiver = 
   new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (ACTION_USB_PERMISSION.equals(action)) {
      
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_PERMISSION", 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_PERMISSION");
      
                  synchronized (this) {
                      UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

                      if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                          if(device != null){
                           connectUsb();
                         }
                      } 
                      else {
                          Toast.makeText(MainActivity.this, 
                            "permission denied for device " + device, 
                            Toast.LENGTH_LONG).show();
                          textStatus.setText("permission denied for device " + device);
                      }
                  }
              }
    }
 };
 
 private final BroadcastReceiver mUsbDeviceReceiver = 
   new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
      
      deviceFound = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_DEVICE_ATTACHED: \n" +
        deviceFound.toString(), 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_DEVICE_ATTACHED: \n" +
        deviceFound.toString());
      
      connectUsb();

     }else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
      
      UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
      
      Toast.makeText(MainActivity.this, 
        "ACTION_USB_DEVICE_DETACHED: \n" +
        device.toString(), 
        Toast.LENGTH_LONG).show();
      textStatus.setText("ACTION_USB_DEVICE_DETACHED: \n" +
        device.toString());
      
      if(device!=null){
       if(device == deviceFound){
        releaseUsb();
       }
      }
      
      textInfo.setText("");
     }
    }
  
 };

}

The setting of usbDeviceConnection.controlTransfer() inside setupUsbComm() is copied from the post: Android USB Host + Arduino: How to communicate without rooting your Android Tablet or Phone

activity_main.xml
<LinearLayout 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:orientation="vertical"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <TextView
        android:id="@+id/textstatus"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/textdevicename"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold|italic" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            
            <TextView
                android:id="@+id/searchedendpoint"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textStyle="bold" />
            
        </LinearLayout>
    </ScrollView>

</LinearLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidusbhost"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-feature android:name="android.hardware.usb.host" />
    <uses-sdk
        android:minSdkVersion="13"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidusbhost.MainActivity"
            android:label="@string/app_name"
            android:configChanges="keyboard|orientation" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
            <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
            
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
            </intent-filter>
            
        </activity>
    </application>

</manifest>


download filesDownload the files.

In Arduino Side:

testSerial.ino
#include <Esplora.h>
#include <TFT.h>
#include <SPI.h>

int prevSw1 = HIGH;
int incomingByte = 0;
String charsIn = "";
char printout[20];  //max char to print: 20
 
void setup() {
  
    EsploraTFT.begin();  
    EsploraTFT.background(0,0,0);
    EsploraTFT.stroke(255,255,255);  //preset stroke color
     
    //Setup Serial Port with baud rate of 9600
    Serial.begin(9600);
    
    //indicate start
    Esplora.writeRGB(255, 255, 255);
    delay(250);
    Esplora.writeRGB(0, 0, 0);
    
}
 
void loop() {
    int sw1 = Esplora.readButton(SWITCH_1);
    if(sw1 != prevSw1){
      if(sw1 == LOW){
        Serial.println("Hello from Arduino Esplora");
      }
      prevSw1 = sw1;
    }
    
    while (Serial.available()) {
      char charRead = Serial.read();
      charsIn.concat(charRead);
    }
    if(charsIn != ""){
      Serial.println("How are you, " + charsIn);
      charsIn.toCharArray(printout, 21);
      EsploraTFT.background(0,0,0);
      EsploraTFT.text(printout, 0, 10);
      charsIn = "";
    }
}

It's same as the code in my another blog: Serial communication between Arduino Esplora and PC



Step-by-step: Android USB Host Mode programming