Thursday, January 31, 2013

Wednesday, January 30, 2013

Move Google Maps V2 with auto best zoom

We can build LatLngBounds object including certain points, and move GoogleMap to the bounds with auto estimated best zoom.

Move Google Maps V2 with auto best zoom


package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;

import android.os.Build;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 private static final LatLng Leicester_Square = new LatLng(51.510278, -0.130278);
 private static final LatLng Covent_Garden = new LatLng(51.51197, -0.1228);
 private static final LatLng Piccadilly_Circus = new LatLng(51.51, -0.134444);
 private static final LatLng Embankment = new LatLng(51.507, -0.122);
 private static final LatLng Charing_Cross = new LatLng(51.5073, -0.12755);
 
 final int RQS_GooglePlayServices = 1;
 MapFragment myMapFragment;
 GoogleMap myMap;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  FragmentManager myFragmentManager = getFragmentManager();
  MapFragment myMapFragment = 
    (MapFragment)myFragmentManager.findFragmentById(R.id.map);
  myMap = myMapFragment.getMap();
  myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
  
  myMap.addMarker(new MarkerOptions().position(Leicester_Square).title("Leicester Square"));
  myMap.addMarker(new MarkerOptions().position(Covent_Garden).title("Covent Garden"));
  myMap.addMarker(new MarkerOptions().position(Piccadilly_Circus).title("Piccadilly Circus"));
  myMap.addMarker(new MarkerOptions().position(Embankment).title("Embankment"));
  myMap.addMarker(new MarkerOptions().position(Charing_Cross).title("Charing Cross"));
  
        final View mapView = getFragmentManager().findFragmentById(R.id.map).getView();
        if (mapView.getViewTreeObserver().isAlive()) {
            mapView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                @SuppressLint("NewApi") // We check which build version we are using.
                @Override
                public void onGlobalLayout() {
                 LatLngBounds bounds = new LatLngBounds.Builder()
                 .include(Leicester_Square)
                 .include(Covent_Garden)
                 .include(Piccadilly_Circus)
                 .include(Embankment)
                 .include(Charing_Cross)
                 .build();
                 
                 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                  mapView.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
                 } else {
                  mapView.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
                 }
                 myMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
                }});    
        }

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();   
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

}


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

Monday, January 28, 2013

Set options of Google Maps Android API v2 in XML

So far we set options of Google Maps Android API v2 using java code, we can also set options in XML.

Set options of Google Maps Android API v2 in XML


Modify layout file, to add options in <fragment> of "com.google.android.gms.maps.MapFragment", also need to include xmlns:map="http://schemas.android.com/apk/res-auto".
<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"
    tools:context=".MainActivity" >

    <fragment
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.MapFragment"
        map:cameraBearing="45"
        map:cameraTargetLat="51.507222"
        map:cameraTargetLng="-0.1275"
        map:cameraTilt="30"
        map:cameraZoom="12"
        map:mapType="satellite"
        map:uiCompass="true"
        map:uiRotateGestures="true"
        map:uiScrollGestures="true"
        map:uiTiltGestures="true"
        map:uiZoomControls="true"
        map:uiZoomGestures="true"/>

</LinearLayout>


package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.MapFragment;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 final int RQS_GooglePlayServices = 1;
 MapFragment myMapFragment;

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

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();   
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

}


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

Sunday, January 27, 2013

Create MapFragment and GoogleMap using Java code

In previous exercises, MapFragment and SupportMapFragment are defined in XML of layout file. We can create it using Java code, without XML.

package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends Activity {
 
 final int RQS_GooglePlayServices = 1;
 private GoogleMap myMap;
 MapFragment myMapFragment;
 private static final String TAG_MYMAPFRAGMENT = "TAG_MyMapFragment";

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

  FragmentManager myFragmentManager = getFragmentManager();
  myMapFragment = 
    (MapFragment)myFragmentManager.findFragmentByTag(TAG_MYMAPFRAGMENT);
  
  if(myMapFragment == null){
   myMapFragment = MapFragment.newInstance();
   FragmentTransaction fragmentTransaction = myFragmentManager.beginTransaction();
   fragmentTransaction.add(android.R.id.content, myMapFragment, TAG_MYMAPFRAGMENT);
   fragmentTransaction.commit();
  }

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();
   
   if(myMap == null){
    myMap = myMapFragment.getMap();
    if(myMap != null){
     myMap.setMyLocationEnabled(true);
     myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
    }else{
     Toast.makeText(getApplicationContext(), 
       "cannot getMap!", 
       Toast.LENGTH_LONG).show();
    }
   }
   
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

}

