The Friend Finder - MapActivity using GPS - FULL SOURCE

Tutorials that use the MapActivity. Many using GPS functionality.

The Friend Finder - MapActivity using GPS - FULL SOURCE

Postby plusminus » Thu Nov 22, 2007 4:39 pm

The Friend Finder - MapActivity using GPS

FULL SOURCE


:idea: Designed/Tested with sdk-version: m3


:?: Problems/Questions: post right below...

AndroidManifest.xml
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.    package="org.anddev.android.friendfinder">
  4.     <uses-permission id="android.permission.READ_CONTACTS"/>
  5.     <uses-permission id="android.permission.CALL_PHONE"/>
  6.     <application android:icon="@drawable/icon">
  7.         <activity class=".FriendFinder" android:label="@string/main_title">
  8.             <intent-filter>
  9.                 <action android:value="android.intent.action.MAIN" />
  10.                 <category android:value="android.intent.category.LAUNCHER" />
  11.             </intent-filter>
  12.         </activity>
  13.         <activity class=".FriendFinderMap" android:label="@string/map_title">
  14.             <intent-filter>
  15.                 <action android:value="android.intent.action.VIEW" />
  16.                 <category android:value="android.intent.category.DEFAULT" />
  17.             </intent-filter>
  18.         </activity>
  19.     </application>
  20. </manifest>
Parsed in 0.004 seconds, using GeSHi 1.0.8.4


res/values/strings.xml
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.     <string name="main_title">FriendFinder - anddev.org</string>
  4.     <string name="main_menu_open_map">Open visual FriendTracker</string>
  5.     <string name="main_list_format">$name ($distance km)</string>
  6.     <string name="main_list_geo_not_set">not set</string>
  7.     <string name="map_title">FriendFinder - anddev.org</string>
  8.     <string name="map_menu_zoom_in">Zoom in (Key: I)</string>
  9.     <string name="map_menu_zoom_out">Zoom out (Key: O)</string>
  10.     <string name="map_menu_back_to_list">Back to list</string>
  11.     <string name="map_menu_toggle_street_satellite">Toggle View: Street / Satellite (Key: T)</string>
  12.     <string name="map_overlay_own_name">Me</string>
  13. </resources>
  14.  
Parsed in 0.004 seconds, using GeSHi 1.0.8.4


src/your_package_structure/Friend.java
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package org.anddev.android.friendfinder;
  2.  
  3. import android.location.Location;
  4.  
  5. /**
  6.  * Small class to combine
  7.  * a Name and a Location.
  8.  * Hit me, I didn't use Getters & Setters. <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />
  9.  */
  10. public class Friend{
  11.         public Location itsLocation = null;
  12.         public String itsName = null;
  13.         public Friend(Location aLocation, String aName){
  14.                 this.itsLocation = aLocation;
  15.                 this.itsName = aName;
  16.         }
  17. }
Parsed in 0.032 seconds, using GeSHi 1.0.8.4


