Friday, March 30, 2012

Example of using PopupWindow

android.widget.PopupWindow can be used to display an arbitrary view. The popup windows is a floating container that appears on top of the current activity.

Example of PopupWindow

Create /res/layout/popup.xml to define the view of the PopupWindow.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    android:background="@android:color/background_light">
 <LinearLayout 
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:orientation="vertical" 
     android:layout_margin="1dp"
     android:background="@android:color/darker_gray">
     >
     <LinearLayout 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:orientation="vertical" 
      android:layout_margin="20dp">
      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="It's a PopupWindow" />
      <ImageView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:src="@drawable/ic_launcher" />
      <Button
          android:id="@+id/dismiss"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:text="Dismiss" />
      </LinearLayout>
 </LinearLayout>
</LinearLayout>


Main activity Java code to handle the PopupWindow
package com.exercise.AndroidPopupWindow;

import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;

public class AndroidPopupWindowActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        final Button btnOpenPopup = (Button)findViewById(R.id.openpopup);
        btnOpenPopup.setOnClickListener(new Button.OnClickListener(){

   @Override
   public void onClick(View arg0) {
    LayoutInflater layoutInflater 
     = (LayoutInflater)getBaseContext()
      .getSystemService(LAYOUT_INFLATER_SERVICE);  
    View popupView = layoutInflater.inflate(R.layout.popup, null);  
             final PopupWindow popupWindow = new PopupWindow(
               popupView, 
               LayoutParams.WRAP_CONTENT,  
                     LayoutParams.WRAP_CONTENT);  
             
             Button btnDismiss = (Button)popupView.findViewById(R.id.dismiss);
             btnDismiss.setOnClickListener(new Button.OnClickListener(){

     @Override
     public void onClick(View v) {
      // TODO Auto-generated method stub
      popupWindow.dismiss();
     }});
               
             popupWindow.showAsDropDown(btnOpenPopup, 50, -30);
         
   }});
    }
}


main.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" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />
    <Button
        android:id="@+id/openpopup"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Open Popup Window" />
    
</LinearLayout>

updated@2015-01-30, with demo video:

Next:
- Disable outside PopupWindow, by setFocusable(true)

Related:
- PopupMenu, for Android 3.0(API Level 11)



More examples of using PopupWindow:


Example of using PopupMenu

Android 3.0(API Level 11) provide android.widget.PopupMenu class, to displays a Menu in a modal popup window anchored to a View. The popup will appear below the anchor view if there is room, or above it if there is not. If the IME is visible the popup will not overlap it until it is touched. Touching outside of the popup will dismiss it.

Example of using PopupMenu

Create a file /res/menu/popupmenu.xml to define the PopupMenu.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <group android:id="@+id/group_popupmenu">
      <item android:id="@+id/menu1"
          android:title="Popup menu item 1"/>
      <item android:id="@+id/menu2"
          android:title="Popup menu item 2"/>
      <item android:id="@+id/menu3"
          android:title="Popup menu item 3"/>
  </group>
</menu>


Main Java code
package com.AndroidPopupMenu;

import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidPopupMenuActivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    
      Button button = (Button)findViewById(R.id.button);
      TextView text = (TextView)findViewById(R.id.text);
      ImageView image = (ImageView)findViewById(R.id.image);
    
      button.setOnClickListener(viewClickListener);
      text.setOnClickListener(viewClickListener);
      image.setOnClickListener(viewClickListener);
    
    
  }

  OnClickListener viewClickListener
  = new OnClickListener(){

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

  private void showPopupMenu(View v){
   PopupMenu popupMenu = new PopupMenu(AndroidPopupMenuActivity.this, v);
      popupMenu.getMenuInflater().inflate(R.menu.popupmenu, popupMenu.getMenu());
    
      popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
   
   @Override
   public boolean onMenuItemClick(MenuItem item) {
    Toast.makeText(AndroidPopupMenuActivity.this,
      item.toString(),
      Toast.LENGTH_LONG).show();
    return true;
   }
  });
    
      popupMenu.show();
  }
}


Main layout, main.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"
  android:gravity="center_horizontal">

  <TextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="@string/hello" />
  <Button
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="A Button"
      />
  <TextView
      android:id="@+id/text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="A TextView"
      />
  <ImageView
      android:id="@+id/image"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:src="@drawable/ic_launcher"
      />

</LinearLayout>


Related:
- PopupWindow

Thursday, March 29, 2012

New Guide for Enterprise Android Developers

A GUIDE TO MOBILIZING YOUR APPS
Timely execution of your company's mobile strategy means getting your development teams up to speed quickly on Android. In this step-by-step guide, you’ll find best practices for each stage of Android app development.

Topics include:
  • Best practices for each stage of mobile development
  • Enterprise-specific considerations such as security and systems integration
  • How to leverage the unique opportunities with mobility and mobile devices
  • Android development and testing tools
  • Deployment strategies

DOWNLOAD DEVELOPER GUIDE: Learn how developing mobile apps differs from desktop apps and what you can do to get up and running fast with Android app development for your enterprise.

Wednesday, March 28, 2012

Google Weather App

