Wednesday, January 27, 2010

Android File Explorer with MapView function

Extends work from "Android File Explorer with JPG's Exif & Photo displayed", and geoDegree class of the article "Convert Exif GPS info to Degree format", In this exercise, a new class AndroidExplorerMapView (actually, it's simliar to the exercises in "AndroidMapper") will be implemented to open a MapView locate the GPS location of a photo.




If the selected JPG file have Exif with GPS tag, the converted location in degree format and a extra MapView button will be shown. Click on the MapView button will start a MapView locate the GPS location of a photo.

The files can be download here, with a sample JPG with Geo tag.

Thursday, January 21, 2010

Convert Exif GPS info to Degree format

In the previous exercise "Android File Explorer with JPG's Exif & Photo displayed", Exif, include GPS info, of a JPG will be retrieve and displayed.

In my own case; I have no digital camera with GPS, but I have a GPS logger. The GPS info can be added into JPG file using GPicSync. But it's in the format of degree, minute, second, not GeoPoint form, as I used in my Mapper exercise. So I have to convert it by myself.



Here I create a class geoDegree to handle the conversion from degree, minute, second form to GeoPoint form.

package com.AndroidExplorer;

import android.media.ExifInterface;

public class geoDegree {
private boolean valid = false;
Float Latitude, Longitude;
geoDegree(ExifInterface exif){
String attrLATITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
String attrLATITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
String attrLONGITUDE = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
String attrLONGITUDE_REF = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);

if((attrLATITUDE !=null)
&& (attrLATITUDE_REF !=null)
&& (attrLONGITUDE != null)
&& (attrLONGITUDE_REF !=null))
{
valid = true;

if(attrLATITUDE_REF.equals("N")){
Latitude = convertToDegree(attrLATITUDE);
}
else{
Latitude = 0 - convertToDegree(attrLATITUDE);
}

if(attrLONGITUDE_REF.equals("E")){
Longitude = convertToDegree(attrLONGITUDE);
}
else{
Longitude = 0 - convertToDegree(attrLONGITUDE);
}

}
};

private Float convertToDegree(String stringDMS){
Float result = null;
String[] DMS = stringDMS.split(",", 3);

String[] stringD = DMS[0].split("/", 2);
Double D0 = new Double(stringD[0]);
Double D1 = new Double(stringD[1]);
Double FloatD = D0/D1;

String[] stringM = DMS[1].split("/", 2);
Double M0 = new Double(stringM[0]);
Double M1 = new Double(stringM[1]);
Double FloatM = M0/M1;

String[] stringS = DMS[2].split("/", 2);
Double S0 = new Double(stringS[0]);
Double S1 = new Double(stringS[1]);
Double FloatS = S0/S1;

result = new Float(FloatD + (FloatM/60) + (FloatS/3600));

return result;


};

public boolean isValid()
{
return valid;
}

@Override
public String toString() {
// TODO Auto-generated method stub
return (String.valueOf(Latitude)
+ ", "
+ String.valueOf(Longitude));
}

public int getLatitudeE6(){
return (int)(Latitude*1000000);
}

public int getLongitudeE6(){
return (int)(Longitude*1000000);
}

}


In a short comming, I will have a exercise to open a MapView locate the GPS location of a photo.

Wednesday, January 13, 2010

Android 2.1 SDK Released

Google announced SDK component for Android 2.1, so that developers can take advantage of the new features introduced in Android 2.1. Please read the Android 2.1 release notes for more details. You can download the Android 2.1 component through the SDK Manager.

In addition to the new SDK, a new USB driver that supports Nexus One is also available today through the SDK Manager. The USB driver page contains more information.

Android Developers Blog: Android 2.1 SDK

You can refer to my article to know how to Install Android SDK on Eclipse 3.5 Galileo, in Ubuntu 9.10. Or, if you have install Android 1.6 SDK or later version, you can refer to another article to upgrade Android SDK using Android SDK and AVD Manager.

Friday, January 8, 2010

Android File Explorer with JPG's Exif & Photo displayed

In the former exercise, "Android File Explorer with JPG's Exif info", only text of Exif will be displayed on the dialog when a JPG file is clicked. Here, I want to show the photo also.



A new dialog, jpgdialog.xml, will be created if a JPG is clicked. It's used to show the Exif and photo of the clicked item. Please note here; onCreateDialog() is only called the very first time a dialog is opened. If we display Exif and photo inside onCreateDialog(), it will always show the first photo when it is created. So the actual code to display the Exif and photo should be placed inside onPrepareDialog().

