Thursday, October 30, 2014

Example of using Here Geocoder API on Android

The simplest use of the Here Geocoder API is to search for an address using complete or partial address information in a single-line input field, the searchtext parameter. Any address information can be provided in the single input field, country, state, county, city, street, house number, or postal code.

You can try the example here:
http://geocoder.cit.api.here.com/6.2/geocode.xml?searchtext=425+W+Randolph+Street+Chicago&gen=7&app_id=DemoAppId01082013GAL&app_code=AJKnXv84fjrb0KIHawS0Tg


This example show how to parse the returned XML on Android.


MainActivity.java
package com.example.androidheregeocoder;

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

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.support.v7.app.ActionBarActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

 public class GeocodingTask extends AsyncTask<String, Void, String> {

  TextView textViewRqs, textViewParsed;
  String rqs;

  GeocodingTask(TextView vRqs, TextView vParsed) {
   textViewRqs = vRqs;
   textViewParsed = vParsed;
  }

  @Override
  protected String doInBackground(String... params) {

   final String rqs = "http://geocoder.cit.api.here.com/6.2/geocode.xml"
     + "?searchtext=" + params[0] + "&gen=7"
     + "&app_id=DemoAppId01082013GAL"
     + "&app_code=AJKnXv84fjrb0KIHawS0Tg";

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textViewRqs.setText(rqs);
    }});
   
   return Parse(rqs).toString();
  }

  @Override
  protected void onPostExecute(String result) {
   textViewParsed.setText(result);
  }

  private HereResponse Parse(String urlString) {
   HereResponse hereResponse = new HereResponse();

   final String XmlTag_Response = "Response";
   final String XmlTag_MetaInfo = "MetaInfo";
   final String XmlTag_Timestamp = "Timestamp";
   final String XmlTag_View = "View";
   final String XmlTag_ViewId = "ViewId";
   final String XmlTag_Result = "Result";
   final String XmlTag_Location = "Location";
   
   final String XmlTag_DisplayPosition = "DisplayPosition";
   final String XmlTag_NavigationPosition = "NavigationPosition";
   final String XmlTag_TopLeft = "TopLeft";
   final String XmlTag_BottomRight = "BottomRight";
   
   final String XmlTag_Latitude = "Latitude";
   final String XmlTag_Longitude = "Longitude";
   
   final String XmlTag_Label = "Label";
   final String XmlTag_Country = "Country";
   final String XmlTag_State = "State";
   final String XmlTag_County = "County";
   final String XmlTag_City = "City";
   final String XmlTag_District = "District";
   final String XmlTag_Street = "Street";
   final String XmlTag_HouseNumber = "HouseNumber";
   final String XmlTag_PostalCode = "PostalCode";
   
   String xmlPara = "";
   String xmlGroupPara = "";

   XmlPullParserFactory factory;
   try {
    factory = XmlPullParserFactory.newInstance();
    factory.setNamespaceAware(false);
    XmlPullParser xpp = factory.newPullParser();
    xpp.setInput((new URL(urlString)).openConnection()
      .getInputStream(), "UTF_8");

    int eventType;
    do {
     xpp.next();
     eventType = xpp.getEventType();

     switch (eventType) {
     case XmlPullParser.START_DOCUMENT:
      xmlPara = "";  //0;
      xmlGroupPara = ""; //0;
      break;

     case XmlPullParser.END_DOCUMENT:
      break;

     case XmlPullParser.START_TAG:
      String tag = xpp.getName();
      
      xmlPara = tag;

      if(tag.equals(XmlTag_DisplayPosition)
       || tag.equals(XmlTag_NavigationPosition)
       || tag.equals(XmlTag_TopLeft)
       || tag.equals(XmlTag_BottomRight)){
       xmlGroupPara = tag;
      }

      break;

     case XmlPullParser.END_TAG:
      break;

     case XmlPullParser.TEXT:
      
      if(xmlPara.equals(XmlTag_Timestamp)){
       hereResponse.Timestamp = xpp.getText();
      }else if(xmlPara.equals(XmlTag_ViewId)){
       hereResponse.ViewId = xpp.getText();
      }else if(xmlPara.equals(XmlTag_Latitude)){
       if(xmlGroupPara.equals(XmlTag_DisplayPosition)){
        hereResponse.DisplayPosition_Latitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_NavigationPosition)){
        hereResponse.NavigationPosition_Latitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_TopLeft)){
        hereResponse.TopLeft_Latitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_BottomRight)){
        hereResponse.BottomRight_Latitude = xpp.getText();
       }
      }else if(xmlPara.equals(XmlTag_Longitude)){
       if(xmlGroupPara.equals(XmlTag_DisplayPosition)){
        hereResponse.DisplayPosition_Longitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_NavigationPosition)){
        hereResponse.NavigationPosition_Longitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_TopLeft)){
        hereResponse.TopLeft_Longitude = xpp.getText();
       }else if(xmlGroupPara.equals(XmlTag_BottomRight)){
        hereResponse.BottomRight_Longitude = xpp.getText();
       }
      }else if(xmlPara.equals(XmlTag_Label)){
       hereResponse.Label = xpp.getText();
      }else if(xmlPara.equals(XmlTag_Country)){
       hereResponse.Country = xpp.getText();
      }else if(xmlPara.equals(XmlTag_State)){
       hereResponse.State = xpp.getText();
      }else if(xmlPara.equals(XmlTag_County)){
       hereResponse.County = xpp.getText();
      }else if(xmlPara.equals(XmlTag_City)){
       hereResponse.City = xpp.getText();
      }else if(xmlPara.equals(XmlTag_District)){
       hereResponse.District = xpp.getText();
      }else if(xmlPara.equals(XmlTag_Street)){
       hereResponse.Street = xpp.getText();
      }else if(xmlPara.equals(XmlTag_HouseNumber)){
       hereResponse.HouseNumber = xpp.getText();
      }else if(xmlPara.equals(XmlTag_PostalCode)){
       hereResponse.PostalCode = xpp.getText();
      }
      
      break;
     }

    } while (eventType != XmlPullParser.END_DOCUMENT);
   } catch (XmlPullParserException e) {
    hereResponse.err = (e.getMessage());
    e.printStackTrace();
   } catch (MalformedURLException e) {
    hereResponse.err = (e.getMessage());
    e.printStackTrace();
   } catch (IOException e) {
    hereResponse.err = (e.getMessage());
    e.printStackTrace();
   }

   return hereResponse;
  }

 }

 public class HereResponse {

  String Timestamp = "";
  String ViewId = "";
  String DisplayPosition_Latitude = "";
  String DisplayPosition_Longitude = "";
  String NavigationPosition_Latitude = "";
  String NavigationPosition_Longitude = "";
  String TopLeft_Latitude = "";
  String TopLeft_Longitude = "";
  String BottomRight_Latitude = "";
  String BottomRight_Longitude = "";
  
  String Label = "";
  String Country = "";
  String State = "";
  String County = "";
  String City = "";
  String District = "";
  String Street = "";
  String HouseNumber = "";
  String PostalCode = "";
  
  String err = "";

  public String toString() {
   return "Timestamp: " + Timestamp + "\n"
    + "ViewId: " + ViewId + "\n"
    + "DisplayPosition_Latitude: " + DisplayPosition_Latitude + "\n"
    + "DisplayPosition_Longitude: " + DisplayPosition_Longitude + "\n"
    + "NavigationPosition_Latitude: " + NavigationPosition_Latitude + "\n"
    + "NavigationPosition_Longitude: " + NavigationPosition_Longitude + "\n"
    + "TopLeft_Latitude: " + TopLeft_Latitude + "\n"
    + "TopLeft_Longitude: " + TopLeft_Longitude + "\n"
    + "BottomRight_Latitude: " + BottomRight_Latitude + "\n"
    + "BottomRight_Longitude: " + BottomRight_Longitude + "\n"
    
    + "Label: " + Label + "\n"
    + "Country: " + Country + "\n"
    + "State: " + State + "\n"
    + "County: " + County + "\n"
    + "City: " + City + "\n"
    + "District: " + District + "\n"
    + "Street: " + Street + "\n"
    + "HouseNumber: " + HouseNumber + "\n"
    + "PostalCode: " + PostalCode + "\n"
    
    + "err: " + err;
  }
 }

 EditText textAddressIn;
 Button buttonGet;
 TextView textRqs, textParsed;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  textAddressIn = (EditText) findViewById(R.id.addressin);
  buttonGet = (Button) findViewById(R.id.get);
  textRqs = (TextView) findViewById(R.id.textrqs);
  textParsed = (TextView) findViewById(R.id.textparsed);

  // for easy testing
  textAddressIn.setText("425 W Randolph Street in Chicago");

  buttonGet.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    String strIn = textAddressIn.getText().toString();
    if (!strIn.equals("")) {
     String strHtml = strIn.replace(" ", "+");
     
     getGetGeocode(strHtml);
    }
   }
  });
 }

 private void getGetGeocode(String addr) {
  new GeocodingTask(textRqs, textParsed).execute(addr);
 }

}