Last exercise demonstrate the basic of Google Weather API. It's modified to be a completed app with better look, with function of searching place.

Google Weather App

Main Java code:
package com.exercise.AndroidGoogleWeather;

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.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

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

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class AndroidGoogleWeatherActivity extends Activity {

class ForecastInformation{
String city;
String postal_code;
String forecast_date;
String current_date_time;
String unit_system;
}

class CurrentConditions{
String condition;
String temp_f;
String temp_c;
String humidity;
String icon;
String wind_condition;
}

class ForecastConditions{
String day_of_week;
String low;
String high;
String icon;
String condition;
}

ForecastInformation forecastInformation;
CurrentConditions currentConditions;
List<ForecastConditions> forecastConditionsList;

Button buttonEnter;
EditText edittextPlace;
ImageView iconCurrent;
TextView textCurrent;
TextView textInfo;
ListView listForcast;


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

buttonEnter = (Button)findViewById(R.id.enter);
edittextPlace = (EditText)findViewById(R.id.place);
iconCurrent = (ImageView)findViewById(R.id.iconcurrent);
textCurrent = (TextView)findViewById(R.id.textcurrent);
textInfo = (TextView)findViewById(R.id.textinfo);
listForcast = (ListView)findViewById(R.id.listforcast);

buttonEnter.setOnClickListener(EnterOnClickListener);

}

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

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String place = edittextPlace.getText().toString();

String weatherString = QueryGoogleWeather(place);
Document weatherDoc = convertStringToDocument(weatherString);

if(parseGoogleWeather(weatherDoc)){
//Display Result
String c = currentConditions.condition + "\n"
+ currentConditions.temp_f + "f\n"
+ currentConditions.temp_c + "c\n"
+ currentConditions.humidity + "\n"
+ currentConditions.wind_condition + "\n";

textCurrent.setText(c);
Bitmap bm = LoadIcon(currentConditions.icon);
iconCurrent.setImageBitmap(bm);

textInfo.setText("city: " + forecastInformation.city + "\n"
+ "postal code: " + forecastInformation.postal_code + "\n"
+ "forecast date: " + forecastInformation.forecast_date + "\n"
+ "current date time: " + forecastInformation.current_date_time + "\n"
+ "unit: " + forecastInformation.unit_system);

listForcast.setAdapter(new MyCustomAdapter(
AndroidGoogleWeatherActivity.this,
R.layout.row,
forecastConditionsList));
}


}

};

public class MyCustomAdapter extends ArrayAdapter<ForecastConditions> {

public MyCustomAdapter(Context context, int textViewResourceId,
List<ForecastConditions> objects) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.row, parent, false);
ImageView iconForecast = (ImageView)row.findViewById(R.id.iforecast);
TextView textForecast = (TextView)row.findViewById(R.id.tforecast);


textForecast.setText(
forecastConditionsList.get(position).day_of_week + "\n"
+ " - " + forecastConditionsList.get(position).condition + "\n"
+ forecastConditionsList.get(position).low + " ~ "
+ forecastConditionsList.get(position).high);

Bitmap bm = LoadIcon(forecastConditionsList.get(position).icon);
iconForecast.setImageBitmap(bm);

return row;
}

}

private Bitmap LoadIcon(String iconURL)
{
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
String image_URL = "http://www.google.com" + iconURL;

Bitmap bitmap = null;
InputStream in = null;
try {
in = OpenHttpConnection(image_URL);
bitmap = BitmapFactory.decodeStream(in, null, bmOptions);
in.close();
} catch (IOException e1) {
}
return bitmap;
}

private InputStream OpenHttpConnection(String strURL) throws IOException{
InputStream inputStream = null;
URL url = new URL(strURL);
URLConnection conn = url.openConnection();

try{
HttpURLConnection httpConn = (HttpURLConnection)conn;
httpConn.setRequestMethod("GET");
httpConn.connect();

if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
inputStream = httpConn.getInputStream();
}
}catch (Exception ex){
}
return inputStream;
}

private boolean parseGoogleWeather(Document srcDoc){

boolean result = false;

forecastInformation = new ForecastInformation();
currentConditions = new CurrentConditions();

//-- Get forecast_information
NodeList forecast_information = srcDoc.getElementsByTagName("forecast_information");
if (forecast_information.getLength() > 0){

//Assume place found if "forecast_information" exist
result = true;

NodeList infoChilds = forecast_information.item(0).getChildNodes();

for(int i=0; i<infoChilds.getLength(); i++){
Node n = infoChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();
if (nName.equalsIgnoreCase("city")){
forecastInformation.city = nValue;
}else if((nName.equalsIgnoreCase("postal_code"))){
forecastInformation.postal_code = nValue;
}else if((nName.equalsIgnoreCase("forecast_date"))){
forecastInformation.forecast_date = nValue;
}else if((nName.equalsIgnoreCase("current_date_time"))){
forecastInformation.current_date_time = nValue;
}else if((nName.equalsIgnoreCase("unit_system"))){
forecastInformation.unit_system = nValue;
}
}
}

//-- Get current_conditions
NodeList current_conditions = srcDoc.getElementsByTagName("current_conditions");
if(current_conditions.getLength()>0){
NodeList currentChilds = current_conditions.item(0).getChildNodes();

for(int i=0; i<currentChilds.getLength(); i++){
Node n = currentChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();
if (nName.equalsIgnoreCase("condition")){
currentConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("temp_f"))){
currentConditions.temp_f = nValue;
}else if((nName.equalsIgnoreCase("temp_c"))){
currentConditions.temp_c = nValue;
}else if((nName.equalsIgnoreCase("humidity"))){
currentConditions.humidity = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
currentConditions.icon = nValue;
}else if((nName.equalsIgnoreCase("wind_condition"))){
currentConditions.wind_condition = nValue;
}
}
}