Both main.xml and row.xml keep no change as in "Android File Explorer with JPG's Exif info".

Create a new /res/layout/jpgdialog.xml, to have a TextView, a ImageView and a Button.
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_root"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="10dip"
android:paddingRight="10dip"
>
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp" />
/>
<ImageView android:id="@+id/image"
android:layout_width="150px"
android:layout_height="150px"
/>
<Button android:id="@+id/okdialogbutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="OK"
/>
</LinearLayout>


Modify AndroidExplorer.java

package com.AndroidExplorer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class AndroidExplorer extends ListActivity {

static final int ID_JPGDIALOG = 0;

String filename;
String exifAttribute;
TextView exifText;
ImageView bmImage;
BitmapFactory.Options bmOptions;
File jpgFile;
Dialog jpgDialog;

private List<String> item = null;
private List<String> path = null;
private String root="/";
private TextView myPath;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myPath = (TextView)findViewById(R.id.path);
getDir(root);
}

private void getDir(String dirPath)
{
myPath.setText("Location: " + dirPath);

item = new ArrayList<String>();
path = new ArrayList<String>();

File f = new File(dirPath);
File[] files = f.listFiles();

if(!dirPath.equals(root))
{

item.add(root);
path.add(root);

item.add("../");
path.add(f.getParent());

}

for(int i=0; i < files.length; i++)
{
File file = files[i];
path.add(file.getPath());
if(file.isDirectory())
item.add(file.getName() + "/");
else
item.add(file.getName());
}

ArrayAdapter<String> fileList =
new ArrayAdapter<String>(this, R.layout.row, item);
setListAdapter(fileList);
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {

File file = new File(path.get(position));

if (file.isDirectory())
{
if(file.canRead())
getDir(path.get(position));
else
{
new AlertDialog.Builder(this)
.setIcon(R.drawable.icon)
.setTitle("[" + file.getName() + "] folder can't be read!")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).show();
}
}
else
{
exifAttribute = null;
filename = file.getName();
String ext = filename.substring(filename.lastIndexOf('.')+1, filename.length());

if(ext.equals("JPG")||ext.equals("jpg"))
{
try {
ExifInterface exif = new ExifInterface(file.toString());
exifAttribute = getExif(exif);
} catch (IOException e) {
// TODO Auto-generated catch block
;
}
jpgFile = file;
showDialog(ID_JPGDIALOG);
}
else{
new AlertDialog.Builder(this)
.setIcon(R.drawable.icon)
.setTitle("[" + filename + "]")
.setMessage(exifAttribute)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).show();
}
}
}

private String getExif(ExifInterface exif)
{
String myAttribute=null;
myAttribute += getTagString(ExifInterface.TAG_DATETIME, exif);
myAttribute += getTagString(ExifInterface.TAG_FLASH, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE_REF, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE_REF, exif);
myAttribute += getTagString(ExifInterface.TAG_IMAGE_LENGTH, exif);
myAttribute += getTagString(ExifInterface.TAG_IMAGE_WIDTH, exif);
myAttribute += getTagString(ExifInterface.TAG_MAKE, exif);
myAttribute += getTagString(ExifInterface.TAG_MODEL, exif);
myAttribute += getTagString(ExifInterface.TAG_ORIENTATION, exif);
myAttribute += getTagString(ExifInterface.TAG_WHITE_BALANCE, exif);
return myAttribute;
}

private String getTagString(String tag, ExifInterface exif)
{
return(tag + " : " + exif.getAttribute(tag) + "\n");
}

@Override
protected Dialog onCreateDialog(int id) {
jpgDialog = null;;
switch(id){
case ID_JPGDIALOG:

Context mContext = this;
jpgDialog = new Dialog(mContext);

jpgDialog.setContentView(R.layout.jpgdialog);
exifText = (TextView) jpgDialog.findViewById(R.id.text);
bmImage = (ImageView)jpgDialog.findViewById(R.id.image);
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 2;

Button okDialogButton = (Button)jpgDialog.findViewById(R.id.okdialogbutton);
okDialogButton.setOnClickListener(okDialogButtonOnClickListener);

break;
default:
break;
}
return jpgDialog;
}