Create MapFragment and GoogleMap using Java code


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

keytool error: java.lang.Exception: Keystore file does not exist

If you have a new Android development setup on your system, and it's your first project, and you want to "display the SHA1 (or MD5) certificate fingerprint". May be you will get the error of:

keytool error: java.lang.Exception: Keystore file does not exist: /.../.android/debug.keystore

To generate the debug.keystore, you have to run any app at least one time. Just create and run any simple "Hello World" to generate it.

Thursday, January 24, 2013

Detect and animate to user location

Last exercise "Implement LocationSource and LocationListener for Google Maps Android API v2" to detect user location. We can modify onLocationChanged() method to animate to updated user location; such that the GoogleMap will always center on user location.

 @Override
 public void onLocationChanged(Location location) {
  if (myLocationListener != null) {
   myLocationListener.onLocationChanged(location);
   
   double lat = location.getLatitude();
   double lon = location.getLongitude();
   
   tvLocInfo.setText(
     "lat: " + lat + "\n" +
     "lon: " + lon);
   
   LatLng latlng= new LatLng(location.getLatitude(), location.getLongitude());
   myMap.animateCamera(CameraUpdateFactory.newLatLng(latlng));
         
  }
 }

Detect and animate to user location


The series:
A simple example using Google Maps Android API v2, step by step.

Rename project after Existing Android Code Into Workspace

It's a tips in using Eclipse. After import Existing Android Code Into Workspace, the project name will be MainActivity, or the name of the main activity. In order to rename it, right click the project -> Refactor -> Rename...

Rename Eclipse project

Implement LocationSource and LocationListener for Google Maps Android API v2

Example to Implement LocationSource and LocationListener for Google Maps Android API v2.

Implement LocationSource and LocationListener for Google Maps Android API v2


package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.LocationSource;
import com.google.android.gms.maps.MapFragment;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
  implements LocationSource, LocationListener{
 
 final int RQS_GooglePlayServices = 1;
 private GoogleMap myMap;
 TextView tvLocInfo;
 
 LocationManager myLocationManager = null;
 OnLocationChangedListener myLocationListener = null;
 Criteria myCriteria;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLocInfo = (TextView)findViewById(R.id.locinfo);
        
        FragmentManager myFragmentManager = getFragmentManager();
        MapFragment myMapFragment 
         = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
        myMap = myMapFragment.getMap();
        
        myMap.setMyLocationEnabled(true);
        
        myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        
        myCriteria = new Criteria();
        myCriteria.setAccuracy(Criteria.ACCURACY_FINE);
        myLocationManager = (LocationManager)getSystemService(LOCATION_SERVICE);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item); 
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();
   
   //Register for location updates using a Criteria, and a callback on the specified looper thread.
   myLocationManager.requestLocationUpdates(
     0L,    //minTime
     0.0f,    //minDistance
     myCriteria,  //criteria
     this,    //listener
     null);   //looper
   
   //Replaces the location source of the my-location layer.
      myMap.setLocationSource(this);
   
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
  
 }

 @Override
 protected void onPause() {
  myMap.setLocationSource(null);
  myLocationManager.removeUpdates(this);
     
  super.onPause();
 }

 @Override
 public void activate(OnLocationChangedListener listener) {
  myLocationListener = listener;
 }

 @Override
 public void deactivate() {
  myLocationListener = null;
 }

 @Override
 public void onLocationChanged(Location location) {
  if (myLocationListener != null) {
   myLocationListener.onLocationChanged(location);
   
   double lat = location.getLatitude();
   double lon = location.getLongitude();
   
   tvLocInfo.setText(
     "lat: " + lat + "\n" +
     "lon: " + lon);
  }
 }

 @Override
 public void onProviderDisabled(String arg0) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void onProviderEnabled(String arg0) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
  // TODO Auto-generated method stub
  
 }

}


