Thursday, April 28, 2011

Disable screen auto-dim, using PowerManager

The class android.os.PowerManager gives you control of the power state of the device.

Device battery life will be significantly affected by the use of this API. Do not acquire WakeLocks unless you really need them, use the minimum levels possible, and be sure to release it as soon as you can.

You can obtain an instance of this class by calling Context.getSystemService().

package com.exercise.AndroidWakeLock;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;

public class AndroidWakeLock extends Activity {

WakeLock wakeLock;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

PowerManager powerManager =
(PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock =
powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK,
"Full Wake Lock");
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
wakeLock.acquire();
}

@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
wakeLock.release();
}
}


Also have to grant permission of "android.permission.WAKE_LOCK" in AndroidManifest.xml.

Wednesday, April 27, 2011

Update GPS TAG, using ExifInterface.setAttribute() and exifInterface.saveAttributes()

Update GPS TAG, using ExifInterface.setAttribute() and exifInterface.saveAttributes()

Last exercise show how to "Read EXIF of JPG file", new member method UpdateGeoTag() will be implemented to update GPS TAG of the file with dummy data.

exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, DUMMY_GPS_LATITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, DUMMY_GPS_LATITUDE_REF);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, DUMMY_GPS_LONGITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, DUMMY_GPS_LONGITUDE_REF);

Once all attributes set, you can call exifInterface.saveAttributes() method to update the file.

with updated GPS TAG

In order to write-back data to file in SD Card, you have to modify AndroidManifest.xml grant permission of "android.permission.WRITE_EXTERNAL_STORAGE".

Related post
- "Convert Exif GPS info to Degree format".

In my exercise, the update Geo location can be recognized automatically by Picasa, Flickr and Nikon ViewNX.

MyExif.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.database.Cursor;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;

public class MyExif {

private File exifFile; //It's the file passed from constructor
private String exifFilePath; //file in Real Path format
private Activity parentActivity; //Parent Activity

private String exifFilePath_withoutext;
private String ext;

private ExifInterface exifInterface;
private Boolean exifValid = false;;

//Exif TAG
//for API Level 8, Android 2.2
private String exif_DATETIME = "";
private String exif_FLASH = "";
private String exif_FOCAL_LENGTH = "";
private String exif_GPS_DATESTAMP = "";
private String exif_GPS_LATITUDE = "";
private String exif_GPS_LATITUDE_REF = "";
private String exif_GPS_LONGITUDE = "";
private String exif_GPS_LONGITUDE_REF = "";
private String exif_GPS_PROCESSING_METHOD = "";
private String exif_GPS_TIMESTAMP = "";
private String exif_IMAGE_LENGTH = "";
private String exif_IMAGE_WIDTH = "";
private String exif_MAKE = "";
private String exif_MODEL = "";
private String exif_ORIENTATION = "";
private String exif_WHITE_BALANCE = "";

//Constructor from path
MyExif(String fileString, Activity parent){
exifFile = new File(fileString);
parentActivity = parent;
exifFilePath = fileString;
PrepareExif();
}

//Constructor from URI
MyExif(Uri fileUri, Activity parent){
exifFile = new File(fileUri.toString());
parentActivity = parent;
exifFilePath = getRealPathFromURI(fileUri);
PrepareExif();
}

private void PrepareExif(){

int dotposition= exifFilePath.lastIndexOf(".");
exifFilePath_withoutext = exifFilePath.substring(0,dotposition);
ext = exifFilePath.substring(dotposition + 1, exifFilePath.length());

if (ext.equalsIgnoreCase("jpg")){
try {
exifInterface = new ExifInterface(exifFilePath);
ReadExifTag();
exifValid = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

private void ReadExifTag(){

exif_DATETIME = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
exif_FLASH = exifInterface.getAttribute(ExifInterface.TAG_FLASH);
exif_FOCAL_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
exif_GPS_DATESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
exif_GPS_LATITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
exif_GPS_LATITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
exif_GPS_LONGITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
exif_GPS_LONGITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
exif_GPS_PROCESSING_METHOD = exifInterface.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
exif_GPS_TIMESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
exif_IMAGE_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_LENGTH);
exif_IMAGE_WIDTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_WIDTH);
exif_MAKE = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
exif_MODEL = exifInterface.getAttribute(ExifInterface.TAG_MODEL);
exif_ORIENTATION = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
exif_WHITE_BALANCE = exifInterface.getAttribute(ExifInterface.TAG_WHITE_BALANCE);

}

private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = parentActivity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}

public String getSummary(){
if(!exifValid){
return ("Invalide EXIF!");
}else{
return( exifFilePath + " : \n" +

"Name without extension: " + exifFilePath_withoutext + "\n" +
"with extension: " + ext + "\n" +

//"Date Time: " + exif_DATETIME + "\n" +
//"Flash: " + exif_FLASH + "\n" +
//"Focal Length: " + exif_FOCAL_LENGTH + "\n" +
//"GPS Date Stamp: " + exif_GPS_DATESTAMP + "\n" +
"GPS Latitude: " + exif_GPS_LATITUDE + "\n" +
"GPS Latitute Ref: " + exif_GPS_LATITUDE_REF + "\n" +
"GPS Longitude: " + exif_GPS_LONGITUDE + "\n" +
"GPS Longitude Ref: " + exif_GPS_LONGITUDE_REF);
//"Processing Method: " + exif_GPS_PROCESSING_METHOD + "\n" +
//"GPS Time Stamp: " + exif_GPS_TIMESTAMP + "\n" +
//"Image Length: " + exif_IMAGE_LENGTH + "\n" +
//"Image Width: " + exif_IMAGE_WIDTH + "\n" +
//"Make: " + exif_MAKE + "\n" +
//"Model: " + exif_MODEL + "\n" +
//"Orientation: " + exif_ORIENTATION + "\n" +
//"White Balance: " + exif_WHITE_BALANCE + "\n");
}
}

public void UpdateGeoTag(){
//with dummy data
final String DUMMY_GPS_LATITUDE = "22/1,21/1,299295/32768";
final String DUMMY_GPS_LATITUDE_REF = "N";
final String DUMMY_GPS_LONGITUDE = "114/1,3/1,207045/4096";
final String DUMMY_GPS_LONGITUDE_REF = "E";

exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE, DUMMY_GPS_LATITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, DUMMY_GPS_LATITUDE_REF);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, DUMMY_GPS_LONGITUDE);
exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, DUMMY_GPS_LONGITUDE_REF);
try {
exifInterface.saveAttributes();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}