@Override
protected void onPrepareDialog(int id, Dialog dialog) {
// TODO Auto-generated method stub

switch(id){
case ID_JPGDIALOG:
dialog.setTitle("[" + filename + "]");
exifText.setText(exifAttribute);
Bitmap bm = BitmapFactory.decodeFile(jpgFile.getPath(), bmOptions);
bmImage.setImageBitmap(bm);

break;
default:
break;
}
}

private Button.OnClickListener okDialogButtonOnClickListener
= new Button.OnClickListener(){

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
jpgDialog.dismiss();
}
};
}


Download the files.

Related Article:
- Update GPS TAG, using ExifInterface.setAttribute() and exifInterface.saveAttributes()

Thursday, January 7, 2010

How to display a JPG in sdcard on ImageView

To display a JPG on ImageView, BitmapFactory.decodeFile() can be used.

display JPG on ImageView

But, in my experience, if I try to display a original photo in 10.0 million pixels by Nikon D80, the application will be stopped unexpectedly. So I have to use options.inSampleSize to reduce sample size.



In this exercise, the source (myJpgPath) of the JPG file is fixed, "/sdcard/DSC_3509.JPG". You have to modify to suit your own case.

Modify main.xml to have a TextView and ImageView to display files name and the photo.
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/jpgname"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/jpgview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


Modify the java file
package com.exercise.AndroidJpgView;

import java.io.File;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

public class AndroidJpgView extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView jpgName = (TextView)findViewById(R.id.jpgname);
ImageView jpgView = (ImageView)findViewById(R.id.jpgview);

String myJpgPath = "/sdcard/DSC_3509.JPG"; //UPDATE WITH YOUR OWN JPG FILE

jpgName.setText(myJpgPath);

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bm = BitmapFactory.decodeFile(myJpgPath, options);
jpgView.setImageBitmap(bm);
}
}


Download the files.



Wednesday, January 6, 2010

Android Scripting Environment, ase_r16.apk, just released.

The Android Scripting Environment (ASE) brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreters directly on the Android device. These scripts have access to many of the APIs available to full-fledged Android applications, but with a greatly simplified interface.

android-scripting Project Home>>

My old article, android-scripting: Android Scripting Environment, described how to install Android Scripting Environment on Android Emulator.

Nexus One Phone - Web meets phone.



http://www.google.com/phone

Sunday, January 3, 2010

Android File Explorer with JPG's Exif info

In the last exercise, Implement a simple File Explorer in Android, if a file is clicked, the application will simple display the file name only. Here, a little bit function will be add: if it's a JPG/jpg file, its Exif attributes will be listed also. This function have been described in former article, Read Exif information in a JPEG file, ExifInterface.




To check a file's extention in Java, the following code can be used:

String filename = file.getName();
String ext = filename.substring(filename.lastIndexOf('.')+1, filename.length());

if(ext.equals("JPG")||ext.equals("jpg"))
{}


To implement the Exif function in the application, it involve modification on the method onListItemClick(), and two more methods; getExif() and getTagString().
 @Override
protected void onListItemClick(ListView l, View v, int position, long id) {

File file = new File(path.get(position));

if (file.isDirectory())
{
if(file.canRead())
getDir(path.get(position));
else
{
new AlertDialog.Builder(this)
.setIcon(R.drawable.icon)
.setTitle("[" + file.getName() + "] folder can't be read!")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).show();
}
}
else
{
String exifAttribute = null;
String filename = file.getName();
String ext = filename.substring(filename.lastIndexOf('.')+1, filename.length());

if(ext.equals("JPG")||ext.equals("jpg"))
{
try {
ExifInterface exif = new ExifInterface(file.toString());
exifAttribute = getExif(exif);
} catch (IOException e) {
// TODO Auto-generated catch block
;
}
}

new AlertDialog.Builder(this)
.setIcon(R.drawable.icon)
.setTitle("[" + filename + "]")
.setMessage(exifAttribute)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}).show();
}
}

private String getExif(ExifInterface exif)
{
String myAttribute=null;
myAttribute += getTagString(ExifInterface.TAG_DATETIME, exif);
myAttribute += getTagString(ExifInterface.TAG_FLASH, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LATITUDE_REF, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE, exif);
myAttribute += getTagString(ExifInterface.TAG_GPS_LONGITUDE_REF, exif);
myAttribute += getTagString(ExifInterface.TAG_IMAGE_LENGTH, exif);
myAttribute += getTagString(ExifInterface.TAG_IMAGE_WIDTH, exif);
myAttribute += getTagString(ExifInterface.TAG_MAKE, exif);
myAttribute += getTagString(ExifInterface.TAG_MODEL, exif);
myAttribute += getTagString(ExifInterface.TAG_ORIENTATION, exif);
myAttribute += getTagString(ExifInterface.TAG_WHITE_BALANCE, exif);
return myAttribute;
}