download filesDownload the files.

Next:
- Detect and animate to user location


The series:
A simple example using Google Maps Android API v2, step by step.

Tuesday, January 22, 2013

Display another layout over GoogleMap

This example demonstrate how to place LinearLayout over GoogleMap, using XML.

Add layout over GoogleMap


<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="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >


    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.MapFragment"/>
    
    <LinearLayout 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="#A0FFFFFF" >
        <TextView
            android:id="@+id/locinfo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher" />
        
    </LinearLayout>

</RelativeLayout>


The series:
A simple example using Google Maps Android API v2, step by step.

Monday, January 21, 2013

Detect Info Window Click, implements OnInfoWindowClickListener.

To detect user click on Info Window, implements OnInfoWindowClickListener. And setOnInfoWindowClickListener() to register it.

Detect Info Window Click


Modify from the post "Create custom info contents for GoogleMaps V2, by implementing custom InfoWindowAdapter".

package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
  implements OnMapLongClickListener, OnInfoWindowClickListener{
 
 class MyInfoWindowAdapter implements InfoWindowAdapter{
  
  private final View myContentsView;
  
  MyInfoWindowAdapter(){
   myContentsView = getLayoutInflater().inflate(R.layout.custom_info_contents, null); 
  }

  @Override
  public View getInfoContents(Marker marker) {
   TextView tvTitle = ((TextView)myContentsView.findViewById(R.id.title));
            tvTitle.setText(marker.getTitle());
            TextView tvSnippet = ((TextView)myContentsView.findViewById(R.id.snippet));
            tvSnippet.setText(marker.getSnippet());
   
            return myContentsView;
  }

  @Override
  public View getInfoWindow(Marker marker) {
   // TODO Auto-generated method stub
   return null;
  }
  
 }
 
 final int RQS_GooglePlayServices = 1;
 private GoogleMap myMap;
 TextView tvLocInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLocInfo = (TextView)findViewById(R.id.locinfo);
        
        FragmentManager myFragmentManager = getFragmentManager();
        MapFragment myMapFragment 
         = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
        myMap = myMapFragment.getMap();
        
        myMap.setMyLocationEnabled(true);
        
        myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
        
        myMap.getUiSettings().setZoomControlsEnabled(true);
        myMap.getUiSettings().setCompassEnabled(true);
        myMap.getUiSettings().setMyLocationButtonEnabled(true);
        
        myMap.getUiSettings().setAllGesturesEnabled(true);
        
        myMap.setTrafficEnabled(true);
        
        myMap.setOnMapLongClickListener(this);
        myMap.setInfoWindowAdapter(new MyInfoWindowAdapter());
        myMap.setOnInfoWindowClickListener(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item); 
 }

 @Override
 protected void onResume() {
  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());
  
  Marker newMarker = myMap.addMarker(new MarkerOptions()
         .position(point)
         .snippet(point.toString()));
  newMarker.setTitle(newMarker.getId());
  
 }

 @Override
 public void onInfoWindowClick(Marker marker) {
  Toast.makeText(getBaseContext(), 
    "Info Window clicked@" + marker.getId(), 
    Toast.LENGTH_SHORT).show();
  
 }
    
}


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

Professional Android Open Accessory Programming with Arduino


Learn how to control your home or car from your Android smartphone - air conditioning, lights, entertainment systems, and more!
Android Open Accessory is a new, simple, and secure protocol for connecting any microcontroller-empowered device to an Android smartphone or tablet. This Wrox guide shows Android programmers how to use AOA with Arduino, the microcontroller platform, to control such systems as lighting, air conditioning, and entertainment systems from Android devices. Furthermore, it teaches the circuit-building skills needed to create games and practical products that also take advantage of Android technology.
  • Introduces Android Open Accessory and shows how to set up the hardware and development environment
  • Explains how to code both Android and Arduino elements of an accessory
  • Features four complete projects developers can build using various sensors and indicators/actuators, including source code
  • Gives Android developers the tools to create powerful, sophisticated projects