AndroidSelectImage.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class AndroidSelectImage extends Activity {

TextView textTargetUri;
ImageView targetImage;
Button buttonSaveImage;

File targetFile;
String exifAttribute;

MyExif myExif;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonLoadImage = (Button)findViewById(R.id.loadimage);
buttonSaveImage = (Button)findViewById(R.id.saveimage);
textTargetUri = (TextView)findViewById(R.id.targeturi);
targetImage = (ImageView)findViewById(R.id.targetimage);

buttonLoadImage.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
buttonSaveImage.setEnabled(false);
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 0);
}});

buttonSaveImage.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
myExif.UpdateGeoTag(); //with dummy data
}});
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK){
Uri targetUri = data.getData();

Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(targetUri));
targetImage.setImageBitmap(bitmap);
buttonSaveImage.setEnabled(true);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

myExif = new MyExif(targetUri, this);
textTargetUri.setText(myExif.getSummary());
}
}

}


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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/loadimage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Load Image"
/>
<Button
android:id="@+id/saveimage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Update Geo Tag (with DUMMY data)"
android:enabled="false"
/>
<TextView
android:id="@+id/targeturi"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/targetimage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


Download the files.

Monday, April 25, 2011

Read EXIF of JPG file

Work on the exercise "Display Gallery selected image using BitmapFactory", function of reading EXIF is added.

EXIF of JPG file

A new class MyExif is implemented to handle the operation on the JPG file, it's used to read EXIF. (May be more functions will be added later)

Note that it's target for API Level 8, Android 2.2, other version will provide more or less TAG of EXIF.

MyExif.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.database.Cursor;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;

public class MyExif {

private File exifFile; //It's the file passed from constructor
private String exifFilePath; //file in Real Path format
private Activity parentActivity; //Parent Activity

private String exifFilePath_withoutext;
private String ext;

private ExifInterface exifInterface;
private Boolean exifValid = false;;

//Exif TAG
//for API Level 8, Android 2.2
private String exif_DATETIME = "";
private String exif_FLASH = "";
private String exif_FOCAL_LENGTH = "";
private String exif_GPS_DATESTAMP = "";
private String exif_GPS_LATITUDE = "";
private String exif_GPS_LATITUDE_REF = "";
private String exif_GPS_LONGITUDE = "";
private String exif_GPS_LONGITUDE_REF = "";
private String exif_GPS_PROCESSING_METHOD = "";
private String exif_GPS_TIMESTAMP = "";
private String exif_IMAGE_LENGTH = "";
private String exif_IMAGE_WIDTH = "";
private String exif_MAKE = "";
private String exif_MODEL = "";
private String exif_ORIENTATION = "";
private String exif_WHITE_BALANCE = "";

//Constructor from path
MyExif(String fileString, Activity parent){
exifFile = new File(fileString);
parentActivity = parent;
exifFilePath = fileString;
PrepareExif();
}

//Constructor from URI
MyExif(Uri fileUri, Activity parent){
exifFile = new File(fileUri.toString());
parentActivity = parent;
exifFilePath = getRealPathFromURI(fileUri);
PrepareExif();
}

private void PrepareExif(){

int dotposition= exifFilePath.lastIndexOf(".");
exifFilePath_withoutext = exifFilePath.substring(0,dotposition);
ext = exifFilePath.substring(dotposition + 1, exifFilePath.length());

if (ext.equalsIgnoreCase("jpg")){
try {
exifInterface = new ExifInterface(exifFilePath);
ReadExifTag();
exifValid = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

private void ReadExifTag(){

exif_DATETIME = exifInterface.getAttribute(ExifInterface.TAG_DATETIME);
exif_FLASH = exifInterface.getAttribute(ExifInterface.TAG_FLASH);
exif_FOCAL_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
exif_GPS_DATESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
exif_GPS_LATITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
exif_GPS_LATITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
exif_GPS_LONGITUDE = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
exif_GPS_LONGITUDE_REF = exifInterface.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
exif_GPS_PROCESSING_METHOD = exifInterface.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
exif_GPS_TIMESTAMP = exifInterface.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
exif_IMAGE_LENGTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_LENGTH);
exif_IMAGE_WIDTH = exifInterface.getAttribute(ExifInterface.TAG_IMAGE_WIDTH);
exif_MAKE = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
exif_MODEL = exifInterface.getAttribute(ExifInterface.TAG_MODEL);
exif_ORIENTATION = exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION);
exif_WHITE_BALANCE = exifInterface.getAttribute(ExifInterface.TAG_WHITE_BALANCE);

}

private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = parentActivity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}

public String getSummary(){
if(!exifValid){
return ("Invalide EXIF!");
}else{
return( exifFilePath + " : \n" +

"Name without extension: " + exifFilePath_withoutext + "\n" +
"with extension: " + ext + "\n" +

"Date Time: " + exif_DATETIME + "\n" +
"Flash: " + exif_FLASH + "\n" +
"Focal Length: " + exif_FOCAL_LENGTH + "\n" +
"GPS Date Stamp: " + exif_GPS_DATESTAMP + "\n" +
"GPS Latitude: " + exif_GPS_LATITUDE + "\n" +
"GPS Latitute Ref: " + exif_GPS_LATITUDE_REF + "\n" +
"GPS Longitude: " + exif_GPS_LONGITUDE + "\n" +
"GPS Longitude Ref: " + exif_GPS_LONGITUDE_REF + "\n" +
"Processing Method: " + exif_GPS_PROCESSING_METHOD + "\n" +
"GPS Time Stamp: " + exif_GPS_TIMESTAMP + "\n" +
"Image Length: " + exif_IMAGE_LENGTH + "\n" +
"Image Width: " + exif_IMAGE_WIDTH + "\n" +
"Make: " + exif_MAKE + "\n" +
"Model: " + exif_MODEL + "\n" +
"Orientation: " + exif_ORIENTATION + "\n" +
"White Balance: " + exif_WHITE_BALANCE + "\n");
}
}
}


