andbook!.pdf - Learning Android Get an anddev.org - Android-Shirt Back to index
anddev.org Header Logo
FAQ Search Top rated articles Browse Feeds anddev.org - Authors Contact Details Register Log in

The Friend Finder - MapActivity using GPS - Part: II / II

Goto page 1, 2, 3  Next
 
       anddev.org - Android Development Community | Android Tutorials | Index -> Map Tutorials
Author Message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Thu Nov 22, 2007 9:04 pm    Post subject: The Friend Finder - MapActivity using GPS - Part: II / II Reply with quote

The Friend Finder - MapActivity using GPS - Part: II / II




Arrow Having completed Part I of this tutorial, this is where we are now:


Arrow But, where we want to get to finally is:


0. Create a new Class called "FriendFinderMap.java" (extending MapActivity)in the same source-folder/package where "FriendFinderMap.java" is located.

In order to make this second Activity startable through an Intent (what is the way you open other Activities in Android), we have to register that new Activity in the AndroidManifest.xml .

XML:
       // ....
        </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>


1. So we add the following lines to 'FriendFinder.java' to get obtain our own menu.
Java:
     /** 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;
     }

There will be no further changes to 'FriendFinder.java'.

2. Lets take a look at 'FriendFinderMap.java's onCreate(...)-method:
It bascially does the same as the FriendFinder(List) but also some Map-Setup and some Graphic/Overlay-Preparation.
Java:
     @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);
     }


3. As the 'refreshFriendsList(...) method does the same as in the first Class ot 99,9% I wont repeat the code here. What it does is putting all friends closer than 'NEARFRIEND_MAX_DISTANCE' to the field 'this.nearFriends'.

4. The same procedure for 'setupForGPSAutoRefreshing()', it it even 100% the same as in the first Class. Also the same for the IntenReceiver, IntentFilter, onFreeze() and onResume() Exclamation

5. The function that was called updateList in the first Class is nwo called updateView() and does not much except updating our own GPS-Location and calling 'myMapView.invalidate()' what causes a full redraw of your MapView, what leads a draw()-call in our 'MyLocationOverlay'-Class and in the end to a moving circle (== us) on the screen. Smile
Java:
     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);
     }


6. What is different in this Class is the way of visualizing data (in the Map not in a List this time). In onCreate we created an Object of the type MyLocationOverlay, which is doing its work everytime the MapView is being redrawn.
Java:
MyLocationOverlay myLocationOverlay = new MyLocationOverlay();

The MyLocationOverlay-class looks the following, as the method is heavily commented I'll just paste it here:
Java:
     /**
      * 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 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);
               }
          }
        }
    }


7. The very last thing we need to do is to add some HotKeys and the Menu, both for Toggling the Sattelite-View and zooming in/out.
Java:
     // 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;
    }


Eclipse Run Button Eclipse Run Button Eclipse Run Button Thats it, we are done. Eclipse Run Button Eclipse Run Button Eclipse Run Button

View: >> Full Source for this Tutorial <<


Regards,
plusminus

_________________

| Android Development Community / Tutorials


Last edited by plusminus on Wed Nov 28, 2007 2:46 am; edited 2 times in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website
flowdi
Freshman


Joined: 25 Nov 2007
Posts: 7

PostPosted: Sun Nov 25, 2007 6:45 pm    Post subject: coordinates accuracy Reply with quote

is it 1,000,000 instead of 10,000 to multiply the coordinates (Double) with
(for the integer values required by the Point-Constructor?)

How does these 'mock locationrovider' work?
i put a .kml-file in data/misc/location/gps/ but it doesn't seem to work?

flo
Back to top
View user's profile Send private message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Sun Nov 25, 2007 8:27 pm    Post subject: Reply with quote

Hello flowdi,

Yap, should be 1.000.000 instead of 10.000. Fixed it Exclamation

I'm just making a small tutorial of what was supposed to the second part of your post Smile

Wont take longer than an hour from now Exclamation
So, stay tuned Smile

[Edit:]
Did it:
Arrow Arrow Arrow Mock LocationProvider - Structure/Explanation (NMEA, $GPRMC)

Regards,
plusminus

_________________

| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
quauhtlimtz
Junior Developer


Joined: 26 Nov 2007
Posts: 13
Location: Mexico

PostPosted: Tue Nov 27, 2007 11:57 pm    Post subject: Reply with quote

Hey, plusminus:

How can you keep the selected item on the ListActivity screen? Everytime the updateList() method is invoked, the screen "loses" its selected item.
Back to top
View user's profile Send private message MSN Messenger
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Wed Nov 28, 2007 2:43 am    Post subject: Reply with quote

quauhtlimtz wrote:
Hey, plusminus:

How can you keep the selected item on the ListActivity screen? Everytime the updateList() method is invoked, the screen "loses" its selected item.


Hello quauhtlimtz,

we need to modify only a few lines in the updateList()-method.
  1. Remember the last SelectionIndex, if there was already an ListAdapter before, that could return us a SelectionIndex.
  2. Update the List Adapter
  3. Try to set the selectionIndex back


Java:
     private void updateList() {
          // .... many lines....

          }

          ArrayAdapter<String> notes =  new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_1, listItems);

          // these 3 lines are new
          long beforeIndex = 0;
          if(this.getListAdapter() != null)
               beforeIndex = this.getSelectionRowID();
               
          this.setListAdapter(notes);

          // these 3 lines are also new
          try{
               this.setSelection((int)beforeIndex);
          }catch (Exception e){}
     }


Was a good issue, so I added it to the Tutorial-Code Exclamation

Regards,
plusminus

_________________

| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
venkat
Senior Developer


Joined: 27 Nov 2007
Posts: 152
Location: India

PostPosted: Mon Dec 03, 2007 4:21 pm    Post subject: Reply with quote

now i can see the distance. for example,

venkat(3.557 km), and number is keep on changing. if i click any one of the menu , nothing is happening.Question


Last edited by venkat on Mon Dec 03, 2007 4:35 pm; edited 2 times in total
Back to top
View user's profile Send private message
venkat
Senior Developer


Joined: 27 Nov 2007
Posts: 152
Location: India

PostPosted: Mon Dec 03, 2007 4:28 pm    Post subject: Reply with quote

dear +-,
i can see one dot and my name on blank map. i can't see any satellite or street view. Sad

can u solve my problem.

Thanks in advance,

Regards,
venkat
Back to top
View user's profile Send private message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Mon Dec 03, 2007 9:04 pm    Post subject: Reply with quote

Hello venkat,

the sattelite-View is toggle over KeyPress to T:
Java:
....
     else if (keyCode == KeyEvent.KEYCODE_T) {
          // Switch to satellite view
          myMapView.toggleSatellite();
....

or through the menu-Button on your Emulator.


You should see one "Dot" moving around in San Fransico with the name "ME" and as you have had listed "venkat" in the List on the start, it should also appear on the MapView Exclamation

Perhaps you forgot to copy-paste sth. Neutral Question

Regards,
plusminus

_________________

| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
venkat
Senior Developer


Joined: 27 Nov 2007
Posts: 152
Location: India

PostPosted: Tue Dec 04, 2007 7:58 am    Post subject: Reply with quote

Dear Plusminus,
i have tried to open sample "maps" application which is given along with emulator. it's also showing blank map only. Exclamation

i have attach my friendfinder application screen shot below. please take a look on that. Smile

can u please tell me, how to enable map on my emulator????? Question

Thanks in advance,

Regards,
venkat
Back to top
View user's profile Send private message
venkat
Senior Developer


Joined: 27 Nov 2007
Posts: 152
Location: India

PostPosted: Tue Dec 04, 2007 8:00 am    Post subject: Reply with quote

Sorry, my attachment is here...


FriendFinder.png
 Description:
my Friend Finder attachment
 Filesize:  8.63 KB
 Viewed:  18818 Time(s)

FriendFinder.png


Back to top
View user's profile Send private message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Tue Dec 04, 2007 9:48 am    Post subject: Reply with quote

Hello venkat,

Arrow answered in the other post. Wink

Regards,
plusminus

_________________

| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
cybersat
Freshman


Joined: 18 Dec 2007
Posts: 5

PostPosted: Thu Jan 03, 2008 7:19 pm    Post subject: Plz help Reply with quote

Code snippet is Superrrr and is working.

Only problem is my gps map pointer location (round dot) is not pointing to right location.

I am from State: kerala, Country: india, and i got "geo:9.590078,72.521792#" from googlemap "link to..." to be placed in Notes of contact address.

But when looked through FriendFinder map, it shows location somewhere near united states .Plz check screen shot attached.



sc.JPG
 Description:
 Filesize:  126 KB
 Viewed:  16057 Time(s)

sc.JPG


Back to top
View user's profile Send private message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Thu Jan 03, 2008 8:18 pm    Post subject: Reply with quote

Hello cybersat,

in the emulator the GPS-"Signal" is a fake one (Near the Google-Headquarters in MountainView California)!

Have a look at this Source explanations/tutorial.
If you are fed up with the built in Moch(Fake) Location-Provider, read Source here.

Regards,
plusminus

_________________

| Android Development Community / Tutorials
Back to top
View user's profile Send private message Send e-mail Visit poster's website
glider
Freshman


Joined: 03 Jan 2008
Posts: 4

PostPosted: Tue Jan 08, 2008 10:52 am    Post subject: Reply with quote

So how do I keep the 'me' in focus and in the middle ?
(even after zoom in/out /pan - i want center to be where the
gps coord is at all times)

Thanks for an awesome howto!
Back to top
View user's profile Send private message
plusminus
Site Admin


Joined: 14 Nov 2007
Posts: 2102
Location: Germany

PostPosted: Tue Jan 08, 2008 4:39 pm    Post subject: Reply with quote

Hello glider,

sth. like this should work:
Java:
         // Animate to the center
          myMapController.animateTo(new Point(myLatitude,myLongitude));


Tell us if worked Smile

Regards,
plusminus