/res/layout/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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidheregeocoder.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/addressin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Get Geocode" />
    
    <TextView
        android:id="@+id/textrqs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:id="@+id/textparsed"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.


download filesDownload the files.

Next:
Search and display Map Tile using Here REST API

~ More examples of using Here Map REST API on Android

Wednesday, October 29, 2014

Free ebook: Creating Mobile Apps with Xamarin.Forms, Preview Edition

Free ebook, Creating Mobile Apps with Xamarin.Forms, Preview Edition, is about writing applications for Xamarin.Forms, the new mobile development platform for iOS, Android, and Windows Phone unveiled by Xamarin in May 2014. Xamarin.Forms lets you write shared user-interface code in C# and XAML (the eXtensible Application Markup Language) that maps to native controls on these three platforms.

This free ebook (PDF and Mobi) can be downloaded HERE.

This ebook is a Preview Edition because it's not complete. It has only six chapters.

Source: MSDN Blogs > Microsoft Press > Free ebook: Creating Mobile Apps with Xamarin.Forms, Preview Edition

Tuesday, October 28, 2014

Here Map Tile REST API example, Base Map, Aerial and Traffic Tile

In this example, we show how to display Here map of Base Map, Aerial and Traffic Tile.


MainActivity.java
package com.example.androidhererestmapimage;

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