Professional Android Open Accessory with Android ADK and Arduino opens exciting new opportunities for Android developers.


Friday, January 18, 2013

Custom InfoWindowAdapter with dynamic icon

Last exercise demonstrate how to "implement custom InfoWindowAdapter", with fixed icon defined in XML. We can generate the icon dynamically in run-time.

Custom InfoWindowAdapter with dynamic icon


To implement dynamic icon, modify layout of the info windows(custom_info_contents.xml) - remove the assigned android:src and assigne android:id="@+id/icon".
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:adjustViewBounds="true"/>
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12dp"
            android:textStyle="bold"/>
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="10dp"/>
    </LinearLayout>

</LinearLayout>


Modify getInfoContents(Marker marker) to load the icon in run-time.
  @Override
  public View getInfoContents(Marker marker) {
   TextView tvTitle = ((TextView)myContentsView.findViewById(R.id.title));
   tvTitle.setText(marker.getTitle());
   TextView tvSnippet = ((TextView)myContentsView.findViewById(R.id.snippet));
   tvSnippet.setText(marker.getSnippet());
            
   ImageView ivIcon = ((ImageView)myContentsView.findViewById(R.id.icon));
   ivIcon.setImageDrawable(getResources().getDrawable(android.R.drawable.ic_menu_gallery));
   
   return myContentsView;
  }



The series:
A simple example using Google Maps Android API v2, step by step.

Thursday, January 17, 2013

Create custom info contents for GoogleMaps V2, by implementing custom InfoWindowAdapter

GoogleMap V2 with custom info contents


Create /res/layout/custom_info_contents.xml to define the layout of our custom info contents.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="5dp"
            android:adjustViewBounds="true"
            android:src="@drawable/ic_launcher"/>
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="12dp"
            android:textStyle="bold"/>
        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="10dp"/>
    </LinearLayout>

</LinearLayout>


To implement our custom info contents, we have to create our custom InfoWindowAdapter class. Override getInfoContents(Marker marker) to return our custom view. And call myMap.setInfoWindowAdapter(new MyInfoWindowAdapter()) to set our InfoWindowAdapter. In this exercise, we haven't handle getInfoWindow(Marker marker), simple return null.
package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
 implements OnMapLongClickListener{
 
 class MyInfoWindowAdapter implements InfoWindowAdapter{

        private final View myContentsView;
  
  MyInfoWindowAdapter(){
   myContentsView = getLayoutInflater().inflate(R.layout.custom_info_contents, null);
  }
  
  @Override
  public View getInfoContents(Marker marker) {
   
   TextView tvTitle = ((TextView)myContentsView.findViewById(R.id.title));
            tvTitle.setText(marker.getTitle());
            TextView tvSnippet = ((TextView)myContentsView.findViewById(R.id.snippet));
            tvSnippet.setText(marker.getSnippet());
   
            return myContentsView;
  }

  @Override
  public View getInfoWindow(Marker marker) {
   // TODO Auto-generated method stub
   return null;
  }
  
 }

 final int RQS_GooglePlayServices = 1;
 GoogleMap myMap;
 TextView tvLocInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLocInfo = (TextView)findViewById(R.id.locinfo);
        
        FragmentManager myFragmentManager = getFragmentManager();
        MapFragment myMapFragment 
         = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
        myMap = myMapFragment.getMap();
        
        myMap.setMyLocationEnabled(true);

        //myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        //myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        //myMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
        
        myMap.getUiSettings().setZoomControlsEnabled(true);
        myMap.getUiSettings().setCompassEnabled(true);
        myMap.getUiSettings().setMyLocationButtonEnabled(true);
        
        myMap.getUiSettings().setRotateGesturesEnabled(true);
        myMap.getUiSettings().setScrollGesturesEnabled(true);
        myMap.getUiSettings().setTiltGesturesEnabled(true);
        myMap.getUiSettings().setZoomGesturesEnabled(true);
        //or myMap.getUiSettings().setAllGesturesEnabled(true);
        
        myMap.setTrafficEnabled(true);
        
        myMap.setOnMapLongClickListener(this);
        
        myMap.setInfoWindowAdapter(new MyInfoWindowAdapter());

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {

  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show(); 
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());

  Marker newMarker = myMap.addMarker(new MarkerOptions()
        .position(point)
        .snippet(point.toString()));
  
  newMarker.setTitle(newMarker.getId());

 }
    
}

