Saturday, July 30, 2011

Draw on a custom View over MapView

By using FrameLayout, we can create a custom View overlap with a MapView, such that we can draw on the canvas of the customer View. Also we can call MapView.getProjection().fromPixels(x, y) to get the coresponding coordinates on the map.

Draw on a custom View over MapView

Further work on the last exercise "Get the the coordinates (Latitude and Longitude) currently displayed on MapView".

Create the custom view, MyView.java
package com.exercise.AndroidMap;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

Paint myPaint;

float x1, y1; //Top Left point
float x2, y2; //Bottom Right point

public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init(){
myPaint = new Paint();
myPaint.setColor(Color.WHITE);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3);
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
int w = getWidth();
int h = getHeight();

x1 = (float)w/4;
x2 = (float)w * 3/4;
y1 = (float)h/4;
y2 = (float)h *3/4;

canvas.drawRect(x1, y1, x2, y2, myPaint);
}

public float getx1(){
return x1;
}

public float getx2(){
return x2;
}

public float gety1(){
return y1;
}

public float gety2(){
return y2;
}

}


main.xml, include own custom View overlap with MapView, using FrameLayout.
<?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/getinfo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Get Info"
/>
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.maps.MapView
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="0PE9qMoMP-Wy2MijPaIfdbg7dUHlub6gWJe-xQw" />
<com.exercise.AndroidMap.MyView
android:id="@+id/myview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
</LinearLayout>


main code, AndroidMapActivity.java
package com.exercise.AndroidMap;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class AndroidMapActivity extends MapActivity {

MapView myMap;
MyView myView;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myMap = (MapView) findViewById(R.id.map);
myMap.setBuiltInZoomControls(true);

Button buttonGetInfo = (Button)findViewById(R.id.getinfo);
buttonGetInfo.setOnClickListener(buttonGetInfoOnClickListener);

myView = (MyView)findViewById(R.id.myview);
}

@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}

Button.OnClickListener buttonGetInfoOnClickListener
= new Button.OnClickListener(){

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

GeoPoint mapCenter = myMap.getMapCenter();

float centerLatitude = (float)(mapCenter.getLatitudeE6())/1000000;
float centerLongitude = (float)(mapCenter.getLongitudeE6())/1000000;

float latitudeSpan = (float)(myMap.getLatitudeSpan())/1000000;
float longitudeSpan = (float)(myMap.getLongitudeSpan()/1000000);

GeoPoint mapTopLeft
= myMap.getProjection().fromPixels((int)myView.getx1(), (int)myView.gety1());
float topLatitude = (float)(mapTopLeft.getLatitudeE6())/1000000;
float leftLongitude = (float)(mapTopLeft.getLongitudeE6())/1000000;

GeoPoint mapBottomRight
= myMap.getProjection().fromPixels((int)myView.getx2(), (int)myView.gety2());
float bottomLatitude = (float)(mapBottomRight.getLatitudeE6())/1000000;
float rightLongitude = (float)(mapBottomRight.getLongitudeE6())/1000000;

int zoomLevel = myMap.getZoomLevel();

String info =
"Center: " + centerLatitude + "/" + centerLongitude + "\n"
+ "Top Left: " + topLatitude + "/" + leftLongitude + "\n"
+ "Bottom Right: " + bottomLatitude + "/" + rightLongitude + "\n"
+ "latitudeSpan: " + latitudeSpan + "\n"
+ "longitudeSpan: " + longitudeSpan + "\n"
+ "zoomLevel: " + zoomLevel;

Toast.makeText(AndroidMapActivity.this,
info,
Toast.LENGTH_LONG).show();
}};
}


AndroidManifest.xml, xml. Grand permission of "android.permission.INTERNET" and include uses-library of "com.google.android.maps".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.exercise.AndroidMap"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".AndroidMapActivity"
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-permission android:name="android.permission.INTERNET"/>
</manifest>



Download the files.

Friday, July 29, 2011

Get the the coordinates (Latitude and Longitude) currently displayed on MapView

Here is a example to get the coordinates (Latitude and Longitude) currently displayed on MapView.

Get the the coordinates (Latitude and Longitude) currently displayed on MapView

To get the coordinate of a point corspondint to a pixel on screen, we can use the method MapView.getProjection().fromPixels(x, y).

package com.exercise.AndroidMap;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class AndroidMapActivity extends MapActivity {

MapView myMap;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myMap = (MapView) findViewById(R.id.map);
myMap.setBuiltInZoomControls(true);

Button buttonGetInfo = (Button)findViewById(R.id.getinfo);
buttonGetInfo.setOnClickListener(buttonGetInfoOnClickListener);
}

@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}

Button.OnClickListener buttonGetInfoOnClickListener
= new Button.OnClickListener(){

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

GeoPoint mapCenter = myMap.getMapCenter();

float centerLatitude = (float)(mapCenter.getLatitudeE6())/1000000;
float centerLongitude = (float)(mapCenter.getLongitudeE6())/1000000;

float latitudeSpan = (float)(myMap.getLatitudeSpan())/1000000;
float longitudeSpan = (float)(myMap.getLongitudeSpan()/1000000);

GeoPoint mapTopLeft = myMap.getProjection().fromPixels(0, 0);
float topLatitude = (float)(mapTopLeft.getLatitudeE6())/1000000;
float leftLongitude = (float)(mapTopLeft.getLongitudeE6())/1000000;

GeoPoint mapBottomRight
= myMap.getProjection().fromPixels(myMap.getWidth(), myMap.getHeight());
float bottomLatitude = (float)(mapBottomRight.getLatitudeE6())/1000000;
float rightLongitude = (float)(mapBottomRight.getLongitudeE6())/1000000;

int zoomLevel = myMap.getZoomLevel();

String info =
"Center: " + centerLatitude + "/" + centerLongitude + "\n"
+ "Top Left: " + topLatitude + "/" + leftLongitude + "\n"
+ "Bottom Right: " + bottomLatitude + "/" + rightLongitude + "\n"
+ "latitudeSpan: " + latitudeSpan + "\n"
+ "longitudeSpan: " + longitudeSpan + "\n"
+ "zoomLevel: " + zoomLevel;

Toast.makeText(AndroidMapActivity.this,
info,
Toast.LENGTH_LONG).show();
}};
}