import android.support.v7.app.ActionBarActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

 public class LoadHereMapTask extends AsyncTask<URL, Void, Bitmap> {
  
  ImageView imageView;
  
  LoadHereMapTask(ImageView v){
   imageView = v;
  }

  @Override
  protected Bitmap doInBackground(URL... params) {
   Bitmap bm = null;
   URL urlMapImage = params[0];
   try {
    bm = BitmapFactory.decodeStream(urlMapImage.openConnection().getInputStream());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return bm;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   imageView.setImageBitmap(result);
  }

 }
 
 private final int optTypeBaseMap = 0;
 private final int optTypeAerialTile = 1;
 private final int optTypeTrafficTile = 2;
 String[] optTypes = {
      "Base Map", 
      "Aerial Tile", 
      "Traffic Tile"};
 
 SeekBar sbZoom;
 Spinner spType;
 TextView textviewMapRqs512, textviewMapRqs256;
 ImageView mapImage1, mapImage2;
 
 ArrayAdapter<String> spTypeAdapter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textviewMapRqs512 = (TextView)findViewById(R.id.maprqs512);
  textviewMapRqs256 = (TextView)findViewById(R.id.maprqs256);
  mapImage1 = (ImageView)findViewById(R.id.mapimage1);
  mapImage2 = (ImageView)findViewById(R.id.mapimage2);
  sbZoom = (SeekBar)findViewById(R.id.sbzoom);
  sbZoom.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    // TODO Auto-generated method stub
    
   }

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

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    updateHereMap();
   }});
  
  spType = (Spinner)findViewById(R.id.sptype);
  spTypeAdapter = new ArrayAdapter<String>(
   this,android.R.layout.simple_spinner_item, optTypes);
  spTypeAdapter.setDropDownViewResource(
    android.R.layout.simple_spinner_dropdown_item);
  spType.setAdapter(spTypeAdapter);
  
  spType.setOnItemSelectedListener(new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    updateHereMap();
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }});
  
  updateHereMap();

 }
 
 private void updateHereMap(){
  URL urlTarget;
  
  try {
   String strTarget512 = genHereMapTileRequest("/512");
   textviewMapRqs512.setText(strTarget512);
   urlTarget = new URL(strTarget512);
   new LoadHereMapTask(mapImage1).execute(urlTarget);
   
   String strTarget256 = genHereMapTileRequest("/256");
   textviewMapRqs256.setText(strTarget256);
   urlTarget = new URL(strTarget256);
   new LoadHereMapTask(mapImage2).execute(urlTarget);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
 }
 
 private String getMercatorProjection(double lat, double lon, int z){
  /*
   * reference:
   * http://developer.here.com/rest-apis/documentation/enterprise-map-tile/topics/key-concepts.html
   */
  
  double latRad = lat * Math.PI/180;
  double n = Math.pow(2, z);
  double xTile = n * ((lon + 180)/360);
  double yTile = n * (1-(Math.log(Math.tan(latRad) + 1/Math.cos(latRad))/Math.PI))/2;
  
  String strProjection = "/"+ String.valueOf(z)
   + "/" + String.valueOf((int)xTile)
   + "/" + String.valueOf((int)yTile);
  
  return strProjection;
 }
 
 private String genHereMapTileRequest(String pixelCnt){
  /*
   * reference:
   * https://developer.here.com/rest-apis/documentation/enterprise-map-tile/topics/resource-map-tile.html
   */
  
  String BaseURL;
  String Path = "/maptile/2.1/";
  String Resource;
  String Version = "/newest";
  String scheme;
  
  int type = spType.getSelectedItemPosition();
  switch(type){
  case optTypeBaseMap:
   BaseURL = "http://1.base.maps.cit.api.here.com";
   Resource = "maptile";
   scheme = "/normal.day";
   break;
  case optTypeAerialTile:
   BaseURL = "http://2.aerial.maps.cit.api.here.com";
   Resource = "maptile";
   scheme = "/satellite.day";
   break;
  case optTypeTrafficTile:
   BaseURL = "http://4.traffic.maps.cit.api.here.com";
   Resource = "traffictile";
   scheme = "/normal.day";
   break;
  default:
   return null;
  }

  String ApplicationId = "DemoAppId01082013GAL";  //for demo
  String ApplicationCode = "AJKnXv84fjrb0KIHawS0Tg"; //for demo
  String png8 = "/png8";
  
  int zoom = sbZoom.getProgress();
  //Berlin
  String strZoomColumnRow = getMercatorProjection(52.525439, 13.38727, zoom);

  String rqs = BaseURL + Path + Resource + Version + scheme + strZoomColumnRow
    + pixelCnt
    + png8
    + "?app_id=" + ApplicationId
    + "&app_code=" + ApplicationCode;

  return rqs;
 }

}