AndroidSelectImage.java
package com.exercise.AndroidSelectImage;

import java.io.File;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class AndroidSelectImage extends Activity {

TextView textTargetUri;
ImageView targetImage;

File targetFile;
String exifAttribute;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonLoadImage = (Button)findViewById(R.id.loadimage);
textTargetUri = (TextView)findViewById(R.id.targeturi);
targetImage = (ImageView)findViewById(R.id.targetimage);

buttonLoadImage.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 0);
}});
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK){
Uri targetUri = data.getData();

Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(targetUri));
targetImage.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

MyExif myExif = new MyExif(targetUri, this);
textTargetUri.setText(myExif.getSummary());
}
}

}


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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/loadimage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Load Image"
/>
<TextView
android:id="@+id/targeturi"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ImageView
android:id="@+id/targetimage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidSelectImage"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidSelectImage"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
<uses-sdk android:minSdkVersion="8" />

</manifest>


Download the files.

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

Sunday, April 24, 2011

Convert URI to real path format

In the exercises "Select Image using Android build-in Gallery" ad "Display Gallery selected image using BitmapFactory", the uri returned from build-in Gallery app is in the format of "content://media/external/images/...". To convert it to the real path format (eg. /mnt/sdcard/dropbox/Eric/....png), the following function can be used.

 public String getRealPathFromURI(Uri contentUri) {
       String[] proj = { MediaStore.Images.Media.DATA };
       Cursor cursor = managedQuery(contentUri, proj, null, null, null);
       int column_index
  = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       return cursor.getString(column_index);
   }


in real path format

Related: Convert between Uri and file path, and load Bitmap from.

Saturday, April 23, 2011

Update Notification

Each notification is uniquely identified by the NotificationManager with an integer ID, the notification can be revised by calling setLatestEventInfo() with new values, change some field values of the Notification, and then call notify() again.

It's a exercise demonstrate how to updte notification, modified from exercise "Start a service to send Notification".

Update Notification

The service will be started when App start. To make it clear to understand, two buttons are implemented to request service to send notification using different Notification ID. Use enter target URL in the EditText field, and click any button to send notification, it will be send out and update notification with the ID.

Layout, 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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="\nService Start in App Start\n"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Target address to open in Browser"
/>
<EditText
android:id="@+id/targetaddr"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/sendnotification_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Send Notification ID 1"
/>
<Button
android:id="@+id/sendnotification_2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Send Notification ID 2"
/>
<Button
android:id="@+id/stopservice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop Service"
/>
</LinearLayout>


Main activity, AndroidNotifyService.java
package com.exercise.AndroidNotifyService;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class AndroidNotifyService extends Activity {

EditText targetAddr;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button buttonStopService = (Button)findViewById(R.id.stopservice);
Button buttonSendNotification1 = (Button)findViewById(R.id.sendnotification_1);
Button buttonSendNotification2 = (Button)findViewById(R.id.sendnotification_2);
targetAddr = (EditText)findViewById(R.id.targetaddr);

//Start the service in App start, instead of clicking button
Intent intent = new Intent(AndroidNotifyService.this, com.exercise.AndroidNotifyService.NotifyService.class);
AndroidNotifyService.this.startService(intent);

buttonStopService.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction(NotifyService.ACTION);
intent.putExtra("RQS", NotifyService.RQS_STOP_SERVICE);
sendBroadcast(intent);
}});

buttonSendNotification1.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction(NotifyService.ACTION);
intent.putExtra("RQS", NotifyService.RQS_SEND_NOTIFICATION_1);
intent.putExtra("TARGET", targetAddr.getText().toString());
sendBroadcast(intent);
}});

buttonSendNotification2.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction(NotifyService.ACTION);
intent.putExtra("RQS", NotifyService.RQS_SEND_NOTIFICATION_2);
intent.putExtra("TARGET", targetAddr.getText().toString());
sendBroadcast(intent);
}});

}
}


The service, NotifyService.java
package com.exercise.AndroidNotifyService;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.IBinder;