Related Article:
- A minimal Map application using MapActivity

next:
- Draw on a custom View over MapView

Thursday, July 28, 2011

Set background color of title bar

Set background color of title bar

package com.exercise.AndroidTitleBar;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;

public class AndroidTitleBarActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        View title = getWindow().findViewById(android.R.id.title);
        View titleBar = (View) title.getParent();
        titleBar.setBackgroundColor(Color.CYAN);

    }
}


Updated: Set icon and background of ActionBar

Tuesday, July 26, 2011

Confirm to Quit? Over-write the BACK key.

To over-write the BACK key, to prompt user for confirmation to quit instead of exiting directly, simply override the onBackPressed() method.

Confirm to Quit? Over-write the BACK key.

package com.exercise.AndroidConfirmQuit;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;

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

@Override
public void onBackPressed() {
// TODO Auto-generated method stub
//super.onBackPressed();
openQuitDialog();
}

private void openQuitDialog(){
AlertDialog.Builder quitDialog
= new AlertDialog.Builder(AndroidConfirmQuitActivity.this);
quitDialog.setTitle("Confirm to Quit?");

quitDialog.setPositiveButton("OK, Quit!", new OnClickListener(){

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

quitDialog.setNegativeButton("NO", new OnClickListener(){

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

}});

quitDialog.show();
}
}


Monday, July 25, 2011

Cancel/remove download from DownloadManager.

In the last exercise, "Set the title of Download on notification, setTitle()", The download query will be alway here after started, even close you app. Such that you always see the Toast of the status (such as "SUCCESSFUL") when you app start. So you have to call remove() method to clear the download, or if you want to stop it before finished.

package com.exercise.AndroidDownloadManager;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidDownloadManagerActivity extends Activity {

final String DOWNLOAD_FILE = "http://goo.gl/w3XV3";

final String strPref_Download_ID = "PREF_DOWNLOAD_ID";

SharedPreferences preferenceManager;
DownloadManager downloadManager;

ImageView image;

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

preferenceManager
= PreferenceManager.getDefaultSharedPreferences(this);
downloadManager
= (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

Button btnStartDownload = (Button)findViewById(R.id.startdownload);
btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);

image = (ImageView)findViewById(R.id.image);
}

Button.OnClickListener btnStartDownloadOnClickListener
= new Button.OnClickListener(){

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

Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);

/*
* request.setAllowedNetworkTypes()-
* Restrict the types of networks over which this download may proceed.
* By default, all network types are allowed.
* - Request.NETWORK_WIFI
* - Request.NETWORK_MOBILE
* - Request.NETWORK_WIFI | Request.NETWORK_MOBILE
*
* request.setAllowedOverRoaming(false) -
* Set whether this download may proceed over a roaming connection.
* By default, roaming is allowed.
*/
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);


/*
* Set Title of Download
*/
request.setTitle("Android-er Download!");

/*
* (for API 11 or higher!)
* Display Download in Notification
*/
//request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

long id = downloadManager.enqueue(request);

//Save the request id
Editor PrefEdit = preferenceManager.edit();
PrefEdit.putLong(strPref_Download_ID, id);
PrefEdit.commit();

}};

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

CheckDwnloadStatus();

IntentFilter intentFilter
= new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
}

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

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
CheckDwnloadStatus();
}
};

private void CheckDwnloadStatus(){

// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
long id = preferenceManager.getLong(strPref_Download_ID, 0);
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);

switch(status){
case DownloadManager.STATUS_FAILED:
String failedReason = "";
switch(reason){
case DownloadManager.ERROR_CANNOT_RESUME:
failedReason = "ERROR_CANNOT_RESUME";
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
failedReason = "ERROR_DEVICE_NOT_FOUND";
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
failedReason = "ERROR_FILE_ALREADY_EXISTS";
break;
case DownloadManager.ERROR_FILE_ERROR:
failedReason = "ERROR_FILE_ERROR";
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
failedReason = "ERROR_HTTP_DATA_ERROR";
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
failedReason = "ERROR_INSUFFICIENT_SPACE";
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
failedReason = "ERROR_TOO_MANY_REDIRECTS";
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
failedReason = "ERROR_UNHANDLED_HTTP_CODE";
break;
case DownloadManager.ERROR_UNKNOWN:
failedReason = "ERROR_UNKNOWN";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"FAILED: " + failedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PAUSED:
String pausedReason = "";

switch(reason){
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
pausedReason = "PAUSED_QUEUED_FOR_WIFI";
break;
case DownloadManager.PAUSED_UNKNOWN:
pausedReason = "PAUSED_UNKNOWN";
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
pausedReason = "PAUSED_WAITING_FOR_NETWORK";
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
pausedReason = "PAUSED_WAITING_TO_RETRY";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"PAUSED: " + pausedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PENDING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"PENDING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"RUNNING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_SUCCESSFUL:

Toast.makeText(AndroidDownloadManagerActivity.this,
"SUCCESSFUL",
Toast.LENGTH_LONG).show();
GetFile();
downloadManager.remove(id);
break;
}
}
}

private void GetFile(){
//Retrieve the saved request id
long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);

