Tuesday 10 January 2012

Creating Context Menu

For creating context menu in an activity, Create a folded called menu in the res folder, add a xml file in the res/menu folder. you can give any name to the xml file.

Below is the sample xml file for context menu in the res/menu folder.

<?xml version="1.0" encoding="utf-8"?>
<menu
  xmlns:android="http://schemas.android.com/apk/res/android">
  
    <item android:id="@+id/take_photo"
        android:title="Take New Photo ">
    </item>
   
    <item android:id="@+id/choose_gallery"
        android:title="Choose from Gallery">
    </item>
   
     <item android:id="@+id/share_cancel"
        android:title="Cancel">
    </item>
   
</menu>



Add as much of menu item by using the item tag. The item tag contain id for the menu and title for the menu.

For accessing the context menu, First register the context menu for any control. here i registered context menu for a button.

Button button01=(Button)findViewById(R.id.button01);
registerForContextMenu(button01);

The context menu will be displayed, on clicking the button01 button.

Add the following code in the activity for opening the context menu and perform some action from selected context menu option.

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
    {
       
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.setHeaderTitle("Post Image");
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.camer_menu, menu);
    }
   
    @Override
    public boolean onContextItemSelected(MenuItem item)
    {
      switch (item.getItemId())
      {
          case R.id.take_photo:
              Toast.makeText(context, "Selected Take Photo", Toast.LENGTH_SHORT).show();
              break;
         
          case R.id.choose_gallery:
                Toast.makeText(context, "Selected Gallery", Toast.LENGTH_SHORT).show();
                break;
       
          case R.id.share_cancel:
              closeContextMenu();
              break;
          default:
            return super.onContextItemSelected(item);
      }
      return true;
    }



Here i displayed Toast on selecting option from the context menu.

Below is the sample output.







Load image from camera or gallery

This post is to demonstrate how to load image from camera or from gallery.

It contain select and clear button at the title bar of the activity, and a text view will contain the title of the acticity.

On clicking select button, a context menu will be opened with three options called "Take New Photo", "Choose from Gallery" and "Cancel".

On Selecting Take New Photo option, the android camera intent will be called and camera view will be opened, the user can take photo, on clicking the capture button in the camera, the image will be stored in the folder of the sdcard, and the taken image will be loaded into the activity.

For accessing the camera hardware of the mobile, the following lines must to be add in the manifest file.

    <uses-permission android:name="android.permission.CAMERA" />
   
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />


For storing the image in the sdcard, you have to add the following permission in the manifest file.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

On Selecting Choose from Gallery option, the android gallery page will be opened, from the gallery you can select image, and the selected image will be added next to the main activity.

Below is the code for loading the image into the table layout with dynamic table row. You can take new picture and load in the table layout or you can select image from gallery and load in the table layout.