public class NotifyService extends Service {

final static String ACTION = "NotifyServiceAction";
//final static String STOP_SERVICE = "";
final static int RQS_STOP_SERVICE = 1;
final static int RQS_SEND_NOTIFICATION_1 = 2;
final static int RQS_SEND_NOTIFICATION_2 = 3;

NotifyServiceReceiver notifyServiceReceiver;

private static final int MY_NOTIFICATION_ID_1=1;
private static final int MY_NOTIFICATION_ID_2=2;
private NotificationManager notificationManager;
private Notification myNotification;

Context myContext;
String myNotificationTitle = "Exercise of Notification!";

@Override
public void onCreate() {
// TODO Auto-generated method stub
notifyServiceReceiver = new NotifyServiceReceiver();
super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(notifyServiceReceiver, intentFilter);

// Send Notification
notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
myNotification = new Notification(R.drawable.icon,
"Notification!",
System.currentTimeMillis());
myContext = getApplicationContext();
myNotification.defaults |= Notification.DEFAULT_SOUND;
myNotification.flags |= Notification.FLAG_AUTO_CANCEL;

return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
this.unregisterReceiver(notifyServiceReceiver);
super.onDestroy();
}

@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}

public class NotifyServiceReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
int rqs = arg1.getIntExtra("RQS", 0);
if (rqs == RQS_STOP_SERVICE){
stopSelf();
}else if(rqs == RQS_SEND_NOTIFICATION_1){
String myTarget = arg1.getStringExtra("TARGET");
SendNotification(MY_NOTIFICATION_ID_1, myTarget);

}else if(rqs == RQS_SEND_NOTIFICATION_2){
String myTarget = arg1.getStringExtra("TARGET");
SendNotification(MY_NOTIFICATION_ID_2, myTarget);
}
}

private void SendNotification(int id, String target){
String notificationText = target;
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(target));
PendingIntent pendingIntent
= PendingIntent.getActivity(myContext,
0, myIntent,
Intent.FLAG_ACTIVITY_NEW_TASK);

myNotification.setLatestEventInfo(myContext,
myNotificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(id, myNotification);
}
}

}


AndroidManifest.xml, to include NotifyService.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidNotifyService"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidNotifyService"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".NotifyService"/>
</application>
</manifest>


Download the files.

Friday, April 22, 2011

Send Notification inside background Thread

In my old exercise, it's shown how to "Start a service to send Notification". It's modified to send the notification inside a background thread here.

package com.exercise.AndroidThreadNotification;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;

public class AndroidThreadNotification extends Activity {

BackgroundThread backgroundThread;
Handler backgroundHandler;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
backgroundThread = new BackgroundThread();
backgroundThread.setRunning(true);
backgroundThread.start();
}

@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
boolean retry = true;
backgroundThread.setRunning(false);

while(retry){
try {
backgroundThread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

public class BackgroundThread extends Thread {
boolean running = false;
final static String ACTION = "NotifyServiceAction";
NotificationManager notificationManager;
Notification myNotification;
private final String myBlog = "http://android-er.blogspot.com/";
private static final int MY_NOTIFICATION_ID=1;

void setRunning(boolean b){
running = b;
}

@Override
public synchronized void start() {
// TODO Auto-generated method stub
super.start();
notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
}

@Override
public void run() {
// TODO Auto-generated method stub
while(running){
try {
sleep(10000); //send notification in every 10sec.
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// Send Notification
myNotification = new Notification(R.drawable.icon,
"Notification!",
System.currentTimeMillis());
Context context = getApplicationContext();
String notificationTitle = "Exercise of Notification!";
String notificationText = "http://android-er.blogspot.com/";
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog));
PendingIntent pendingIntent
= PendingIntent.getActivity(getBaseContext(),
0, myIntent,
Intent.FLAG_ACTIVITY_NEW_TASK);
myNotification.defaults |= Notification.DEFAULT_SOUND;
myNotification.flags |= Notification.FLAG_AUTO_CANCEL;
myNotification.setLatestEventInfo(context,
notificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
}
}
}
}


Download the files.

HelloGallery, read picture files from SD, display in ImageView.

It's a old exercise "HelloGallery, read picture files from SD, using File ArrayList" to demonstrate how to use Gallery. It's modified to add a ImageView to show the large version of the clicked item in Gallery.

HelloGallery, read picture files from SD, display in ImageView.

Create a file /res/values/attrs.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Theme">
<attr name="android:galleryItemBackground" />
</declare-styleable>
</resources>


Modify /res/layout/main.xml to include a Gallery and ImageView.
<?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">
<Gallery
android:id="@+id/gallery"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/imageview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>


Main code, HelloGallery.java.
package com.exercise.HelloGallery;

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

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class HelloGallery extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

final ImageView imageView = (ImageView)findViewById(R.id.imageview);

Gallery g = (Gallery) findViewById(R.id.gallery);
final List<String> SD = ReadSDCard();
g.setAdapter(new ImageAdapter(this, SD));

g.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent,
View v, int position, long id) {

String imageInSD = SD.get(position);

Toast.makeText(HelloGallery.this,
imageInSD,
Toast.LENGTH_LONG).show();

Bitmap bitmap = BitmapFactory.decodeFile(imageInSD);
imageView.setImageBitmap(bitmap);

}
});
}

private List<String> ReadSDCard()
{
List<String> tFileList = new ArrayList<String>();

//It have to be matched with the directory in SDCard
File f = new File("/sdcard/pictures/");

File[] files=f.listFiles();

for(int i=0; i<files.length; i++)
{
File file = files[i];
//add the selected file type only
String curFile=file.getPath();
String ext=curFile.substring(curFile.lastIndexOf(".")+1,
curFile.length()).toLowerCase();
if(ext.equals("jpg")||ext.equals("gif")||ext.equals("png"))
tFileList.add(file.getPath());
}

return tFileList;
}

public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
private List<String> FileList;

public ImageAdapter(Context c, List<String> fList) {
mContext = c;
FileList = fList;
TypedArray a = obtainStyledAttributes(R.styleable.Theme);
mGalleryItemBackground = a.getResourceId(
R.styleable.Theme_android_galleryItemBackground,
0);
a.recycle();
}

