Monday, December 14, 2009

Implement a Help Dialog, using onCreateOptionsMenu(), onOptionsItemSelected() and AlertDialog.Builder.



Follow the code from previouse exercise, Move the marker on MapView with Zoom Control Seekbar.
In this exercise, a OptionsMenu with a single OptionsItem of help will be added.

The option items is added to the option menu in the method onCreateOptionsMenu(), in which initialize the contents of the Activity's standard options menu.

Because it's only one item in the menu, Menu.add(CharSequence title) is used to add item to the menu. Otherwise, Menu.add(int groupId, int itemId, int order, CharSequence title) or Menu.add(int groupId, int itemId, int order, int titleRes) have to be used.

onOptionsItemSelected() will be called whenever an item in options menu is selected. Also, because it's only one item in the menu, so there are no need to check which item have been selected, otherwise, you have to check the itemId.

Add the following three method in the class AndroidMapView:

 public boolean onCreateOptionsMenu(Menu menu)
{
menu.add("Help");
return super.onCreateOptionsMenu(menu);
}

private void openOptionsHelpDialog()
{
new AlertDialog.Builder(this)
.setTitle(R.string.help_title).setMessage(R.string.help_message)
.setPositiveButton(R.string.help_ok,
new DialogInterface.OnClickListener() {

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

}
}
)
.show();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
super.onOptionsItemSelected(item);
openOptionsHelpDialog();
return true;
}


Implement a file helpmessage.xml in the folder /res/values/, it's used to hold the text used inside the Help Dialog.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="help_title">Help!</string>
<string name="help_message">\n
Pan on the Map: touch the screen and move.\n
Update location: touch on the screen.\n
Zoom: slice on the SeekBar on bottom.\n
</string>
<string name="help_ok">OK</string>
</resources>


Download the files.

Friday, December 11, 2009

Optimize your layouts using layoutopt

layoutopt is a command-line tool that helps you optimize the layouts and layout hierarchies of your applications. You can run it against your layout files or resource directories to quickly check for inefficiencies or other types of problems that could be affecting the performance of your application.

Wednesday, December 9, 2009

Move the marker on MapView with Zoom Control Seekbar

In the last exercise, Move the marker on MapView, user touch on screen to pan the Map and update marker. It's very confuse with the BuiltInZoomControls function. So I separate the zoom function outside the MapView in this exercise. It's a SeekBar under the MapView, user can change the zoom level by sliding on the SeekBar.



It involve modification on mymapview.xml and AndroidMapView.java.

mymapview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<CheckBox
android:id="@+id/satellite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" Satellite "
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/longitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Longitude:"
/>
<TextView
android:id="@+id/latitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Latitude:"
/>
</LinearLayout>
</LinearLayout>
<com.google.android.maps.MapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:apiKey="0pkoAyp5YM52XRlxoRPJeJbP0Tp69yYlrRO7lJg"
/>
<SeekBar
android:id="@+id/zoombar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="20"
android:progress="0"/>
</LinearLayout>


AndroidMapView.java
package com.AndroidMapper;

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

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

public class AndroidMapView extends MapActivity {

private TextView myLongitude, myLatitude;
private CheckBox mySatellite;

private MapView myMapView;
private MapController myMapController;

private SeekBar myZoomBar;

private void SetSatellite()
{
myMapView.setSatellite(mySatellite.isChecked());
};

@Override
protected void onCreate(Bundle icicle) {
// TODO Auto-generated method stub
super.onCreate(icicle);
setContentView(R.layout.mymapview);

Bundle bundle = this.getIntent().getExtras();
int Mode = bundle.getInt("Mode");

myMapView = (MapView)findViewById(R.id.mapview);
myMapController = myMapView.getController();
myMapView.setBuiltInZoomControls(false);

myLongitude = (TextView)findViewById(R.id.longitude);
myLatitude = (TextView)findViewById(R.id.latitude);
mySatellite = (CheckBox)findViewById(R.id.satellite);
mySatellite.setOnClickListener(mySatelliteOnClickListener);

myZoomBar = (SeekBar)findViewById(R.id.zoombar);
SetZoomLevel();
myZoomBar.setOnSeekBarChangeListener(myZoomBarOnSeekBarChangeListener);

SetSatellite();

if(Mode == 0)
{
GeoPoint initGeoPoint = myMapView.getMapCenter();
CenterLocation(initGeoPoint);
}
else if(Mode == 1)
{
int intLatitude = bundle.getInt("Latitude");
int intLongitude = bundle.getInt("Longitude");
GeoPoint initGeoPoint = new GeoPoint(intLatitude, intLongitude);
CenterLocation(initGeoPoint);
}
}

private SeekBar.OnSeekBarChangeListener myZoomBarOnSeekBarChangeListener =
new SeekBar.OnSeekBarChangeListener(){

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

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

}

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

}
};