package cm.camera.table;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Gravity;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class LoadImage extends Activity
{
    Activity activity=null;
    Context context=null;
   
    Button header_left_btn=null;
    Button header_right_btn=null;
    TextView header_text=null;
    TableLayout image_table=null;
   
    ArrayList<String> image_list=new ArrayList<String>();
    ArrayList<Drawable> image_drawable=new ArrayList<Drawable>();
    String path="";
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.main);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.header);
       
        activity=LoadImage.this;
        context=LoadImage.this;
       
        header_left_btn=(Button)findViewById(R.id.header_left_btn);
        header_right_btn=(Button)findViewById(R.id.header_right_btn);
        header_text=(TextView)findViewById(R.id.header_text);
        image_table=(TableLayout)findViewById(R.id.image_table);
       
        header_text.setText("Image Table");
        header_left_btn.setText("Select");
        header_right_btn.setText("Clear");
        registerForContextMenu(header_left_btn);
       
        header_left_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                openContextMenu(header_left_btn);
            }
        });
       
        header_right_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                image_list.clear();
                image_drawable.clear();
                deletePhotos();
                updateImageTable();
            }
        });
    }
   
    public void deletePhotos()
    {
        String folder=Environment.getExternalStorageDirectory() +"/LoadImg";
        File f=new File(folder);
        if(f.isDirectory())
        {
            File[] files=f.listFiles();
            Log.v("Load Image", "Total Files To Delete=====>>>>>"+files.length);
            for(int i=0;i<files.length;i++)
            {
                String fpath=folder+File.separator+files[i].getName().toString().trim();
                System.out.println("File Full Path======>>>"+fpath);
                File nf=new File(fpath);
                if(nf.exists())
                {
                    nf.delete();
                }
            }
        }
    }
   
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
    {
       
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.setHeaderTitle("Post Image");
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.camer_menu, menu);
    }
   
    @Override
    public boolean onContextItemSelected(MenuItem item)
    {
      switch (item.getItemId())
      {
          case R.id.take_photo:
              //Toast.makeText(context, "Selected Take Photo", Toast.LENGTH_SHORT).show();
              takePhoto();
              break;
         
          case R.id.choose_gallery:
              //Toast.makeText(context, "Selected Gallery", Toast.LENGTH_SHORT).show();
              Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
              photoPickerIntent.setType("image/*");
              startActivityForResult(photoPickerIntent, 1);
             
              break;
       
          case R.id.share_cancel:
              closeContextMenu();
              break;
          default:
            return super.onContextItemSelected(item);
      }
      return true;
    }
   
    public void takePhoto()
    {
         Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
         File folder = new File(Environment.getExternalStorageDirectory() + "/LoadImg");

         if(!folder.exists())
         {
             folder.mkdir();
         }        
         final Calendar c = Calendar.getInstance();
         String new_Date= c.get(Calendar.DAY_OF_MONTH)+"-"+((c.get(Calendar.MONTH))+1)   +"-"+c.get(Calendar.YEAR) +" " + c.get(Calendar.HOUR) + "-" + c.get(Calendar.MINUTE)+ "-"+ c.get(Calendar.SECOND);
         path=String.format(Environment.getExternalStorageDirectory() +"/LoadImg/%s.png","LoadImg("+new_Date+")");
         File photo = new File(path);
         intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photo));
         startActivityForResult(intent, 2);
    }
   
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
       
        if(requestCode==1)
        {
            Uri photoUri = data.getData();
            if (photoUri != null)
            {
                String[] filePathColumn = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(photoUri, filePathColumn, null, null, null);
                cursor.moveToFirst();
                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String filePath = cursor.getString(columnIndex);
                cursor.close();
                Log.v("Load Image", "Gallery File Path=====>>>"+filePath);
                image_list.add(filePath);
                Log.v("Load Image", "Image List Size=====>>>"+image_list.size());
               
                //updateImageTable();
                new GetImages().execute();
            }
        }
       
        if(requestCode==2)
        {
            Log.v("Load Image", "Camera File Path=====>>>"+path);
            image_list.add(path);
             Log.v("Load Image", "Image List Size=====>>>"+image_list.size());
            //updateImageTable();
             new GetImages().execute();
        }
    }
   
    public void updateImageTable()
    {
        image_table.removeAllViews();
       
        if(image_drawable.size() > 0)
        {
            for(int i=0; i<image_drawable.size(); i++)
            {
                TableRow tableRow=new TableRow(this);
                tableRow.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
                tableRow.setGravity(Gravity.CENTER_HORIZONTAL);
                tableRow.setPadding(5, 5, 5, 5);
                for(int j=0; j<1; j++)
                {
                    ImageView image=new ImageView(this);
                    image.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
                   
                    /*Bitmap bitmap = BitmapFactory.decodeFile(image_list.get(i).toString().trim());
                    bitmap = Bitmap.createScaledBitmap(bitmap,500, 500, true);
                    Drawable d=loadImagefromurl(bitmap);*/
                    image.setBackgroundDrawable(image_drawable.get(i));
                   
                    tableRow.addView(image, 200, 200);
                }
                image_table.addView(tableRow);
            }
        }
    }
   
    public Drawable loadImagefromurl(Bitmap icon)
    {
        Drawable d=new BitmapDrawable(icon);       
        return d;
    }
   
    public class GetImages extends AsyncTask<Void, Void, Void>
    {
        public ProgressDialog progDialog=null;
       
        protected void onPreExecute()
        {
            progDialog=ProgressDialog.show(context, "", "Loading...",true);
        }
        @Override
        protected Void doInBackground(Void... params)
        {
            image_drawable.clear();
            for(int i=0; i<image_list.size(); i++)
            {
                Bitmap bitmap = BitmapFactory.decodeFile(image_list.get(i).toString().trim());
                bitmap = Bitmap.createScaledBitmap(bitmap,500, 500, true);
                Drawable d=loadImagefromurl(bitmap);
               
                image_drawable.add(d);
            }
            return null;
        }   
           
        protected void onPostExecute(Void result)
        {
            if(progDialog.isShowing())
            {
                progDialog.dismiss();
            }
            updateImageTable();
        }
    }
}