public int getCount() {
return FileList.size();
}

public Object getItem(int position) {
return position;
}

public long getItemId(int position) {
return position;
}

public View getView(int position, View convertView,
ViewGroup parent) {
ImageView i = new ImageView(mContext);

Bitmap bm = BitmapFactory.decodeFile(
FileList.get(position).toString());
i.setImageBitmap(bm);

i.setLayoutParams(new Gallery.LayoutParams(150, 100));
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setBackgroundResource(mGalleryItemBackground);

return i;
}
}
}


Download the files.


next:
- HelloGallery, read picture files from SD, display in ImageView, and set as Wallpaper

Wednesday, April 20, 2011

Unzip compressed file, using java.util.zip

java.util.zip package of Android can help to extract compressed file in ZIP format.

Modify from previous exercise "How to get file extension using java code", implement a function unzip().

If the extention of the returned file using Intent.ACTION_GET_CONTENT" is "zip", call the function unzip() to extract compressed file.

package com.exercise.AndroidPick_a_File;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

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

public class AndroidPick_a_File extends Activity {

TextView textFile, textFileName, textFolder;
TextView textFileName_WithoutExt, textFileName_Ext;

private static final int PICKFILE_RESULT_CODE = 1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button buttonPick = (Button)findViewById(R.id.buttonpick);
textFile = (TextView)findViewById(R.id.textfile);
textFolder = (TextView)findViewById(R.id.textfolder);
textFileName = (TextView)findViewById(R.id.textfilename);

textFileName_WithoutExt
= (TextView)findViewById(R.id.textfilename_withoutext);
textFileName_Ext
= (TextView)findViewById(R.id.textfilename_ext);

buttonPick.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent,PICKFILE_RESULT_CODE);

}});
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {
// TODO Auto-generated method stub
switch(requestCode){
case PICKFILE_RESULT_CODE:
if(resultCode==RESULT_OK){

String FilePath = data.getData().getPath();
String FileName = data.getData().getLastPathSegment();
int lastPos = FilePath.length() - FileName.length();
String Folder = FilePath.substring(0, lastPos);

textFile.setText("Full Path: \n" + FilePath + "\n");
textFolder.setText("Folder: \n" + Folder + "\n");
textFileName.setText("File Name: \n" + FileName + "\n");

filename thisFile = new filename(FileName);

textFileName_WithoutExt.setText("Filename without Ext: "
+ thisFile.getFilename_Without_Ext());
textFileName_Ext.setText("Ext: " + thisFile.getExt());

if(thisFile.getExt().equalsIgnoreCase("zip")){
unzip(FilePath, Folder);
}

}
break;

}
}

private class filename{

String filename_Without_Ext = "";
String ext = "";

filename(String file){
int dotposition= file.lastIndexOf(".");
filename_Without_Ext = file.substring(0,dotposition);
ext = file.substring(dotposition + 1, file.length());
}

String getFilename_Without_Ext(){
return filename_Without_Ext;
}

String getExt(){
return ext;
}
}

private void unzip(String src, String dest){

final int BUFFER_SIZE = 4096;

BufferedOutputStream bufferedOutputStream = null;
FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(src);
ZipInputStream zipInputStream
= new ZipInputStream(new BufferedInputStream(fileInputStream));
ZipEntry zipEntry;

while ((zipEntry = zipInputStream.getNextEntry()) != null){

String zipEntryName = zipEntry.getName();
File file = new File(dest + zipEntryName);

if (file.exists()){

} else {
if(zipEntry.isDirectory()){
file.mkdirs();
}else{
byte buffer[] = new byte[BUFFER_SIZE];
FileOutputStream fileOutputStream = new FileOutputStream(file);
bufferedOutputStream
= new BufferedOutputStream(fileOutputStream, BUFFER_SIZE);
int count;

while ((count
= zipInputStream.read(buffer, 0, BUFFER_SIZE)) != -1) {
bufferedOutputStream.write(buffer, 0, count);
}

bufferedOutputStream.flush();
bufferedOutputStream.close();
}
}
}
zipInputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


Keep using the layout file main.xml in the previous exercise "How to get file extension using java code".

In order to write back the extracted files, modify AndroidManifest.xml to grant permission of "android.permission.WRITE_EXTERNAL_STORAGE".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidPick_a_File"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidPick_a_File"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
</manifest>


Download the files.

Monday, April 18, 2011

Read Text file from internet, using Java code

This exercise show how to read text file from internet. The file's url is hard coded to be "http://sites.google.com/site/androidersite/text.txt".

Read Text file from internet, using Java code

package com.exercise.AndroidInternetTxt;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class AndroidInternetTxt extends Activity {

TextView textMsg, textPrompt;
final String textSource = "http://sites.google.com/site/androidersite/text.txt";

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textPrompt = (TextView)findViewById(R.id.textprompt);
textMsg = (TextView)findViewById(R.id.textmsg);

textPrompt.setText("Wait...");

URL textUrl;
try {
textUrl = new URL(textSource);
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(textUrl.openStream()));
String StringBuffer;
String stringText = "";
while ((StringBuffer = bufferReader.readLine()) != null) {
stringText += StringBuffer;
}
bufferReader.close();
textMsg.setText(stringText);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
textMsg.setText(e.toString());
}

textPrompt.setText("Finished!");

}
}


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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:id="@+id/textprompt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textmsg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>


Modify AndroidManifest.xml to grant permission of "android.permission.INTERNET".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidInternetTxt"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidInternetTxt"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
</manifest>


Download the files.