As a exercise, you can try to return null in getInfoContents(Marker marker), and return the custom view in getInfoWindow(Marker marker) to check the result.


download filesDownload the files.

Next:
- Implement Custom InfoWindowAdapter with dynamic icon
- Detect Info Window Click, implements OnInfoWindowClickListener


The series:
A simple example using Google Maps Android API v2, step by step.

Implement bouncing marker for Google Maps Android API v2

bouncing marker

Example to implement a bouncing marker:
  //Make the marker bounce
        final Handler handler = new Handler();
        
        final long startTime = SystemClock.uptimeMillis();
        final long duration = 2000;
        
        Projection proj = myMap.getProjection();
        final LatLng markerLatLng = marker.getPosition();
        Point startPoint = proj.toScreenLocation(markerLatLng);
        startPoint.offset(0, -100);
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);

        final Interpolator interpolator = new BounceInterpolator();

        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - startTime;
                float t = interpolator.getInterpolation((float) elapsed / duration);
                double lng = t * markerLatLng.longitude + (1 - t) * startLatLng.longitude;
                double lat = t * markerLatLng.latitude + (1 - t) * startLatLng.latitude;
                marker.setPosition(new LatLng(lat, lng));

                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                }
            }
        });
        



The code in main activity:
package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.graphics.Point;
import android.view.Menu;
import android.view.MenuItem;
import android.view.animation.BounceInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
 implements OnMapLongClickListener, OnMarkerClickListener{
 
 final int RQS_GooglePlayServices = 1;
 
 GoogleMap myMap;
 
 TextView tvLocInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLocInfo = (TextView)findViewById(R.id.locinfo);
        
        FragmentManager myFragmentManager = getFragmentManager();
        MapFragment myMapFragment 
         = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
        myMap = myMapFragment.getMap();
        
        myMap.setMyLocationEnabled(true);

        //myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        //myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        //myMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
        
        myMap.getUiSettings().setZoomControlsEnabled(true);
        myMap.getUiSettings().setCompassEnabled(true);
        myMap.getUiSettings().setMyLocationButtonEnabled(true);
        
        myMap.getUiSettings().setRotateGesturesEnabled(true);
        myMap.getUiSettings().setScrollGesturesEnabled(true);
        myMap.getUiSettings().setTiltGesturesEnabled(true);
        myMap.getUiSettings().setZoomGesturesEnabled(true);
        //or myMap.getUiSettings().setAllGesturesEnabled(true);
        
        myMap.setTrafficEnabled(true);
        
        myMap.setOnMapLongClickListener(this);
        myMap.setOnMarkerClickListener(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.menu_legalnotices:
   String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
     getApplicationContext());
   AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
   LicenseDialog.setTitle("Legal Notices");
   LicenseDialog.setMessage(LicenseInfo);
   LicenseDialog.show();
   return true; 
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {

  super.onResume();
  
  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show(); 
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices); 
  }
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());
  
  BitmapDescriptor bitmapDescriptor 
   = BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher);
  
  myMap.addMarker(new MarkerOptions()
        .position(point)
        .icon(bitmapDescriptor)
        .title(point.toString()));

 }

 @Override
 public boolean onMarkerClick(final Marker marker) {

  //Make the marker bounce
        final Handler handler = new Handler();
        
        final long startTime = SystemClock.uptimeMillis();
        final long duration = 2000;
        
        Projection proj = myMap.getProjection();
        final LatLng markerLatLng = marker.getPosition();
        Point startPoint = proj.toScreenLocation(markerLatLng);
        startPoint.offset(0, -100);
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);

        final Interpolator interpolator = new BounceInterpolator();

        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - startTime;
                float t = interpolator.getInterpolation((float) elapsed / duration);
                double lng = t * markerLatLng.longitude + (1 - t) * startLatLng.longitude;
                double lat = t * markerLatLng.latitude + (1 - t) * startLatLng.latitude;
                marker.setPosition(new LatLng(lat, lng));

                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                }
            }
        });
        
        //return false; //have not consumed the event
        return true; //have consumed the event
 }
    
}


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