//-- Get forecast_conditions
NodeList forecast_conditions = srcDoc.getElementsByTagName("forecast_conditions");
if (forecast_conditions.getLength()>0){
int forecast_conditions_length = forecast_conditions.getLength();

forecastConditionsList = new ArrayList<ForecastConditions>();

for(int j=0; j<forecast_conditions_length; j++){

ForecastConditions tmpForecastConditions = new ForecastConditions();

NodeList forecasrChilds = forecast_conditions.item(j).getChildNodes();

for(int i=0; i<forecasrChilds.getLength(); i++){

Node n = forecasrChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();

if (nName.equalsIgnoreCase("condition")){
tmpForecastConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("day_of_week"))){
tmpForecastConditions.day_of_week = nValue;
}else if((nName.equalsIgnoreCase("low"))){
tmpForecastConditions.low = nValue;
}else if((nName.equalsIgnoreCase("high"))){
tmpForecastConditions.high = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
tmpForecastConditions.icon = nValue;
}
}
forecastConditionsList.add(tmpForecastConditions);
}
}

return result;
}

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();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return dest;
}

private String QueryGoogleWeather(String p){

String uriPlace = Uri.encode(p);

String qResult = "";
String queryString = "http://www.google.com/ig/api?hl=en&weather=" + uriPlace;

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();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return qResult;
}
}


main.xml layout
<?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" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/enter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="- Enter -"/>
<EditText
android:id="@+id/place"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:id="@+id/iconcurrent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/textcurrent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:gravity="center"/>

</LinearLayout>
<TextView
android:id="@+id/textinfo"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ListView
android:id="@+id/listforcast"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ListView>
</LinearLayout>


row.xml, the row layout of the custom 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/iforecast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp" />
<TextView
android:id="@+id/tforecast"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.

Tuesday, March 27, 2012

Get Google Weather

It's another online weather info provided by Google:
http://www.google.com/ig/api?hl=en&weather=new%20york

Similar to Yahoo! Weather. It return weather information in XML format. It's a example to get New York weather from Google.

Get Google Weather

package com.exercise.AndroidGoogleWeather;

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 java.util.List;

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

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

public class AndroidGoogleWeatherActivity extends Activity {

class CurrentConditions{
String condition;
String temp_f;
String temp_c;
String humidity;
String icon;
String wind_condition;
}

class ForecastConditions{
String day_of_week;
String low;
String high;
String icon;
String condition;
}

CurrentConditions currentConditions;
List<ForecastConditions> forecastConditionsList;

TextView tvCurrentConditions;


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

String weatherString = QueryGoogleWeather();
Document weatherDoc = convertStringToDocument(weatherString);
parseGoogleWeather(weatherDoc);

//Display Result
String s = "\n"
+ currentConditions.condition + "\n"
+ currentConditions.temp_f + "\n"
+ currentConditions.temp_c + "\n"
+ currentConditions.humidity + "\n"
+ currentConditions.icon + "\n"
+ currentConditions.wind_condition + "\n";

for(int k=0; k < 4; k++){
s += "\n"
+ forecastConditionsList.get(k).condition + "\n"
+ forecastConditionsList.get(k).day_of_week + "\n"
+ forecastConditionsList.get(k).low + "\n"
+ forecastConditionsList.get(k).high + "\n"
+ forecastConditionsList.get(k).icon + "\n";
}

tvCurrentConditions.setText(s);

}

private void parseGoogleWeather(Document srcDoc){

currentConditions = new CurrentConditions();

//-- Get current_conditions
NodeList current_conditions = srcDoc.getElementsByTagName("current_conditions");
NodeList currentChilds = current_conditions.item(0).getChildNodes();

for(int i=0; i<currentChilds.getLength(); i++){
Node n = currentChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();
if (nName.equalsIgnoreCase("condition")){
currentConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("temp_f"))){
currentConditions.temp_f = nValue;
}else if((nName.equalsIgnoreCase("temp_c"))){
currentConditions.temp_c = nValue;
}else if((nName.equalsIgnoreCase("humidity"))){
currentConditions.humidity = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
currentConditions.icon = nValue;
}else if((nName.equalsIgnoreCase("wind_condition"))){
currentConditions.wind_condition = nValue;
}
}

//-- Get forecast_conditions
NodeList forecast_conditions = srcDoc.getElementsByTagName("forecast_conditions");
int forecast_conditions_length = forecast_conditions.getLength();