Sunday, April 17, 2011

How to get file extension using java code

To get extension, we can use the following java code:

int dotposition= file.lastIndexOf(".");
filename_Without_Ext = file.substring(0,dotposition);
ext = file.substring(dotposition + 1, file.length());


Modify last exercise "More for Pick a file using Intent.ACTION_GET_CONTENT", a new class filename is implemented to get file extention and filename without extention.

get file extension using java code

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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/buttonpick"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="- PICK a file -"
/>
<TextView
android:id="@+id/textfile"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfolder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfilename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfilename_withoutext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfilename_ext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>


main code
package com.exercise.AndroidPick_a_File;

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

public class AndroidPick_a_File extends Activity {

TextView textFile, textFileName, textFolder;
TextView textFileName_WithoutExt, textFileName_Ext;

private static final int PICKFILE_RESULT_CODE = 1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button buttonPick = (Button)findViewById(R.id.buttonpick);
textFile = (TextView)findViewById(R.id.textfile);
textFolder = (TextView)findViewById(R.id.textfolder);
textFileName = (TextView)findViewById(R.id.textfilename);

textFileName_WithoutExt = (TextView)findViewById(R.id.textfilename_withoutext);
textFileName_Ext = (TextView)findViewById(R.id.textfilename_ext);

buttonPick.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent,PICKFILE_RESULT_CODE);

}});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
switch(requestCode){
case PICKFILE_RESULT_CODE:
if(resultCode==RESULT_OK){

String FilePath = data.getData().getPath();
String FileName = data.getData().getLastPathSegment();
int lastPos = FilePath.length() - FileName.length();
String Folder = FilePath.substring(0, lastPos);

textFile.setText("Full Path: \n" + FilePath + "\n");
textFolder.setText("Folder: \n" + Folder + "\n");
textFileName.setText("File Name: \n" + FileName + "\n");

filename thisFile = new filename(FileName);
textFileName_WithoutExt.setText("Filename without Ext: " + thisFile.getFilename_Without_Ext());
textFileName_Ext.setText("Ext: " + thisFile.getExt());

}
break;

}
}

private class filename{

String filename_Without_Ext = "";
String ext = "";

filename(String file){
int dotposition= file.lastIndexOf(".");
filename_Without_Ext = file.substring(0,dotposition);
ext = file.substring(dotposition + 1, file.length());
}

String getFilename_Without_Ext(){
return filename_Without_Ext;
}

String getExt(){
return ext;
}
}

}


Download the files.

Related:
- Unzip compressed file, using java.util.zip

Thursday, April 14, 2011

More for Pick a file using Intent.ACTION_GET_CONTENT

In the exercise "Pick a file using Intent.ACTION_GET_CONTENT", with full path of the returned file. It will will modified to retrieve the folder path, and file name.

More for Pick a file using Intent.ACTION_GET_CONTENT

package com.exercise.AndroidPick_a_File;

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

public class AndroidPick_a_File extends Activity {

TextView textFile, textFileName, textFolder;

private static final int PICKFILE_RESULT_CODE = 1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button buttonPick = (Button)findViewById(R.id.buttonpick);
textFile = (TextView)findViewById(R.id.textfile);
textFolder = (TextView)findViewById(R.id.textfolder);
textFileName = (TextView)findViewById(R.id.textfilename);

buttonPick.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("file/*");
startActivityForResult(intent,PICKFILE_RESULT_CODE);

}});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
switch(requestCode){
case PICKFILE_RESULT_CODE:
if(resultCode==RESULT_OK){

String FilePath = data.getData().getPath();
String FileName = data.getData().getLastPathSegment();
int lastPos = FilePath.length() - FileName.length();
String Folder = FilePath.substring(0, lastPos);

textFile.setText("Full Path: \n" + FilePath + "\n");
textFolder.setText("Folder: \n" + Folder + "\n");
textFileName.setText("File Name: \n" + FileName + "\n");
}
break;

}
}
}


<?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"
/>
<Button
android:id="@+id/buttonpick"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="- PICK a file -"
/>
<TextView
android:id="@+id/textfile"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfolder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textfilename"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>


Download the files.

Related:
- How to get file extension using java code

Wednesday, April 13, 2011

Auto start a service with Intent of "android.intent.action.BOOT_COMPLETED" action

Last exercise "Start a service to send Notification" show how to start a service by user clicking in a activity. In this exercise, a BroadcastReceiver will be implemented to receive Intent of "android.intent.action.BOOT_COMPLETED" action after power-up, no interactive with user.

"android.intent.action.BOOT_COMPLETED" is Broadcast Action, is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.

Create a new class AutoStartNotifyReceiver.java, extends BroadcastReceiver. Simple do the same thing as that in Start button OnClickListener in last exercise "Start a service to send Notification", start a service.
package com.exercise.AndroidNotifyService;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class AutoStartNotifyReceiver extends BroadcastReceiver {

private final String BOOT_COMPLETED_ACTION = "android.intent.action.BOOT_COMPLETED";

@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub

if(intent.getAction().equals(BOOT_COMPLETED_ACTION)){
Intent myIntent = new Intent(context, com.exercise.AndroidNotifyService.NotifyService.class);
context.startService(myIntent);
}

}

}


In order to receive Intent of "android.intent.action.BOOT_COMPLETED", modify AndroidManifest.xml to add <receiver> for AutoStartNotifyReceiver, also grant permission of "android.permission.RECEIVE_BOOT_COMPLETED".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidNotifyService"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidNotifyService"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".NotifyService"/>
<receiver android:name=".AutoStartNotifyReceiver" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
</application>
</manifest>


Keep using the other files implemented in last exercise "Start a service to send Notification".