/res/layout/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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidhererestmapimage.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <SeekBar
        android:id="@+id/sbzoom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="13"
        android:progress="5" />
    
    <Spinner
        android:id="@+id/sptype"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_margin="5dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/maprqs512"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <ImageView
                android:id="@+id/mapimage1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_margin="5dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/maprqs256"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <ImageView
                android:id="@+id/mapimage2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

~ More examples of using Here Map REST API on Android

Monday, October 27, 2014

Example of using Here Map Tile REST API on Android

HERE Map Tile API is a RESTful API that retrieves map images for all regions of the world. To get a map image, formulate a request that combines the URL and a set of parameters to specify details such as position, format, zoom level, map type of the map image. You can embed the resulting map image in web pages and applications.

The Map Tile API serves map tiles obtained by mapping points on the surface of a sphere (the globe) to points on a plane, using the normalized Mercator projection.

It's a example of using HERE Map Tile REST API on Android (not Native SDK).


MainActivity.java
package com.example.androidhererestmapimage;

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

import android.support.v7.app.ActionBarActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

 public class LoadHereMapTask extends AsyncTask<URL, Void, Bitmap> {
  
  ImageView imageView;
  
  LoadHereMapTask(ImageView v){
   imageView = v;
  }

  @Override
  protected Bitmap doInBackground(URL... params) {
   Bitmap bm = null;
   URL urlMapImage = params[0];
   try {
    bm = BitmapFactory.decodeStream(urlMapImage.openConnection().getInputStream());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return bm;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   imageView.setImageBitmap(result);
  }

 }
 
 SeekBar sbZoom;
 TextView textviewMapRqs512, textviewMapRqs256;
 ImageView mapImage1, mapImage2;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  textviewMapRqs512 = (TextView)findViewById(R.id.maprqs512);
  textviewMapRqs256 = (TextView)findViewById(R.id.maprqs256);
  mapImage1 = (ImageView)findViewById(R.id.mapimage1);
  mapImage2 = (ImageView)findViewById(R.id.mapimage2);
  sbZoom = (SeekBar)findViewById(R.id.sbzoom);
  sbZoom.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    // TODO Auto-generated method stub
    
   }

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

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {
    updateHereMap();
   }});
  
  updateHereMap();

 }
 
 private void updateHereMap(){
  URL urlTarget;
  
  try {
   String strTarget512 = genHereMapTileRequest("/512");
   textviewMapRqs512.setText(strTarget512);
   urlTarget = new URL(strTarget512);
   new LoadHereMapTask(mapImage1).execute(urlTarget);
   
   String strTarget256 = genHereMapTileRequest("/256");
   textviewMapRqs256.setText(strTarget256);
   urlTarget = new URL(strTarget256);
   new LoadHereMapTask(mapImage2).execute(urlTarget);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
 }
 
 private String getMercatorProjection(double lat, double lon, int z){
  /*
   * reference:
   * http://developer.here.com/rest-apis/documentation/enterprise-map-tile/topics/key-concepts.html
   */
  
  double latRad = lat * Math.PI/180;
  double n = Math.pow(2, z);
  double xTile = n * ((lon + 180)/360);
  double yTile = n * (1-(Math.log(Math.tan(latRad) + 1/Math.cos(latRad))/Math.PI))/2;
  
  String strProjection = "/"+ String.valueOf(z)
   + "/" + String.valueOf((int)xTile)
   + "/" + String.valueOf((int)yTile);
  
  return strProjection;
 }
 
 private String genHereMapTileRequest(String pixelCnt){
  
  String BaseURL = "http://1.base.maps.cit.api.here.com";
  String Path = "/maptile/2.1/";
  String Resource = "maptile";
  String Version = "/newest";
  String NormalDay = "/normal.day";
  String ApplicationId = "DemoAppId01082013GAL";  //for demo
  String ApplicationCode = "AJKnXv84fjrb0KIHawS0Tg"; //for demo
  String png8 = "/png8";
  
  int zoom = sbZoom.getProgress();
  //Berlin
  String strZoomColumnRow = getMercatorProjection(52.525439, 13.38727, zoom);

  String rqs = BaseURL + Path + Resource + Version + NormalDay + strZoomColumnRow
    + pixelCnt
    + png8
    + "?app_id=" + ApplicationId
    + "&app_code=" + ApplicationCode;

  return rqs;
 }

}

