Wednesday, 31 October 2012

List Images with thumbnails, implementing custom SimpleCursorAdapter.

Last exercise demonstrate how to get Thumbnails. Now we can implement our custom SimpleCursorAdapter to list the Images in MediaStore.Images.Media with associated Thumbnail if exist.

List Images with thumbnails, implementing custom SimpleCursorAdapter.


Create a file, /res/layout/row.xml, to define the layout of the rows in the ListView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<ImageView
android:id="@+id/thumb"
android:layout_width="100dp"
android:layout_height="100dp"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>


Modify the code to implement MyAdapter class extends SimpleCursorAdapter.
package com.example.androidlistimages;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MainActivity extends ListActivity {

//define source of MediaStore.Images.Media, internal or external storage
final Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
final Uri thumbUri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI;
final String thumb_DATA = MediaStore.Images.Thumbnails.DATA;
final String thumb_IMAGE_ID = MediaStore.Images.Thumbnails.IMAGE_ID;

//SimpleCursorAdapter mySimpleCursorAdapter;
MyAdapter mySimpleCursorAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();

mySimpleCursorAdapter = new MyAdapter(
this,
android.R.layout.simple_list_item_1,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

setListAdapter(mySimpleCursorAdapter);

getListView().setOnItemClickListener(myOnItemClickListener);
}

OnItemClickListener myOnItemClickListener
= new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Cursor cursor = mySimpleCursorAdapter.getCursor();
cursor.moveToPosition(position);

int int_ID = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
getThumbnail(int_ID);
}};

private Bitmap getThumbnail(int id){

String[] thumbColumns = {thumb_DATA, thumb_IMAGE_ID};

CursorLoader thumbCursorLoader = new CursorLoader(
this,
thumbUri,
thumbColumns,
thumb_IMAGE_ID + "=" + id,
null,
null);

Cursor thumbCursor = thumbCursorLoader.loadInBackground();

Bitmap thumbBitmap = null;
if(thumbCursor.moveToFirst()){
int thCulumnIndex = thumbCursor.getColumnIndex(thumb_DATA);

String thumbPath = thumbCursor.getString(thCulumnIndex);

Toast.makeText(getApplicationContext(),
thumbPath,
Toast.LENGTH_LONG).show();

thumbBitmap = BitmapFactory.decodeFile(thumbPath);

//Create a Dialog to display the thumbnail
AlertDialog.Builder thumbDialog = new AlertDialog.Builder(MainActivity.this);
ImageView thumbView = new ImageView(MainActivity.this);
thumbView.setImageBitmap(thumbBitmap);
LinearLayout layout = new LinearLayout(MainActivity.this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(thumbView);
thumbDialog.setView(layout);
thumbDialog.show();

}else{
Toast.makeText(getApplicationContext(),
"NO Thumbnail!",
Toast.LENGTH_LONG).show();
}

return thumbBitmap;
}

public class MyAdapter extends SimpleCursorAdapter{

Cursor myCursor;
Context myContext;

public MyAdapter(Context context, int layout, Cursor c, String[] from,
int[] to, int flags) {
super(context, layout, c, from, to, flags);

myCursor = c;
myContext = context;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if(row==null){
LayoutInflater inflater=getLayoutInflater();
row=inflater.inflate(R.layout.row, parent, false);
}

ImageView thumbV = (ImageView)row.findViewById(R.id.thumb);
TextView textV = (TextView)row.findViewById(R.id.text);

myCursor.moveToPosition(position);

int myID = myCursor.getInt(myCursor.getColumnIndex(MediaStore.Images.Media._ID));
String myData = myCursor.getString(myCursor.getColumnIndex(MediaStore.Images.Media.DATA));
textV.setText(myData);

String[] thumbColumns = {thumb_DATA, thumb_IMAGE_ID};
CursorLoader thumbCursorLoader = new CursorLoader(
myContext,
thumbUri,
thumbColumns,
thumb_IMAGE_ID + "=" + myID,
null,
null);
Cursor thumbCursor = thumbCursorLoader.loadInBackground();

Bitmap myBitmap = null;
if(thumbCursor.moveToFirst()){
int thCulumnIndex = thumbCursor.getColumnIndex(thumb_DATA);
String thumbPath = thumbCursor.getString(thCulumnIndex);
myBitmap = BitmapFactory.decodeFile(thumbPath);
thumbV.setImageBitmap(myBitmap);
}

return row;
}

}
}


download filesDownload the files.

Related:
- List MediaStore.Images.Thumbnails in GridView, with custom SimpleCursorAdapter.


Tuesday, 30 October 2012

Get thumbnails (in MediaStore.Images.Thumbnails) associated with MediaStore.Images.Media

Last exercise demonstrate how to "Get path of image in MediaStore.Images.Media from SimpleCursorAdapter". In this exercise, the associated thumbnails (in MediaStore.Images.Thumbnails) can be retrieved via the Cursor.