ParcelFileDescriptor file;
try {
file = downloadManager.openDownloadedFile(downloadID);
FileInputStream fileInputStream
= new ParcelFileDescriptor.AutoCloseInputStream(file);
Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
image.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


Sunday, July 24, 2011

Set the title of Download on notification, setTitle()

The method setTitle() of Request can be used to set the title of this download, to be displayed in notifications (if enabled).

Set the title of Download on notification, setTitle()

For API level 11 or higher, you can also control whether a system notification is posted by the download manager while this download is running or when it is completed, by calling setNotificationVisibility().

Continuous from last exercise "Restrict the types of networks over which DownloadManager may proceed".

package com.exercise.AndroidDownloadManager;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidDownloadManagerActivity extends Activity {

final String DOWNLOAD_FILE = "http://goo.gl/w3XV3";

final String strPref_Download_ID = "PREF_DOWNLOAD_ID";

SharedPreferences preferenceManager;
DownloadManager downloadManager;

ImageView image;

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

preferenceManager
= PreferenceManager.getDefaultSharedPreferences(this);
downloadManager
= (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

Button btnStartDownload = (Button)findViewById(R.id.startdownload);
btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);

image = (ImageView)findViewById(R.id.image);
}

Button.OnClickListener btnStartDownloadOnClickListener
= new Button.OnClickListener(){

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

Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);

/*
* request.setAllowedNetworkTypes()-
* Restrict the types of networks over which this download may proceed.
* By default, all network types are allowed.
* - Request.NETWORK_WIFI
* - Request.NETWORK_MOBILE
* - Request.NETWORK_WIFI | Request.NETWORK_MOBILE
*
* request.setAllowedOverRoaming(false) -
* Set whether this download may proceed over a roaming connection.
* By default, roaming is allowed.
*/
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);


/*
* Set Title of Download
*/
request.setTitle("Android-er Download!");

/*
* (for API 11 or higher!)
* Display Download in Notification
*/
//request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

long id = downloadManager.enqueue(request);

//Save the request id
Editor PrefEdit = preferenceManager.edit();
PrefEdit.putLong(strPref_Download_ID, id);
PrefEdit.commit();

}};

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

CheckDwnloadStatus();

IntentFilter intentFilter
= new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
}

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

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
CheckDwnloadStatus();
}
};

private void CheckDwnloadStatus(){

// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
long id = preferenceManager.getLong(strPref_Download_ID, 0);
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);

switch(status){
case DownloadManager.STATUS_FAILED:
String failedReason = "";
switch(reason){
case DownloadManager.ERROR_CANNOT_RESUME:
failedReason = "ERROR_CANNOT_RESUME";
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
failedReason = "ERROR_DEVICE_NOT_FOUND";
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
failedReason = "ERROR_FILE_ALREADY_EXISTS";
break;
case DownloadManager.ERROR_FILE_ERROR:
failedReason = "ERROR_FILE_ERROR";
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
failedReason = "ERROR_HTTP_DATA_ERROR";
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
failedReason = "ERROR_INSUFFICIENT_SPACE";
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
failedReason = "ERROR_TOO_MANY_REDIRECTS";
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
failedReason = "ERROR_UNHANDLED_HTTP_CODE";
break;
case DownloadManager.ERROR_UNKNOWN:
failedReason = "ERROR_UNKNOWN";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"FAILED: " + failedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PAUSED:
String pausedReason = "";

switch(reason){
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
pausedReason = "PAUSED_QUEUED_FOR_WIFI";
break;
case DownloadManager.PAUSED_UNKNOWN:
pausedReason = "PAUSED_UNKNOWN";
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
pausedReason = "PAUSED_WAITING_FOR_NETWORK";
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
pausedReason = "PAUSED_WAITING_TO_RETRY";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"PAUSED: " + pausedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PENDING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"PENDING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"RUNNING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_SUCCESSFUL:

Toast.makeText(AndroidDownloadManagerActivity.this,
"SUCCESSFUL",
Toast.LENGTH_LONG).show();
GetFile();
break;
}
}
}

private void GetFile(){
//Retrieve the saved request id
long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);

ParcelFileDescriptor file;
try {
file = downloadManager.openDownloadedFile(downloadID);
FileInputStream fileInputStream
= new ParcelFileDescriptor.AutoCloseInputStream(file);
Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
image.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


next:
- Cancel/remove download from DownloadManager.

Saturday, July 23, 2011

Restrict the types of networks over which DownloadManager may proceed.

In the last exercise "Check DownloadManager status and reason of FAILED and PAUSED"; we can restrict the types of networks over which DownloadManager may proceed, by calling setAllowedNetworkTypes() and setAllowedOverRoaming().

request.setAllowedNetworkTypes()-
Restrict the types of networks over which this download may proceed. By default, all network types are allowed.
- Request.NETWORK_WIFI
- Request.NETWORK_MOBILE
- Request.NETWORK_WIFI | Request.NETWORK_MOBILE

request.setAllowedOverRoaming(false) -
Set whether this download may proceed over a roaming connection. By default, roaming is allowed.

package com.exercise.AndroidDownloadManager;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidDownloadManagerActivity extends Activity {

final String DOWNLOAD_FILE = "http://goo.gl/w3XV3";

final String strPref_Download_ID = "PREF_DOWNLOAD_ID";

SharedPreferences preferenceManager;
DownloadManager downloadManager;

ImageView image;

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

preferenceManager
= PreferenceManager.getDefaultSharedPreferences(this);
downloadManager
= (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

Button btnStartDownload = (Button)findViewById(R.id.startdownload);
btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);

image = (ImageView)findViewById(R.id.image);
}

Button.OnClickListener btnStartDownloadOnClickListener
= new Button.OnClickListener(){

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

Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);

/*
* request.setAllowedNetworkTypes()-
* Restrict the types of networks over which this download may proceed.
* By default, all network types are allowed.
* - Request.NETWORK_WIFI
* - Request.NETWORK_MOBILE
* - Request.NETWORK_WIFI | Request.NETWORK_MOBILE
*
* request.setAllowedOverRoaming(false) -
* Set whether this download may proceed over a roaming connection.
* By default, roaming is allowed.
*/
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);