/res/layout/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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androidhererestmapimage.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <SeekBar
        android:id="@+id/sbzoom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="13"
        android:progress="5" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_margin="5dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/maprqs512"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <ImageView
                android:id="@+id/mapimage1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_margin="5dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/maprqs256"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <ImageView
                android:id="@+id/mapimage2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

~ More examples of using Here Map REST API on Android

Saturday, October 25, 2014

Android Application Development for the Intel Platform

The number of Android devices running on Intel processors has increased since Intel and Google announced, in late 2011, that they would be working together to optimize future versions of Android for Intel Atom processors. Today, Intel processors can be found in Android smartphones and tablets made by some of the top manufacturers of Android devices, such as Samsung, Lenovo, and Asus.

The increase in Android devices featuring Intel processors has created a demand for Android applications optimized for Intel Architecture: Android Application Development for the Intel® Platform is the perfect introduction for software engineers and mobile app developers. Through well-designed app samples, code samples and case studies, the book teaches Android application development based on the Intel platform—including for smartphones, tablets, and embedded devices—covering performance tuning, debugging and optimization.

Android Application Development for the Intel Platform

This book is jointly developed for individual learning by Intel Software College and China Shanghai JiaoTong University.

What you’ll learn
  • Comprehensive introduction to the Intel ® Embedded and mobile hardware platform
  • Android app GUI design principles and guidelines
  • Covers the latest Intel Android development tools, including Intel Beacon Mountain version 0.6 and the Intel Compiler
  • NDK and C/C++ optimization
  • Designing and optimizing for low-power consumption
Who this book is for
The book is primarily for app developers, software engineers and open-source programming enthusiasts, but can also be used by for training programs and Codeacademy-style programs.

Friday, October 24, 2014

GUI Design for Android Apps

GUI Design for Android Apps is the perfect—and concise—introduction for mobile app developers and designers. Through easy-to-follow tutorials, code samples, and case studies, the book shows the must-know principles for user-interface design for Android apps running on the Intel platform, including smartphones, tablets and embedded devices.

This book is jointly developed for individual learning by Intel Software College and China Shanghai JiaoTong University, and is excerpted from Android Application Development for the Intel® Platform.

What you’ll learn
  • Key aspects of why UI and UX design for embedded systems is different than for desktops
  • Troubleshooting UI design issues
  • Understanding how key concepts such as state transition, context class, and intent work
  • How to use the interface app design tools provided by Android
  • Planning for complex apps (apps with multiple activities)
  • Optimizing app design for touch screen input
Who this book is for
The book is primarily for app developers, software engineers and open-source programming enthusiasts, but can also be used by for training programs and Codeacademy-style programs.