Below is the layout, that are used for loading the image. The name of the layout called main.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#BFD6E8">
   
    <ScrollView android:id="@+id/image_scroll"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
       
        <TableLayout android:id="@+id/image_table"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content">
        </TableLayout>
       
    </ScrollView>

</LinearLayout>


I added the Custom title bar in the activity. For creating custom title bar, please Refer the link below.

http://tjkannan.blogspot.com/2012/01/custom-title-bar.html

Below is the sample output screens.
































Custom Title Bar

For creating custom Title bar in android, For that Add styles.xml in the res/values folder.

The styles.xml file contains the following code.

<?xml version="1.0" encoding="UTF-8"?>
<resources>

    <style name="WindowTitleBackground" >   
        <item name="android:background">@android:color/transparent</item>       
    </style>
   
</resources>


Create colors.xml file in the res/values folder. Add colors that are needed for the application.

The colors.xml file contains the following code.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="orange">#ff5500</color>
<color name="white">#ffffff</color>
<color name="transparent">#00000000</color>
<color name="date_color">#999999</color>
<color name="black">#000000</color>
<color name="gray">#999999</color>
<color name="blue">#0066cc</color>
<color name="gold">#e6b121</color>
<color name="blueback">#99FFFF</color>
 <color name="articlecolor">#3399FF</color>
 <color name="article_title">#3399FF</color>
<color name="cachecolor">#8ad0e8</color>
<color name="red">#FF0000</color>
<color name="pink">#FF00FF</color>
<color name="green">#00FF00</color>
<color name="mycolor">#FF9900</color>
</resources>


Add themes.xml file in the res/values folder.
themes.xml file contains the following code.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme" parent="android:Theme">
        <item name="android:windowTitleSize">60px</item>
        <item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground</item>         
       
    </style>
</resources>


The created style will be added into the theme file.
After creating these files open android manifest file and apply the theme into the whole application or an activity.

manifest file code

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="cm.camera.table"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="4" />
   
        <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".LoadImage" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/MyTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>


The yellow highlighted code is the code for applying the created theme for an activity.

Create a layout for the custom title bar, the layout contain any android controls.

The below layout cobe is the sample layout for the custom title bar.

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="60px"
    android:layout_gravity="fill_horizontal"
    android:layout_width="fill_parent"
    android:background="#095C9B"
    android:orientation="horizontal">

        <Button  android:id="@+id/header_left_btn"
            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="5dp"
             android:layout_centerVertical="true"
             android:text=" Back"
             android:textColor="#000000"/>
       

        <TextView android:id="@+id/header_text"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_toRightOf="@+id/header_left_btn"
            android:layout_toLeftOf="@+id/header_right_btn"
            android:text="Header Text"
            android:textSize="20sp"
            android:textStyle="bold"
            android:textColor="#FFFFFF"
            android:gravity="center"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:singleLine="true" />
           
        <Button  android:id="@+id/header_right_btn"
            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="5dp"
             android:layout_centerVertical="true"
             android:text=" Share"  
             android:textColor="#000000"/>
       
</RelativeLayout>


I used two buttons and one text view in the layout.

Add the following lines in the on create method.

        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.header);


The onCreate method in the activity will look like the below.

@Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.main);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.header);
    }


The yellow Highlighted line replaces the default title bar to the custom title bar.

Run the application, you will get the output like below.


Number Puzzle

The Below program is the Splash Screen, After finishing the splash screen activity, the options page will be displayed.


package com.dynamic.layout;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;

public class Splash_Screen extends Activity
{
    public static final String PREFS_NAME = "ScorePrefs";
    static SharedPreferences settings;
    SharedPreferences.Editor editor;
   
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash_screen);
       
        new CountDownTimer(5000,1000){

            @Override
            public void onFinish()
            {
                // TODO Auto-generated method stub
                finish();
                Intent ingridmenu=new Intent(Splash_Screen.this,OptionLayout.class);
                startActivity(ingridmenu);
            }

            @Override
            public void onTick(long millisUntilFinished)
            {
                Log.d("Timer Coundown", Long.toString(millisUntilFinished));
                // TODO Auto-generated method stub
               
            }
           
        }.start();
    }
}