src/your_package_structure/FriendFinder.java
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package org.anddev.android.friendfinder;
  2.  
  3. import java.text.DecimalFormat;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import java.util.regex.Matcher;
  7. import java.util.regex.Pattern;
  8.  
  9. import android.app.ListActivity;
  10. import android.content.Context;
  11. import android.content.Intent;
  12. import android.content.IntentFilter;
  13. import android.content.IntentReceiver;
  14. import android.database.Cursor;
  15. import android.location.Location;
  16. import android.location.LocationManager;
  17. import android.location.LocationProvider;
  18. import android.os.Bundle;
  19. import android.provider.Contacts.People;
  20. import android.view.Menu;
  21. import android.widget.ArrayAdapter;
  22.  
  23. public class FriendFinder extends ListActivity {
  24.         // ===========================================================
  25.         // Fields
  26.         // ===========================================================
  27.        
  28.         protected static final String MY_LOCATION_CHANGED_ACTION = new String("android.intent.action.LOCATION_CHANGED");
  29.         protected LocationManager myLocationManager = null;
  30.         protected Location myLocation = null;
  31.        
  32.         protected boolean doUpdates = true;
  33.         protected MyIntentReceiver myIntentReceiver = null;
  34.         protected final IntentFilter myIntentFilter =  new IntentFilter(MY_LOCATION_CHANGED_ACTION);
  35.        
  36.         protected final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 25; // in Meters
  37.         protected final long MINIMUM_TIME_BETWEEN_UPDATE = 2500; // in Milliseconds
  38.        
  39.         /** Minimum distance in meters for a friend
  40.          * to be recognize as a Friend to be drawn */
  41.         protected static final int NEARFRIEND_MAX_DISTANCE = 10000000;  // 10.000km
  42.        
  43.         /** List of friends in */
  44.         protected ArrayList<Friend> allFriends = new ArrayList<Friend>();
  45.        
  46.         // ===========================================================
  47.         // Extra-Class
  48.         // ===========================================================
  49.  
  50.  
  51.         /**
  52.          * This tiny IntentReceiver updates
  53.          * our stuff as we receive the intents
  54.          * (LOCATION_CHANGED_ACTION) we told the
  55.          * myLocationManager to send to us.
  56.          */
  57.         class MyIntentReceiver extends IntentReceiver {
  58.                 @Override
  59.                 public void onReceiveIntent(Context context, Intent intent) {
  60.                         if(FriendFinder.this.doUpdates)
  61.                                 FriendFinder.this.updateList(); // Will simply update our list, when receiving an intent
  62.                 }
  63.         }
  64.  
  65.         // ===========================================================
  66.         // """Constructors""" (or the Entry-Point of it all)
  67.         // ===========================================================
  68.         /** Called when the activity is first created. */
  69.         @Override
  70.         public void onCreate(Bundle icicle) {
  71.                 super.onCreate(icicle);
  72.  
  73.                 /* The first thing we need to do is to setup our own
  74.                  * locationManager, that will support us with our own gps data */
  75.                 this.myLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
  76.  
  77.                 /* Update the list of our friends once on the start,
  78.                  * as they are not(yet) moving, no updates to them are necessary */
  79.                 this.refreshFriendsList();
  80.                
  81.                 /* Initiate the update of the contactList
  82.                  * manually for the first time */
  83.                 this.updateList();
  84.  
  85.                 /* Prepare the things, that will give
  86.                  * us the ability, to receive Information
  87.                  * about our GPS-Position. */
  88.                 this.setupForGPSAutoRefreshing();
  89.         }
  90.        
  91.         /**
  92.          * Restart the receiving, when we are back on line.
  93.          */
  94.         @Override
  95.         public void onResume() {
  96.                 super.onResume();
  97.                 this.doUpdates = true;
  98.                
  99.                 /* As we only want to react on the LOCATION_CHANGED
  100.                  * intents we made the OS send out, we have to
  101.                  * register it along with a filter, that will only
  102.                  * "pass through" on LOCATION_CHANGED-Intents.
  103.                  */
  104.                 this.registerReceiver(this.myIntentReceiver, this.myIntentFilter);
  105.         }
  106.        
  107.         /**
  108.          * Make sure to stop the animation when we're no longer on screen,
  109.          * failing to do so will cause a lot of unnecessary cpu-usage!
  110.          */
  111.         @Override
  112.         public void onFreeze(Bundle icicle) {
  113.                 this.doUpdates = false;
  114.                 this.unregisterReceiver(this.myIntentReceiver);
  115.                 super.onFreeze(icicle);
  116.         }
  117.  
  118.         /** Register with our LocationManager to send us
  119.          * an intent (who's Action-String we defined above)
  120.          * when  an intent to the location manager,
  121.          * that we want to get informed on changes to our own position.
  122.          * This is one of the hottest features in Android.
  123.          */
  124.         private void setupForGPSAutoRefreshing() {
  125.  
  126.                 // Get the first provider available
  127.                 List<LocationProvider> providers = this.myLocationManager.getProviders();
  128.                 LocationProvider provider = providers.get(0);
  129.                
  130.                 this.myLocationManager.requestUpdates(provider, MINIMUM_TIME_BETWEEN_UPDATE,
  131.                                                                                                 MINIMUM_DISTANCECHANGE_FOR_UPDATE,
  132.                                                                                                 new Intent(MY_LOCATION_CHANGED_ACTION));
  133.                
  134.                
  135.                 /* Create an IntentReceiver, that will react on the
  136.                  * Intents we said to our LocationManager to send to us. */
  137.                 this.myIntentReceiver = new MyIntentReceiver();
  138.  
  139.                 /*
  140.                  * In onResume() the following method will be called automatically!
  141.                  * registerReceiver(this.myIntentReceiver, this.myIntentFilter);
  142.                  */
  143.         }
  144.  
  145.         /** Called only the first time the options menu is displayed.
  146.          * Create the menu entries.
  147.          *  Menus are added in the order they are hardcoded. */
  148.         @Override
  149.         public boolean onCreateOptionsMenu(Menu menu) {
  150.                 boolean supRetVal = super.onCreateOptionsMenu(menu);
  151.                 menu.add(0, 0, getString(R.string.main_menu_open_map));
  152.                 return supRetVal;
  153.         }
  154.         @Override
  155.         public boolean onOptionsItemSelected(Menu.Item item) {
  156.                 switch (item.getId()) {
  157.                         case 0:
  158.                                 startSubActivity(new Intent(this, FriendFinderMap.class), 0);
  159.                                 return true;
  160.                 }
  161.                 return false;
  162.         }
  163.  
  164.         // ===========================================================
  165.         // Methods
  166.         // ===========================================================
  167.        
  168.         private void refreshFriendsList(){
  169.                 Cursor c = getContentResolver().query(People.CONTENT_URI,
  170.                                 null, null, null, People.NAME + " ASC");
  171.                 /* This method allows the activity to take
  172.          * care of managing the given Cursor's lifecycle
  173.          * for you based on the activity's lifecycle. */
  174.                 startManagingCursor(c);
  175.  
  176.                 int notesColumn = c.getColumnIndex(People.NOTES);
  177.                 int nameColumn = c.getColumnIndex(People.NAME);
  178.                
  179.                 // Moves the cursor to the first row
  180.                 // and returns true if there is sth. to get
  181.                 if (c.first()) {
  182.                         do {           
  183.                                 String notesString = c.getString(notesColumn);
  184.                                
  185.                                 Location friendLocation = null;
  186.                                 if (notesString != null) {
  187.                                         // Pattern for extracting geo-ContentURIs from the notes.
  188.                                         final String geoPattern = "(geo:[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\,[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\#)";
  189.                                         // Compile and use regular expression
  190.                                         Pattern pattern = Pattern.compile(geoPattern);
  191.  
  192.                                         CharSequence inputStr = notesString;
  193.                                         Matcher matcher = pattern.matcher(inputStr);
  194.  
  195.                                         boolean matchFound = matcher.find();
  196.                                         if (matchFound) {
  197.                                                 // We take the first match available
  198.                                                 String groupStr = matcher.group(0);
  199.                                                 // And parse the Lat/Long-GeoPos-Values from it
  200.                                                 friendLocation = new Location();
  201.                                                 String latid = groupStr.substring(groupStr.indexOf(":") + 1,
  202.                                                                 groupStr.indexOf(","));
  203.                                                 String longit = groupStr.substring(groupStr.indexOf(",") + 1,
  204.                                                                 groupStr.indexOf("#"));
  205.                                                 friendLocation.setLongitude(Float.parseFloat(longit));
  206.                                                 friendLocation.setLatitude(Float.parseFloat(latid));
  207.                                         }
  208.                                 }
  209.                                 String friendName = c.getString(nameColumn);
  210.                                 allFriends.add(new Friend(friendLocation, friendName));
  211.                         } while (c.next());
  212.                 }
  213.         }
  214.        
  215.         private void updateList() {
  216.                 // Refresh our location...
  217.                 this.myLocation = myLocationManager.getCurrentLocation("gps");
  218.                
  219.                 ArrayList<String> listItems = new ArrayList<String>();
  220.                
  221.                 // For each Friend
  222.                 for(Friend aNearFriend : this.allFriends){
  223.                         /* Load the row-entry-format defined as a String
  224.                          * and replace $name with the contact's name we
  225.                          * get from the cursor */
  226.                         String curLine = new String(getString(R.string.main_list_format));
  227.                         curLine = curLine.replace("$name", aNearFriend.itsName);
  228.                        
  229.                         if(aNearFriend.itsLocation != null){
  230.                                 if( this.myLocation.distanceTo(aNearFriend.itsLocation) <
  231.                                                                         NEARFRIEND_MAX_DISTANCE){
  232.                                         final DecimalFormat df = new DecimalFormat("####0.000");
  233.                                         String formattedDistance =
  234.                                                 df.format(this.myLocation.distanceTo(
  235.                                                                                 aNearFriend.itsLocation) / 1000);
  236.                                         curLine = curLine.replace("$distance", formattedDistance);
  237.                                 }
  238.                         }else{
  239.                                 curLine = curLine.replace("$distance",
  240.                                                 getString(R.string.main_list_geo_not_set));
  241.                         }
  242.                        
  243.                         listItems.add(curLine);
  244.                 }
  245.  
  246.                 ArrayAdapter<String> notes =  new ArrayAdapter<String>(this,
  247.                                 android.R.layout.simple_list_item_1, listItems);
  248.  
  249.                 this.setListAdapter(notes);
  250.         }
  251. }