Thursday, October 23, 2014

Here REST API example, set zoom level

Example to set zoom level of using Here REST API:


MainActivity.java
package com.example.androidhererestmapimage;

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

import android.support.v7.app.ActionBarActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;

public class MainActivity extends ActionBarActivity {

 public class LoadHereMapTask extends AsyncTask<URL, Void, Bitmap> {
  
  ImageView imageView;
  
  LoadHereMapTask(ImageView v){
   imageView = v;
  }

  @Override
  protected Bitmap doInBackground(URL... params) {
   Bitmap bm = null;
   URL urlMapImage = params[0];
   try {
    bm = BitmapFactory.decodeStream(urlMapImage.openConnection().getInputStream());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return bm;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   imageView.setImageBitmap(result);
  }

 }

 String[] optResource = {
   "1", "2", "3", "4", "5", "6", "7", "8",
   "9", "10", "11", "12", "13", "14", "15", "16",
 };
 
 Spinner spZoom;
 ImageView mapImage;

 ArrayAdapter<String> spZoomAdapter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  mapImage = (ImageView)findViewById(R.id.mapimage);

  spZoom = (Spinner)findViewById(R.id.spzoom);
  spZoomAdapter = new ArrayAdapter<String>(
   this,android.R.layout.simple_spinner_item, optResource);
  spZoomAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  spZoom.setAdapter(spZoomAdapter);
  
  spZoom.setOnItemSelectedListener(new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    updateHereMap();
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }});
 }
 
 private void updateHereMap(){
  URL urlTarget;
  try {
   urlTarget = new URL(genHereMapImageRequest());
   new LoadHereMapTask(mapImage).execute(urlTarget);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
 }
 
 private String genHereMapImageRequest(){
  
  String BaseURL = "http://image.maps.cit.api.here.com";
  String Path = "/mia/1.6/";
  String Resource = "mapview";
  String ApplicationId = "DemoAppId01082013GAL";  //for demo
  String ApplicationCode = "AJKnXv84fjrb0KIHawS0Tg"; //for demo
  String location = "52.378,13.520";     //Berlin
  String width = "1000";
  String height = "400";
  
  String strZoom = (String) spZoom.getItemAtPosition(
    spZoom.getSelectedItemPosition());
  
  String rqs = BaseURL + Path + Resource 
    + "?app_id=" + ApplicationId
    + "&app_code=" + ApplicationCode
    + "&c=" + location
    + "&h=" + height
          + "&w=" + width
          + "&z=" + strZoom;

  return rqs;
 }

}

/res/layout/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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidhererestmapimage.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Spinner
        android:id="@+id/spzoom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <ImageView
        android:id="@+id/mapimage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

Related:
- Load Here map image, using REST API

Androidify, create your Android character with animation

Androidify yourself!

Create, accessorize and share Android characters that look like you, your best friend, your Uncle Sal... anyone, really.

With 25 new animations, you can make them laugh, dance, cheer, rock out, or all sorts of other moves.

You can also send your animated Android characters in texts or chats as emoticons. Or share them as animated GIFs and pics. So work it, people! Show the world how you roll.
And don’t forget to submit your creations to the Androidify.com Gallery where they can hang with Android characters from around the world and possibly be selected to appear in the new Android advertising campaign.



Visit: https://play.google.com/store/apps/details?id=com.google.android.apps.androidify

Wednesday, October 22, 2014

Load Here map image, using REST API

This example show how to load Here map image, using REST API (not Native SDK). HERE, a Nokia company, is a global leader in the mapping and location intelligence business.



The Here Map Image API Developer's Quick Start Guide provide information to help you start using the Map Image API.

app_id and app_code are authentication credentials. You can use the demo credentials in the examples for testing, but must substitute them with your own unique values in your website or application. See Acquiring Credentials for more information.

MainActivity.java
package com.example.androidhererestmapimage;

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