private void SetZoomLevel()
{
int myZoomLevel = myZoomBar.getProgress()+1;
myMapController.setZoom(myZoomLevel);
Toast.makeText(this,
"Zoom Level : " + String.valueOf(myZoomLevel),
Toast.LENGTH_LONG).show();
};

private void placeMarker(int markerLatitude, int markerLongitude)
{
Drawable marker=getResources().getDrawable(
android.R.drawable.ic_menu_myplaces);
marker.setBounds(0, 0, marker.getIntrinsicWidth(),
marker.getIntrinsicHeight());
myMapView.getOverlays().add(new InterestingLocations(marker,
markerLatitude, markerLongitude));
}

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

private void CenterLocation(GeoPoint centerGeoPoint)
{
myMapController.animateTo(centerGeoPoint);

myLongitude.setText("Longitude: "+
String.valueOf((float)centerGeoPoint.getLongitudeE6()/1000000));
myLatitude.setText("Latitude: "+
String.valueOf((float)centerGeoPoint.getLatitudeE6()/1000000));
placeMarker(centerGeoPoint.getLatitudeE6(),
centerGeoPoint.getLongitudeE6());
};

private CheckBox.OnClickListener mySatelliteOnClickListener =
new CheckBox.OnClickListener(){

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

class InterestingLocations extends ItemizedOverlay<OverlayItem>{

private List<OverlayItem> locations =
new ArrayList<OverlayItem>();
private Drawable marker;
private OverlayItem myOverlayItem;

boolean MoveMap;

public InterestingLocations(Drawable defaultMarker,
int LatitudeE6, int LongitudeE6) {
super(defaultMarker);
// TODO Auto-generated constructor stub
this.marker=defaultMarker;
// create locations of interest
GeoPoint myPlace = new GeoPoint(LatitudeE6,LongitudeE6);
myOverlayItem = new OverlayItem(myPlace, "My Place", "My Place");
locations.add(myOverlayItem);

populate();
}

@Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return locations.get(i);
}

@Override
public int size() {
// TODO Auto-generated method stub
return locations.size();
}

@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
// TODO Auto-generated method stub
super.draw(canvas, mapView, shadow);

boundCenterBottom(marker);
}

@Override
public boolean onTouchEvent(MotionEvent arg0, MapView arg1) {
// TODO Auto-generated method stub
//super.onTouchEvent(arg0, arg1);



int Action = arg0.getAction();
if (Action == MotionEvent.ACTION_UP){

if(!MoveMap)
{
Projection proj = myMapView.getProjection();
GeoPoint loc = proj.fromPixels((int)arg0.getX(), (int)arg0.getY());

//remove the last marker
myMapView.getOverlays().remove(0);

CenterLocation(loc);
}

}
else if (Action == MotionEvent.ACTION_DOWN){

MoveMap = false;

}
else if (Action == MotionEvent.ACTION_MOVE){
MoveMap = true;
}

return super.onTouchEvent(arg0, arg1);
//return false;
}
}
}


Download the files.

Tuesday, December 8, 2009

Move the marker on MapView

In the last exercises, Display a marker on MapView, using Overlays and Get center location of a map, using MapView.getMapCenter(), a marker is displayed on the center of the MapView. In this exercise, I want to add the capability of moving the marker on the Map. Unfortunately, I can't find any solution (from books and internet) to move (drag) the marker on MapView, similar to web version. Finally, I made a alternative.

If user Touch on screen without moving, it will be treated as update marker, the marker will be place on the new location, and it will be centered on the MapView. If user Touch on screen and Move, it will be treated as pan the MapView, the marker will not be changed.



The main logic is in the method onTouchEvent(MotionEvent arg0, MapView arg1), ACTION_UP, ACTION_DOWN and ACTION_MOVE cases.

((int)arg0.getX(), (int)arg0.getY()) is the on-screen pixel coordinates, it can be translated to latitude/longitude(GePoint) using Projection.fromPixels.

AndroidMapView.java


package com.AndroidMapper;

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

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