Get thumbnails (in MediaStore.Images.Thumbnails) associated with MediaStore.Images.Media


package com.example.androidlistimages;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MainActivity extends ListActivity {

//define source of MediaStore.Images.Media, internal or external storage
final Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
final Uri thumbUri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI;
final String thumb_DATA = MediaStore.Images.Thumbnails.DATA;
final String thumb_IMAGE_ID = MediaStore.Images.Thumbnails.IMAGE_ID;

SimpleCursorAdapter mySimpleCursorAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();

mySimpleCursorAdapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

setListAdapter(mySimpleCursorAdapter);

getListView().setOnItemClickListener(myOnItemClickListener);
}

OnItemClickListener myOnItemClickListener
= new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Cursor cursor = mySimpleCursorAdapter.getCursor();
cursor.moveToPosition(position);

int int_ID = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
getThumbnail(int_ID);
}};

private Bitmap getThumbnail(int id){

String[] thumbColumns = {thumb_DATA, thumb_IMAGE_ID};

CursorLoader thumbCursorLoader = new CursorLoader(
this,
thumbUri,
thumbColumns,
thumb_IMAGE_ID + "=" + id,
null,
null);

Cursor thumbCursor = thumbCursorLoader.loadInBackground();

Bitmap thumbBitmap = null;
if(thumbCursor.moveToFirst()){
int thCulumnIndex = thumbCursor.getColumnIndex(thumb_DATA);

String thumbPath = thumbCursor.getString(thCulumnIndex);

Toast.makeText(getApplicationContext(),
thumbPath,
Toast.LENGTH_LONG).show();

thumbBitmap = BitmapFactory.decodeFile(thumbPath);

//Create a Dialog to display the thumbnail
AlertDialog.Builder thumbDialog = new AlertDialog.Builder(MainActivity.this);
ImageView thumbView = new ImageView(MainActivity.this);
thumbView.setImageBitmap(thumbBitmap);
LinearLayout layout = new LinearLayout(MainActivity.this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(thumbView);
thumbDialog.setView(layout);
thumbDialog.show();

}else{
Toast.makeText(getApplicationContext(),
"NO Thumbnail!",
Toast.LENGTH_LONG).show();
}

return thumbBitmap;
}
}


download filesDownload the files.


Next:
- List Images with thumbnails, implementing custom SimpleCursorAdapter.


Friday, 26 October 2012

Get path of image in MediaStore.Images.Media from SimpleCursorAdapter

The post "List images in MediaStore.Images.Media" demonstrate how to list images in MediaStore.Images.Media with SimpleCursorAdapter. It's modified to retrieve the path of the clicked item using Cursor.

Get path of image in MediaStore.Images.Media from SimpleCursorAdapter


package com.example.androidlistimages;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;
import android.app.ListActivity;
import android.database.Cursor;

public class MainActivity extends ListActivity {

//define source of MediaStore.Images.Media, internal or external storage
Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//Uri sourceUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;

SimpleCursorAdapter mySimpleCursorAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();

mySimpleCursorAdapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

setListAdapter(mySimpleCursorAdapter);

getListView().setOnItemClickListener(myOnItemClickListener);
}

OnItemClickListener myOnItemClickListener
= new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Cursor cursor = mySimpleCursorAdapter.getCursor();
cursor.moveToPosition(position);
String _id = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
Uri selUri = Uri.withAppendedPath(sourceUri, _id);

Toast.makeText(getApplicationContext(),
selUri.getPath(),
Toast.LENGTH_LONG).show();

}};

}


download filesDownload the files.

Next:
- Get the associated thumbnails


Thursday, 25 October 2012

email send images exercise, with spinner of pre-defined subjects.

Refer to the last exercise "Start activity to send email with multiple images attached, with build-in MediaStore.Images.Media selector", it always send email with images attached. So I want to have a spinner with pre-defined email subjects for user to easy choice.

email send images exercise, with spinner of pre-defined subjects.

Create /res/values/array.xml to provide the pre-defined email subjects.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="subject">
<item>My Photos</item>
<item>Share with you</item>
<item>Please check</item>
<item>Hello Friend</item>
</string-array>
</resources>


Modify layout to replace EditText of email subject with a <Spinner>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email address:"/>
<EditText
android:id="@+id/email_address"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Choice Subject:"/>
<Spinner
android:id="@+id/spinner_subject"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter Text:"/>
<EditText
android:id="@+id/email_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send"/>
<ListView
android:id="@+id/filelist"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


Modify the code:
package com.example.androidselectmultifiles;

import java.util.ArrayList;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Spinner;