long id = downloadManager.enqueue(request);

//Save the request id
Editor PrefEdit = preferenceManager.edit();
PrefEdit.putLong(strPref_Download_ID, id);
PrefEdit.commit();

}};

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

CheckDwnloadStatus();

IntentFilter intentFilter
= new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
}

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

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
CheckDwnloadStatus();
}
};

private void CheckDwnloadStatus(){

// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
long id = preferenceManager.getLong(strPref_Download_ID, 0);
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);

switch(status){
case DownloadManager.STATUS_FAILED:
String failedReason = "";
switch(reason){
case DownloadManager.ERROR_CANNOT_RESUME:
failedReason = "ERROR_CANNOT_RESUME";
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
failedReason = "ERROR_DEVICE_NOT_FOUND";
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
failedReason = "ERROR_FILE_ALREADY_EXISTS";
break;
case DownloadManager.ERROR_FILE_ERROR:
failedReason = "ERROR_FILE_ERROR";
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
failedReason = "ERROR_HTTP_DATA_ERROR";
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
failedReason = "ERROR_INSUFFICIENT_SPACE";
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
failedReason = "ERROR_TOO_MANY_REDIRECTS";
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
failedReason = "ERROR_UNHANDLED_HTTP_CODE";
break;
case DownloadManager.ERROR_UNKNOWN:
failedReason = "ERROR_UNKNOWN";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"FAILED: " + failedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PAUSED:
String pausedReason = "";

switch(reason){
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
pausedReason = "PAUSED_QUEUED_FOR_WIFI";
break;
case DownloadManager.PAUSED_UNKNOWN:
pausedReason = "PAUSED_UNKNOWN";
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
pausedReason = "PAUSED_WAITING_FOR_NETWORK";
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
pausedReason = "PAUSED_WAITING_TO_RETRY";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"PAUSED: " + pausedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PENDING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"PENDING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"RUNNING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_SUCCESSFUL:

Toast.makeText(AndroidDownloadManagerActivity.this,
"SUCCESSFUL",
Toast.LENGTH_LONG).show();
GetFile();
break;
}
}
}

private void GetFile(){
//Retrieve the saved request id
long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);

ParcelFileDescriptor file;
try {
file = downloadManager.openDownloadedFile(downloadID);
FileInputStream fileInputStream
= new ParcelFileDescriptor.AutoCloseInputStream(file);
Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
image.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


next:
- Set the title of Download on notification, setTitle()

Friday, July 22, 2011

Check DownloadManager status and reason of FAILED and PAUSED

Modify from "Sample code using android.app.DownloadManager", implement CheckDwnloadStatus() to check DownloadManager status whenever success and onResume().

Check DownloadManager status and reason of FAILED and PAUSED

package com.exercise.AndroidDownloadManager;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidDownloadManagerActivity extends Activity {

final String DOWNLOAD_FILE = "http://goo.gl/w3XV3";

final String strPref_Download_ID = "PREF_DOWNLOAD_ID";

SharedPreferences preferenceManager;
DownloadManager downloadManager;

ImageView image;

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

preferenceManager
= PreferenceManager.getDefaultSharedPreferences(this);
downloadManager
= (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

Button btnStartDownload = (Button)findViewById(R.id.startdownload);
btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);

image = (ImageView)findViewById(R.id.image);
}

Button.OnClickListener btnStartDownloadOnClickListener
= new Button.OnClickListener(){

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

Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
DownloadManager.Request request = new DownloadManager.Request(downloadUri);
long id = downloadManager.enqueue(request);

//Save the request id
Editor PrefEdit = preferenceManager.edit();
PrefEdit.putLong(strPref_Download_ID, id);
PrefEdit.commit();

}};

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

CheckDwnloadStatus();

IntentFilter intentFilter
= new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
}

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

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
CheckDwnloadStatus();
}
};

private void CheckDwnloadStatus(){

// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
long id = preferenceManager.getLong(strPref_Download_ID, 0);
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);

switch(status){
case DownloadManager.STATUS_FAILED:
String failedReason = "";
switch(reason){
case DownloadManager.ERROR_CANNOT_RESUME:
failedReason = "ERROR_CANNOT_RESUME";
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
failedReason = "ERROR_DEVICE_NOT_FOUND";
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
failedReason = "ERROR_FILE_ALREADY_EXISTS";
break;
case DownloadManager.ERROR_FILE_ERROR:
failedReason = "ERROR_FILE_ERROR";
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
failedReason = "ERROR_HTTP_DATA_ERROR";
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
failedReason = "ERROR_INSUFFICIENT_SPACE";
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
failedReason = "ERROR_TOO_MANY_REDIRECTS";
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
failedReason = "ERROR_UNHANDLED_HTTP_CODE";
break;
case DownloadManager.ERROR_UNKNOWN:
failedReason = "ERROR_UNKNOWN";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"FAILED: " + failedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PAUSED:
String pausedReason = "";

switch(reason){
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
pausedReason = "PAUSED_QUEUED_FOR_WIFI";
break;
case DownloadManager.PAUSED_UNKNOWN:
pausedReason = "PAUSED_UNKNOWN";
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
pausedReason = "PAUSED_WAITING_FOR_NETWORK";
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
pausedReason = "PAUSED_WAITING_TO_RETRY";
break;
}

Toast.makeText(AndroidDownloadManagerActivity.this,
"PAUSED: " + pausedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PENDING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"PENDING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(AndroidDownloadManagerActivity.this,
"RUNNING",
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_SUCCESSFUL:

Toast.makeText(AndroidDownloadManagerActivity.this,
"SUCCESSFUL",
Toast.LENGTH_LONG).show();
GetFile();
break;
}
}
}

private void GetFile(){
//Retrieve the saved request id
long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);