forecastConditionsList = new ArrayList<ForecastConditions>();

for(int j=0; j<forecast_conditions_length; j++){

ForecastConditions tmpForecastConditions = new ForecastConditions();

NodeList forecasrChilds = forecast_conditions.item(j).getChildNodes();

for(int i=0; i<forecasrChilds.getLength(); i++){

Node n = forecasrChilds.item(i);

String nName = n.getNodeName();
String nValue
= n.getAttributes().getNamedItem("data").getNodeValue().toString();

if (nName.equalsIgnoreCase("condition")){
tmpForecastConditions.condition = nValue;
}else if((nName.equalsIgnoreCase("day_of_week"))){
tmpForecastConditions.day_of_week = nValue;
}else if((nName.equalsIgnoreCase("low"))){
tmpForecastConditions.low = nValue;
}else if((nName.equalsIgnoreCase("high"))){
tmpForecastConditions.high = nValue;
}else if((nName.equalsIgnoreCase("icon"))){
tmpForecastConditions.icon = nValue;
}

}

forecastConditionsList.add(tmpForecastConditions);

}


}

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();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return dest;
}

private String QueryGoogleWeather(){
String qResult = "";
String queryString = "http://www.google.com/ig/api?hl=en&weather=new%20york";

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();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidGoogleWeatherActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return qResult;
}
}


<?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" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/currentconditions"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.

Next:
- Google Weather App

Related:
- Get weather info from Yahoo! Weather RSS Feed.
- Get description from Yahoo! Weather RSS feed, and display in WebView.

Monday, March 26, 2012

Search WOEID from http://query.yahooapis.com/

In previous exercises "Get weather info from Yahoo! Weather RSS Feed" and "Get description from Yahoo! Weather RSS feed, and display in WebView", I search Yahoo Weather with fixed WOEID. How can I know the WOEID of a certain place? Yahoo provide a web service to search WOEID.

Here is a example for "new york", you can get the woeid from the returned xml.
http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=%22New%20York%22&format=xml

www.yahooapis.com

It's a example to list the woeid(s) from the returned xml from query.yahooapis.com. Enter the place you want to search in the TextView, and click the "Search WOEID by place" button. The query will be sent to http://query.yahooapis.com/ with expected place, and the returned xml will be parsed, and the woeid(s) will be listed.

Search WOEID from http://query.yahooapis.com/

package com.exercise.AndroidSearchWOEID;

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.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class AndroidSearchWOEIDActivity 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 yahooapisBase = "http://query.yahooapis.com/v1/public/yql?q=select*from%20geo.places%20where%20text=";
final String yahooapisFormat = "&format=xml";
String yahooAPIsQuery;

EditText place;
Button search;
ListView listviewWOEID;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.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{
 ArrayList<String> l = QueryYahooAPIs();

 ArrayAdapter<String> aa = new ArrayAdapter<String>(
   getBaseContext(), android.R.layout.simple_list_item_1, l);

 listviewWOEID.setAdapter(aa);
}
}

};

private ArrayList<String> QueryYahooAPIs(){

 String uriPlace = Uri.encode(place.getText().toString());

 yahooAPIsQuery = yahooapisBase
   + "%22" + uriPlace + "%22"
   + yahooapisFormat;

 String woeidString = QueryYahooWeather(yahooAPIsQuery);
 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();
Toast.makeText(getBaseContext(),
    e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),
    e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(),
    e.toString(), Toast.LENGTH_LONG).show();
}

 return dest;

}

private String QueryYahooWeather(String queryString){

 String qResult = "";

 HttpClient httpClient = new DefaultHttpClient();

 //return Uri.encode(queryString);

    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();
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}

    return qResult;

}

}


main.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" >

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


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.

Related:
- Get weather info from Yahoo! Weather RSS Feed
- Search WOEID and query Yahoo Weather


Sunday, March 25, 2012

Get description from Yahoo! Weather RSS feed, and display in WebView.

Last exercise "Get weather info from Yahoo! Weather RSS Feed" get information from Yahoo! Weather RSS feed, and display in simple text form. Inside the returned feed, there are elements with Tag Name of "description". The second one is in html coded form.