Wednesday, January 16, 2013

Google TV Add-on with emulator is available in Android SDK



Google TV SDK Add-on allows developers to create Google TV-specific Android Virtual Devices (AVDs) for the Android emulator. The Google TV Add-on package is available from the Android AVD and SDK Manager. To know more about Google TV Add-on and how to install, read GoogleTV Add-On doc.

You now have the Google TV Add-on. To learn how to run the emulator, see the section Using Emulator.

Load custom marker on GoogleMap V2

To load custom icon as marker of GoogleMap V2, save the icon in drawable folder. Load it using the code:

  
  BitmapDescriptor bitmapDescriptor 
   = BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher);
  
  myMap.addMarker(new MarkerOptions()
        .position(point)
        .icon(bitmapDescriptor)
        .title(point.toString()));


GoogleMap V2 with custom marker


The series:
A simple example using Google Maps Android API v2, step by step.

Tuesday, January 15, 2013

Change marker color of GoogleMaps V2

To change color of the default marker of Google Maps Android API v2, add .icon(BitmapDescriptor) when create MarkerOptions.

  BitmapDescriptor bitmapDescriptor 
   = BitmapDescriptorFactory.defaultMarker(
     BitmapDescriptorFactory.HUE_AZURE);
  
  myMap.addMarker(new MarkerOptions()
        .position(point)
        .icon(bitmapDescriptor)
        .title(point.toString()));

change color of the default marker of Google Maps Android API v2


download filesDownload the files.

The series:
A simple example using Google Maps Android API v2, step by step.

Monday, January 14, 2013

UPDATE NOW! Oracle JDK 7u11 released



Oracle releasdd JDK 7u11 to answer the the flaw in Java software integrated with web browsers.

This release contains fixes for security vulnerabilities. For more information, see Oracle Security Alert for CVE-2013-0422.

Java SE 7 Update 11 is available from the following download sites:


Saturday, January 12, 2013

Oracle is aware of a flaw in Java software integrated with web browsers

Posted at +Oracle: Oracle is aware of a flaw in Java software integrated with web browsers. The flaw is limited to JDK7. It does not exist in other releases of Java, and does not affect Java applications directly installed and running on servers, desktops, laptops, and other devices. A fix will be available shortly.


Oracle is aware of a flaw in Java software integrated with web browsers



Wednesday, January 9, 2013

Enable/Disable various gestures for GoogleMap

To enable/disable various gestures for GoogleMap, call setRotateGesturesEnabled(boolean enabled), setScrollGesturesEnabled(boolean enabled), setTiltGesturesEnabled(boolean enabled) and setZoomGesturesEnabled(boolean enabled), or you can call setAllGesturesEnabled(boolean enabled) to set all gestures.

Example:
  myMap.getUiSettings().setRotateGesturesEnabled(true);
  myMap.getUiSettings().setScrollGesturesEnabled(true);
  myMap.getUiSettings().setTiltGesturesEnabled(true);
  myMap.getUiSettings().setZoomGesturesEnabled(true);
  //or myMap.getUiSettings().setAllGesturesEnabled(true);


The series:
A simple example using Google Maps Android API v2, step by step.

Tuesday, January 8, 2013

Display ZoomControls, Compass and MyLocation buttons on GoogleMap.

To enable/disable ZoomControls, Compass and MyLocation buttons on GoogleMap, call the following methods of the UiSettings for GoogleMap.
  • setZoomControlsEnabled (boolean enabled):

    Enables or disables the zoom controls. If enabled, the zoom controls are a pair of buttons (one for zooming in, one for zooming out) that appear on the screen. When pressed, they cause the camera to zoom in (or out) by one zoom level. If disabled, the zoom controls are not shown.

    By default, the zoom controls are enabled.

  • setCompassEnabled (boolean enabled):

    Enables or disables the compass. The compass is an icon on the map that indicates the direction of north on the map. If enabled, it is only shown when the camera is tilted or rotated away from its default orientation (tilt of 0 and a bearing of 0). When a user clicks the compass, the camera orients itself to its default orientation and fades away shortly after. If disabled, the compass will never be displayed.

    By default, the compass is enabled (and hence shown when the camera is not in the default orientation).

  • setMyLocationButtonEnabled (boolean enabled):

    Enables or disables the my-location button. The my-location button causes the camera to move such that the user's location is in the center of the map. If the button is enabled, it is only shown when the my-location layer is enabled.

    By default, the my-location button is enabled (and hence shown when the my-location layer is enabled).