Parsed in 0.060 seconds, using GeSHi 1.0.8.4


src/your_package_structure/FriendFinderMap.java
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package org.anddev.android.friendfinder;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.regex.Matcher;
  6. import java.util.regex.Pattern;
  7.  
  8. import android.content.Context;
  9. import android.content.Intent;
  10. import android.content.IntentFilter;
  11. import android.content.IntentReceiver;
  12. import android.database.Cursor;
  13. import android.graphics.Canvas;
  14. import android.graphics.Paint;
  15. import android.graphics.RectF;
  16. import android.graphics.Paint.Style;
  17. import android.location.Location;
  18. import android.location.LocationManager;
  19. import android.location.LocationProvider;
  20. import android.os.Bundle;
  21. import android.os.Handler;
  22. import android.provider.Contacts.People;
  23. import android.view.KeyEvent;
  24. import android.view.Menu;
  25.  
  26. import com.google.android.maps.MapActivity;
  27. import com.google.android.maps.MapController;
  28. import com.google.android.maps.MapView;
  29. import com.google.android.maps.Overlay;
  30. import com.google.android.maps.OverlayController;
  31. import com.google.android.maps.Point;
  32.  
  33.  
  34. public class FriendFinderMap extends MapActivity {
  35.  
  36.         // ===========================================================
  37.         // Fields
  38.         // ===========================================================
  39.        
  40.         private static final String MY_LOCATION_CHANGED_ACTION =
  41.                                 new String("android.intent.action.LOCATION_CHANGED");
  42.        
  43.         /** Minimum distance in meters for a friend
  44.          * to be recognize as a Friend to be drawn */
  45.         protected static final int NEARFRIEND_MAX_DISTANCE = 10000000;  // 10.000km
  46.        
  47.         final Handler mHandler = new Handler();
  48.        
  49.         /*
  50.          * Stuff we need to save as fields,
  51.          * because we want to use multiple
  52.          * of them in different methods.  
  53.          */
  54.         protected boolean doUpdates = true;
  55.         protected MapView myMapView = null;
  56.         protected MapController myMapController = null;
  57.         protected OverlayController myOverlayController = null;
  58.  
  59.         protected LocationManager myLocationManager = null;
  60.         protected Location myLocation = null;
  61.         protected MyIntentReceiver myIntentReceiver = null;
  62.         protected final IntentFilter myIntentFilter =
  63.                                 new IntentFilter(MY_LOCATION_CHANGED_ACTION);
  64.        
  65.         /** List of friends in */
  66.         protected ArrayList<Friend> nearFriends = new ArrayList<Friend>();
  67.        
  68.         // ===========================================================
  69.         // Extra-Classes
  70.         // ===========================================================
  71.        
  72.         /**
  73.          * This tiny IntentReceiver updates
  74.          * our stuff as we receive the intents
  75.          * (LOCATION_CHANGED_ACTION) we told the
  76.          * myLocationManager to send to us.
  77.          */
  78.         class MyIntentReceiver extends IntentReceiver {
  79.                 @Override
  80.                 public void onReceiveIntent(Context context, Intent intent) {
  81.                         if(FriendFinderMap.this.doUpdates)
  82.                                 FriendFinderMap.this.updateView();
  83.                 }
  84.         }
  85.        
  86.         /**
  87.          * This method is so huge,
  88.          * because it does a lot of FANCY painting.
  89.          * We could shorten this method to a few lines.
  90.          * But as users like eye-candy apps <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" /> ...
  91.          */
  92.     protected class MyLocationOverlay extends Overlay {
  93.         @Override
  94.         public void draw(Canvas canvas, PixelCalculator calculator, boolean shadow) {
  95.                 super.draw(canvas, calculator, shadow);
  96.                 // Setup our "brush"/"pencil"/ whatever...
  97.                 Paint paint = new Paint();
  98.                 paint.setTextSize(14);
  99.                
  100.                 // Create a Point that represents our GPS-Location
  101.                 Double lat = FriendFinderMap.this.myLocation.getLatitude() * 1E6;
  102.                 Double lng = FriendFinderMap.this.myLocation.getLongitude() * 1E6;
  103.                 Point point = new Point(lat.intValue(), lng.intValue());
  104.                
  105.                 int[] myScreenCoords = new int[2];
  106.                 // Converts lat/lng-Point to OUR coordinates on the screen.
  107.                 calculator.getPointXY(point, myScreenCoords);
  108.                
  109.                 // Draw a circle for our location
  110.                 RectF oval = new RectF(myScreenCoords[0] - 7, myScreenCoords[1] + 7,
  111.                                                         myScreenCoords[0] + 7, myScreenCoords[1] - 7);
  112.                
  113.                 // Setup a color for our location
  114.                 paint.setStyle(Style.FILL);
  115.                 paint.setARGB(255, 80, 150, 30); // Nice strong Android-Green    
  116.                 // Draw our name
  117.                 canvas.drawText(getString(R.string.map_overlay_own_name),
  118.                                                         myScreenCoords[0] +9, myScreenCoords[1], paint);
  119.                
  120.                 // Change the paint to a 'Lookthrough' Android-Green
  121.                 paint.setARGB(80, 156, 192, 36);
  122.                 paint.setStrokeWidth(1);
  123.                 // draw an oval around our location
  124.                 canvas.drawOval(oval, paint);
  125.                
  126.                  // With a black stroke around the oval we drew before.
  127.                 paint.setARGB(255,0,0,0);
  128.                 paint.setStyle(Style.STROKE);
  129.                 canvas.drawCircle(myScreenCoords[0], myScreenCoords[1], 7, paint);
  130.                
  131.                 int[] friendScreenCoords = new int[2];
  132.                 //Draw each friend with a line pointing to our own location.
  133.                 for(Friend aFriend : FriendFinderMap.this.nearFriends){
  134.                         lat = aFriend.itsLocation.getLatitude() * 1E6;
  135.                         lng = aFriend.itsLocation.getLongitude() * 1E6;
  136.                         point = new Point(lat.intValue(), lng.intValue());
  137.  
  138.                         // Converts lat/lng-Point to coordinates on the screen.
  139.                         calculator.getPointXY(point, friendScreenCoords);
  140.                         if(Math.abs(friendScreenCoords[0]) < 2000 && Math.abs(friendScreenCoords[1]) < 2000){
  141.                                 // Draw a circle for this friend and his name
  142.                                 oval = new RectF(friendScreenCoords[0] - 7, friendScreenCoords[1] + 7,
  143.                                                                 friendScreenCoords[0] + 7, friendScreenCoords[1] - 7);
  144.                                
  145.                         // Setup a color for all friends
  146.                                 paint.setStyle(Style.FILL);
  147.                                 paint.setARGB(255, 255, 0, 0); // Nice red                     
  148.                                 canvas.drawText(aFriend.itsName, friendScreenCoords[0] +9,
  149.                                                                         friendScreenCoords[1], paint);
  150.                                
  151.                                 // Draw a line connecting us to the current Friend
  152.                                 paint.setARGB(80, 255, 0, 0); // Nice red, more look through...
  153.  
  154.                         paint.setStrokeWidth(2);
  155.                                 canvas.drawLine(myScreenCoords[0], myScreenCoords[1],
  156.                                                                 friendScreenCoords[0], friendScreenCoords[1], paint);
  157.                         paint.setStrokeWidth(1);
  158.                         // draw an oval around our friends location
  159.                                 canvas.drawOval(oval, paint);
  160.                                
  161.                                  // With a black stroke around the oval we drew before.
  162.                                 paint.setARGB(255,0,0,0);
  163.                                 paint.setStyle(Style.STROKE);
  164.                                 canvas.drawCircle(friendScreenCoords[0], friendScreenCoords[1], 7, paint);
  165.                         }
  166.                 }
  167.         }
  168.     }
  169.  
  170.         // ===========================================================
  171.         // """Constructor""" (or the Entry-Point of this class)
  172.         // ===========================================================
  173.         @Override
  174.         protected void onCreate(Bundle icicle) {
  175.                 super.onCreate(icicle);
  176.                
  177.                 /* Create a new MapView and show it */
  178.                 this.myMapView = new MapView(this);
  179.                 this.setContentView(myMapView);
  180.                 /* MapController is capable of zooming
  181.                  * and animating and stuff like that */
  182.                 this.myMapController = this.myMapView.getController();
  183.                
  184.                 /* With these objects we are capable of
  185.                  * drawing graphical stuff on top of the map */
  186.                 this.myOverlayController = this.myMapView.createOverlayController();
  187.                 MyLocationOverlay myLocationOverlay = new MyLocationOverlay();
  188.                 this.myOverlayController.add(myLocationOverlay, true);
  189.                
  190.                 this.myMapController.zoomTo(2); // Far out
  191.                
  192.                 // Initialize the LocationManager
  193.                 this.myLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
  194.                 this.updateView();
  195.                
  196.                 /* Prepare the things, that will give
  197.                  * us the ability, to receive Information
  198.                  * about our GPS-Position. */
  199.                 this.setupForGPSAutoRefreshing();
  200.                
  201.                 /* Update the list of our friends once on the start,
  202.                  * as they are not(yet) moving, no updates to them are necessary */
  203.                 this.refreshFriendsList(NEARFRIEND_MAX_DISTANCE);
  204.         }
  205.        
  206.         /**
  207.          * Restart the receiving, when we are back on line.
  208.          */
  209.         @Override
  210.         public void onResume() {
  211.                 super.onResume();
  212.                 this.doUpdates = true;
  213.                
  214.                 /* As we only want to react on the LOCATION_CHANGED
  215.                  * intents we made the OS send out, we have to
  216.                  * register it along with a filter, that will only
  217.                  * "pass through" on LOCATION_CHANGED-Intents.
  218.                  */
  219.                 registerReceiver(this.myIntentReceiver, this.myIntentFilter);
  220.         }
  221.        
  222.         /**
  223.          * Make sure to stop the animation when we're no longer on screen,
  224.          * failing to do so will cause a lot of unnecessary cpu-usage!
  225.          */
  226.         @Override
  227.         public void onFreeze(Bundle icicle) {
  228.                 this.doUpdates = false;
  229.                 unregisterReceiver(this.myIntentReceiver);
  230.                 super.onFreeze(icicle);
  231.         }
  232.        
  233.         // ===========================================================
  234.         // Overridden methods
  235.         // ===========================================================
  236.        
  237.         // Called only the first time the options menu is displayed.
  238.         // Create the menu entries.
  239.         // Menu adds items in the order shown.
  240.         @Override
  241.         public boolean onCreateOptionsMenu(Menu menu) {
  242.                 boolean supRetVal = super.onCreateOptionsMenu(menu);
  243.                 menu.add(0, 0, getString(R.string.map_menu_zoom_in));
  244.                 menu.add(0, 1, getString(R.string.map_menu_zoom_out));
  245.                 menu.add(0, 2, getString(R.string.map_menu_toggle_street_satellite));
  246.                 menu.add(0, 3, getString(R.string.map_menu_back_to_list));
  247.                 return supRetVal;
  248.         }
  249.        
  250.         @Override
  251.         public boolean onOptionsItemSelected(Menu.Item item){
  252.             switch (item.getId()) {
  253.                     case 0:
  254.                         // Zoom not closer than possible
  255.                         this.myMapController.zoomTo(Math.min(21, this.myMapView.getZoomLevel() + 1));
  256.                         return true;
  257.                     case 1:
  258.                         // Zoom not farer than possible
  259.                         this.myMapController.zoomTo(Math.max(1, this.myMapView.getZoomLevel() - 1));
  260.                         return true;
  261.                     case 2:
  262.                         // Switch to satellite view
  263.                     myMapView.toggleSatellite();
  264.                         return true;
  265.                     case 3:
  266.                         this.finish();
  267.                         return true;
  268.             }
  269.             return false;
  270.         }
  271.        
  272.         @Override
  273.     public boolean onKeyDown(int keyCode, KeyEvent event) {
  274.         if (keyCode == KeyEvent.KEYCODE_I) {
  275.                 // Zoom not closer than possible
  276.                 this.myMapController.zoomTo(Math.min(21, this.myMapView.getZoomLevel() + 1));
  277.             return true;
  278.         } else if (keyCode == KeyEvent.KEYCODE_O) {
  279.                 // Zoom not farer than possible
  280.                 this.myMapController.zoomTo(Math.max(1, this.myMapView.getZoomLevel() - 1));
  281.             return true;
  282.         } else if (keyCode == KeyEvent.KEYCODE_T) {
  283.                 // Switch to satellite view
  284.             myMapView.toggleSatellite();
  285.             return true;
  286.         }
  287.         return false;
  288.     }
  289.  
  290.         // ===========================================================
  291.         // Methods
  292.         // ===========================================================
  293.        
  294.         private void setupForGPSAutoRefreshing() {
  295.                 /* Register with out LocationManager to send us
  296.                  * an intent (whos Action-String we defined above)
  297.                  * when  an intent to the location manager,
  298.                  * that we want to get informed on changes to our own position.
  299.                  * This is one of the hottest features in Android.
  300.                  */
  301.                 final long MINIMUM_DISTANCECHANGE_FOR_UPDATE = 25; // in Meters
  302.                 final long MINIMUM_TIME_BETWEEN_UPDATE = 5000; // in Milliseconds
  303.                 // Get the first provider available
  304.                 List<LocationProvider> providers = this.myLocationManager.getProviders();
  305.                 LocationProvider provider = providers.get(0);
  306.                
  307.                 this.myLocationManager.requestUpdates(provider, MINIMUM_TIME_BETWEEN_UPDATE,
  308.                                 MINIMUM_DISTANCECHANGE_FOR_UPDATE, new Intent(MY_LOCATION_CHANGED_ACTION));
  309.                
  310.                 /* Create an IntentReceiver, that will react on the
  311.                  * Intents we made our LocationManager to send to us.
  312.                  */
  313.                 this.myIntentReceiver = new MyIntentReceiver();
  314.        
  315.                 /*
  316.                  * In onResume() the following method will be called automatically!
  317.                  * registerReceiver(this.myIntentReceiver, this.myIntentFilter);
  318.                  */
  319.         }
  320.        
  321.         private void updateView() {
  322.                 // Refresh our gps-location
  323.                 this.myLocation = myLocationManager.getCurrentLocation("gps");
  324.                
  325.                 /* Redraws the mapViee, which also makes our
  326.                  * OverlayController redraw our Circles and Lines */
  327.                 this.myMapView.invalidate();
  328.                
  329.                 /* As the location of our Friends is static and
  330.                  * for performance-reasons, we do not call this */
  331.                 // this.refreshFriendsList(NEARFRIEND_MAX_DISTANCE);
  332.         }
  333.        
  334.         private void refreshFriendsList(long maxDistanceInMeter){
  335.                 Cursor c = getContentResolver().query(People.CONTENT_URI, null, null, null, People.NAME + " ASC");
  336.                 startManagingCursor(c);
  337.  
  338.                 int notesColumn = c.getColumnIndex(People.NOTES);
  339.                 int nameColumn = c.getColumnIndex(People.NAME);
  340.                
  341.                 // Moves the cursor to the first row
  342.                 // and returns true if there is sth. to get
  343.                 if (c.first()) {
  344.                         do {           
  345.                                 String notesString = c.getString(notesColumn);
  346.                                
  347.                                 Location friendLocation = null;
  348.                                 if (notesString != null) {
  349.                                         // Pattern for extracting geo-ContentURIs from the notes.
  350.                                         final String geoPattern = "(geo:[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\,[\\-]?[0-9]{1,3}\\.[0-9]{1,6}\\#)";
  351.                                         // Compile and use regular expression
  352.                                         Pattern pattern = Pattern.compile(geoPattern);
  353.  
  354.                                         CharSequence inputStr = notesString;
  355.                                         Matcher matcher = pattern.matcher(inputStr);
  356.  
  357.                                         boolean matchFound = matcher.find();
  358.                                         if (matchFound) {
  359.                                                 // We take the first match available
  360.                                                 String groupStr = matcher.group(0);
  361.                                                 // And parse the Lat/Long-GeoPos-Values from it
  362.                                                 friendLocation = new Location();
  363.                                                 String latid = groupStr.substring(groupStr.indexOf(":") + 1, groupStr.indexOf(","));
  364.                                                 String longit = groupStr.substring(groupStr.indexOf(",") + 1, groupStr.indexOf("#"));
  365.                                                 friendLocation.setLongitude(Float.parseFloat(longit));
  366.                                                 friendLocation.setLatitude(Float.parseFloat(latid));
  367.                                         }
  368.                                 }
  369.                                 if(friendLocation != null
  370.                                                 && this.myLocation.distanceTo(friendLocation) < maxDistanceInMeter){
  371.                                         String friendName = c.getString(nameColumn);
  372.                                         nearFriends.add(new Friend(friendLocation, friendName));
  373.                                 }
  374.                         } while (c.next());
  375.                 }
  376.         }
  377. }