example:
<description>
<![CDATA[
<img src="http://l.yimg.com/a/i/us/we/52/26.gif"/><br /> <b>Current Conditions:</b><br /> Cloudy, 47 F<BR /> <BR /><b>Forecast:</b><BR /> Sun - Few Showers. High: 57 Low: 47<br /> Mon - Sunny/Wind. High: 53 Low: 30<br /> <br /> <a href="http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/USNY0996_f.html">Full Forecast at Yahoo! Weather</a><BR/><BR/> (provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/>
]]>
</description>


This example demonstrate how to retrieve description elements from Yahoo! Weather RSS feed, and display on a WebView.

Get description from Yahoo! Weather RSS feed, and display in WebView.

package com.exercise.AndroidYahooWeatherDOM;

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

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.widget.Toast;

public class AndroidYahooWeatherDOMActivity extends Activity {

WebView webView;

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

String weatherString = QueryYahooWeather();
Document weatherDoc = convertStringToDocument(weatherString);

String weatherResult = parseWeatherDescription(weatherDoc);
webView.loadData(weatherResult, "text/html", "UTF-8");

}
private String parseWeatherDescription(Document srcDoc){
String weatherDescription="";

NodeList nodeListDescription = srcDoc.getElementsByTagName("description");
if(nodeListDescription.getLength()>=0){
for(int i=0; i<nodeListDescription.getLength(); i++){
weatherDescription += nodeListDescription.item(i).getTextContent()+"<br/>";
}
}else{
weatherDescription = ("No Description!");
}

return weatherDescription;
}

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();
Toast.makeText(AndroidYahooWeatherDOMActivity.this,
e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
e.printStackTrace();
Toast.makeText(AndroidYahooWeatherDOMActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidYahooWeatherDOMActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return dest;
}

private String QueryYahooWeather(){

String qResult = "";
String queryString = "http://weather.yahooapis.com/forecastrss?w=2459115";

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();
Toast.makeText(AndroidYahooWeatherDOMActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(AndroidYahooWeatherDOMActivity.this,
e.toString(), Toast.LENGTH_LONG).show();
}

return qResult;
}
}


Modify main.xml to add a WebView.
<?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" >

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />

<WebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</LinearLayout>



You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.


Related:
- Search WOEID from http://query.yahooapis.com/.
- Get Google Weather

Friday, March 23, 2012

Get weather info from Yahoo! Weather RSS Feed

The Yahoo! Weather RSS feed enables you to get up-to-date weather information, http://developer.yahoo.com/weather/.

The Weather RSS feed request follows simple HTTP GET syntax: start with a base URL and then add parameters and values after a question mark (?).

ex: Weather RSS feed for New York
http://weather.yahooapis.com/forecastrss?w=2459115

where 2459115 is WOEID for New York. You can find the code for any location from http://weather.yahoo.com/.

The another exercise show how to Search WOEID from http://query.yahooapis.com/.

The returned XML will like it:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
 <channel>

<title>Yahoo! Weather - New York, NY</title>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/USNY0996_f.html</link>
<description>Yahoo! Weather for New York, NY</description>
<language>en-us</language>
<lastBuildDate>Fri, 23 Mar 2012 8:49 pm EDT</lastBuildDate>
<ttl>60</ttl>
<yweather:location city="New York" region="NY"   country="United States"/>
<yweather:units temperature="F" distance="mi" pressure="in" speed="mph"/>
<yweather:wind chill="60"   direction="0"   speed="0" />
<yweather:atmosphere humidity="49"  visibility="10"  pressure="30.08"  rising="0" />
<yweather:astronomy sunrise="6:52 am"   sunset="7:10 pm"/>
<image>
<title>Yahoo! Weather</title>
<width>142</width>
<height>18</height>
<link>http://weather.yahoo.com</link>
<url>http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif</url>
</image>
<item>
<title>Conditions for New York, NY at 8:49 pm EDT</title>
<geo:lat>40.71</geo:lat>
<geo:long>-74.01</geo:long>
<link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/USNY0996_f.html</link>
<pubDate>Fri, 23 Mar 2012 8:49 pm EDT</pubDate>
<yweather:condition  text="Fair"  code="33"  temp="60"  date="Fri, 23 Mar 2012 8:49 pm EDT" />
<description><![CDATA[
<img src="http://l.yimg.com/a/i/us/we/52/33.gif"/><br />
<b>Current Conditions:</b><br />
Fair, 60 F<BR />
<BR /><b>Forecast:</b><BR />
Fri - Mostly Cloudy. High: 72 Low: 52<br />
Sat - PM Showers. High: 61 Low: 49<br />
<br />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/USNY0996_f.html">Full Forecast at Yahoo! Weather</a><BR/><BR/>
(provided by <a href="http://www.weather.com" >The Weather Channel</a>)<br/>
]]></description>
<yweather:forecast day="Fri" date="23 Mar 2012" low="52" high="72" text="Mostly Cloudy" code="27" />
<yweather:forecast day="Sat" date="24 Mar 2012" low="49" high="61" text="PM Showers" code="39" />
<guid isPermaLink="false">USNY0996_2012_03_24_7_00_EDT</guid>
</item>
</channel>
</rss>
<!-- api1.weather.sg1.yahoo.com compressed/chunked Fri Mar 23 18:50:03 PDT 2012 -->


Yahoo! Weather RSS Feed

It's a example to get Get weather info from Yahoo! Weather RSS Feed. Query Yahoo using HttpGet, then parse the returned XML using DOM. Please note that I only parse the returned RSS partially for demonstration, NOT ALL.

Get weather info from Yahoo! Weather RSS Feed

package com.exercise.AndroidYahooWeatherDOM;

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.Node;
import org.xml.sax.SAXException;

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

public class AndroidYahooWeatherDOMActivity 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(){

 return "\n- " + 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";
 
}
}

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
     weather = (TextView)findViewById(R.id.weather);
  
  
     String weatherString = QueryYahooWeather();
     Document weatherDoc = convertStringToDocument(weatherString);

     MyWeather weatherResult = parseWeather(weatherDoc);
     weather.setText(weatherResult.toString());
 }

 private MyWeather parseWeather(Document srcDoc){

  MyWeather myWeather = new MyWeather();

  //<description>Yahoo! Weather for New York, NY</description>
  myWeather.description = srcDoc.getElementsByTagName("description")
    .item(0)
    .getTextContent();

  //<yweather:location city="New York" region="NY" country="United States"/>
  Node locationNode = srcDoc.getElementsByTagName("yweather:location").item(0);
  myWeather.city = locationNode.getAttributes()
  .getNamedItem("city")
  .getNodeValue()
  .toString();
myWeather.region = locationNode.getAttributes()
  .getNamedItem("region")
  .getNodeValue()
  .toString();
myWeather.country = locationNode.getAttributes()
  .getNamedItem("country")
  .getNodeValue()
  .toString();

//<yweather:wind chill="60" direction="0" speed="0"/>
Node windNode = srcDoc.getElementsByTagName("yweather:wind").item(0);
myWeather.windChill = windNode.getAttributes()
  .getNamedItem("chill")
  .getNodeValue()
  .toString();
myWeather.windDirection = windNode.getAttributes()
  .getNamedItem("direction")
  .getNodeValue()
  .toString();
myWeather.windSpeed = windNode.getAttributes()
  .getNamedItem("speed")
  .getNodeValue()
  .toString();

//<yweather:astronomy sunrise="6:52 am" sunset="7:10 pm"/>
Node astronomyNode = srcDoc.getElementsByTagName("yweather:astronomy").item(0);
myWeather.sunrise = astronomyNode.getAttributes()
  .getNamedItem("sunrise")
  .getNodeValue()
  .toString();
myWeather.sunset = astronomyNode.getAttributes()
  .getNamedItem("sunset")
  .getNodeValue()
  .toString();

//<yweather:condition text="Fair" code="33" temp="60" date="Fri, 23 Mar 2012 8:49 pm EDT"/>
Node conditionNode = srcDoc.getElementsByTagName("yweather:condition").item(0);
myWeather.conditiontext = conditionNode.getAttributes()
  .getNamedItem("text")
  .getNodeValue()
  .toString();
myWeather.conditiondate = conditionNode.getAttributes()
  .getNamedItem("date")
  .getNodeValue()
  .toString();

  return myWeather;
 }

 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();
 Toast.makeText(AndroidYahooWeatherDOMActivity.this,
     e1.toString(), Toast.LENGTH_LONG).show();
} catch (SAXException e) {
 e.printStackTrace();
 Toast.makeText(AndroidYahooWeatherDOMActivity.this,
     e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
 e.printStackTrace();
 Toast.makeText(AndroidYahooWeatherDOMActivity.this,
     e.toString(), Toast.LENGTH_LONG).show();
}

  return dest;
 }

 private String QueryYahooWeather(){

  String qResult = "";
  String queryString = "http://weather.yahooapis.com/forecastrss?w=2459115";

  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();
 Toast.makeText(AndroidYahooWeatherDOMActivity.this,
     e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
 e.printStackTrace();
 Toast.makeText(AndroidYahooWeatherDOMActivity.this,
     e.toString(), Toast.LENGTH_LONG).show();
}

     return qResult;
 }
}