import android.support.v7.app.ActionBarActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends ActionBarActivity {
 
 public class LoadHereMapTask extends AsyncTask<URL, Void, Bitmap> {
  
  ImageView imageView;
  
  LoadHereMapTask(ImageView v){
   imageView = v;
  }

  @Override
  protected Bitmap doInBackground(URL... params) {
   Bitmap bm = null;
   URL urlMapImage = params[0];
   try {
    bm = BitmapFactory.decodeStream(urlMapImage.openConnection().getInputStream());
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   return bm;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   imageView.setImageBitmap(result);
  }

 }

 ImageView mapImage;
 LoadHereMapTask loadHereMapTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mapImage = (ImageView)findViewById(R.id.mapimage);
  
  loadHereMapTask = new LoadHereMapTask(mapImage);
  
  URL urlTarget;
  try {
   urlTarget = new URL(genHereMapImageRequest());
   loadHereMapTask.execute(urlTarget);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
  
 }
 
 private String genHereMapImageRequest(){
  
  String BaseURL = "http://image.maps.cit.api.here.com";
  String Path = "/mia/1.6/";
  String Resource = "mapview";
  String ApplicationId = "DemoAppId01082013GAL";  //for demo
  String ApplicationCode = "AJKnXv84fjrb0KIHawS0Tg"; //for demo
  String location = "52.378,13.520";     //Berlin  
  
  String rqs = BaseURL + Path + Resource 
    + "?app_id=" + ApplicationId
    + "&app_code=" + ApplicationCode
    + "&c=" + location;

  return rqs;
 }

}

/res/layout/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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidhererestmapimage.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <ImageView
        android:id="@+id/mapimage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

uses-permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

More examples:
Here REST API example, set zoom level
Using Here Map Tile REST API on Android
- Base Map, Aerial and Traffic Tile
Using Here Geocoder API on Android
Search and display Map Tile using Here REST API

Map app HERE support Android devices now

HERE offers fast, accurate maps that are always ready to use, with or without an internet connection. Search for places, find routes and get turn-by-turn voice guidance wherever you are. Underground, on holiday, or even in the middle of nowhere: HERE just works, always.



Features
  • Offline navigation: Interactive maps and turn-by-turn voice guidance are still available even without an internet connection.
  • Maps to download and to use offline for nearly 100 countries.
  • Public transport maps and directions for over 800 cities in over 40 countries, also when you’re offline.
  • Live traffic info for more than 40 countries.
  • Plan your journey on beta.here.com, then find your way there using your mobile.
  • Personalise your map by creating Collections of your favourite places.
  • Share your location with family and friends in real time as you go via Glympse. It’s private, secure and safe.
Please note that this is a beta version of the application that is stlil undergoing final testing. It is a known issue that using a cache cleaner on your phone may disable navigation voices. We're investigating and will release an update soon.



Download HERE App for Android: http://here.com/beta/android/
Visit HERE Web: http://here.com/

[Remark: Somebody comment that "something strange happens, do not let login with credentials in the mobile app, only on the website"]

How it install and run on Nexus 7 (1st generation), without sign-in:

Sunday, October 12, 2014

Add and Remove view dynamically, keep views after orientation changed

Refer to my old example "Add and Remove view dynamically", the new views will be clean after orientation change. This post show how to save and restory data in onSaveInstanceState() and onRestoreInstanceState() to keep the views.


MainActivity.java
package com.example.androiddynamicview;

import java.util.ArrayList;
import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {

 EditText textIn;
 Button buttonAdd;
 LinearLayout container;
 ArrayList<CharSequence> itemList;
 
 String TAG = "AndroidDynamicView";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  Log.i(TAG, "onCreate()");

  textIn = (EditText) findViewById(R.id.textin);
  buttonAdd = (Button) findViewById(R.id.add);
  container = (LinearLayout) findViewById(R.id.container);
  
  itemList = new ArrayList<CharSequence>();

  buttonAdd.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View arg0) {
    
    addNewView(textIn.getText().toString());

   }
  });
 }

 @Override
 protected void onSaveInstanceState(Bundle outState) {
  // TODO Auto-generated method stub
  super.onSaveInstanceState(outState);
  
  Log.i(TAG, "onSaveInstanceState()");
  
  outState.putCharSequenceArrayList("KEY_ITEMS", itemList);
  
 }

 @Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onRestoreInstanceState(savedInstanceState);
  
  Log.i(TAG, "onRestoreInstanceState()");
  
  ArrayList<CharSequence> savedItemList = savedInstanceState.getCharSequenceArrayList("KEY_ITEMS");
  if(savedItemList != null){
   for(CharSequence s : savedItemList){
    addNewView(s);
    
   }
  }
 }

 private void addNewView(final CharSequence newText){
  LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  final View newView = layoutInflater.inflate(R.layout.row, null);
  TextView textOut = (TextView) newView
    .findViewById(R.id.textout);
  textOut.setText(newText);
  Button buttonRemove = (Button) newView
    .findViewById(R.id.remove);
  buttonRemove.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    ((LinearLayout) newView.getParent())
      .removeView(newView);
    itemList.remove(newText);
   }
  });

  container.addView(newView);
  itemList.add(newText);
 }

}