Parsed in 0.084 seconds, using GeSHi 1.0.8.4


Regards,
plusminus
Attachments
FriendFinder.zip
Friend Finder Full Source
(68.15 KiB) Downloaded 8133 times
Last edited by plusminus on Mon Sep 29, 2008 1:49 am, edited 9 times in total.
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Top

Postby Lex » Thu Nov 22, 2007 5:43 pm

Very nice job.
Though you put 2 times the AndroidManifest.xml instead of strings.xml :wink:
Lex
Developer
Developer
 
Posts: 30
Joined: Fri Nov 16, 2007 11:03 pm

Postby plusminus » Thu Nov 22, 2007 7:03 pm

Thx.

:shock: I do need to sleep more :!:

:idea: All Fixed :!: Code is running MUCH more smooth now :!:

Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Postby quauhtlimtz » Mon Nov 26, 2007 6:00 pm

When running the application it displays my location near from Africa, however, when I display the altitude and longitud of myLocation variable, it contains a location near from San Francisco. What could it be wrong? Everything else works good.

Here is the image:

Image
quauhtlimtz
Junior Developer
Junior Developer
 
Posts: 13
Joined: Mon Nov 26, 2007 5:56 pm
Location: Mexico

Postby plusminus » Mon Nov 26, 2007 6:40 pm