main.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" >

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


You have to modify AndroidManifest.xml to grand permission of "android.permission.INTERNET"

Download the files.

Next:
- Get description from Yahoo! Weather RSS feed, and display in WebView.
- Search WOEID from http://query.yahooapis.com/.
- Search WOEID and query Yahoo Weather
- Get Google Weather

Updated version:
- Get weather info from Yahoo! Weather RSS Feed in background thread

Thursday, March 22, 2012

SDK Tools and ADT updated revision 17

Updated SDK Tools and ADT revision 17, with a lot of new features and bug fixes in various areas such as Lint, the build system as well as the emulator.

Details: Android Developers BLog - http://android-developers.blogspot.com/2012/03/updated-sdk-tools-and-adt-revision-17.html

Wednesday, March 21, 2012

AndEngine - FREE 2D OpenGL Game Engine for Android platform

AndEngine
AndEngine is a free Open Source 2D OpenGL Game Engine for the Android platform.

Website: http://www.andengine.org/

Try it on your Android device by installing AndEngine - Examples in Google Play, the application contains various Examples that showcase what developers can do with this engine.

Install this to stay tuned with the progress.

Join the AndEngine-Community at:
http://www.andengine.org/forums/


AndEngine - Examples

Create your own app. No coding required - with Andromo

With Andromo, anyone can make a pro-quality Android app. There's no programming required, plus Andromo generates 100% pure native Android apps. Use your app to promote your business, share events and news, or launch your million dollar idea. It's quick, easy and free.

http://andromo.com/


Create Android Apps for Free with Andromo from Indigo Rose Software on Vimeo.




Saturday, March 17, 2012

eBook for FREE: What's New in Java 7?


Java 7 has a number of features that will please developers. Madhusudhan Konda provides an overview of these, including strings in switch statements, multi-catch exception handling, try-with-resource statements, the new File System API, extensions of the JVM, support for dynamically-typed languages, and the fork and join framework for task parallelism.