The Below Program is the Option page Activity.

package com.dynamic.layout;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class OptionLayout extends Activity
{
    DBRecordHandler recHandler=null;
   
    Button start_btn=null;
    Button scores_btn=null;
    Button exit_btn=null;
   
    static int screenWidth=0,screenHeight=0;
   
    public static ArrayList<MoveListValues> scoreList=new ArrayList<MoveListValues>();
   
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.options_layout);
       
        Display display = getWindowManager().getDefaultDisplay();
        screenWidth = display.getWidth();
        screenHeight = display.getHeight();
        Log.d("screenWidth",Integer.toString(screenWidth));
        Log.d("Screen Height",Integer.toString(screenHeight));
       
        start_btn=(Button)findViewById(R.id.start_btn);
        scores_btn=(Button)findViewById(R.id.scores_btn);
        exit_btn=(Button) findViewById(R.id.exit_btn);
       
        getScoreRecords();
       
        start_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                Intent instart=new Intent(OptionLayout.this, DynamicLayout.class);
                startActivity(instart);
            }
           
        });
       
        scores_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                Intent inscore=new Intent(OptionLayout.this, ScoreList.class);
                startActivity(inscore);
            }
           
        });
       
        exit_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                finish();
            }
           
        });
    }
   
    public void getScoreRecords()
    {
        scoreList.clear();
       
        recHandler=new DBRecordHandler(OptionLayout.this);
        recHandler.open();
       
        Cursor cur=recHandler.getAllUser();
        startManagingCursor(cur);
        cur.moveToFirst();
        if(cur.getCount()>0)
        {
            while(cur.isAfterLast()==false)
            {   
                //Log.v("OptionLayout", "Name========>>>"+cur.getString(cur.getColumnIndex(DBRecordHandler.USERNAME)));
                //Log.v("OptionLayout", "Moves========>>>"+cur.getString(cur.getColumnIndex(DBRecordHandler.MOVES)));
                //Log.v("OptionLayout", "Time========>>>"+cur.getString(cur.getColumnIndex(DBRecordHandler.TIME)));
               
                String name=cur.getString(cur.getColumnIndex(DBRecordHandler.USERNAME));
                String moves=cur.getString(cur.getColumnIndex(DBRecordHandler.MOVES));
                String time=cur.getString(cur.getColumnIndex(DBRecordHandler.TIME));
               
                scoreList.add(new MoveListValues(name, moves, time));
               
                cur.moveToNext();
            }
        }
       
        else
        {
            Toast.makeText(OptionLayout.this, "No Scores Details", Toast.LENGTH_SHORT).show();
        }
        recHandler.close();
    }
   
    public void onResume()
    {
        super.onResume();
        Log.v("OptionLayout", "=========== Calling OnResume ============");
        getScoreRecords();
    }
}

Below is the Layout that are used in the Option activity.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  android:gravity="center"
  android:background="#112C4F">
 
  <Button android:id="@+id/start_btn"
      android:layout_width="fill_parent"
      android:layout_height="50dp"
      android:layout_marginLeft="20dp"
      android:layout_marginRight="20dp"
      android:text="Start"
      android:textColor="#FFFFFF"
      android:textStyle="bold"
      android:textSize="18sp"
      android:background="@drawable/shuffle_button_selector">
  </Button>
 
   <Button android:id="@+id/scores_btn"
      android:layout_width="fill_parent"
      android:layout_height="50dp"
      android:layout_marginLeft="20dp"
      android:layout_marginRight="20dp"
      android:layout_marginTop="10dp"
      android:text="Scores"
      android:textColor="#FFFFFF"
      android:textStyle="bold"
      android:textSize="18sp"
      android:background="@drawable/shuffle_button_selector">
  </Button>
 
   <Button android:id="@+id/exit_btn"
      android:layout_width="fill_parent"
      android:layout_height="50dp"
      android:layout_marginLeft="20dp"
      android:layout_marginRight="20dp"
      android:layout_marginTop="10dp"
      android:text="Exit"
      android:textColor="#FFFFFF"
      android:textStyle="bold"
      android:textSize="18sp"
      android:background="@drawable/shuffle_button_selector">
  </Button>
 