Hello quauhtlimtz,

there was a little typing-error (or copy-pasting...):

Replace the '100000' (hundred-thousand) with '1000000' (1 Million) or '1E6' here:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.     protected class MyLocationOverlay extends Overlay {
  2.  
  3.         @Override
  4.  
  5.         public void draw(Canvas canvas, PixelCalculator calculator, boolean shadow) {
  6.  
  7.                 super.draw(canvas, calculator, shadow);
  8.  
  9.                 // ...
  10.  
  11.                
  12.  
  13.                 // Create a Point that represents our GPS-Location
  14.  
  15.                 Double lat = FriendFinderMap.this.myLocation.getLatitude() * 100000; // Change to 1E6
  16.  
  17.                 Double lng = FriendFinderMap.this.myLocation.getLongitude() * 100000; // Change to 1E6
Parsed in 0.036 seconds, using GeSHi 1.0.8.4

Fixed it above too :!:

Should work now doesn't it :?:

Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Postby quauhtlimtz » Mon Nov 26, 2007 6:49 pm

It works all good now!! :D

Do you know if there is a way to interact with the points where your friends are? For example, when locate a friend I wish to talk then I click on its location and another screen appears.
quauhtlimtz
Junior Developer
Junior Developer
 
Posts: 13
Joined: Mon Nov 26, 2007 5:56 pm
Location: Mexico

Top

Postby plusminus » Mon Nov 26, 2007 6:52 pm

Hey quauhtlimtz,

you mean clicking the points on the Map, to start a call or open their Contact-Details :?:

Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Postby quauhtlimtz » Mon Nov 26, 2007 6:53 pm

Yeah, exactly that.
quauhtlimtz
Junior Developer
Junior Developer
 
Posts: 13
Joined: Mon Nov 26, 2007 5:56 pm
Location: Mexico

Postby plusminus » Mon Nov 26, 2007 11:48 pm

Hello quauhtlimtz,

I've been first trying then searching for examples for very long now o_O and even the simplest OnClickListener on a MapView doesn't want to work:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.                 this.myMapView.setOnClickListener(new OnClickListener(){
  2.  
  3.                         @Override
  4.  
  5.                         public void onClick(View arg0) {
  6.  
  7.                                 // Doen't get called once  <img src="http://www.anddev.org/images/smilies/sad.png" alt=":-(" title="Sad" />
  8.  
  9.                                 Log.e("onClick", "was called");
  10.  
  11.                                 int i = 0 / 0;
  12.  
  13.                         }
  14.  
  15.                 });
Parsed in 0.039 seconds, using GeSHi 1.0.8.4


I found some rumours saying that it is not (yet !) possible, so I'll keep an eye open on that issue :!:

Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Postby quauhtlimtz » Tue Nov 27, 2007 12:09 am

Heyl, plusminus:

I will inquire to see if it can be done with some other way. Thank you for your fast and useful answers. :)
quauhtlimtz
Junior Developer
Junior Developer
 
Posts: 13
Joined: Mon Nov 26, 2007 5:56 pm
Location: Mexico

error w/ "this.setListAdapter(notes)"

Postby rtheman » Wed Nov 28, 2007 9:52 pm

A newbie at programming java as most of my programming experience was C++ back in college days.

I'm getting an error on the line "this.setListAdapter(notes);" within updateList() in FriendFinder.java The error reads "The method setListAdapter(ArrayAdapter<String>_ is undefined for the type FriendFinder.

I tried searching through the source code you provided in this post, but I couldn't find "setListAdapter" listed / declare anywhere.

Can anyone help out?
rtheman
Freshman
Freshman
 
Posts: 4
Joined: Wed Nov 28, 2007 9:46 pm

Postby plusminus » Wed Nov 28, 2007 10:30 pm

Hello rtheman,

if you did not Copy+Paste the full source, did you change the Class FriendFinder extends from Activity :arrow: ListActivity :?:

should look like this:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public class FriendFinder extends ListActivity {
Parsed in 0.036 seconds, using GeSHi 1.0.8.4


Did this help :?:

Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

permission error?

Postby ScottYelich » Fri Nov 30, 2007 4:49 pm

when I run this -- I get an error popup that says:
an error has occurred...
unable to start activity...
java.lang.securityexception ...
android.permissions.READ_CONTACTS required for provider contacts.
ScottYelich
Freshman
Freshman
 
Posts: 3
Joined: Thu Nov 29, 2007 9:57 pm

Postby plusminus » Fri Nov 30, 2007 5:07 pm

Hello Scott,

ensure, that you didn't forget the permissions in the AndroidManifest.xml :!:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  4.  
  5.    package="org.anddev.android.friendfinder">
  6.  
  7.     <uses-permission id="android.permission.READ_CONTACTS"/>
  8.  
  9.     <uses-permission id="android.permission.CALL_PHONE"/>
  10.  
  11.     ....
Parsed in 0.001 seconds, using GeSHi 1.0.8.4


Regards,
plusminus
Image
Image | Android Development Community / Tutorials
User avatar
plusminus
Site Admin
Site Admin
 
Posts: 2688
Joined: Wed Nov 14, 2007 8:37 pm
Location: Schriesheim, Germany

Emulator error :)

Postby venkat » Mon Dec 03, 2007 1:17 pm

Dear +/-,
while i am running your code i am getting my Contacts displaying like below,

zzzzzzzz (not set km)
xyzzzzzw(not set km)
abcdeww(not set km)


it's not handling click event at all. it's displaying nothing. can you tell me what is may be the error ???

Thanks in advance,

regards,
venkat :?:
venkat
Senior Developer
Senior Developer
 
Posts: 152
Joined: Tue Nov 27, 2007 5:42 am
Location: India

Top
Next

Return to Map Tutorials

Who is online

Users browsing this forum: No registered users and 2 guests