ParcelFileDescriptor file;
try {
file = downloadManager.openDownloadedFile(downloadID);
FileInputStream fileInputStream
= new ParcelFileDescriptor.AutoCloseInputStream(file);
Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
image.setImageBitmap(bm);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


Download the files.


next:
- Restrict the types of networks over which DownloadManager may proceed.

Thursday, July 21, 2011

Check Network Connectivity

To check network connectivity, we can use ConnectivityManager to get info of active network.

Check Network Connectivity

package com.exercise.AndroidNetworkConnectivity;

import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.widget.Toast;

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


ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

if (activeNetworkInfo == null){
Toast.makeText(AndroidNetworkConnectivityActivity.this,
"No Active Network",
Toast.LENGTH_LONG).show();
}else{
if (activeNetworkInfo.isConnected()){
Toast.makeText(AndroidNetworkConnectivityActivity.this,
"network is Connected",
Toast.LENGTH_LONG).show();
}else if (activeNetworkInfo.isConnectedOrConnecting()){
Toast.makeText(AndroidNetworkConnectivityActivity.this,
"network is Connecting",
Toast.LENGTH_LONG).show();
}
}
}
}


Remark: uses permission of "android.permission.ACCESS_NETWORK_STATE" is needed.

Sample code using android.app.DownloadManager

android.app.DownloadManager (introduced in API Level 9) is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots.

android.app.DownloadManager
android.app.DownloadManager
android.app.DownloadManager

In order to permit your app download from internet, AndroidManifest.xml have to be modified to grant permission of "android.permission.INTERNET".

Java code:
package com.exercise.AndroidDownloadManager;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class AndroidDownloadManagerActivity extends Activity {
 
 final String DOWNLOAD_FILE = "http://goo.gl/w3XV3";

 final String strPref_Download_ID = "PREF_DOWNLOAD_ID";
 
 SharedPreferences preferenceManager;
 DownloadManager downloadManager;
 
 ImageView image;
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
      
       preferenceManager
        = PreferenceManager.getDefaultSharedPreferences(this);
       downloadManager
        = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
      
       Button btnStartDownload = (Button)findViewById(R.id.startdownload);
       btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);
      
       image = (ImageView)findViewById(R.id.image);
   }
  
   Button.OnClickListener btnStartDownloadOnClickListener
   = new Button.OnClickListener(){

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   
   Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
   DownloadManager.Request request = new DownloadManager.Request(downloadUri);
   long id = downloadManager.enqueue(request);
   
   //Save the request id
   Editor PrefEdit = preferenceManager.edit();
   PrefEdit.putLong(strPref_Download_ID, id);
   PrefEdit.commit();

  }};

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

  IntentFilter intentFilter
   = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
  registerReceiver(downloadReceiver, intentFilter);
 }

 @Override
 protected void onPause() {
  // TODO Auto-generated method stub
  super.onPause();
  unregisterReceiver(downloadReceiver);
 }
  
 private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

  @Override
  public void onReceive(Context arg0, Intent arg1) {
   // TODO Auto-generated method stub
   DownloadManager.Query query = new DownloadManager.Query();
   query.setFilterById(preferenceManager.getLong(strPref_Download_ID, 0));
   Cursor cursor = downloadManager.query(query);
   if(cursor.moveToFirst()){
    int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
    int status = cursor.getInt(columnIndex);
    if(status == DownloadManager.STATUS_SUCCESSFUL){
     
     //Retrieve the saved request id
     long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);
     
     ParcelFileDescriptor file;
     try {
      file = downloadManager.openDownloadedFile(downloadID);
      FileInputStream fileInputStream
       = new ParcelFileDescriptor.AutoCloseInputStream(file);
      Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
      image.setImageBitmap(bm);
     } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     
    }
   }
  } 
 };
}


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/startdownload"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="Start Download"
   />
<ImageView
   android:id="@+id/image"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   />
</LinearLayout>

download filesDownload the files.


Wednesday, July 20, 2011

Display a indeterminate progress bar on title bar

To display a indeterminate progress bar on title bar, we have to request Window Feature of Window.FEATURE_INDETERMINATE_PROGRESS.

Place the code; before setContentView(R.layout.main):
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

then call setProgressBarIndeterminateVisibility(true/false) to turn it on/off.

Display a indeterminate progress bar on title bar

Modify from the exercise "ProgressDialog + Thread"
package com.exercise.AndroidProgressDialog;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Window;
import android.widget.Toast;

public class AndroidProgressDialogActivity extends Activity {

ProgressDialog progressDialog;
BackgroundThread backgroundThread;

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

requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.main);

setProgressBarIndeterminateVisibility(true);
progressDialog = ProgressDialog.show(AndroidProgressDialogActivity.this,
"ProgressDialog", "Wait!");

backgroundThread = new BackgroundThread();
backgroundThread.setRunning(true);
backgroundThread.start();
}



public class BackgroundThread extends Thread{
volatile boolean running = false;
int cnt;

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

@Override
public void run() {
// TODO Auto-generated method stub
while(running){
try {
sleep(1000);
if(cnt-- == 0){
running = false;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
handler.sendMessage(handler.obtainMessage());
}
}

Handler handler = new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub

setProgressBarIndeterminateVisibility(false);
progressDialog.dismiss();

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

Toast.makeText(AndroidProgressDialogActivity.this,
"dismissed", Toast.LENGTH_LONG).show();
}

};
}


next:
- Cancel ProgressDialog

Using resources of string-array

We can define the content of String array in XML, then load the array with getResources().getStringArray(R.array.xxx).

Create a file /res/values/array.xml to define the array
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string-array name="DayOfWeek">
<item>Sunday</item>
<item>Monday</item>
<item>Tuesday</item>
<item>Wednesday</item>
<item>Thursday</item>
<item>Friday</item>
<item>Saturday</item>
</string-array>
</resources>


package com.exercise.AndroidStringArray;

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