public class MainActivity extends Activity {

EditText edittextEmailAddress;
Spinner spinnerSubject;
EditText edittextEmailText;
Button btnSend;
ListView listViewFiles;

ArrayList<Uri> arrayUri = new ArrayList<Uri>();
ArrayAdapter<Uri> myFileListAdapter;

final int RQS_SENDEMAIL = 1;

SimpleCursorAdapter listAdapter;

final Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ListAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

edittextEmailAddress = (EditText)findViewById(R.id.email_address);
edittextEmailText = (EditText)findViewById(R.id.email_text);

btnSend = (Button)findViewById(R.id.send);
btnSend.setOnClickListener(btnSendOnClickListener);

listViewFiles = (ListView)findViewById(R.id.filelist);
String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();
listAdapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

listViewFiles.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

listViewFiles.setAdapter(listAdapter);

//Prepare Spinner for subject
spinnerSubject = (Spinner)findViewById(R.id.spinner_subject);
ArrayAdapter<CharSequence> adapterSpinnerSubject = ArrayAdapter.createFromResource(this, R.array.subject, android.R.layout.simple_spinner_item);
adapterSpinnerSubject.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerSubject.setAdapter(adapterSpinnerSubject);
}

private ArrayList<Uri> getSelectedFiles(){
ArrayList<Uri> arrayU = new ArrayList<Uri>();

SparseBooleanArray checkedArray = listViewFiles.getCheckedItemPositions();

for(int i=0; i<checkedArray.size(); i++)
{
int pos = checkedArray.keyAt(i);
Cursor cursor = listAdapter.getCursor();
cursor.moveToPosition(pos);
String _id = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
Uri selUri = Uri.withAppendedPath(sourceUri, _id);
arrayU.add(selUri);
}

return arrayU;
}

OnClickListener btnSendOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {

arrayUri = getSelectedFiles();

String emailAddress = edittextEmailAddress.getText().toString();

//retrieve spinnerSubject selection
String emailSubject = spinnerSubject.getSelectedItem().toString();

String emailText = edittextEmailText.getText().toString();
String emailAddressList[] = {emailAddress};

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_EMAIL, emailAddressList);
intent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
intent.putExtra(Intent.EXTRA_TEXT, emailText);

if(arrayUri.isEmpty()){
//Send email without photo attached
intent.setAction(Intent.ACTION_SEND);
intent.setType("plain/text");
}else if(arrayUri.size() == 1){
//Send email with ONE photo attached
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, arrayUri.get(0));
intent.setType("image/*");
}else{
//Send email with MULTI photo attached
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayUri);
intent.setType("image/*");
}

startActivity(Intent.createChooser(intent, "Choice App to send email:"));
}};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK){
switch(requestCode){
case RQS_SENDEMAIL:
break;
}
}
}

}


download filesDownload the files.


Wednesday, 24 October 2012

Start activity to send email with multiple images attached, with build-in MediaStore.Images.Media selector.

The previous post demonstrate how to "Start activity to send email with multi images attached" using Android's Gallery App select images one-by-one. And the post "List images in MediaStore.Images.Media, with multiple selection" demonstrate how to implement our own image files selector. They are merged to have our own images selector to attach images in email.

Start activity to send email with multiple images attached, with build-in MediaStore.Images.Media selector.


package com.example.androidselectmultifiles;

import java.util.ArrayList;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

EditText edittextEmailAddress;
EditText edittextEmailSubject;
EditText edittextEmailText;
Button btnSend;
ListView listViewFiles;

ArrayList<Uri> arrayUri = new ArrayList<Uri>();
ArrayAdapter<Uri> myFileListAdapter;

final int RQS_SENDEMAIL = 1;

SimpleCursorAdapter listAdapter;

final Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ListAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

edittextEmailAddress = (EditText)findViewById(R.id.email_address);
edittextEmailSubject = (EditText)findViewById(R.id.email_subject);
edittextEmailText = (EditText)findViewById(R.id.email_text);

btnSend = (Button)findViewById(R.id.send);
btnSend.setOnClickListener(btnSendOnClickListener);

listViewFiles = (ListView)findViewById(R.id.filelist);
String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();
listAdapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

listViewFiles.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

listViewFiles.setAdapter(listAdapter);
}

private ArrayList<Uri> getSelectedFiles(){
ArrayList<Uri> arrayU = new ArrayList<Uri>();

SparseBooleanArray checkedArray = listViewFiles.getCheckedItemPositions();

for(int i=0; i<checkedArray.size(); i++)
{
int pos = checkedArray.keyAt(i);
Cursor cursor = listAdapter.getCursor();
cursor.moveToPosition(pos);
String _id = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
Uri selUri = Uri.withAppendedPath(sourceUri, _id);
arrayU.add(selUri);
}

return arrayU;
}

OnClickListener btnSendOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {

arrayUri = getSelectedFiles();

String emailAddress = edittextEmailAddress.getText().toString();
String emailSubject = edittextEmailSubject.getText().toString();
String emailText = edittextEmailText.getText().toString();
String emailAddressList[] = {emailAddress};

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_EMAIL, emailAddressList);
intent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
intent.putExtra(Intent.EXTRA_TEXT, emailText);