</LinearLayout>


Three buttons are used in the option page, first one is start to start the puzzle, second is scores to list the highscores in the puzzle and third one is exit to close the application.


OnClicking the start button, the puzzle activity will be started.

Below is the program for creating the view of the puzzle.

package com.dynamic.layout;

import java.util.ArrayList;
import java.util.Collections;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.Chronometer.OnChronometerTickListener;

public class DynamicLayout extends Activity implements OnClickListener
{
    public static final int LEFT_MOVE=1;
    public static final int RIGHT_MOVE=2;
    public static final int TOP_MOVE=3;
    public static final int BOTTOM_MOVE=4;
   
    TableLayout tableLayout=null;
    Button shuffle_btn=null;
    TextView moves=null;
    TextView least_moves=null;
    Chronometer time_count=null;
   
    DBRecordHandler recHandler=null;
   
    int value=0, move_count=0;
    String currentTime;
    long elapsedTime = 0;
   
    public ArrayList<String> numbers=new ArrayList<String>();
    public ArrayList<String> real_numbers=new ArrayList<String>();
    public String[][] num_array=new String[4][4];
    ArrayList<MoveListValues> nearest_list=new ArrayList<MoveListValues>();
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        tableLayout=(TableLayout)findViewById(R.id.table_layout);
        shuffle_btn=(Button)findViewById(R.id.shuffle_btn);
        moves=(TextView)findViewById(R.id.moves_count);
        least_moves=(TextView)findViewById(R.id.least_moves);
        time_count=(Chronometer)findViewById(R.id.timer_count);
       
        try
        {
            if(OptionLayout.scoreList.size()<1)
            {
                least_moves.setText("Least Move : 0");
            }
           
            else
            {
                least_moves.setText("Least Move : "+OptionLayout.scoreList.get(0).moves.trim());
            }
        }
        catch(Exception e)
        {
           
        }
       
       
       
        for(int i=1; i<16; i++)
        {
            real_numbers.add(Integer.toString(i));
        }
        real_numbers.add("");
       
        storeNumberList();
        shuffle();
       
        //time_count.start();
       