public class AndroidStringArrayActivity extends Activity {

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

String[] myStringArray = getResources().getStringArray(R.array.DayOfWeek);
String textOut = "";

for(int i = 0; i < myStringArray.length; i++){
textOut += myStringArray[i] + "\n";
}

text.setText(textOut);
}
}



<?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/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>



Using resources of string-array

Tuesday, July 19, 2011

TabWidget, with AnalogClock and DigitalClock

TabWidget, with AnalogClock
TabWidget, with DigitalClock

main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<AnalogClock android:id="@+id/tabAnalogClock"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<DigitalClock android:id="@+id/tabDigitalClock"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</FrameLayout>
</LinearLayout>
</TabHost>


package com.exercise.AndroidTabWidget;

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

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

TabHost tabs=(TabHost)findViewById(R.id.tabhost);
tabs.setup();

TabHost.TabSpec tabSpecAnalog = tabs.newTabSpec("tagAnalogClock");
tabSpecAnalog.setContent(R.id.tabAnalogClock);
tabSpecAnalog.setIndicator("Analog");

TabHost.TabSpec tabSpecDigital=tabs.newTabSpec("tagDigitalClock");
tabSpecDigital.setContent(R.id.tabDigitalClock);
tabSpecDigital.setIndicator("Digitl");

tabs.addTab(tabSpecAnalog);
tabs.addTab(tabSpecDigital);
}
}



Download the files.

Monday, July 18, 2011

Load Flickr images in background thread

In the exercise "Display Flickr photos in Gallery using BaseAdapter", the Flickr photos are loaded in foreground thread. If it take long time to load photos from Flickr server, the app will be killed by Android OS. In this exercise, the job will be moved to a background thread, and a ProgressDialog will be displayed to user. (For example of using background thread and ProgressDialog, refer the post "ProgressDialog + Thread").

Load Flickr images in background thread

package com.exercise.AndroidFlickr;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;

public class AndroidFlickrActivity extends Activity {

ProgressDialog progressDialog;
BackgroundThread backgroundThread;

public class FlickrImage {
String Id;
String Owner;
String Secret;
String Server;
String Farm;
String Title;

Bitmap FlickrBitmap;

FlickrImage(String _Id, String _Owner, String _Secret,
String _Server, String _Farm, String _Title){
Id = _Id;
Owner = _Owner;
Secret = _Secret;
Server = _Server;
Farm = _Farm;
Title = _Title;

FlickrBitmap = preloadBitmap();
}

private Bitmap preloadBitmap(){
Bitmap bm= null;

String FlickrPhotoPath =
"http://farm" + Farm + ".static.flickr.com/"
+ Server + "/" + Id + "_" + Secret + "_m.jpg";

URL FlickrPhotoUrl = null;

try {
FlickrPhotoUrl = new URL(FlickrPhotoPath);

HttpURLConnection httpConnection
= (HttpURLConnection) FlickrPhotoUrl.openConnection();
httpConnection.setDoInput(true);
httpConnection.connect();
InputStream inputStream = httpConnection.getInputStream();
bm = BitmapFactory.decodeStream(inputStream);

} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return bm;
}

public Bitmap getBitmap(){
return FlickrBitmap;
}

}

class FlickrAdapter extends BaseAdapter{
private Context context;
private FlickrImage[] FlickrAdapterImage;;

FlickrAdapter(Context c, FlickrImage[] fImage){
context = c;
FlickrAdapterImage = fImage;
}

public int getCount() {
// TODO Auto-generated method stub
return FlickrAdapterImage.length;
}

public Object getItem(int position) {
// TODO Auto-generated method stub
return FlickrAdapterImage[position];
}

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

public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView image;
if (convertView == null) {
image = new ImageView(context);
image.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
image.setPadding(8, 8, 8, 8);
} else {
image = (ImageView) convertView;
}

image.setImageBitmap(FlickrAdapterImage[position].getBitmap());

return image;
}

}

FlickrImage[] myFlickrImage;

/*
* FlickrQuery = FlickrQuery_url
* + FlickrQuery_per_page
* + FlickrQuery_nojsoncallback
* + FlickrQuery_format
* + FlickrQuery_tag + q
* + FlickrQuery_key + FlickrApiKey
*/

String FlickrQuery_url = "http://api.flickr.com/services/rest/?method=flickr.photos.search";
String FlickrQuery_per_page = "&per_page=10";
String FlickrQuery_nojsoncallback = "&nojsoncallback=1";
String FlickrQuery_format = "&format=json";
String FlickrQuery_tag = "&tags=";
String FlickrQuery_key = "&api_key=";

// Apply your Flickr API:
// www.flickr.com/services/apps/create/apply/?
String FlickrApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

//final String DEFAULT_SEARCH = "Bill_Gate";
final String DEFAULT_SEARCH = "new_york";

EditText searchText;
Button searchButton;

Gallery photoBar;

Bitmap bmFlickr;

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

searchText = (EditText)findViewById(R.id.searchtext);
searchText.setText(DEFAULT_SEARCH);
searchButton = (Button)findViewById(R.id.searchbutton);

photoBar = (Gallery)findViewById(R.id.photobar);

searchButton.setOnClickListener(searchButtonOnClickListener);
}

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

public void onClick(View arg0) {
// TODO Auto-generated method stub
progressDialog = ProgressDialog.show(AndroidFlickrActivity.this,
"ProgressDialog", "Wait!");

backgroundThread = new BackgroundThread();
backgroundThread.setRunning(true);
backgroundThread.start();




}};


private String QueryFlickr(String q){

String qResult = null;

String qString =
FlickrQuery_url
+ FlickrQuery_per_page
+ FlickrQuery_nojsoncallback
+ FlickrQuery_format
+ FlickrQuery_tag + q
+ FlickrQuery_key + FlickrApiKey;

HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(qString);

try {
HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();

if (httpEntity != null){
InputStream inputStream = httpEntity.getContent();
Reader in = new InputStreamReader(inputStream);
BufferedReader bufferedreader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();

String stringReadLine = null;

while ((stringReadLine = bufferedreader.readLine()) != null) {
stringBuilder.append(stringReadLine + "\n");
}

qResult = stringBuilder.toString();
inputStream.close();
}

} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return qResult;
}