if(arrayUri.isEmpty()){
//Send email without photo attached
intent.setAction(Intent.ACTION_SEND);
intent.setType("plain/text");
}else if(arrayUri.size() == 1){
//Send email with ONE photo attached
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, arrayUri.get(0));
intent.setType("image/*");
}else{
//Send email with MULTI photo attached
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayUri);
intent.setType("image/*");
}

startActivity(Intent.createChooser(intent, "Choice App to send email:"));
}};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_OK){
switch(requestCode){
case RQS_SENDEMAIL:
break;
}
}
}

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email address:"/>
<EditText
android:id="@+id/email_address"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email Subject:"/>
<EditText
android:id="@+id/email_subject"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailSubject"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter Text:"/>
<EditText
android:id="@+id/email_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send"/>
<ListView
android:id="@+id/filelist"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


download filesDownload the files.

Next:
- email send images exercise, with spinner of pre-defined subjects.


Tuesday, 23 October 2012

List images in MediaStore.Images.Media, with multiple selection.

Last exercise how to "List images in MediaStore.Images.Media". It's modified to have multiple selection on the ListView.

List images in MediaStore.Images.Media, with multiple selection.


package com.example.androidlistimages;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.app.ListActivity;
import android.database.Cursor;

public class MainActivity extends ListActivity {

//define source of MediaStore.Images.Media, internal or external storage
Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//Uri sourceUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();

ListAdapter adapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

setListAdapter(adapter);
}

}


download filesDownload the files.

Read the post "Start activity to send email with multiple images attached, with build-in MediaStore.Images.Media selector" to know how to retrieve the selected images.

List images in MediaStore.Images.Media

This exercise demonstrate how to list images in MediaStore.Images.Media.

List images in MediaStore.Images.Media


Modify MainActivity.java extends ListActivity.
package com.example.androidlistimages;

import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListAdapter;
import android.app.ListActivity;
import android.database.Cursor;

public class MainActivity extends ListActivity {

//define source of MediaStore.Images.Media, internal or external storage
Uri sourceUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//Uri sourceUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);

String[] from = {MediaStore.MediaColumns.TITLE};
int[] to = {android.R.id.text1};

CursorLoader cursorLoader = new CursorLoader(
this,
sourceUri,
null,
null,
null,
MediaStore.Audio.Media.TITLE);

Cursor cursor = cursorLoader.loadInBackground();

ListAdapter adapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
}


}


download filesDownload the files.

Remark:
Compare with my old exercise, "List audio media in MediaStore.Audio.Media" and "Start activity to play MediaStore.Video.Media by intent with action of Intent.ACTION_VIEW", both managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) and SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) are deprecated. See how we use CursorLoader here.

Next:
- Get path of image in MediaStore.Images.Media from SimpleCursorAdapter
- List images in MediaStore.Images.Media, with multiple selection.

Compare with:
- Query Contacts database, display in ListView.


Start activity to send email with multi images attached, with action of ACTION_SEND_MULTIPLE.

The post "Send email with Image by starting activity using Intent of ACTION_SEND" demonstrate how to send SINGLE image. It's modified to send multi images with action of Intent.ACTION_SEND_MULTIPLE. The Uris of the attached images are stored in a ArrayList, and pass to intent via putParcelableArrayListExtra() method.

Start activity to send multi images attached


package com.example.androidselectmultifiles;

import java.util.ArrayList;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

EditText edittextEmailAddress;
EditText edittextEmailSubject;
EditText edittextEmailText;
Button btnAddFile, btnSend;
ListView listViewFiles;

ArrayList<Uri> arrayUri = new ArrayList<Uri>();
ArrayAdapter<Uri> myFileListAdapter;

final int RQS_LOADIMAGE = 0;
final int RQS_SENDEMAIL = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

edittextEmailAddress = (EditText)findViewById(R.id.email_address);
edittextEmailSubject = (EditText)findViewById(R.id.email_subject);
edittextEmailText = (EditText)findViewById(R.id.email_text);

btnAddFile = (Button)findViewById(R.id.addphoto);
btnSend = (Button)findViewById(R.id.send);
btnAddFile.setOnClickListener(btnAddFileOnClickListener);
btnSend.setOnClickListener(btnSendOnClickListener);

myFileListAdapter = new ArrayAdapter<Uri>(
MainActivity.this,
android.R.layout.simple_list_item_1,
arrayUri);
listViewFiles = (ListView)findViewById(R.id.filelist);
listViewFiles.setAdapter(myFileListAdapter);
}

OnClickListener btnAddFileOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_LOADIMAGE);

}};