Example:

  myMap.getUiSettings().setZoomControlsEnabled(true);
  myMap.getUiSettings().setCompassEnabled(true);
  myMap.getUiSettings().setMyLocationButtonEnabled(true);

Display ZoomControls, Compass and MyLocation buttons on GoogleMap.


The series:
A simple example using Google Maps Android API v2, step by step.

Reminder: Windows 8 Previews will expire SOON!




Just a reminder, if you are using Windows 8 Preview, it will expire soon:
  • Windows 8 Developer Preview and Consumer Preview will expire on January 15, 2013
  • Windows 8 Release Preview will expire on January 16, 2013

Source: Microsoft Community


Monday, January 7, 2013

Nokia HERE, delivering maps for Apple iPhone, Android and Firefox OS

Nokia is taking its mapping solutions out to the wider world in the form of HERE, offering HERE for iOS for Apple iPhone and iPad users and offering Android developers the chance to make compelling mapping apps for their own platform.

Source: NOKNOK, powered by Nokia


Google Maps Android API v2 example: Draggable Marker

To make the marker draggable:
- sets the draggability for the marker to true by calling draggable(true) when new the MarkerOptions.
- implements OnMarkerDragListener in your activity.
- call myMap.setOnMarkerDragListener(this).
- override onMarkerDrag(), onMarkerDragEnd() and onMarkerDragStart().

Draggable Marker


package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.location.Location;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
 implements OnMapClickListener, OnMapLongClickListener, OnMarkerDragListener{
 
 final int RQS_GooglePlayServices = 1;
 private GoogleMap myMap;
 
 Location myLocation;
 TextView tvLocInfo;
 
 boolean markerClicked;
 PolygonOptions polygonOptions;
 Polygon polygon;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  tvLocInfo = (TextView)findViewById(R.id.locinfo);
  
  FragmentManager myFragmentManager = getFragmentManager();
  MapFragment myMapFragment 
   = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
  myMap = myMapFragment.getMap();
  
  myMap.setMyLocationEnabled(true);
  
  myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
  
  myMap.setOnMapClickListener(this);
  myMap.setOnMapLongClickListener(this);
  myMap.setOnMarkerDragListener(this);

  markerClicked = false;
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
     case R.id.menu_legalnotices:
      String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
        getApplicationContext());
      AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
      LicenseDialog.setTitle("Legal Notices");
      LicenseDialog.setMessage(LicenseInfo);
      LicenseDialog.show();
         return true;
     }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {

  super.onResume();

  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices);
  }
  
 }

 @Override
 public void onMapClick(LatLng point) {
  tvLocInfo.setText(point.toString());
  myMap.animateCamera(CameraUpdateFactory.newLatLng(point));
  
  markerClicked = false;
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());
  myMap.addMarker(new MarkerOptions()
       .position(point)
       .draggable(true));
  
  markerClicked = false;
 }

 @Override
 public void onMarkerDrag(Marker marker) {
  tvLocInfo.setText("Marker " + marker.getId() + " Drag@" + marker.getPosition());
 }

 @Override
 public void onMarkerDragEnd(Marker marker) {
  tvLocInfo.setText("Marker " + marker.getId() + " DragEnd");
 }

 @Override
 public void onMarkerDragStart(Marker marker) {
  tvLocInfo.setText("Marker " + marker.getId() + " DragStart");
  
 }

}




download filesDownload the files.



The series:
A simple example using Google Maps Android API v2, step by step.

Sunday, January 6, 2013

Tips to add Support Library