Download the files.

Tuesday, April 12, 2011

Start a service to send Notification

Last exercise show how to "send a Notification" in activity. In this exercise, main activity start a service, and notification is sent in service run in background.

Start a service to send Notification

main.xml to have buttons to start and stop service.
<?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"
/>
<Button
android:id="@+id/startservice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Service to send Notification"
/>
<Button
android:id="@+id/stopservice"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Stop Service"
/>
</LinearLayout>

main activity, AndroidNotifyService.java simple start and stop the service.
package com.exercise.AndroidNotifyService;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class AndroidNotifyService extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonStartService = (Button)findViewById(R.id.startservice);
Button buttonStopService = (Button)findViewById(R.id.stopservice);

buttonStartService.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(AndroidNotifyService.this, com.exercise.AndroidNotifyService.NotifyService.class);
AndroidNotifyService.this.startService(intent);
}});

buttonStopService.setOnClickListener(new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction(NotifyService.ACTION);
intent.putExtra("RQS", NotifyService.STOP_SERVICE);
sendBroadcast(intent);
}});

}
}
[================================================
Correction@2011-0424: Please change the code
intent.putExtra("RQS", NotifyService.STOP_SERVICE);
to
intent.putExtra("RQS", NotifyService.RQS_STOP_SERVICE);
================================================]

NotifyService.java, our service to send notification.
package com.exercise.AndroidNotifyService;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.IBinder;

public class NotifyService extends Service {

final static String ACTION = "NotifyServiceAction";
final static String STOP_SERVICE = "";
final static int RQS_STOP_SERVICE = 1;

NotifyServiceReceiver notifyServiceReceiver;

private static final int MY_NOTIFICATION_ID=1;
private NotificationManager notificationManager;
private Notification myNotification;
private final String myBlog = "http://android-er.blogspot.com/";

@Override
public void onCreate() {
// TODO Auto-generated method stub
notifyServiceReceiver = new NotifyServiceReceiver();
super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(notifyServiceReceiver, intentFilter);

// Send Notification
notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
myNotification = new Notification(R.drawable.icon,
"Notification!",
System.currentTimeMillis());
Context context = getApplicationContext();
String notificationTitle = "Exercise of Notification!";
String notificationText = "http://android-er.blogspot.com/";
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog));
PendingIntent pendingIntent
= PendingIntent.getActivity(getBaseContext(),
0, myIntent,
Intent.FLAG_ACTIVITY_NEW_TASK);
myNotification.defaults |= Notification.DEFAULT_SOUND;
myNotification.flags |= Notification.FLAG_AUTO_CANCEL;
myNotification.setLatestEventInfo(context,
notificationTitle,
notificationText,
pendingIntent);
notificationManager.notify(MY_NOTIFICATION_ID, myNotification);

return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
this.unregisterReceiver(notifyServiceReceiver);
super.onDestroy();
}

@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}

public class NotifyServiceReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
int rqs = arg1.getIntExtra("RQS", 0);
if (rqs == RQS_STOP_SERVICE){
stopSelf();
}
}
}

}


Modify AndroidManifest.xml to add our service.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidNotifyService"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AndroidNotifyService"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".NotifyService"/>
</application>
</manifest>


Download the files.

Related:
- Auto start a service with Intent of "android.intent.action.BOOT_COMPLETED" action
- Send Notification inside background Thread
- Update Notification

Monday, April 11, 2011

A simple example to send a Notification

A simple example to send a Notification

package com.exercise.AndroidNotification;

import java.util.Calendar;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class AndroidNotification extends Activity {

private static final int MY_NOTIFICATION_ID=1;
private NotificationManager notificationManager;
private Notification myNotification;

private final String myBlog = "http://android-er.blogspot.com/";

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       Button buttonSend = (Button)findViewById(R.id.send);
      
       buttonSend.setOnClickListener(new Button.OnClickListener(){

  @Override
  public void onClick(View arg0) {
   // TODO Auto-generated method stub
   notificationManager =
    (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
   myNotification = new Notification(R.drawable.icon,
     "Notification!",
     System.currentTimeMillis());
   Context context = getApplicationContext();
   String notificationTitle = "Exercise of Notification!";
   String notificationText = "http://android-er.blogspot.com/";
   Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog));
   PendingIntent pendingIntent
     = PendingIntent.getActivity(AndroidNotification.this,
       0, myIntent,
       Intent.FLAG_ACTIVITY_NEW_TASK);
   myNotification.defaults |= Notification.DEFAULT_SOUND;
   myNotification.flags |= Notification.FLAG_AUTO_CANCEL;
   myNotification.setLatestEventInfo(context,
      notificationTitle,
      notificationText,
      pendingIntent);
   notificationManager.notify(MY_NOTIFICATION_ID, myNotification);
  
  }});
   }
}


<?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"
   />
<Button
   android:id="@+id/send"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="Send a Notification"
   />
</LinearLayout>


Download the files.

Related Article:
- Start a service to send Notification

Updated:
- The Notification.Builder has been added to make it easier to construct Notifications.

Sunday, April 10, 2011

Adobe® Photoshop® Touch SDK preview for Adobe Photoshop CS5

The Photoshop Touch SDK allows applications on Android™, Blackberry, and iOS mobile and tablet devices, as well as Mac OS and Windows® operating systems, to interact with Photoshop CS5.

With this SDK, developers can create and enable apps to drive and/or communicate with Photoshop CS5 (version 12.0.4 or later) via a TCP connection. It’s now possible for developers to create an eBook of Photoshop tutorials that allows users to drive an Action within Photoshop CS5 from within the eBook. Or, if you find yourself inspired by an ocean view, use a tablet device to mix the colors you see and send those colors directly back to Photoshop CS5 without ever leaving the beach. There are so many possibilities, and with the Photoshop Touch SDK, Adobe is opening Photoshop up to the community to bring these, and other scenarios we haven’t even imagined yet to life.

