Sunday, February 8, 2009

App #1.0 - Beer Radar

I want to create an application, where it downloads bar location and some necessary details such as price of a beer, location and last call time. Also, I want it to be plotted with the user's current GPS location. Also, I want to have a server where user's can upload their recommended bars so that other user's may see it on their screens.

Download Source Code Below.


1. Download Bar Details from Server
* 2. Plot Bar Details with respect to the user's current gps location
3. Upload Bar Details to Server
4. Be able adjust the coverage of the radar (1 km - 10 km)

But for this tutorial, I just want to implement #2, since I still can't find a nice free server to host my server app.


STEP 1. Create
- this is just a POJO for the Bar Details. It also stores the longitude and latitude values of the Bar.


import java.text.DecimalFormat;

public class BeerLocation {

private int id;
private String name;
private String price;
private String description;
private String lastCallTime;
private double latitude;
private double longitude;
private DecimalFormat df = new DecimalFormat("####.##");

public BeerLocation(String name, String price, String description,
String lastCallTime, double latitude, double longitude) { = name;
this.price = price;
this.description = description;
this.lastCallTime = lastCallTime;
this.latitude = latitude;
this.longitude = longitude;

public String toString() {
return name + ", " + price + " ( " + df.format(longitude) + ", " + df.format(latitude) + " ) ";

public BeerLocation() {

public int getId() {
return id;

public void setId(int id) { = id;

public String getName() {
return name;

public void setName(String name) { = name;

public String getPrice() {
return price;

public void setPrice(String price) {
this.price = price;

public String getDescription() {
return description;

public void setDescription(String description) {
this.description = description;

public String getLastCallTime() {
return lastCallTime;

public void setLastCallTime(String lastCallTime) {
this.lastCallTime = lastCallTime;

public double getLatitude() {
return latitude;

public void setLatitude(double latitude) {
this.latitude = latitude;

public double getLongitude() {
return longitude;

public void setLongitude(double longitude) {
this.longitude = longitude;


STEP 2. Create interface
- contains the method to retrieve a List of Bar Details. Currently, the implementation is just hard-coded and will be replaced on the next iterationsof this application.


import java.util.List;

public interface BeerLocationService {
public List retrieveAllBeerLocations();

STEP 3. Create
- Just create a java.util.List and add BeerLocation to the list.


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


public class BeerLocationServiceMemory implements BeerLocationService {

private List beerLocations = new ArrayList();
public List retrieveAllBeerLocations() {
beerLocations.add( new BeerLocation("Chili Pepper's", "Php45.0", "", "9:00AM", 50, 50));
beerLocations.add( new BeerLocation("OTB", "Php45.0", "", "3:00AM", 0, 0));
beerLocations.add( new BeerLocation("Gerry's Grill", "Php38.0", "", "00:00AM", 235, 100));
beerLocations.add( new BeerLocation("Giligan's", "Php40.0", "", "03:00AM", 180, 150));
return beerLocations;


STEP 1. Create BeerRadarView
- Extend the android.view.View class. The View class contains the onDraw(Canvas) method which is where the painting is done. The onDraw(Canvas) method is similar to the paint(Graphics g) of AWT and/or Swing components. Even the draw methods are almost the same. (example. g.drawArc(...), canvas.drawArc(...), g.drawLine(...), canvas.drawLine(...) and so forth. The only difference is that the canvas stores most of its paint/draw properties in a Paint object.
- The Paint class stores common drawing properties such as color, font size, stoke etc.
- The coordinates are also the same for both canvas and graphics. 0,0 is the upperleft-most and MAX_WIDTH, MAX_HEIGHT is on the lower right-most.

protected void onDraw(Canvas canvas) {
if(!hasInitialized) {
drawBeer(canvas, beerLocations);
String currentLocation = "( " + df.format(currentLongitude) + ", " + df.format(currentLatitude) + " )";
canvas.drawText(currentLocation, midpointX-30, midpointY-5, paintScreenText);

STEP 2. Drawing the Radar Grid
- Just plot two lines that looks like a corsair.

STEP 3. Drawing the Radar Circles
- This uses the canvas.drawCircle(...) which actually is not on the graphics class. The canvas.drawArc(...), is different from the drawCircle, since it uses a RectF to get the size of the arc/ellipse to be drawn.

private void drawRadarGrid(Canvas canvas) {
canvas.drawLine(0, midpointY, screenWidth, midpointY, paintRadarGrid);
canvas.drawLine(midpointX, 0, midpointX, screenHeight, paintRadarGrid);

STEP 4. Animated the Radar
- Use the circle path formula
x = A cos(radian);
y = A Sine(radian);
Where A is the amplitude.
- Since I am using 0-360 degrees for the angles, it is necessary to convert degrees to radians.
- Radian = Angle * (PI / 180)

private void drawRadar(Canvas canvas) {
if (startAngle > 360) {
startAngle = 0;
float x = (float) (minimumScreenSize / 2 * Math.cos(startAngle
* (Math.PI / 180)));
float y = (float) (minimumScreenSize / 2 * Math.sin(startAngle
* (Math.PI / 180)));
canvas.drawLine(getWidth() / 2, getHeight() / 2, x + getWidth() / 2, y
+ getHeight() / 2, paintRadar);
startAngle += 3;

STEP 5. Plotting the BeerLocation data.
- Plot the longitude and latitude of the BeerLocation with respect to the user's current GPS location
- x = (beerLoc.getLongitude() + midpointX - currentLongitude - BEER_ICON_SIZE);
Since the screens midpoint is not 0, the longitude must the adjusted. The + (positive) value of X should be in the WEST part of the screen. So the midpoint of the X-axis must be added to the location's longitude. Also, to adjust it to the user's current location, the currentLongitude is subtracted. The BEER_ICON_SIZE is subtracted just so it becomes centered.
- y = (midpointY - beerLoc.getLatitude() + currentLatitude - BEER_ICON_SIZE);
There's a slight difference between the computation of Y, since the + (positive) value of y should be on the NORTH part of the screen, thus, the point is adjusted. So, midpoint of Y is subtracted with the beer location's latitude. Also, the currentLatitude is added to the equation.
- The maximum coverage is not yet adjustable yet. In the future, I'll modify so that the user can select a minimum radius of 1KM and a maximum radius of 10KM. I currently do not know how each degrees of the longitude and latitude translates into KM. I'll research on it first.

private void drawBeer(Canvas canvas, List beerLocations) {
if(beerIcon == null) {
beerIcon = BitmapFactory.decodeResource(this.getResources(),;
for(BeerLocation beerLoc : beerLocations) {
float x = (float)(beerLoc.getLongitude() + midpointX - currentLongitude - BEER_ICON_SIZE);
float y = (float)(midpointY - beerLoc.getLatitude() + currentLatitude - BEER_ICON_SIZE);
canvas.drawBitmap(beerIcon, x, y, paintScreenText);
canvas.drawText(beerLoc.toString(), x, y, paintScreenText);

STEP 1. Set the BeerRadarView as the Activity's contentView

public void onCreate(Bundle savedInstanceState) {
beerRadarView = new BeerRadarView(this);
thread = new Thread(new MyThreadRunner());

STEP 2. Create a android.os.Handler that invalidate's the view when called. Invalidate is similar to calling awt/swing component's repaint() method.

"When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing
the top-level application objects (activities, intent receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will than be scheduled in the Handler's message queue and processed when appropriate."

Handler updateHandler = new Handler() {
/** Gets called on every message that is received */
// @Override
public void handleMessage(Message msg) {
switch (msg.what) {

STEP 3. implement android.location.LocationListener on the Activity

public class BeerRadar extends Activity implements LocationListener {

- Implement the necessary methods.

public void onLocationChanged(Location location) {

public void onProviderDisabled(String provider) {


public void onProviderEnabled(String provider) {

public void onStatusChanged(String provider, int status, Bundle extras) {

- Use onLocationChanged(Location location) to update the user's current location

private void setCurrentGpsLocation(Location location) {
if (location == null) {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
LocationManager.GPS_PROVIDER, 0, 0, this);
location = locationManager
longitude = location.getLongitude();
latitude = location.getLatitude();
Message msg = new Message();


Since it just an emulator, you can use the DDMS perspective to update the longitude and latitude.Longitude =50, Latitude = 50

Longitude =120, Latitude = 100

Source Code

Android Camera Capture Tutorial