/res/layout/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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.androiddynamicview.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="Add" />

        <EditText
            android:id="@+id/textin"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_toLeftOf="@id/add" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    </LinearLayout>

</LinearLayout>

/res/layout/row.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <Button
        android:id="@+id/remove"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="Remove" />

    <TextView
        android:id="@+id/textout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@id/remove" />

</RelativeLayout>


download filesDownload the files.

Friday, October 10, 2014

How Google Works

How Google Works

Google Executive Chairman and ex-CEO Eric Schmidt and former SVP of Products Jonathan Rosenberg came to Google over a decade ago as proven technology executives. At the time, the company was already well-known for doing things differently, reflecting the visionary--and frequently contrarian--principles of founders Larry Page and Sergey Brin. If Eric and Jonathan were going to succeed, they realized they would have to relearn everything they thought they knew about management and business.

Today, Google is a global icon that regularly pushes the boundaries of innovation in a variety of fields. HOW GOOGLE WORKS is an entertaining, page-turning primer containing lessons that Eric and Jonathan learned as they helped build the company. The authors explain how technology has shifted the balance of power from companies to consumers, and that the only way to succeed in this ever-changing landscape is to create superior products and attract a new breed of multifaceted employees whom Eric and Jonathan dub "smart creatives." Covering topics including corporate culture, strategy, talent, decision-making, communication, innovation, and dealing with disruption, the authors illustrate management maxims ("Consensus requires dissension," "Exile knaves but fight for divas," "Think 10X, not 10%") with numerous insider anecdotes from Google's history, many of which are shared here for the first time.

In an era when everything is speeding up, the best way for businesses to succeed is to attract smart-creative people and give them an environment where they can thrive at scale. HOW GOOGLE WORKS explains how to do just that.

Tuesday, October 7, 2014

Android Apps for Absolute Beginners, Third edition

Anybody can start building multimedia apps for the Android platform, and this book will show you how! Now updated to include both Android 4.4 and the new Android L, Android Apps for Absolute Beginners, Third Edition takes you through the process of getting your first Android apps up and running using plain English and practical examples. If you have a great idea for an Android app, but have never programmed before, then this book is for you.

Android Apps for Absolute Beginners

This book cuts through the fog of jargon and mystery that surrounds Android apps development, and gives you simple, step-by-step instructions to get you started.
  • Teaches Android application development in language anyone can understand, giving you the best possible start in Android development
  • Provides simple, step-by-step examples that make learning easy, allowing you to pick up the concepts without fuss
  • Offers clear code descriptions and layout so that you can get your apps running as soon as possible
This book covers both Android 4.4 (KitKat) and Android L, but is also backwards compatible to cover the previous Android releases since Android 1.5.

What you’ll learn
  • Download, install, and configure the latest software needed for Android app development
  • Work efficiently using an integrated development environment (IDE)
  • Build useful, attractive applications and get them working immediately
  • Develop apps for both Android 4.4 and Android L
  • Create apps with ease using XML markup and drag-and-drop graphical layout editors
  • Use new media and graphics to skin your app so that it has maximum appeal
  • Create advanced apps combining XML, Java and new media content
Who this book is for

If you have a great idea for an Android app, but have never programmed before, then this book is for you. You don’t need to have any previous computer programming skills—as long as you have a desire to learn, and you know which end of the mouse is which, the world of Android apps development awaits!

Table of Contents

1. Setting Up Your Android App Development System
2. Configuring Your Android App Development System
3. An Introduction to the Android Application Development Platform
4. Introduction to XML: Defining an Android App, its Design, and Constants
5. Introduction to Java: Objects, Methods, Classes and Interfaces
6. Android Screen Design: Writing to the Display using Activity and View
7. Making Apps Interactive: Intents, Event Handling and Menus
8: Android UI Design: Using ViewGroup Layout Containers
9: Android Graphics Design: Making Your UI Designs Visual
10: Android Animation: Making Your UI Designs Animated
11: Digital Video: Streaming Video, MediaPlayer, MediaController class
12: Digital Audio: Providing Aural Feedback for UI Designs & SoundPool
13: Services and Threads: Background Processin
14: Content Providers: Providing Data to Application
15: Developing for Android Wearable Devices
16: The Future of Android: 64-bit Android L
17: Appendix A: Audio Concepts, Terminology, and Codecs