In case you need to add Android Support Library, such as android-support-v4.jar; Google documents suggested to:
- In Eclipse Select Project > Properties, select Java Build Path, and navigate to Libraries.
- Select Add External Jars, include the following jar files, and click OK: <android-sdk-folder>/extras/android/compatibility/v4/android-support-v4.jar

But...I found that it is not always work, even always NOT work!

No error when you compile your code, but fail with error "Caused by: java.lang.NoClassDefFoundError: youractivity" at runtime.

My alternatively, Right click your project, select Android Tools > Add Support Library...

Add Support Library...


----------

Here is another solution advised by Stefan de Bruijn in comments:
- create a folder called "libs", NOT "lib".
- copy the required jar in "libs" folder.
- Update Java Build Path by selecting "Add JARs..." (NOT "Add External JARs...") to add the jar in libs.
- like this: java.lang.NoClassDefFoundError: com.google.ads.AdView.

Friday, January 4, 2013

Google Maps Android API v2 example: Draw Polygon on GoogleMap

Last post demonstrate how to "Draw Polyline on GoogleMap of Google Maps Android API v2", we can draw Polygon using the almost same procedure.

Draw Polygon on GoogleMap


package com.example.androidmapsv2;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity 
 implements OnMapClickListener, OnMapLongClickListener, OnMarkerClickListener{
 
 final int RQS_GooglePlayServices = 1;
 private GoogleMap myMap;
 
 Location myLocation;
 TextView tvLocInfo;
 
 boolean markerClicked;
 PolygonOptions polygonOptions;
 Polygon polygon;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  tvLocInfo = (TextView)findViewById(R.id.locinfo);
  
  FragmentManager myFragmentManager = getFragmentManager();
  MapFragment myMapFragment 
   = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
  myMap = myMapFragment.getMap();
  
  myMap.setMyLocationEnabled(true);
  
  myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
  
  myMap.setOnMapClickListener(this);
  myMap.setOnMapLongClickListener(this);
  myMap.setOnMarkerClickListener(this);

  markerClicked = false;
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.activity_main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
     case R.id.menu_legalnotices:
      String LicenseInfo = GooglePlayServicesUtil.getOpenSourceSoftwareLicenseInfo(
        getApplicationContext());
      AlertDialog.Builder LicenseDialog = new AlertDialog.Builder(MainActivity.this);
      LicenseDialog.setTitle("Legal Notices");
      LicenseDialog.setMessage(LicenseInfo);
      LicenseDialog.show();
         return true;
     }
  return super.onOptionsItemSelected(item);
 }

 @Override
 protected void onResume() {

  super.onResume();

  int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
  
  if (resultCode == ConnectionResult.SUCCESS){
   Toast.makeText(getApplicationContext(), 
     "isGooglePlayServicesAvailable SUCCESS", 
     Toast.LENGTH_LONG).show();
  }else{
   GooglePlayServicesUtil.getErrorDialog(resultCode, this, RQS_GooglePlayServices);
  }
  
 }

 @Override
 public void onMapClick(LatLng point) {
  tvLocInfo.setText(point.toString());
  myMap.animateCamera(CameraUpdateFactory.newLatLng(point));
  
  markerClicked = false;
 }

 @Override
 public void onMapLongClick(LatLng point) {
  tvLocInfo.setText("New marker added@" + point.toString());
  myMap.addMarker(new MarkerOptions().position(point).title(point.toString()));
  
  markerClicked = false;
 }

 @Override
 public boolean onMarkerClick(Marker marker) {
  
  if(markerClicked){
   
   if(polygon != null){
    polygon.remove();
    polygon = null;
   }
   
   polygonOptions.add(marker.getPosition());
   polygonOptions.strokeColor(Color.RED);
   polygonOptions.fillColor(Color.BLUE);
   polygon = myMap.addPolygon(polygonOptions);
  }else{
   if(polygon != null){
    polygon.remove();
    polygon = null;
   }
   
   polygonOptions = new PolygonOptions().add(marker.getPosition());
   markerClicked = true;
  }
  
  return true;
 }

}



download filesDownload the files.


Next:
- Implement Draggable Marker

Update:
- Google Maps Android API v2 now support anti-clockwise polygons

The series:
A simple example using Google Maps Android API v2, step by step.