public class AndroidMapView extends MapActivity {

private TextView myLongitude, myLatitude;
private CheckBox mySatellite;

private MapView myMapView;
private MapController myMapController;

private void SetSatellite()
{
myMapView.setSatellite(mySatellite.isChecked());
};

@Override
protected void onCreate(Bundle icicle) {
// TODO Auto-generated method stub
super.onCreate(icicle);
setContentView(R.layout.mymapview);

Bundle bundle = this.getIntent().getExtras();
int Mode = bundle.getInt("Mode");

myMapView = (MapView)findViewById(R.id.mapview);
myMapController = myMapView.getController();
myMapView.setBuiltInZoomControls(true);

myLongitude = (TextView)findViewById(R.id.longitude);
myLatitude = (TextView)findViewById(R.id.latitude);
mySatellite = (CheckBox)findViewById(R.id.satellite);
mySatellite.setOnClickListener(mySatelliteOnClickListener);

SetSatellite();

if(Mode == 0)
{
GeoPoint initGeoPoint = myMapView.getMapCenter();
CenterLocation(initGeoPoint);
}
else if(Mode == 1)
{
int intLatitude = bundle.getInt("Latitude");
int intLongitude = bundle.getInt("Longitude");
GeoPoint initGeoPoint = new GeoPoint(intLatitude, intLongitude);
CenterLocation(initGeoPoint);
}
}

private void placeMarker(int markerLatitude, int markerLongitude)
{
Drawable marker=getResources().getDrawable(
android.R.drawable.ic_menu_myplaces);
marker.setBounds(0, 0, marker.getIntrinsicWidth(),
marker.getIntrinsicHeight());
myMapView.getOverlays().add(new InterestingLocations(marker,
markerLatitude, markerLongitude));
}

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

private void CenterLocation(GeoPoint centerGeoPoint)
{
myMapController.animateTo(centerGeoPoint);

myLongitude.setText("Longitude: "+
String.valueOf((float)centerGeoPoint.getLongitudeE6()/1000000));
myLatitude.setText("Latitude: "+
String.valueOf((float)centerGeoPoint.getLatitudeE6()/1000000));
placeMarker(centerGeoPoint.getLatitudeE6(),
centerGeoPoint.getLongitudeE6());
};

private CheckBox.OnClickListener mySatelliteOnClickListener =
new CheckBox.OnClickListener(){

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

class InterestingLocations extends ItemizedOverlay<OverlayItem>{

private List<OverlayItem> locations =
new ArrayList<OverlayItem>();
private Drawable marker;
private OverlayItem myOverlayItem;

boolean MoveMap;

public InterestingLocations(Drawable defaultMarker,
int LatitudeE6, int LongitudeE6) {
super(defaultMarker);
// TODO Auto-generated constructor stub
this.marker=defaultMarker;
// create locations of interest
GeoPoint myPlace = new GeoPoint(LatitudeE6,LongitudeE6);
myOverlayItem = new OverlayItem(myPlace, "My Place", "My Place");
locations.add(myOverlayItem);

populate();
}

@Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return locations.get(i);
}

@Override
public int size() {
// TODO Auto-generated method stub
return locations.size();
}

@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
// TODO Auto-generated method stub
super.draw(canvas, mapView, shadow);

boundCenterBottom(marker);
}

@Override
public boolean onTouchEvent(MotionEvent arg0, MapView arg1) {
// TODO Auto-generated method stub
//super.onTouchEvent(arg0, arg1);



int Action = arg0.getAction();
if (Action == MotionEvent.ACTION_UP){

if(!MoveMap)
{
Projection proj = myMapView.getProjection();
GeoPoint loc = proj.fromPixels((int)arg0.getX(), (int)arg0.getY());

//remove the last marker
myMapView.getOverlays().remove(0);

CenterLocation(loc);
}

}
else if (Action == MotionEvent.ACTION_DOWN){

MoveMap = false;

}
else if (Action == MotionEvent.ACTION_MOVE){
MoveMap = true;
}

return super.onTouchEvent(arg0, arg1);
//return false;
}
}
}


Download the files.

Sunday, December 6, 2009

MOTODEV Studio for Android

MOTODEV Studio for Android is a Complete Development Package: One installer ensures an integrated development environment with Eclipse 3.5 and Android Development Tools (ADT) plus automatic download and configuration of the latest Android SDK.

MOTODEV Studio for Android Version 1.0.2 now support Android 1.1, Android 1.5, Android 1.6, Android 2.0 (Motorola Droid and Milestone)

MOTODEV Web Site

Friday, December 4, 2009

Android 2.0.1, Release 1 is available

Android 2.0.1 is a minor platform release deployable to Android-powered handsets starting in December 2009. This release includes minor API changes, bug fixes and framework behavioral changes.

