The Friend Finder - MapActivity using GPS
FULL SOURCE
AndroidManifest.xml
Using xml Syntax Highlighting
- <?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>
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
res/values/strings.xml
Using xml Syntax Highlighting
- <?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>
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
src/your_package_structure/Friend.java
Using java Syntax Highlighting
- 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. <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />
- */
- public class Friend{
- public Location itsLocation = null;
- public String itsName = null;
- public Friend(Location aLocation, String aName){
- this.itsLocation = aLocation;
- this.itsName = aName;
- }
- }
Parsed in 0.033 seconds, using GeSHi 1.0.8.4
src/your_package_structure/FriendFinder.java
Using java Syntax Highlighting
- 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);
- }
- }
Parsed in 0.064 seconds, using GeSHi 1.0.8.4
src/your_package_structure/FriendFinderMap.java
Using java Syntax Highlighting
- 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 <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" /> ...
- */
- 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());
- }
- }
- }
Parsed in 0.085 seconds, using GeSHi 1.0.8.4
Regards,
plusminus