OnClickListener btnSendOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {
String emailAddress = edittextEmailAddress.getText().toString();
String emailSubject = edittextEmailSubject.getText().toString();
String emailText = edittextEmailText.getText().toString();
String emailAddressList[] = {emailAddress};

Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_EMAIL, emailAddressList);
intent.putExtra(Intent.EXTRA_SUBJECT, emailSubject);
intent.putExtra(Intent.EXTRA_TEXT, emailText);

if(arrayUri.isEmpty()){
//Send email without photo attached
intent.setAction(Intent.ACTION_SEND);
intent.setType("plain/text");
}else if(arrayUri.size() == 1){
//Send email with ONE photo attached
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, arrayUri.get(0));
intent.setType("image/*");
}else{
//Send email with MULTI photo attached
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayUri);
intent.setType("image/*");
}

startActivity(Intent.createChooser(intent, "Choice App to send email:"));

}};

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

if (resultCode == RESULT_OK){
switch(requestCode){
case RQS_LOADIMAGE:
Uri imageUri = data.getData();
arrayUri.add(imageUri);
myFileListAdapter.notifyDataSetChanged();
break;
case RQS_SENDEMAIL:
break;
}
}
}


}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email address:"/>
<EditText
android:id="@+id/email_address"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter email Subject:"/>
<EditText
android:id="@+id/email_subject"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailSubject"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter Text:"/>
<EditText
android:id="@+id/email_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

<Button
android:id="@+id/addphoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add photo"/>
<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send"/>
<ListView
android:id="@+id/filelist"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


download filesDownload the files.

Next:
- Start activity to send email with multiple images attached, with build-in MediaStore.Images.Media selector.

Monday, 22 October 2012

Samsung Chromebook (Wi-Fi, 11.6-Inch) $249, (3G, 11.6-Inch) $349.99

Samsung Google Chromebook Series 3 Wi-Fi - Dual Core 1.7GHz, 11.6", 2GB RAM & 16GB Flash Storage (XE303C12-A01US)
Price:$249.00
Samsung Google Chromebook Series 3 Wi-Fi + 3G Verizon - Dual Core 1.7GHz, 11.6", 2GB RAM & 16GB Flash Storage (XE303C12-H01US)
Price:$329.99
- Samsung Google Chromebook Series 3 Wi-Fi - Dual Core 1.7GHz, 11.6", 2GB RAM & 16GB Flash Storage (XE303C12-A01US) only $249.00

- Samsung Google Chromebook Series 3 Wi-Fi + 3G Verizon - Dual Core 1.7GHz, 11.6", 2GB RAM & 16GB Flash Storage (XE303C12-H01US) only $329.99


Search WOEID and query Yahoo Weather

In my old posts, demonstrate how to "Search WOEID from http://query.yahooapis.com/" and "Get weather info from Yahoo! Weather RSS Feed". This exercise merge both together.

Search WOEID and query Yahoo Weather

User enter location to be searched for WOEID, then clicked the WOEID to start another activity querying Yahoo for the weather.

And also, the code to read from internet have been moved to AsyncTask to prevent from NetworkOnMainThreadException.

Main activity, MainActivity.java.
package com.example.androidwoeidweather;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

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.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;

public class MainActivity extends Activity {

//Example for "New York"
//http://query.yahooapis.com/v1/public/yql?q=select*from geo.places where text="New York"&format=xml
final String yahooPlaceApisBase = "http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=";
final String yahooapisFormat = "&format=xml";
String yahooPlaceAPIsQuery;

EditText place;
Button search;
ListView listviewWOEID;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

place = (EditText)findViewById(R.id.place);
search = (Button)findViewById(R.id.search);
listviewWOEID = (ListView)findViewById(R.id.woeidlist);

search.setOnClickListener(searchOnClickListener);
}

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

@Override
public void onClick(View arg0) {
if(place.getText().toString().equals("")){
Toast.makeText(getBaseContext(),
"Enter place!",
Toast.LENGTH_LONG).show();
}else{
new MyQueryYahooPlaceTask().execute();
}
}
};

private class MyQueryYahooPlaceTask extends AsyncTask<Void, Void, Void>{

ArrayList<String> l;

@Override
protected Void doInBackground(Void... arg0) {
l = QueryYahooPlaceAPIs();
return null;
}

@Override
protected void onPostExecute(Void result) {
ArrayAdapter<String> aa = new ArrayAdapter<String>(
getBaseContext(), android.R.layout.simple_list_item_1, l);
listviewWOEID.setAdapter(aa);

listviewWOEID.setOnItemClickListener(new OnItemClickListener(){

@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {

String selWoeid = parent.getItemAtPosition(position).toString();

/*
Toast.makeText(getApplicationContext(),
selWoeid,
Toast.LENGTH_LONG).show();
*/

Intent intent = new Intent();
intent.setClass(MainActivity.this, GetWeather.class);
Bundle bundle = new Bundle();
bundle.putCharSequence("SEL_WOEID", selWoeid);
intent.putExtras(bundle);
startActivity(intent);
}});

super.onPostExecute(result);
}

}