private FlickrImage[] ParseJSON(String json){

FlickrImage[] flickrImage = null;

bmFlickr = null;
String flickrId;
String flickrOwner;
String flickrSecret;
String flickrServer;
String flickrFarm;
String flickrTitle;

try {
JSONObject JsonObject = new JSONObject(json);
JSONObject Json_photos = JsonObject.getJSONObject("photos");
JSONArray JsonArray_photo = Json_photos.getJSONArray("photo");

flickrImage = new FlickrImage[JsonArray_photo.length()];
for (int i = 0; i < JsonArray_photo.length(); i++){
JSONObject FlickrPhoto = JsonArray_photo.getJSONObject(i);
flickrId = FlickrPhoto.getString("id");
flickrOwner = FlickrPhoto.getString("owner");
flickrSecret = FlickrPhoto.getString("secret");
flickrServer = FlickrPhoto.getString("server");
flickrFarm = FlickrPhoto.getString("farm");
flickrTitle = FlickrPhoto.getString("title");
flickrImage[i] = new FlickrImage(flickrId, flickrOwner, flickrSecret,
flickrServer, flickrFarm, flickrTitle);
}

} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return flickrImage;
}

public class BackgroundThread extends Thread{
volatile boolean running = false;
int cnt;

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

@Override
public void run() {
// TODO Auto-generated method stub
String searchQ = searchText.getText().toString();
String searchResult = QueryFlickr(searchQ);

myFlickrImage = ParseJSON(searchResult);


handler.sendMessage(handler.obtainMessage());
}
}

Handler handler = new Handler(){

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub

progressDialog.dismiss();
photoBar.setAdapter(new FlickrAdapter(AndroidFlickrActivity.this, myFlickrImage));
Toast.makeText(AndroidFlickrActivity.this,
"Flickr images loaded", Toast.LENGTH_LONG).show();
}

};

}


Download the files.

Saturday, July 16, 2011

ProgressDialog + Thread

In this exercise, we will be implementing a background Thread. When the app start, a ProgressDialog will be shown, and a Thread will be start. When the thread finished in 10 seconds, it will generate a handler message to dismiss the ProgressDialog.

ProgressDialog.show()
progressDialog.dismiss()


package com.exercise.AndroidProgressDialog;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;

public class AndroidProgressDialogActivity extends Activity {

ProgressDialog progressDialog;
BackgroundThread backgroundThread;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      progressDialog = ProgressDialog.show(AndroidProgressDialogActivity.this,
              "ProgressDialog", "Wait!");
    