Details>>>

If you have installed Android 1.6 or later SDK packages with Eclipse, you can update your Android SDK using the Android SDK and AVD Manager.

Click Window on Eclipse top menu, select Android SDK and AVD Manager.


Select Available Packages on the left and select the components you want to update, and click Install Selected.


Click to select Accept All and click Install Accepted.


Wait for Installing, then restart Eclipse.


After Eclipse restarted, click Window -> Preferences, and click Android on the left. You will be asked to update ADT to the latest version.


To update ADT, click Help -> Check for Updates in Eclipse.


The list of Updates will be come out soon. Select All and click Next, and then Finish.


Accept the Security Warning by clicking OK.


And finally accept Restart Eclipse again.

That's All.

Tuesday, December 1, 2009

Get center location of a map, using MapView.getMapCenter().

In the last exercise, Display a marker on MapView, using Overlays, a marker will be displayed in Mode 1 (with starting location) only. In this exercise, current center location of the Map in Mode 0 (without starting location) will be retrieved using the method MapView.getMapCenter(). Such that the appearance of both mode will be kept consistance.



To achieve it, AndroidMapView have to be modified, to add function in onCreate() to handle Mode 0.

package com.AndroidMapper;

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

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

public class AndroidMapView extends MapActivity {

private TextView myLongitude, myLatitude;
private CheckBox mySatellite;

private MapView myMapView;
private MapController myMapController;

private void SetSatellite()
{
myMapView.setSatellite(mySatellite.isChecked());
};

@Override
protected void onCreate(Bundle icicle) {
// TODO Auto-generated method stub
super.onCreate(icicle);
setContentView(R.layout.mymapview);

Bundle bundle = this.getIntent().getExtras();
int Mode = bundle.getInt("Mode");

myMapView = (MapView)findViewById(R.id.mapview);
myMapController = myMapView.getController();
myMapView.setBuiltInZoomControls(true);

myLongitude = (TextView)findViewById(R.id.longitude);
myLatitude = (TextView)findViewById(R.id.latitude);
mySatellite = (CheckBox)findViewById(R.id.satellite);
mySatellite.setOnClickListener(mySatelliteOnClickListener);

SetSatellite();

if(Mode == 0)
{
GeoPoint initGeoPoint = myMapView.getMapCenter();
CenterLocation(initGeoPoint);
}
else if(Mode == 1)
{
int intLatitude = bundle.getInt("Latitude");
int intLongitude = bundle.getInt("Longitude");
GeoPoint initGeoPoint = new GeoPoint(intLatitude, intLongitude);
CenterLocation(initGeoPoint);
}

}

private void placeMarker(int markerLatitude, int markerLongitude)
{
Drawable marker=getResources().getDrawable(
android.R.drawable.ic_menu_myplaces);
marker.setBounds(0, 0, marker.getIntrinsicWidth(),
marker.getIntrinsicHeight());
myMapView.getOverlays().add(new InterestingLocations(marker,
markerLatitude, markerLongitude));
}

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

private void CenterLocation(GeoPoint centerGeoPoint)
{
myMapController.animateTo(centerGeoPoint);

myLongitude.setText("Longitude: "+
String.valueOf((float)centerGeoPoint.getLongitudeE6()/1000000));
myLatitude.setText("Latitude: "+
String.valueOf((float)centerGeoPoint.getLatitudeE6()/1000000));
placeMarker(centerGeoPoint.getLatitudeE6(),
centerGeoPoint.getLongitudeE6());
};

private CheckBox.OnClickListener mySatelliteOnClickListener =
new CheckBox.OnClickListener(){

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

class InterestingLocations extends ItemizedOverlay<OverlayItem>{

private List<OverlayItem> locations =
new ArrayList<OverlayItem>();
private Drawable marker;

public InterestingLocations(Drawable defaultMarker,
int LatitudeE6, int LongitudeE6) {
super(defaultMarker);
// TODO Auto-generated constructor stub
this.marker=defaultMarker;
// create locations of interest
GeoPoint myPlace = new GeoPoint(LatitudeE6,LongitudeE6);
locations.add(new OverlayItem(myPlace ,
"My Place", "My Place"));
populate();
}

@Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return locations.get(i);
}

@Override
public int size() {
// TODO Auto-generated method stub
return locations.size();
}

@Override
public void draw(Canvas canvas, MapView mapView,
boolean shadow) {
// TODO Auto-generated method stub
super.draw(canvas, mapView, shadow);

boundCenterBottom(marker);
}
}
}


Other files are same as previous exercise.

Download the files.