private ArrayList<String> QueryYahooPlaceAPIs(){
String uriPlace = Uri.encode(place.getText().toString());

yahooPlaceAPIsQuery = yahooPlaceApisBase
+ "%22" + uriPlace + "%22"
+ yahooapisFormat;

String woeidString = QueryYahooWeather(yahooPlaceAPIsQuery);
Document woeidDoc = convertStringToDocument(woeidString);
return parseWOEID(woeidDoc);
}

private ArrayList<String> parseWOEID(Document srcDoc){
ArrayList<String> listWOEID = new ArrayList<String>();

NodeList nodeListDescription = srcDoc.getElementsByTagName("woeid");
if(nodeListDescription.getLength()>=0){
for(int i=0; i<nodeListDescription.getLength(); i++){
listWOEID.add(nodeListDescription.item(i).getTextContent());
}
}else{
listWOEID.clear();
}

return listWOEID;
}

private Document convertStringToDocument(String src){
Document dest = null;

DocumentBuilderFactory dbFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder parser;

try {
parser = dbFactory.newDocumentBuilder();
dest = parser.parse(new ByteArrayInputStream(src.getBytes()));
} catch (ParserConfigurationException e1) {
e1.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return dest;
}

private String QueryYahooWeather(String queryString){
String qResult = "";

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

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();
}
} catch (ClientProtocolException e) {
e.printStackTrace();;
} catch (IOException e) {
e.printStackTrace();
}

return qResult;
}

}


Layout of the main activity, activity_main.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<EditText
android:id="@+id/place"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Search WOEID by place" />
<ListView
android:id="@+id/woeidlist"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />

</LinearLayout>


The activity to query weather from Yahoo, GetWeather.java.
package com.example.androidwoeidweather;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

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.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

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