private String getTagString(String tag, ExifInterface exif)
{
return(tag + " : " + exif.getAttribute(tag) + "\n");
}



Next: Android File Explorer with JPG's Exif & Photo displayed


Download the files.



Saturday, January 2, 2010

Implement a simple File Explorer in Android

It's a simple File Explorer in Android.



The files information can be read using java.io.File, using the code:
File f = new File(dirPath);
File[] files = f.listFiles();

The name of the files/folders will be added in a ArrayList. If it's not the root, two more elements (the root and the parent) will be added in the front of the ArrayList.

Then, the ArrayList will be adapted to a ArrayAdapter, and also set to be displayed on screen.

In case any item is clicked; if it's a file, the name will be display in a dialog; if it's a directory (isDirectory) and can be read (canRead), will open the selected directory; if it's a directory and CANNOT be read, a message will be prompt.




Create a layout file /res/layout/row.xml, which is the layout of each row the the list.
<?xml version="1.0" encoding="utf-8"?>

<TextView 

  xmlns:android="http://schemas.android.com/apk/res/android"

  android:id="@+id/rowtext"

  android:layout_width="fill_parent"

     android:layout_height="25px"

     android:textSize="23sp" />


Modify /res/layout/main.xml to have a List:
<?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"

    >

<TextView

 android:id="@+id/path"

    android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    />

<ListView

 android:id="@android:id/list"

 android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

 />

<TextView

 android:id="@android:id/empty"

 android:layout_width="fill_parent" 

    android:layout_height="wrap_content" 

    android:text="No Data"

 />

</LinearLayout>


remark: TextView with id empty will be display IF the list is empty.

Modify the code, AndroidExplorer.java
package com.AndroidExplorer;



import java.io.File;

import java.util.ArrayList;

import java.util.List;

import android.app.AlertDialog;

import android.app.ListActivity;

import android.content.DialogInterface;

import android.os.Bundle;

import android.view.View;

import android.widget.ArrayAdapter;

import android.widget.ListView;

import android.widget.TextView;



public class AndroidExplorer extends ListActivity {

 

 private List<String> item = null;

 private List<String> path = null;

 private String root="/";

 private TextView myPath;

 

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        myPath = (TextView)findViewById(R.id.path);

        getDir(root);

    }

    

    private void getDir(String dirPath)

    {

     myPath.setText("Location: " + dirPath);

     

     item = new ArrayList<String>();

     path = new ArrayList<String>();

     

     File f = new File(dirPath);

     File[] files = f.listFiles();

     

     if(!dirPath.equals(root))

     {



      item.add(root);

      path.add(root);

      

      item.add("../");

      path.add(f.getParent());

            

     }

     

     for(int i=0; i < files.length; i++)

     {

       File file = files[i];

       path.add(file.getPath());

       if(file.isDirectory())

        item.add(file.getName() + "/");

       else

        item.add(file.getName());

     }



     ArrayAdapter<String> fileList =

      new ArrayAdapter<String>(this, R.layout.row, item);

     setListAdapter(fileList);

    }



 @Override

 protected void onListItemClick(ListView l, View v, int position, long id) {

  

  File file = new File(path.get(position));

  

  if (file.isDirectory())

  {

   if(file.canRead())

    getDir(path.get(position));

   else

   {

    new AlertDialog.Builder(this)

    .setIcon(R.drawable.icon)

    .setTitle("[" + file.getName() + "] folder can't be read!")

    .setPositiveButton("OK", 

      new DialogInterface.OnClickListener() {

       

       @Override

       public void onClick(DialogInterface dialog, int which) {

        // TODO Auto-generated method stub

       }

      }).show();

   }

  }

  else

  {

   new AlertDialog.Builder(this)

    .setIcon(R.drawable.icon)

    .setTitle("[" + file.getName() + "]")

    .setPositiveButton("OK", 

      new DialogInterface.OnClickListener() {

       

       @Override

       public void onClick(DialogInterface dialog, int which) {

        // TODO Auto-generated method stub

       }

      }).show();

  }

 }

}


- Updated: Example of File Explorer in Android.