        shuffle_btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                storeNumberList();
                shuffle();
            }
        });
       
        time_count.setOnChronometerTickListener(new OnChronometerTickListener(){

            @Override
            public void onChronometerTick(Chronometer chronometer)
            {
                // TODO Auto-generated method stub
                long minutes = ((SystemClock.elapsedRealtime() - time_count.getBase()) / 1000) / 60;
                long seconds = ((SystemClock.elapsedRealtime() - time_count.getBase()) / 1000) % 60;
               
                String min=Long.toString(minutes);
                String sec=Long.toString(seconds);
               
                if(sec.length()<2)
                {
                    sec="0"+sec;
                }
                currentTime = min + ":" + sec;
                //Log.v("DynamicLayout", "Current Time=====>>>"+currentTime);
               
                chronometer.setText("Time : "+currentTime);
                //elapsedTime = SystemClock.elapsedRealtime();
            }
           
        });
    }
   
    public void storeNumberList()
    {
        numbers.clear();
        for(int i=1; i<16; i++)
        {
            numbers.add(Integer.toString(i));
        }
        numbers.add("");
    }
   
    public void shuffle()
    {
        //Collections.shuffle(numbers);
       
        move_count=0;
        moves.setText("Moves = "+move_count);
       
        time_count.setBase(SystemClock.elapsedRealtime());
        time_count.start();
       
        displayShuffledRows();
    }

    public void displayShuffledRows()
    {
        // TODO Auto-generated method stub
        tableLayout.removeAllViews();
        value=0;
        int ei=-1,ej=-1;
       
        for(int i=0; i<4; i++)
        {
            TableRow tableRow=new TableRow(this);
            tableRow.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            tableRow.setGravity(Gravity.CENTER_HORIZONTAL);
            for(int j=0; j<4; j++)
            {
                Button button=new Button(this);
               
                button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
               
                num_array[i][j]=numbers.get(value);
               
                if(numbers.get(value).equals(""))
                {
                    ei=i;
                    ej=j;
                }
               
                button.setText(""+numbers.get(value));
                button.setTextSize(25.0f);
                button.setBackgroundResource(R.drawable.number_buttons_selector);
                button.setTextColor(Color.WHITE);
                button.setOnClickListener(this);
               
                value++;
               
                if(OptionLayout.screenWidth==540)
                {
                    tableRow.addView(button,120,120);
                }
                else
                {
                    tableRow.addView(button,60,60);
                }
               
               
            }
           
            tableLayout.addView(tableRow);
        }
       
        getNearestValues(ei,ej);
    }
   
    public void getNearestValues(int i, int j)
    {
        nearest_list.clear();
       
        //Log.v("Dynamic Layout", "Empty Position=============>>>"+i+","+j);
       
        if(i==0 && j==0)
        {
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }
        else if(i==0 && (j==1 || j==2))
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));           
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }       
        else if(i==0 && j==3)
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }       
        else if((i==1 || i==2) && j==0)
        {
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }
        else if((i==1 || i==2) && (j==1 || j==2))
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }       
        else if((i==1 || i==2) && j==3)
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
            nearest_list.add(new MoveListValues(num_array[i+1][j], BOTTOM_MOVE, i+1, j, i, j));
        }       
        else if(i==3 && j==0)
        {
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
        }
        else if(i==3 && (j==1 || j==2))
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i][j+1], RIGHT_MOVE, i, j+1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
        }       
        else if(i==3 && j==3)
        {
            nearest_list.add(new MoveListValues(num_array[i][j-1], LEFT_MOVE, i, j-1, i, j));
            nearest_list.add(new MoveListValues(num_array[i-1][j], TOP_MOVE, i-1, j, i, j));
        }
        else
        {
            Toast.makeText(DynamicLayout.this, "I and J value are Negative", Toast.LENGTH_SHORT).show();
        }   
    }

    @Override
    public void onClick(View v)
    {
        // TODO Auto-generated method stub
        String text=((Button) v).getText().toString();
       
        numbers.clear();
       
        for(int i=0; i<nearest_list.size(); i++)
        {
            if(text.equalsIgnoreCase(nearest_list.get(i).number.trim()))
            {
                move_count++;
                //Log.v("DynamicLayout", "Direction==========>>>"+nearest_list.get(i).direction);
                int empty_i=nearest_list.get(i).empty_i;
                int empty_j=nearest_list.get(i).empty_j;
               
                int move_i=nearest_list.get(i).move_i;
                int move_j=nearest_list.get(i).move_j;
               
                String temp=num_array[move_i][move_j];
                num_array[move_i][move_j]="";
                num_array[empty_i][empty_j]=temp;
            }
        }
       
        for(int i=0; i<4; i++)
        {
            for(int j=0; j<4; j++)
            {
                //Log.v("Printing Num Array", "After Values======("+i+","+j+")=========>>>"+num_array[i][j]);
                numbers.add(num_array[i][j]);
            }
        }
        moves.setText("Moves = "+move_count);
        displayShuffledRows();
        int i=0;
        comparition(i);
    }
   
    public void comparition(int i)
    {
        if(i<real_numbers.size())
        {
            //System.out.println("List 1 value=====>>>"+real_numbers.get(i) + " List 2 Value=====>>>"+numbers.get(i));
            if(real_numbers.get(i).equals(numbers.get(i)))
            {
                //System.out.println("Comparition Progress.....");
                i++;
                if(i==real_numbers.size())
                {
                    //System.out.println("Solution Obtained.....");
                    time_count.stop();
                    showAlert(DynamicLayout.this, "Solution Obtained in "+move_count+" Moves and Time is "+currentTime);
                }
                else
                {
                    comparition(i);
                }
            }
            else
            {
                //System.out.println("Solution Not Obtained.....");
            }
        }
    }
   
    public void insertRecord(String name)
    {
        recHandler=new DBRecordHandler(DynamicLayout.this);
        recHandler.open();
        long res=recHandler.insertRecord(name, move_count, currentTime);
        Log.v("Record Inserted========>>>", Long.toString(res));
        recHandler.close();
    }
   
    public void showAlert(Context context, String desc)
    {
       
        final AlertDialog alert=new AlertDialog.Builder(context).create();

        alert.setTitle("Congratulation");
        alert.setMessage(desc);
        alert.setIcon(R.drawable.smile_emotion);

        // Set an EditText view to get user input
        final EditText input = new EditText(this);
        input.setHint("Name");
        alert.setView(input);

        alert.setButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton)
            {
              String value = input.getText().toString();
              insertRecord(value);
              shuffle();
              alert.dismiss();
            }
        });


        alert.show();
    }
}