This SDK delivers a completely new way for people to enhance, transform and enjoy the billions of images captured on devices of all types. We can’t wait to see what you create.

link:
- http://www.adobe.com/devnet/photoshop.html

Google I/O Live - join Google I/O anywhere!


Visit www.google.com/io on May 10-11 from anywhere you have a reliable Internet connection for I/O Live.

I/O Live will bring all of the excitement at Moscone Center to our website, where the keynotes, sessions and Developer Sandbox will come to life for audiences all over the world.



Google Maps API/Google Earth APIs Terms of Service updated - you should know

Google Maps API/Google Earth APIs Terms of Service updated with a number of notable changes.

Developers are now permitted to use the Static Maps API outside of a web browser. Developers of mobile apps that are sold for a fee through an online store such as the Android Market and Apple App Store no longer require a Google Maps API Premier license. This brings the Terms of the web based Maps APIs into line with the Terms of the Android Maps API and iOS SDK.

There are also a number of changes that relate to advertising and usage limits. It is required that any new Maps API applications going forward display any advertising delivered in the maps imagery, unless the site concerned has a Google Maps API Premier license. The opt-out from displaying such advertising that was offered in earlier versions of the Terms will continue to apply to any existing Maps API applications...

...and much more.

If you are developing, will develop Android App using Google Maps API, you should read it.
- Google Geo Developers Blog - Updates to the Google Maps API/Google Earth APIs Terms of Service.

Mono for Android: develop Anroid app on C# and .NET, by Novell.

Mono for Android enables developers to use Microsoft™ Visual Studio™ to create C# and .NET based applications that run on Android phones and tablets. Developers can use their existing skills and reuse code and libraries that have been built with .NET, while taking advantage of native Android APIs.

- http://mono-android.net/

Thursday, April 7, 2011

A simple exercise of Video Capture using MediaRecorder

This exercise cannot run on Android 2.3 and higher, please refer A simple exercise of Video Capture using MediaRecorder, for Android 2.3 or higher for updated version.

------------------------------------------------------

It's a A simple exercise of Video Capture. Please note that it only show the simple steps to achieve video capture, without handle the various exception case. The app start with a video preview in a SurfaceView, and some initialization of MediaRecorder. When user click on the REC button, the video capture will be started, once user click on the STOP button, recording will be stopped, and the video will be save in "/sdcard/myvideo.mp4".

A simple exercise of Video Capture using MediaRecorder

First of all, modify AndroidManifest.xml to set screen orientation of landscape, and theme of fullscreen, such that we have more space for our preview. And also grant permission of "android.permission.RECORD_AUDIO", "android.permission.CAMERA" and "android.permission.WRITE_EXTERNAL_STORAGE".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.exercise.AndroidVideoCapture"
     android:versionCode="1"
     android:versionName="1.0">
   <uses-sdk android:minSdkVersion="8" />

   <application android:icon="@drawable/icon" android:label="@string/app_name">
       <activity android:name=".AndroidVideoCapture"
                 android:label="@string/app_name"
                 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                 android:screenOrientation="landscape">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>

   </application>
   <uses-permission android:name="android.permission.RECORD_AUDIO"/>
   <uses-permission android:name="android.permission.CAMERA"/>
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>


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"
   >
<LinearLayout
   android:orientation="horizontal"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
<SurfaceView
android:id="@+id/videoview"
android:layout_width="720px"
android:layout_height="480px"/>
<Button
android:id="@+id/mybutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="REC"
android:textSize="12dp"/>
</LinearLayout>
</LinearLayout>


package com.exercise.AndroidVideoCapture;

import java.io.IOException;

import android.app.Activity;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;

public class AndroidVideoCapture extends Activity implements SurfaceHolder.Callback{

Button myButton;
MediaRecorder mediaRecorder;
SurfaceHolder surfaceHolder;
boolean recording;

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
      
       recording = false;
      
       mediaRecorder = new MediaRecorder();
       initMediaRecorder();
      
       setContentView(R.layout.main);
      
       SurfaceView myVideoView = (SurfaceView)findViewById(R.id.videoview);
       surfaceHolder = myVideoView.getHolder();
       surfaceHolder.addCallback(this);
       surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
      
       myButton = (Button)findViewById(R.id.mybutton);
       myButton.setOnClickListener(myButtonOnClickListener);
   }
  
   private Button.OnClickListener myButtonOnClickListener
   = new Button.OnClickListener(){

 @Override
 public void onClick(View arg0) {
  // TODO Auto-generated method stub
  if(recording){
   mediaRecorder.stop();
   mediaRecorder.release();
   finish();
  }else{
   mediaRecorder.start();
   recording = true;
   myButton.setText("STOP");
  }
 }};
  
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
 // TODO Auto-generated method stub

}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
 // TODO Auto-generated method stub
 prepareMediaRecorder();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
 // TODO Auto-generated method stub

}

private void initMediaRecorder(){
 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
       mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
       CamcorderProfile camcorderProfile_HQ = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
       mediaRecorder.setProfile(camcorderProfile_HQ);
       mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
       mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
       mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M
}

private void prepareMediaRecorder(){
 mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
 try {
  mediaRecorder.prepare();
 } catch (IllegalStateException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
}
}


Related Articles:
- Start Video Recording using android.provider.MediaStore.ACTION_VIDEO_CAPTURE
- CamcorderProfile: predefined camcorder profile settings for camcorder applications