From the Author

This is an on-line article published on O'Reilly at radar.oreilly.com/2011/09/java7-features.html (2nd Sept 2011). It does not constitute a book in any form but a condensed technical write-up on new features of Java 7.
O'Reilly team has kindly prepared this article as a small booklet so it can be digested on your electronic readers for FREE.

What's New in Java 7?

getFrameAtTime: videoFrame is a NULL pointer

If you run the exercise of MediaPlayer for Video with un-supported video format, and monitor the LogCat report:- You will notice that error of "getFrameAtTime: videoFrame is a NULL pointer" will be thrown in MediaMetadataRetriever. This happen when VideoListFragment.java try to get Thumbnail in getView(). No Thumbnail will be returned. It's OK in this case.

getFrameAtTime: videoFrame is a NULL pointer

BUT - problem is: after valid Thumbnail returned for supported video format, error "getFrameAtTime: videoFrame is a NULL pointer" will not be thrown again, and the old thumbnail will be returned for later un-supported video format. So the list will display a in-correct thumbnail for un-supported video format.

Currently, I have no any solution for this problem! I even don't know if it's a fault in my code, or is a bug from Android. I hope anybody can leave me comments to solve the problem.

A mileStone of MediaPlay Exercise for video

MediaPlay Exercise for video
My exercise of MediaPlay for video is almost finished. But there are still have some problem in last exercise:

- When you play a narrow video, then play a wider video: the new SurfaceView will be narrow, even cannot play. It's because the the code calculate aspect ratio (doPreSet() in PlayerFragment.java) base on the current SurfaceView, not the whole available area. To solve it, a LinearLayout is added to hold the SurfaceView, allocate whole available area. calculate aspect ratio base on the the LinearLayout.

- Improve life-cycle of the mediaPlayer, and the background thread for timelineMonitor.

- And a un-solved problem of getFrameAtTime: videoFrame is a NULL pointer for un-supported video.

Download the files.

Friday, March 16, 2012

Control play time of video

Modify the last exercise "Display video timeline, in ProgressBar". Replace the ProgressBar with a SeekBar, implement SeekBar.OnSeekBarChangeListener to handle SeekBar change from user, to seek to expected time of video.

Control play time of video

Modify /res/layout/playerlayout.xml to replace ProgressBar with SeekBar.
<?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" >

<SeekBar
android:id="@+id/timeline"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="0"
/>
<SurfaceView
android:id="@+id/surfaceview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />

</LinearLayout>


Modify PlayerFragment.java to implement SeekBar.OnSeekBarChangeListener.
package com.exercise.AndroidListMedia;

import java.io.IOException;

import android.app.Fragment;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.SeekBar;
import android.widget.Toast;
import android.media.AudioManager;

public class PlayerFragment extends Fragment
implements SurfaceHolder.Callback {

Uri targetUri = null;

MediaPlayer mediaPlayer;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
SeekBar timelineBar;

runnableTimeline timelineMonitor;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.playerlayout, container, false);
surfaceView = (SurfaceView)view.findViewById(R.id.surfaceview);

timelineBar = (SeekBar)view.findViewById(R.id.timeline);
timelineBar.setOnSeekBarChangeListener(timelineBarSeekBarChangeListener);

getActivity().getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setFixedSize(176, 144);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

timelineMonitor = new runnableTimeline();
Thread thread = new Thread(timelineMonitor);
thread.start();

return view;
}

SeekBar.OnSeekBarChangeListener timelineBarSeekBarChangeListener
= new SeekBar.OnSeekBarChangeListener(){

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if(fromUser){
if(mediaPlayer != null){
int totalDuration = mediaPlayer.getDuration();
int currentDuration = totalDuration * progress/100;
mediaPlayer.seekTo(currentDuration);
}
}

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub

}

};

public void doPlayPause(){
if (targetUri != null){
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
}else{
mediaPlayer.start();
}
}

}

public void doStop(){
if (targetUri != null){
mediaPlayer.stop();

try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
}

mediaPlayer.seekTo(0);

}
}

private void doPreSet(){

if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
}

mediaPlayer = new MediaPlayer();

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDisplay(surfaceHolder);

try {
mediaPlayer.setDataSource(getActivity().getApplicationContext(), targetUri);
mediaPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
}

/*
* Handle aspect ratio
*/
int surfaceView_Width = surfaceView.getWidth();
int surfaceView_Height = surfaceView.getHeight();

float video_Width = mediaPlayer.getVideoWidth();
float video_Height = mediaPlayer.getVideoHeight();

float ratio_width = surfaceView_Width/video_Width;
float ratio_height = surfaceView_Height/video_Height;
float aspectratio = video_Width/video_Height;

LayoutParams layoutParams = surfaceView.getLayoutParams();

if (ratio_width > ratio_height){
layoutParams.width = (int) (surfaceView_Height * aspectratio);
layoutParams.height = surfaceView_Height;
}else{
layoutParams.width = surfaceView_Width;
layoutParams.height = (int) (surfaceView_Width / aspectratio);
}