Below is the layout that are used in the puzzle view. Layout name is main.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:background="#112C4F">
   
    <RelativeLayout android:id="@+id/timer_count_rellayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
       
        <TextView android:id="@+id/least_moves"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="5dp"
            android:text="Least Moves"
            android:textStyle="bold"
            android:textSize="15sp"
            android:textColor="#FFFFFF">
        </TextView>
       
        <Chronometer android:id="@+id/timer_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/least_moves"
            android:format="0:00"   
            android:textColor="#FFFFFF"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="10dp">
        </Chronometer>
       
        <TextView android:id="@+id/moves_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:layout_below="@+id/least_moves"
            android:text="Moves"
            android:textStyle="bold"
            android:textSize="15sp"
            android:textColor="#FFFFFF">
        </TextView>
       
    </RelativeLayout>
   
   
   
    <TableLayout android:id="@+id/table_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center">
    </TableLayout>
   
    <Button android:id="@+id/shuffle_btn"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginTop="10dp"
        android:background="@drawable/shuffle_button_selector"
        android:text="Shuffle"
        android:textColor="#FFFFFF">
    </Button>

</LinearLayout>


Text view for Displaying the least moves.
Chronometer for running the time.
Text view for Displaying the moves count.
Table Layout for displaying the puzzle numbers.
Button for suffle the puzzle numbers.

OnClicking the suffle button, the puzzle will be restarted, timer will also be restarted.

Sqlite database will be used for maintaining the scores details.

The following two class is used for creating the database and managing records in the database

package com.dynamic.layout;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

public class DataBaseHandler extends SQLiteOpenHelper
{
   
    public static String DataBase_Create="create table movecountdb(_id integer primary key autoincrement,"
        +"username text not null, moves integer not null, time text not null);";

    public DataBaseHandler(Context context, String name, CursorFactory factory,int version)
    {
        super(context, name, null, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase db)
    {
        // TODO Auto-generated method stub
        System.out.println("******** Table Created ***********");
        db.execSQL(DataBase_Create);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        // TODO Auto-generated method stub
        Log.w(DataBaseHandler.class.getName(), "Upgraded Database From "+oldVersion+" to "+newVersion+" Which Will Destroy All old Data");
        db.execSQL("Drop table if exist userdetails");
        onCreate(db);
    }

}


For Managing Records, the following class is used.

package com.dynamic.layout;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class DBRecordHandler
{
    public static String USERNAME="username";
    public static String MOVES="moves";
    public static String TIME="time";
    public static String ROW_ID="_id";
   
    public SQLiteDatabase database;
    public DataBaseHandler dbhandler;
   
    public static String DataBase_Name="movesdetails";
    public static int Database_version=2;
    public static String Table_Name="movecountdb";
    public Context context=null;
   
    public DBRecordHandler(Context context)
    {
        this.context=context;
        dbhandler=new DataBaseHandler(context,DataBase_Name,null,Database_version);
        database=dbhandler.getWritableDatabase();             
    }
   
    public DBRecordHandler open()
    {
        dbhandler=new DataBaseHandler(context,DataBase_Name,null,Database_version);
        database=dbhandler.getWritableDatabase(); 
        return this;
    }
   
    public void close()
    {
        dbhandler.close();
    }
   
    public long insertRecord(String username,int moves,String time)
    {
        ContentValues conval=addDetails(username, moves, time);
        long res=database.insert(Table_Name, null, conval);
        return res;
    }
   
    /*public int updateRecord(long row_id, String username, String password, String email)
    {
        ContentValues updateValues=addDetails(username, password, email);
        int res=database.update(Table_Name, updateValues, ROW_ID+"="+row_id, null);
        return res;
    }
   
    public int deleteRecord(long row_id)
    {
        int res=database.delete(Table_Name, ROW_ID+"="+row_id, null);
        return res;
    }*/
   
    public ContentValues addDetails(String username, int moves, String time)
    {
        Log.v("Record Handler", "username==========>>>"+username);
        Log.v("Record Handler", "Moves==========>>>"+moves);
        Log.v("Record Handler", "Time==========>>>"+time);
       
        ContentValues values=new ContentValues();
        values.put(USERNAME, username);
        values.put(MOVES, moves);
        values.put(TIME, time);
        return values;
    }
   
    public Cursor getAllUser()
    {
        Cursor cur=database.query(Table_Name, new String[]{ROW_ID,USERNAME,MOVES,TIME}, null, null, null, null, MOVES+" ASC");
        return cur;
    }

}


On Clicking the score option in the option page, the score activity will be started.

Below is the class for score activity.

package com.dynamic.layout;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class ScoreList extends Activity
{
    ListView scorelist=null;
   
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.scores_list);
       