      backgroundThread = new BackgroundThread();
      backgroundThread.setRunning(true);
      backgroundThread.start();
  }



  public class BackgroundThread extends Thread{
   volatile boolean running = false;
   int cnt;
  
   void setRunning(boolean b){
    running = b;
    cnt = 10;
   }

 @Override
 public void run() {
  // TODO Auto-generated method stub
  while(running){
   try {
    sleep(1000);
    if(cnt-- == 0){
     running = false;
    }
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  handler.sendMessage(handler.obtainMessage());
 }
  }

  Handler handler = new Handler(){

 @Override
 public void handleMessage(Message msg) {
  // TODO Auto-generated method stub
  progressDialog.dismiss();

  boolean retry = true;
  while(retry){
   try {
    backgroundThread.join();
    retry = false;
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 
  Toast.makeText(AndroidProgressDialogActivity.this,
    "dismissed", Toast.LENGTH_LONG).show();
 }
  
  };
}


next:
- Display a indeterminate progress bar on title bar

Remark:
progressDialog.dismiss(); 
must be in a try/catch block. otherwise the app crashes if you rotate (landscape/portrait) the device during running of the BackgroundThread. 
~ thanks Iiasa Laxenburg's comments.

ProgressDialog

android.app.ProgressDialog is a dialog showing a progress indicator and an optional text message or view.

ProgressDialog

call the show() method to start the ProgressDialog, and call dismiss() method to remove it from the screen (refer to the next article ProgressDialog + Thread).

package com.exercise.AndroidProgressDialog;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;

public class AndroidProgressDialogActivity extends Activity {

ProgressDialog progressDialog;

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

progressDialog = ProgressDialog.show(AndroidProgressDialogActivity.this,
"ProgressDialog", "Wait!");
/*
* To stop the ProgressDialog, call progressDialog.dismiss();
*/
}
}


next:
- ProgressDialog + Thread

Android 3.2 Platform and Updated SDK tools

Android 3.2 platform announced, an incremental release that adds several new capabilities for users and developers. The new platform includes API changes and the API level is 13.
  • Optimizations for a wider range of tablets.

  • Compatibility zoom for fixed-sized apps.

  • Media sync from SD card. On devices that support a removable SD card, users can now load media files directly from the SD card to apps that use them.

  • Extended screen support API.


Please note that the SDK Tools(r12), Eclipse plug-in(ADT 12) and NDK(r6) have been updated also.

Source: Android Developers Blog: Android 3.2 Platform and Updated SDK tools

Thursday, July 14, 2011

Display Flickr photos in Gallery using BaseAdapter

In this exercise, we are going to modify last exercise "Load array of photos from Flickr" to display the photo array in Gallery widget.

Display Flickr photos in Gallery using BaseAdapter

We have to implement a FlickrAdapter class extends BaseAdapter, to adapt the photos in a Gallery.

package com.exercise.AndroidFlickr;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Gallery;
import android.widget.ImageView;

public class AndroidFlickrActivity extends Activity {

public class FlickrImage {
String Id;
String Owner;
String Secret;
String Server;
String Farm;
String Title;

Bitmap FlickrBitmap;

FlickrImage(String _Id, String _Owner, String _Secret,
String _Server, String _Farm, String _Title){
Id = _Id;
Owner = _Owner;
Secret = _Secret;
Server = _Server;
Farm = _Farm;
Title = _Title;

FlickrBitmap = preloadBitmap();
}

private Bitmap preloadBitmap(){
Bitmap bm= null;

String FlickrPhotoPath =
"http://farm" + Farm + ".static.flickr.com/"
+ Server + "/" + Id + "_" + Secret + "_m.jpg";

URL FlickrPhotoUrl = null;

try {
FlickrPhotoUrl = new URL(FlickrPhotoPath);

HttpURLConnection httpConnection
= (HttpURLConnection) FlickrPhotoUrl.openConnection();
httpConnection.setDoInput(true);
httpConnection.connect();
InputStream inputStream = httpConnection.getInputStream();
bm = BitmapFactory.decodeStream(inputStream);

} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return bm;
}

public Bitmap getBitmap(){
return FlickrBitmap;
}

}

class FlickrAdapter extends BaseAdapter{
private Context context;
private FlickrImage[] FlickrAdapterImage;;

FlickrAdapter(Context c, FlickrImage[] fImage){
context = c;
FlickrAdapterImage = fImage;
}

public int getCount() {
// TODO Auto-generated method stub
return FlickrAdapterImage.length;
}

public Object getItem(int position) {
// TODO Auto-generated method stub
return FlickrAdapterImage[position];
}

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

public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView image;
if (convertView == null) {
image = new ImageView(context);
image.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
image.setScaleType(ImageView.ScaleType.CENTER_CROP);
image.setPadding(8, 8, 8, 8);
} else {
image = (ImageView) convertView;
}

image.setImageBitmap(FlickrAdapterImage[position].getBitmap());

return image;
}

}

FlickrImage[] myFlickrImage;

/*
* FlickrQuery = FlickrQuery_url
* + FlickrQuery_per_page
* + FlickrQuery_nojsoncallback
* + FlickrQuery_format
* + FlickrQuery_tag + q
* + FlickrQuery_key + FlickrApiKey
*/

String FlickrQuery_url = "http://api.flickr.com/services/rest/?method=flickr.photos.search";
String FlickrQuery_per_page = "&per_page=10";
String FlickrQuery_nojsoncallback = "&nojsoncallback=1";
String FlickrQuery_format = "&format=json";
String FlickrQuery_tag = "&tags=";
String FlickrQuery_key = "&api_key=";

// Apply your Flickr API:
// www.flickr.com/services/apps/create/apply/?
String FlickrApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

//final String DEFAULT_SEARCH = "Bill_Gate";
final String DEFAULT_SEARCH = "new_york";

EditText searchText;
Button searchButton;

Gallery photoBar;

Bitmap bmFlickr;

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

searchText = (EditText)findViewById(R.id.searchtext);
searchText.setText(DEFAULT_SEARCH);
searchButton = (Button)findViewById(R.id.searchbutton);

photoBar = (Gallery)findViewById(R.id.photobar);

searchButton.setOnClickListener(searchButtonOnClickListener);
}

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

public void onClick(View arg0) {
// TODO Auto-generated method stub
String searchQ = searchText.getText().toString();
String searchResult = QueryFlickr(searchQ);

myFlickrImage = ParseJSON(searchResult);

photoBar.setAdapter(new FlickrAdapter(AndroidFlickrActivity.this, myFlickrImage));

}};


private String QueryFlickr(String q){

String qResult = null;

String qString =
FlickrQuery_url
+ FlickrQuery_per_page
+ FlickrQuery_nojsoncallback
+ FlickrQuery_format
+ FlickrQuery_tag + q
+ FlickrQuery_key + FlickrApiKey;

HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(qString);

try {
HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();

if (httpEntity != null){
InputStream inputStream = httpEntity.getContent();
Reader in = new InputStreamReader(inputStream);
BufferedReader bufferedreader = new BufferedReader(in);
StringBuilder stringBuilder = new StringBuilder();

String stringReadLine = null;

while ((stringReadLine = bufferedreader.readLine()) != null) {
stringBuilder.append(stringReadLine + "\n");
}

qResult = stringBuilder.toString();
inputStream.close();
}

} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return qResult;
}

private FlickrImage[] ParseJSON(String json){

FlickrImage[] flickrImage = null;

bmFlickr = null;
String flickrId;
String flickrOwner;
String flickrSecret;
String flickrServer;
String flickrFarm;
String flickrTitle;

try {
JSONObject JsonObject = new JSONObject(json);
JSONObject Json_photos = JsonObject.getJSONObject("photos");
JSONArray JsonArray_photo = Json_photos.getJSONArray("photo");

flickrImage = new FlickrImage[JsonArray_photo.length()];
for (int i = 0; i < JsonArray_photo.length(); i++){
JSONObject FlickrPhoto = JsonArray_photo.getJSONObject(i);
flickrId = FlickrPhoto.getString("id");
flickrOwner = FlickrPhoto.getString("owner");
flickrSecret = FlickrPhoto.getString("secret");
flickrServer = FlickrPhoto.getString("server");
flickrFarm = FlickrPhoto.getString("farm");
flickrTitle = FlickrPhoto.getString("title");
flickrImage[i] = new FlickrImage(flickrId, flickrOwner, flickrSecret,
flickrServer, flickrFarm, flickrTitle);
}

} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return flickrImage;
}

}


<?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"
/>
<EditText
android:id="@+id/searchtext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/searchbutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Search"
/>
<TextView
android:id="@+id/queryresult"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Gallery
android:id="@+id/photobar"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:spacing="10dp"
/>
</LinearLayout>


Modify AndroidManifest.xml to grant permission of "android.permission.INTERNET".

Download the files.


next:
- Load Flickr images in background thread