public class GetWeather extends Activity {

TextView weather;

class MyWeather{

String description;
String city;
String region;
String country;

String windChill;
String windDirection;
String windSpeed;

String sunrise;
String sunset;

String conditiontext;
String conditiondate;

public String toString(){

String s;

s = description + " -\n\n" + "city: " + city + "\n"
+ "region: " + region + "\n"
+ "country: " + country + "\n\n"
+ "Wind\n"
+ "chill: " + windChill + "\n"
+ "direction: " + windDirection + "\n"
+ "speed: " + windSpeed + "\n\n"
+ "Sunrise: " + sunrise + "\n"
+ "Sunset: " + sunset + "\n\n"
+ "Condition: " + conditiontext + "\n"
+ conditiondate +"\n";

return s;
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_weather);
weather = (TextView)findViewById(R.id.weather);

Bundle bundle = this.getIntent().getExtras();
String sel_woeid = (String)bundle.getCharSequence("SEL_WOEID");

new MyQueryYahooWeatherTask(sel_woeid).execute();

Toast.makeText(getApplicationContext(),
sel_woeid,
Toast.LENGTH_LONG).show();
}

private class MyQueryYahooWeatherTask extends AsyncTask<Void, Void, Void>{

String woeid;
String weatherResult;
String weatherString;

MyQueryYahooWeatherTask(String w){
woeid = w;
}

@Override
protected Void doInBackground(Void... arg0) {
weatherString = QueryYahooWeather();
Document weatherDoc = convertStringToDocument(weatherString);

if(weatherDoc != null){
weatherResult = parseWeather(weatherDoc).toString();
}else{
weatherResult = "Cannot convertStringToDocument!";
}

return null;
}

@Override
protected void onPostExecute(Void result) {
weather.setText(weatherResult);
super.onPostExecute(result);
}

private String QueryYahooWeather(){
String qResult = "";
String queryString = "http://weather.yahooapis.com/forecastrss?w=" + woeid;

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

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();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return qResult;
}

private Document convertStringToDocument(String src){
Document dest = null;

DocumentBuilderFactory dbFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder parser;

try {
parser = dbFactory.newDocumentBuilder();
dest = parser.parse(new ByteArrayInputStream(src.getBytes()));
} catch (ParserConfigurationException e1) {
e1.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return dest;
}

private MyWeather parseWeather(Document srcDoc){

MyWeather myWeather = new MyWeather();

//<description>Yahoo! Weather for New York, NY</description>
NodeList descNodelist = srcDoc.getElementsByTagName("description");
if(descNodelist != null && descNodelist.getLength() > 0){
myWeather.description = descNodelist.item(0).getTextContent();
}else{
myWeather.description = "EMPTY";
}

//<yweather:location city="New York" region="NY" country="United States"/>
NodeList locationNodeList = srcDoc.getElementsByTagName("yweather:location");
if(locationNodeList != null && locationNodeList.getLength() > 0){
Node locationNode = locationNodeList.item(0);
NamedNodeMap locNamedNodeMap = locationNode.getAttributes();

myWeather.city = locNamedNodeMap.getNamedItem("city").getNodeValue().toString();
myWeather.region = locNamedNodeMap.getNamedItem("region").getNodeValue().toString();
myWeather.country = locNamedNodeMap.getNamedItem("country").getNodeValue().toString();
}else{
myWeather.city = "EMPTY";
myWeather.region = "EMPTY";
myWeather.country = "EMPTY";
}

//<yweather:wind chill="60" direction="0" speed="0"/>
NodeList windNodeList = srcDoc.getElementsByTagName("yweather:wind");
if(windNodeList != null && windNodeList.getLength() > 0){
Node windNode = windNodeList.item(0);
NamedNodeMap windNamedNodeMap = windNode.getAttributes();

myWeather.windChill = windNamedNodeMap.getNamedItem("chill").getNodeValue().toString();
myWeather.windDirection = windNamedNodeMap.getNamedItem("direction").getNodeValue().toString();
myWeather.windSpeed = windNamedNodeMap.getNamedItem("speed").getNodeValue().toString();
}else{
myWeather.windChill = "EMPTY";
myWeather.windDirection = "EMPTY";
myWeather.windSpeed = "EMPTY";
}

//<yweather:astronomy sunrise="6:52 am" sunset="7:10 pm"/>
NodeList astNodeList = srcDoc.getElementsByTagName("yweather:astronomy");
if(astNodeList != null && astNodeList.getLength() > 0){
Node astNode = astNodeList.item(0);
NamedNodeMap astNamedNodeMap = astNode.getAttributes();

myWeather.sunrise = astNamedNodeMap.getNamedItem("sunrise").getNodeValue().toString();
myWeather.sunset = astNamedNodeMap.getNamedItem("sunset").getNodeValue().toString();
}else{
myWeather.sunrise = "EMPTY";
myWeather.sunset = "EMPTY";
}

//<yweather:condition text="Fair" code="33" temp="60" date="Fri, 23 Mar 2012 8:49 pm EDT"/>
NodeList conditionNodeList = srcDoc.getElementsByTagName("yweather:condition");
if(conditionNodeList != null && conditionNodeList.getLength() > 0){
Node conditionNode = conditionNodeList.item(0);
NamedNodeMap conditionNamedNodeMap = conditionNode.getAttributes();

myWeather.conditiontext = conditionNamedNodeMap.getNamedItem("text").getNodeValue().toString();
myWeather.conditiondate = conditionNamedNodeMap.getNamedItem("date").getNodeValue().toString();
}else{
myWeather.conditiontext = "EMPTY";
myWeather.conditiondate = "EMPTY";
}

return myWeather;
}

}

}


Layout of GetWeather, layout_weather.xml.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/weather"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</ScrollView>

</LinearLayout>


Modify AndroidManifest.xml to add activity ".GetWeather" and permission of "android.permission.INTERNET".
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidwoeidweather"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".GetWeather">
</activity>
</application>

</manifest>


download filesDownload the files.

Friday, 19 October 2012

AutoCompleteTextView with dynamic suggested words

The post "Example of AutoCompleteTextView" demonstrate AutoCompleteTextView with pre-defined suggested words. It's modified to have dynamic suggested words in this exercise.

AutoCompleteTextView with dynamic suggested words

myAutoCompleteAdapter employ a List<string> instead of String[]. Such that we can modify the contain dynamically. When user finish enter by clicking on OK button, it will check if the words is contained in the List<string>. If not, it will be added, and the adapter will be updated.

package com.example.androidautocompletetextview;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements TextWatcher{

AutoCompleteTextView myAutoComplete;
String item[]={
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};

List<String> myList;
ArrayAdapter<String> myAutoCompleteAdapter;

Button buttonOK;
TextView autoList;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

myAutoComplete = (AutoCompleteTextView)findViewById(R.id.myautocomplete);

prepareMyList();
myAutoComplete.addTextChangedListener(this);

myAutoCompleteAdapter = new ArrayAdapter<String>(
MainActivity.this,
android.R.layout.simple_dropdown_item_1line,
myList);

myAutoComplete.setAdapter(myAutoCompleteAdapter);

buttonOK = (Button)findViewById(R.id.ok);
buttonOK.setOnClickListener(OkOnClickListener);

autoList = (TextView)findViewById(R.id.autolist);
}

private void prepareMyList(){
//prepare your list of words for AutoComplete
myList = new ArrayList<String>();
for(int i = 0; i < item.length; i++){
myList.add(item[i]);
}
}

OnClickListener OkOnClickListener
= new OnClickListener(){

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

String newAdd = myAutoComplete.getText().toString();

if(!myList.contains(newAdd)){
myList.add(newAdd);

// I don't know why simple notifyDataSetChanged()
// cannot update the autocomplete words
//myAutoCompleteAdapter.notifyDataSetChanged();

//update the autocomplete words
myAutoCompleteAdapter = new ArrayAdapter<String>(
MainActivity.this,
android.R.layout.simple_dropdown_item_1line,
myList);

myAutoComplete.setAdapter(myAutoCompleteAdapter);
}

//display the words in myList for your reference
String s = "";
for(int i = 0; i < myList.size(); i++){
s += myList.get(i) + "\n";
}
autoList.setText(s);
}};

@Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub

}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub

}

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<AutoCompleteTextView
android:id="@+id/myautocomplete"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"/>
<Button
android:id="@+id/ok"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="OK"/>
<TextView
android:id="@+id/autolist"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


download filesDownload the files.

MOTODEV ends



Motorola launched the MOTODEV Android Portal in 2009 to provide developers with the technical support and resources needed to create quality apps for Motorola devices.

On November 1, the MOTODEV portal, tech library, support forums and social media sites will transition and we’ll begin redirecting users to a new Developer Resources page on Motorola.com for downloads and links to the rich set of tools, support forums and technical documentation now available in the broader Android community such as: Google Android Developers and Stack Overflow.

~ Full announcement from MOTODEV.

Create Animation using Matrix

The former exercise demonstrate how to "Using Matrix create scaled bitmap". In this exercise, we will create animation using matrix.

Create Animation using Matrix


package com.example.androidmatrixanimation;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.Matrix;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
import android.view.animation.Transformation;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

Button myButton;
ImageView myImage1, myImage2;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

myButton = (Button)findViewById(R.id.mybutton);
myImage1 = (ImageView)findViewById(R.id.myimage1);
myImage2 = (ImageView)findViewById(R.id.myimage2);

myButton.setOnClickListener(myOnClickListener);
myImage1.setOnClickListener(myOnClickListener);
myImage2.setOnClickListener(myOnClickListener);

}

OnClickListener myOnClickListener
= new OnClickListener(){

@Override
public void onClick(View v) {
applyAnimation(v);

}
};

private void applyAnimation(View v){
MyAnimation myAnimation = new MyAnimation();
myAnimation.setDuration(5000);
myAnimation.setFillAfter(true);
myAnimation.setInterpolator(new OvershootInterpolator());

v.startAnimation(myAnimation);
}

public class MyAnimation extends Animation{

@Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
super.applyTransformation(interpolatedTime, t);

final Matrix matrix = t.getMatrix();
matrix.setScale(interpolatedTime, interpolatedTime);
}
}

}


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/mybutton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<ImageView
android:id="@+id/myimage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="@drawable/ic_launcher" />
<ImageView
android:id="@+id/myimage2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
android:src="@drawable/ic_launcher" />

</LinearLayout>




download filesDownload the files.

Download the APK.

Thursday, 18 October 2012

AndroidKickstartR, Start your next Android app in 10 seconds.



AndroidKickstartR helps you to quickly create a well configured Android application using the most popular libraries. It creates and configures your project for you. Just focus on code!

Visit: http://androidkickstartr.com/

Android Apps Security



Android Apps Security provides guiding principles for how to best design and develop Android apps with security in mind. It explores concepts that can be used to secure apps and how developers can use and incorporate these security features into their apps.

This book will provide developers with the information they need to design useful, high-performing, and secure apps that expose end-users to as little risk as possible. 
  • Overview of Android OS versions, features, architecture and security. 
  • Detailed examination of areas where attacks on applications can take place and what controls should be implemented to protect private user data
  • In-depth guide to data encryption, authentication techniques, enterprise security and applied real-world examples of these concepts

What you’ll learn

  • How to identify data that should be secured
  • How to use the Android APIs to ensure confidentiality and integrity of data
  • How to build secure apps for the enterprise
  • About Public Key Infrastructure, encryption APIs and how to implement them in apps
  • About owners, access control lists and permissions to allow user control over App properties
  • About client-server apps and how to manage authentication, transport layer encryption and server-side security

Who this book is for

This book is for intermediate and experienced Android app developers that are already familiar with writing apps from scratch. It discusses mechanisms on how apps can be secured so that private, end-user data is kept secure on the device and while in transit. If you’re just embarking on the path to Android development, then this book may prove to be a useful companion to other developer guides.

Table of Contents

  1. Android Architecture & Security Controls
  2. The Foundation of an App
  3. Who Has Access?
  4. Designing and Developing 3 Sample Apps
  5. Using PKI & Encryption
  6. Interfacing with Web Services
  7. Writing for the Enterprise
  8. Designing and Developing 3 More Sample Apps
  9. Publishing and Selling Your Apps
  10. Malware, Spyware and Your End-User
  11. API Reference