| Author |
Message |
plusminus Site Admin


Joined: 14 Nov 2007 Posts: 2439 Location: College Park, MD
|
Posted: Thu Nov 22, 2007 4:39 pm Post subject: The Friend Finder - MapActivity using GPS - FULL SOURCE |
|
|
The Friend Finder - MapActivity using GPS
FULL SOURCE
Designed/Tested with sdk-version: m3
Problems/Questions: post right below...
AndroidManifest.xml
| XML: | <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.anddev.android.friendfinder">
<uses-permission id="android.permission.READ_CONTACTS"/>
<uses-permission id="android.permission.CALL_PHONE"/>
<application android:icon="@drawable/icon">
<activity class=".FriendFinder" android:label="@string/main_title">
<intent-filter>
<action android:value="android.intent.action.MAIN" />
<category android:value="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity class=".FriendFinderMap" android:label="@string/map_title">
<intent-filter>
<action android:value="android.intent.action.VIEW" />
<category android:value="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest> |
res/values/strings.xml
| XML: | <?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="main_title">FriendFinder - anddev.org</string>
<string name="main_menu_open_map">Open visual FriendTracker</string>
<string name="main_list_format">$name ($distance km)</string>
<string name="main_list_geo_not_set">not set</string>
<string name="map_title">FriendFinder - anddev.org</string>
<string name="map_menu_zoom_in">Zoom in (Key: I)</string>
<string name="map_menu_zoom_out">Zoom out (Key: O)</string>
<string name="map_menu_back_to_list">Back to list</string>
<string name="map_menu_toggle_street_satellite">Toggle View: Street / Satellite (Key: T)</string>
<string name="map_overlay_own_name">Me</string>
</resources>
|
src/your_package_structure/Friend.java
| Java: | package org. anddev. android. friendfinder;
import android. location. Location;
/**
* Small class to combine
* a Name and a Location.
* Hit me, I didn't use Getters & Setters.
*/
public class Friend {
public Location itsLocation = null;
public String itsName = null;
public Friend (Location aLocation, String aName ){
this. itsLocation = aLocation;
this. itsName = aName;
}
} |
src/your_package_structure/FriendFinder.java
| Java: | package org.anddev.android.friendfinder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentReceiver;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.view.Menu;
import android.widget.ArrayAdapter;
public class FriendFinder extends ListActivity {
// ===========================================================
// Fields
// ===========================================================
protected static final String MY_LOCATION_CHANGED_ACTION = new String("android.intent.action.LOCATION_CHANGED");
protected LocationManager myLocationManager = null;
protected Location myLocation = null;
protected boolean doUpdates = true;
protected MyIntentReceiver myIntentReceiver = null;
protected final IntentFilter myIntentFilter = new IntentFilter(MY_LOCATION_CHANGED_ACTION);
protected final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 25; // in Meters
protected final long MINIMUM_TIME_BETWEEN_UPDATE = 2500; // in Milliseconds
/** Minimum distance in meters for a friend
* to be recognize as a Friend to be drawn */
protected static final int NEARFRIEND_MAX_DISTANCE = 10000000; // 10.000km
/** List of friends in */
protected ArrayList<Friend> allFriends = new ArrayList<Friend>();
// ===========================================================
// Extra-Class
// ===========================================================
/**
* This tiny IntentReceiver updates
* our stuff as we receive the intents
* (LOCATION_CHANGED_ACTION) we told the
* myLocationManager to send to us.
*/
class MyIntentReceiver extends IntentReceiver {
@Override
public void onReceiveIntent(Context context, Intent intent) {
if(FriendFinder.this.doUpdates)
FriendFinder.this.updateList(); // Will simply update our list, when receiving an intent
}
}
// ===========================================================
// """Constructors""" (or the Entry-Point of it all)
// ===========================================================
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* The first thing we need to do is to setup our own
* locationManager, that will support us with our own gps data */
this.myLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
/* Update the list of our friends once on the start,
* as they are not(yet) moving, no updates to them are necessary */
this.refreshFriendsList();
/* Initiate the update of the contactList
* manually for the first time */
this.updateList();
/* Prepare the things, that will give
* us the ability, to receive Information
* about our GPS-Position. */
this.setupForGPSAutoRefreshing();
}
/**
* Restart the receiving, when we are back on line.
*/
@Override
public void onResume() {
super.onResume();
this.doUpdates = true;
/* As we only want to react on the LOCATION_CHANGED
* intents we made the OS send out, we have to
* register it along with a filter, that will only
* "pass through" on LOCATION_CHANGED-Intents.
*/
this.registerReceiver(this.myIntentReceiver, this.myIntentFilter);
}
/**
* Make sure to stop the animation when we're no longer on screen,
* failing to do so will cause a lot of unnecessary cpu-usage!
*/
@Override
public void onFreeze(Bundle icicle) {
this.doUpdates = false;
this.unregisterReceiver(this.myIntentReceiver);
super.onFreeze(icicle);
}
/** Register with our LocationManager to send us
* an intent (who's Action-String we defined above)
* when an intent to the location manager,
* that we want to get informed on changes to our own position.
* This is one of the hottest features in Android.
*/
private void setupForGPSAutoRefreshing() {
// Get the first provider available
List<LocationProvider> providers = this.myLocationManager.getProviders();
LocationProvider provider = providers.get(0);
this.myLocationManager.requestUpdates(provider, MINIMUM_TIME_BETWEEN_UPDATE,
MINIMUM_DISTANCECHANGE_FOR_UPDATE,
new Intent(MY_LOCATION_CHANGED_ACTION));
/* Create an IntentReceiver, that will react on the
* Intents we said to our LocationManager to send to us. */
this.myIntentReceiver = new MyIntentReceiver();
/*
* In onResume() the following method will be called automatically!
* registerReceiver(this.myIntentReceiver, this.myIntentFilter);
*/
}
/** Called only the first time the options menu is displayed.
* Create the menu entries.
* Menus are added in the order they are hardcoded. */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean supRetVal = super.onCreateOptionsMenu(menu);
menu.add(0, 0, getString(R.string.main_menu_open_map));
return supRetVal;
}
@Override
public boolean onOptionsItemSelected(Menu.Item item) {
switch (item.getId()) {
case 0:
startSubActivity(new Intent(this, FriendFinderMap.class), 0);
return true;
}
return false;
}
// ===========================================================
// Methods
// ===========================================================
private void refreshFriendsList(){
Cursor c = getContentResolver().query(People.CONTENT_URI,
null, null, null, People.NAME + " ASC");
/* This method allows the activity to take
* care of managing the given Cursor's lifecycle
* for you based on the activity's lifecycle. */
startManagingCursor(c);
int notesColumn = c.getColumnIndex(People.NOTES);
int nameColumn = c.getColumnIndex(People.NAME);
// Moves the cursor to the first row
// and returns true if there is sth. to get
if (c.first()) {
do {
String notesString = c.getString(notesColumn);
Location friendLocation = null;
if (notesString != null) {
// Pattern for extracting geo-ContentURIs from the notes.
final String geoPattern = "(geo:[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\,[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\#)";
// Compile and use regular expression
Pattern pattern = Pattern.compile(geoPattern);
CharSequence inputStr = notesString;
Matcher matcher = pattern.matcher(inputStr);
boolean matchFound = matcher.find();
if (matchFound) {
// We take the first match available
String groupStr = matcher.group(0);
// And parse the Lat/Long-GeoPos-Values from it
friendLocation = new Location();
String latid = groupStr.substring(groupStr.indexOf(":") + 1,
groupStr.indexOf(","));
String longit = groupStr.substring(groupStr.indexOf(",") + 1,
groupStr.indexOf("#"));
friendLocation.setLongitude(Float.parseFloat(longit));
friendLocation.setLatitude(Float.parseFloat(latid));
}
}
String friendName = c.getString(nameColumn);
allFriends.add(new Friend(friendLocation, friendName));
} while (c.next());
}
}
private void updateList() {
// Refresh our location...
this.myLocation = myLocationManager.getCurrentLocation("gps");
ArrayList<String> listItems = new ArrayList<String>();
// For each Friend
for(Friend aNearFriend : this.allFriends){
/* Load the row-entry-format defined as a String
* and replace $name with the contact's name we
* get from the cursor */
String curLine = new String(getString(R.string.main_list_format));
curLine = curLine.replace("$name", aNearFriend.itsName);
if(aNearFriend.itsLocation != null){
if( this.myLocation.distanceTo(aNearFriend.itsLocation) <
NEARFRIEND_MAX_DISTANCE){
final DecimalFormat df = new DecimalFormat("####0.000");
String formattedDistance =
df.format(this.myLocation.distanceTo(
aNearFriend.itsLocation) / 1000);
curLine = curLine.replace("$distance", formattedDistance);
}
}else{
curLine = curLine.replace("$distance",
getString(R.string.main_list_geo_not_set));
}
listItems.add(curLine);
}
ArrayAdapter<String> notes = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, listItems);
this.setListAdapter(notes);
}
} |
src/your_package_structure/FriendFinderMap.java
| Java: | package org. anddev. android. friendfinder;
import java. util. ArrayList;
import java. util. List;
import java. util. regex. Matcher;
import java. util. regex. Pattern;
import android. content. Context;
import android. content. Intent;
import android. content. IntentFilter;
import android. content. IntentReceiver;
import android. database. Cursor;
import android. graphics. Canvas;
import android. graphics. Paint;
import android. graphics. RectF;
import android. graphics. Paint. Style;
import android. location. Location;
import android. location. LocationManager;
import android. location. LocationProvider;
import android. os. Bundle;
import android. os. Handler;
import android. provider. Contacts. People;
import android. view. KeyEvent;
import android. view. Menu;
import com. google. android. maps. MapActivity;
import com. google. android. maps. MapController;
import com. google. android. maps. MapView;
import com. google. android. maps. Overlay;
import com. google. android. maps. OverlayController;
import com. google. android. maps. Point;
public class FriendFinderMap extends MapActivity {
// ===========================================================
// Fields
// ===========================================================
private static final String MY_LOCATION_CHANGED_ACTION =
new String("android.intent.action.LOCATION_CHANGED");
/** Minimum distance in meters for a friend
* to be recognize as a Friend to be drawn */
protected static final int NEARFRIEND_MAX_DISTANCE = 10000000; // 10.000km
final Handler mHandler = new Handler ();
/*
* Stuff we need to save as fields,
* because we want to use multiple
* of them in different methods.
*/
protected boolean doUpdates = true;
protected MapView myMapView = null;
protected MapController myMapController = null;
protected OverlayController myOverlayController = null;
protected LocationManager myLocationManager = null;
protected Location myLocation = null;
protected MyIntentReceiver myIntentReceiver = null;
protected final IntentFilter myIntentFilter =
new IntentFilter (MY_LOCATION_CHANGED_ACTION );
/** List of friends in */
protected ArrayList<Friend> nearFriends = new ArrayList<Friend> ();
// ===========================================================
// Extra-Classes
// ===========================================================
/**
* This tiny IntentReceiver updates
* our stuff as we receive the intents
* (LOCATION_CHANGED_ACTION) we told the
* myLocationManager to send to us.
*/
class MyIntentReceiver extends IntentReceiver {
@Override
public void onReceiveIntent (Context context, Intent intent ) {
if(FriendFinderMap. this. doUpdates)
FriendFinderMap. this. updateView();
}
}
/**
* This method is so huge,
* because it does a lot of FANCY painting.
* We could shorten this method to a few lines.
* But as users like eye-candy apps ...
*/
protected class MyLocationOverlay extends Overlay {
@Override
public void draw (Canvas canvas, PixelCalculator calculator, boolean shadow ) {
super. draw(canvas, calculator, shadow );
// Setup our "brush"/"pencil"/ whatever...
Paint paint = new Paint();
paint. setTextSize(14);
// Create a Point that represents our GPS-Location
Double lat = FriendFinderMap. this. myLocation. getLatitude() * 1E6;
Double lng = FriendFinderMap. this. myLocation. getLongitude() * 1E6;
Point point = new Point(lat. intValue(), lng. intValue());
int[] myScreenCoords = new int[2];
// Converts lat/lng-Point to OUR coordinates on the screen.
calculator. getPointXY(point, myScreenCoords );
// Draw a circle for our location
RectF oval = new RectF (myScreenCoords [0] - 7, myScreenCoords [1] + 7,
myScreenCoords [0] + 7, myScreenCoords [1] - 7);
// Setup a color for our location
paint. setStyle(Style. FILL);
paint. setARGB(255, 80, 150, 30); // Nice strong Android-Green
// Draw our name
canvas. drawText(getString (R. string. map_overlay_own_name),
myScreenCoords [0] +9, myScreenCoords [1], paint );
// Change the paint to a 'Lookthrough' Android-Green
paint. setARGB(80, 156, 192, 36);
paint. setStrokeWidth(1);
// draw an oval around our location
canvas. drawOval(oval, paint );
// With a black stroke around the oval we drew before.
paint. setARGB(255, 0, 0, 0);
paint. setStyle(Style. STROKE);
canvas. drawCircle(myScreenCoords [0], myScreenCoords [1], 7, paint );
int[] friendScreenCoords = new int[2];
//Draw each friend with a line pointing to our own location.
for(Friend aFriend : FriendFinderMap. this. nearFriends){
lat = aFriend. itsLocation. getLatitude() * 1E6;
lng = aFriend. itsLocation. getLongitude() * 1E6;
point = new Point(lat. intValue(), lng. intValue());
// Converts lat/lng-Point to coordinates on the screen.
calculator. getPointXY(point, friendScreenCoords );
if(Math. abs(friendScreenCoords [0]) < 2000 && Math. abs(friendScreenCoords [1]) < 2000){
// Draw a circle for this friend and his name
oval = new RectF (friendScreenCoords [0] - 7, friendScreenCoords [1] + 7,
friendScreenCoords [0] + 7, friendScreenCoords [1] - 7);
// Setup a color for all friends
paint. setStyle(Style. FILL);
paint. setARGB(255, 255, 0, 0); // Nice red
canvas. drawText(aFriend. itsName, friendScreenCoords [0] +9,
friendScreenCoords [1], paint );
// Draw a line connecting us to the current Friend
paint. setARGB(80, 255, 0, 0); // Nice red, more look through...
paint. setStrokeWidth(2);
canvas. drawLine(myScreenCoords [0], myScreenCoords [1],
friendScreenCoords [0], friendScreenCoords [1], paint );
paint. setStrokeWidth(1);
// draw an oval around our friends location
canvas. drawOval(oval, paint );
// With a black stroke around the oval we drew before.
paint. setARGB(255, 0, 0, 0);
paint. setStyle(Style. STROKE);
canvas. drawCircle(friendScreenCoords [0], friendScreenCoords [1], 7, paint );
}
}
}
}
// ===========================================================
// """Constructor""" (or the Entry-Point of this class)
// ===========================================================
@Override
protected void onCreate (Bundle icicle ) {
super. onCreate(icicle );
/* Create a new MapView and show it */
this. myMapView = new MapView (this);
this. setContentView(myMapView );
/* MapController is capable of zooming
* and animating and stuff like that */
this. myMapController = this. myMapView. getController();
/* With these objects we are capable of
* drawing graphical stuff on top of the map */
this. myOverlayController = this. myMapView. createOverlayController();
MyLocationOverlay myLocationOverlay = new MyLocationOverlay ();
this. myOverlayController. add(myLocationOverlay, true);
this. myMapController. zoomTo(2); // Far out
// Initialize the LocationManager
this. myLocationManager = (LocationManager )getSystemService (Context. LOCATION_SERVICE);
this. updateView();
/* Prepare the things, that will give
* us the ability, to receive Information
* about our GPS-Position. */
this. setupForGPSAutoRefreshing();
/* Update the list of our friends once on the start,
* as they are not(yet) moving, no updates to them are necessary */
this. refreshFriendsList(NEARFRIEND_MAX_DISTANCE );
}
/**
* Restart the receiving, when we are back on line.
*/
@Override
public void onResume () {
super. onResume();
this. doUpdates = true;
/* As we only want to react on the LOCATION_CHANGED
* intents we made the OS send out, we have to
* register it along with a filter, that will only
* "pass through" on LOCATION_CHANGED-Intents.
*/
registerReceiver (this. myIntentReceiver, this. myIntentFilter);
}
/**
* Make sure to stop the animation when we're no longer on screen,
* failing to do so will cause a lot of unnecessary cpu-usage!
*/
@Override
public void onFreeze (Bundle icicle ) {
this. doUpdates = false;
unregisterReceiver (this. myIntentReceiver);
super. onFreeze(icicle );
}
// ===========================================================
// Overridden methods
// ===========================================================
// Called only the first time the options menu is displayed.
// Create the menu entries.
// Menu adds items in the order shown.
@Override
public boolean onCreateOptionsMenu (Menu menu ) {
boolean supRetVal = super. onCreateOptionsMenu(menu );
menu. add(0, 0, getString (R. string. map_menu_zoom_in));
menu. add(0, 1, getString (R. string. map_menu_zoom_out));
menu. add(0, 2, getString (R. string. map_menu_toggle_street_satellite));
menu. add(0, 3, getString (R. string. map_menu_back_to_list));
return supRetVal;
}
@Override
public boolean onOptionsItemSelected (Menu. Item item ){
switch (item. getId()) {
case 0:
// Zoom not closer than possible
this. myMapController. zoomTo(Math. min(21, this. myMapView. getZoomLevel() + 1));
return true;
case 1:
// Zoom not farer than possible
this. myMapController. zoomTo(Math. max(1, this. myMapView. getZoomLevel() - 1));
return true;
case 2:
// Switch to satellite view
myMapView. toggleSatellite();
return true;
case 3:
this. finish();
return true;
}
return false;
}
@Override
public boolean onKeyDown (int keyCode, KeyEvent event ) {
if (keyCode == KeyEvent. KEYCODE_I) {
// Zoom not closer than possible
this. myMapController. zoomTo(Math. min(21, this. myMapView. getZoomLevel() + 1));
return true;
} else if (keyCode == KeyEvent. KEYCODE_O) {
// Zoom not farer than possible
this. myMapController. zoomTo(Math. max(1, this. myMapView. getZoomLevel() - 1));
return true;
} else if (keyCode == KeyEvent. KEYCODE_T) {
// Switch to satellite view
myMapView. toggleSatellite();
return true;
}
return false;
}
// ===========================================================
// Methods
// ===========================================================
private void setupForGPSAutoRefreshing () {
/* Register with out LocationManager to send us
* an intent (whos Action-String we defined above)
* when an intent to the location manager,
* that we want to get informed on changes to our own position.
* This is one of the hottest features in Android.
*/
final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 25; // in Meters
final long MINIMUM_TIME_BETWEEN_UPDATE = 5000; // in Milliseconds
// Get the first provider available
List<LocationProvider> providers = this. myLocationManager. getProviders();
LocationProvider provider = providers. get(0);
this. myLocationManager. requestUpdates(provider, MINIMUM_TIME_BETWEEN_UPDATE,
MINIMUM_DISTANCECHANGE_FOR_UPDATE, new Intent (MY_LOCATION_CHANGED_ACTION ));
/* Create an IntentReceiver, that will react on the
* Intents we made our LocationManager to send to us.
*/
this. myIntentReceiver = new MyIntentReceiver ();
/*
* In onResume() the following method will be called automatically!
* registerReceiver(this.myIntentReceiver, this.myIntentFilter);
*/
}
private void updateView () {
// Refresh our gps-location
this. myLocation = myLocationManager. getCurrentLocation("gps");
/* Redraws the mapViee, which also makes our
* OverlayController redraw our Circles and Lines */
this. myMapView. invalidate();
/* As the location of our Friends is static and
* for performance-reasons, we do not call this */
// this.refreshFriendsList(NEARFRIEND_MAX_DISTANCE);
}
private void refreshFriendsList (long maxDistanceInMeter ){
Cursor c = getContentResolver (). query(People. CONTENT_URI, null, null, null, People. NAME + " ASC");
startManagingCursor (c );
int notesColumn = c. getColumnIndex(People. NOTES);
int nameColumn = c. getColumnIndex(People. NAME);
// Moves the cursor to the first row
// and returns true if there is sth. to get
if (c. first()) {
do {
String notesString = c. getString(notesColumn );
Location friendLocation = null;
if (notesString != null) {
// Pattern for extracting geo-ContentURIs from the notes.
final String geoPattern = "(geo:[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\,[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\#)";
// Compile and use regular expression
Pattern pattern = Pattern. compile(geoPattern );
CharSequence inputStr = notesString;
Matcher matcher = pattern. matcher(inputStr );
boolean matchFound = matcher. find();
if (matchFound ) {
// We take the first match available
String groupStr = matcher. group(0);
// And parse the Lat/Long-GeoPos-Values from it
friendLocation = new Location ();
String latid = groupStr. substring(groupStr. indexOf(":") + 1, groupStr. indexOf(","));
String longit = groupStr. substring(groupStr. indexOf(",") + 1, groupStr. indexOf("#"));
friendLocation. setLongitude(Float. parseFloat(longit ));
friendLocation. setLatitude(Float. parseFloat(latid ));
}
}
if(friendLocation != null
&& this. myLocation. distanceTo(friendLocation ) < maxDistanceInMeter ){
String friendName = c. getString(nameColumn );
nearFriends. add(new Friend (friendLocation, friendName ));
}
} while (c. next());
}
}
} |
Regards,
plusminus
| Description: |
| Friend Finder Full Source |
|
 Download |
| Filename: |
FriendFinder.zip |
| Filesize: |
68.15 KB |
| Downloaded: |
1340 Time(s) |
_________________
Please remember, that this board is give & take 
| Android Development Community / Tutorials
Last edited by plusminus on Mon Sep 29, 2008 1:49 am; edited 9 times in total |
|
| Back to top |
| |