surfaceView.setLayoutParams(layoutParams);

}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mediaPlayer.release();
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub

}

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

}

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

}

public void setTargetUri(Uri u, int id){
targetUri = u;

getActivity().setTitle("ID: " + id + " / Uri: " + u.toString());

doPreSet();
mediaPlayer.start();
}

private class runnableTimeline implements Runnable{

@Override
public void run() {
while(true){
if(mediaPlayer != null){
int totalDuration = mediaPlayer.getDuration();
int currentDuration = mediaPlayer.getCurrentPosition();
int currentTime = (int)(100 * currentDuration/totalDuration);
timelineBar.setProgress(currentTime);
}else{
timelineBar.setProgress(0);
}

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

}

}


Download the files.


Next:
- A milestone of MediaPlay Exercise for video

Thursday, March 15, 2012

The HP webOS 3.0.5 SDK released

Downloading and Installing the 3.0.5 SDK and PDK
The HP webOS 3.0.5 SDK contains the libraries necessary to do both JavaScript development and C/C++ development. For JavaScript development, the SDK includes the command line tools needed to package, download, and debug applications, as well as sample code, reference code, and reference documentation. For C/C++ development, the SDK also includes the Plug-in Development Kit (PDK), which includes a GCC compiler, SDL and OpenGL code libraries, project templates, sample source code, scripts, utilities, documents. You will be given an opportunity to opt out of installing the PDK during the installation process.

You can install the SDK on Windows, OS X, and Ubuntu Linux host PCs. For C/C++ development, the SDK integrates with Visual Studio on Windows, and Xcode on OS X, although you can use command-line tools if you prefer. (App templates are currently only available for Xcode 3.6 and earlier.)

Link: Downloading and Installing the 3.0.5 SDK and PDK

Display video timeline, in ProgressBar

Modify from last exercise "Implement ActionBar for our Media Player App", we want to display the timeline of video in ProgressBar.

Display video timeline, in ProgressBar

Modify /res/layout/playerlayout.xml to add a ProgressBar.
<?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" >

<ProgressBar
android:id="@+id/timeline"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="0"
/>
<SurfaceView
android:id="@+id/surfaceview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />


</LinearLayout>


Modify PlayerFragment.java, implement a new class runnableTimeline implements Runnable, to monitor the CurrentPosition of mediaPlay.
package com.exercise.AndroidListMedia;

import java.io.IOException;

import android.app.Fragment;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.media.AudioManager;

public class PlayerFragment extends Fragment
implements SurfaceHolder.Callback {

Uri targetUri = null;

MediaPlayer mediaPlayer;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
ProgressBar timelineBar;

runnableTimeline timelineMonitor;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.playerlayout, container, false);
surfaceView = (SurfaceView)view.findViewById(R.id.surfaceview);
timelineBar = (ProgressBar)view.findViewById(R.id.timeline);

getActivity().getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setFixedSize(176, 144);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

timelineMonitor = new runnableTimeline();
Thread thread = new Thread(timelineMonitor);
thread.start();

return view;
}

public void doPlayPause(){
if (targetUri != null){
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
}else{
mediaPlayer.start();
}
}

}

public void doStop(){
if (targetUri != null){
mediaPlayer.stop();

try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
}

mediaPlayer.seekTo(0);

}
}

private void doPreSet(){

if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
}

mediaPlayer = new MediaPlayer();

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDisplay(surfaceHolder);

try {
mediaPlayer.setDataSource(getActivity().getApplicationContext(), targetUri);
mediaPlayer.prepare();
} catch (IllegalArgumentException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity(), e.toString(), Toast.LENGTH_LONG).show();
}

/*
* Handle aspect ratio
*/
int surfaceView_Width = surfaceView.getWidth();
int surfaceView_Height = surfaceView.getHeight();

float video_Width = mediaPlayer.getVideoWidth();
float video_Height = mediaPlayer.getVideoHeight();

float ratio_width = surfaceView_Width/video_Width;
float ratio_height = surfaceView_Height/video_Height;
float aspectratio = video_Width/video_Height;

LayoutParams layoutParams = surfaceView.getLayoutParams();

if (ratio_width > ratio_height){
layoutParams.width = (int) (surfaceView_Height * aspectratio);
layoutParams.height = surfaceView_Height;
}else{
layoutParams.width = surfaceView_Width;
layoutParams.height = (int) (surfaceView_Width / aspectratio);
}

surfaceView.setLayoutParams(layoutParams);

}

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mediaPlayer.release();
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub

}

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

}

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

}

public void setTargetUri(Uri u, int id){
targetUri = u;

getActivity().setTitle("ID: " + id + " / Uri: " + u.toString());

doPreSet();
mediaPlayer.start();
}

private class runnableTimeline implements Runnable{

@Override
public void run() {
while(true){
if(mediaPlayer != null){
int totalDuration = mediaPlayer.getDuration();
int currentDuration = mediaPlayer.getCurrentPosition();
int currentTime = (int)(100 * currentDuration/totalDuration);
timelineBar.setProgress(currentTime);
}else{
timelineBar.setProgress(0);
}

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

}

}


Download the files.

Next:
- Control play time of video