        scorelist=(ListView)findViewById(R.id.score_listview);
        scorelist.setAdapter(new ScoreListAdapter(this));
    }
   
    public class ScoreListAdapter extends BaseAdapter
    {
        Context mycontext=null;
       
        public ScoreListAdapter(Context c)
        {
            mycontext=c;
        }

        @Override
        public int getCount()
        {
            // TODO Auto-generated method stub
            return OptionLayout.scoreList.size();
        }

        @Override
        public Object getItem(int position)
        {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public long getItemId(int position)
        {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            // TODO Auto-generated method stub
            ViewHolder holder=null;
            if(convertView==null)
            {
                LayoutInflater minflater=LayoutInflater.from(mycontext);
                convertView=minflater.inflate(R.layout.score_list_row, null);
                holder=new ViewHolder();
                holder.textname=(TextView)convertView.findViewById(R.id.name_textview);
                holder.textmove=(TextView)convertView.findViewById(R.id.move_textview);
                holder.texttime=(TextView)convertView.findViewById(R.id.time_textview);
               
                convertView.setTag(holder);
            }
            else
            {
                holder=(ViewHolder)convertView.getTag();
            }
           
            holder.textname.setText(OptionLayout.scoreList.get(position).name.trim());
            holder.textmove.setText("Moves : "+OptionLayout.scoreList.get(position).moves.trim());
            holder.texttime.setText("Time = "+OptionLayout.scoreList.get(position).time.trim());
           
            return convertView;
        }
       
        class ViewHolder
        {
             TextView textname;
             TextView textmove;
             TextView texttime;
        }

    }

}


layout used in the score list class is scores_list.xml

Below is the scores_list.xml content.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
 
  <ListView android:id="@+id/score_listview"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content">
  </ListView>
 
</LinearLayout>


Below is the layout that are inflated in the score list list view. The name of the layout is score_list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
 
  <TextView android:id="@+id/name_textview"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_marginLeft="10dp"
      android:layout_marginTop="10dp"
      android:text="Name"
      android:textStyle="bold"
      android:textSize="20sp"
      android:textColor="#FFFFFF">
  </TextView>
 
  <TextView android:id="@+id/move_textview"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_below="@+id/name_textview"
      android:layout_alignParentLeft="true"
      android:layout_marginLeft="10dp"
      android:layout_marginTop="10dp"
      android:text="Total Moves : 200 "
      android:textStyle="bold"
      android:textSize="15sp"
      android:textColor="#FFFFFF">
  </TextView>
 
  <TextView android:id="@+id/time_textview"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_below="@+id/name_textview"
      android:layout_alignParentRight="true"
      android:layout_marginRight="10dp"
      android:layout_marginTop="10dp"
      android:text="Time = 0:00"
      android:textStyle="bold"
      android:textSize="15sp"
      android:textColor="#FFFFFF">
  </TextView>
 
</RelativeLayout>

One more class is created called MoveListValues.jave, this class is used for storing the puzzle possible moves and the corresponding numbers and the direction of the move. It also used for storing the score details. This class is used in the ArrayList Type.

package com.dynamic.layout;

public class MoveListValues
{
    public String number;
    public int direction;
    public int move_i, move_j;
    public int empty_i, empty_j;
   
    public String name, moves, time;
   
    public MoveListValues(String number, int direction, int move_i, int move_j, int empty_i, int empty_j)
    {
        this.number=number;
        this.direction=direction;
        this.move_i=move_i;
        this.move_j=move_j;
        this.empty_i=empty_i;
        this.empty_j=empty_j;
    }
   
    public MoveListValues(String name, String moves, String time)
    {
        this.name=name;
        this.moves=moves;
        this.time=time;
    }

}


Below is the sample output screens.