/**
* Copyright 2010 Mark Wyszomierski
*/
package com.joelapenna.foursquared;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.OverlayItem;
import com.joelapenna.foursquare.types.Group;
import com.joelapenna.foursquare.types.Venue;
import com.joelapenna.foursquared.maps.CrashFixMyLocationOverlay;
import com.joelapenna.foursquared.maps.VenueItemizedOverlayWithIcons;
import com.joelapenna.foursquared.maps.VenueItemizedOverlayWithIcons.VenueItemizedOverlayTapListener;
import com.joelapenna.foursquared.util.GeoUtils;
import com.joelapenna.foursquared.util.UiUtil;
import com.joelapenna.foursquared.widget.MapCalloutView;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
import java.util.ArrayList;
/**
* Takes an array of venues and shows them on a map.
*
* @date June 30, 2010
* @author Mark Wyszomierski (markww@gmail.com)
*/
public class NearbyVenuesMapActivity extends MapActivity {
public static final String TAG = "NearbyVenuesMapActivity";
public static final boolean DEBUG = FoursquaredSettings.DEBUG;
public static final String INTENT_EXTRA_VENUES = Foursquared.PACKAGE_NAME
+ ".NearbyVenuesMapActivity.INTENT_EXTRA_VENUES";
private StateHolder mStateHolder;
private String mTappedVenueId;
private MapCalloutView mCallout;
private MapView mMapView;
private MapController mMapController;
private ArrayList<VenueItemizedOverlayWithIcons> mVenueGroupOverlays =
new ArrayList<VenueItemizedOverlayWithIcons>();
private MyLocationOverlay mMyLocationOverlay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_map_activity);
Object retained = getLastNonConfigurationInstance();
if (retained != null && retained instanceof StateHolder) {
mStateHolder = (StateHolder) retained;
} else {
if (getIntent().hasExtra(INTENT_EXTRA_VENUES)) {
Parcelable[] parcelables = getIntent().getParcelableArrayExtra(
INTENT_EXTRA_VENUES);
Group<Venue> venues = new Group<Venue>();
for (int i = 0; i < parcelables.length; i++) {
venues.add((Venue)parcelables[i]);
}
mStateHolder = new StateHolder(venues);
} else {
Log.e(TAG, TAG + " requires venue array in intent extras.");
finish();
return;
}
}
ensureUi();
}
private void ensureUi() {
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.setBuiltInZoomControls(true);
mMapController = mMapView.getController();
mMyLocationOverlay = new CrashFixMyLocationOverlay(this, mMapView);
mMapView.getOverlays().add(mMyLocationOverlay);
mCallout = (MapCalloutView) findViewById(R.id.map_callout);
mCallout.setVisibility(View.GONE);
mCallout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(NearbyVenuesMapActivity.this, VenueActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(VenueActivity.INTENT_EXTRA_VENUE_ID, mTappedVenueId);
startActivity(intent);
}
});
// One CheckinItemizedOverlay per group!
VenueItemizedOverlayWithIcons mappableVenuesOverlay = createMappableVenuesOverlay(
mStateHolder.getVenues());
if (mappableVenuesOverlay != null) {
mVenueGroupOverlays.add(mappableVenuesOverlay);
}
if (mVenueGroupOverlays.size() > 0) {
mMapView.getOverlays().addAll(mVenueGroupOverlays);
recenterMap();
} else {
Toast.makeText(this, getResources().getString(
R.string.friendsmapactivity_no_checkins), Toast.LENGTH_LONG).show();
finish();
}
}
@Override
public void onResume() {
super.onResume();
mMyLocationOverlay.enableMyLocation();
if (UiUtil.sdkVersion() > 3) {
mMyLocationOverlay.enableCompass();
}
}
@Override
public void onPause() {
super.onPause();
mMyLocationOverlay.disableMyLocation();
if (UiUtil.sdkVersion() > 3) {
mMyLocationOverlay.disableCompass();
}
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
/**
* We can do something more fun here like create an overlay per category, so the user
* can hide parks and show only bars, for example.
*/
private VenueItemizedOverlayWithIcons createMappableVenuesOverlay(Group<Venue> venues) {
Group<Venue> mappableVenues = new Group<Venue>();
for (Venue it : venues) {
mappableVenues.add(it);
}
if (mappableVenues.size() > 0) {
VenueItemizedOverlayWithIcons overlay = new VenueItemizedOverlayWithIcons(
this,
((Foursquared) getApplication()).getRemoteResourceManager(),
getResources().getDrawable(R.drawable.pin_checkin_multiple),
mVenueOverlayTapListener);
overlay.setGroup(mappableVenues);
return overlay;
} else {
return null;
}
}
private void recenterMap() {
// Previously we'd try to zoom to span, but this gives us odd results a lot of times,
// so falling back to zoom at a fixed level.
GeoPoint center = mMyLocationOverlay.getMyLocation();
if (center != null) {
mMapController.animateTo(center);
mMapController.setZoom(14);
} else {
// Location overlay wasn't ready yet, try using last known geolocation from manager.
Location bestLocation = GeoUtils.getBestLastGeolocation(this);
if (bestLocation != null) {
mMapController.animateTo(GeoUtils.locationToGeoPoint(bestLocation));
mMapController.setZoom(14);
} else {
// We have no location information at all, so we'll just show the map at a high
// zoom level and the user can zoom in as they wish.
Venue venue = mStateHolder.getVenues().get(0);
mMapController.animateTo(new GeoPoint(
(int)(Float.valueOf(venue.getGeolat()) * 1E6),
(int)(Float.valueOf(venue.getGeolong()) * 1E6)));
mMapController.setZoom(8);
}
}
}
/**
* Handle taps on one of the pins.
*/
private VenueItemizedOverlayTapListener mVenueOverlayTapListener =
new VenueItemizedOverlayTapListener() {
@Override
public void onTap(OverlayItem itemSelected, OverlayItem itemLastSelected, Venue venue) {
mTappedVenueId = venue.getId();
mCallout.setTitle(venue.getName());
mCallout.setMessage(venue.getAddress());
mCallout.setVisibility(View.VISIBLE);
mMapController.animateTo(GeoUtils.stringLocationToGeoPoint(
venue.getGeolat(), venue.getGeolong()));
}
@Override
public void onTap(GeoPoint p, MapView mapView) {
mCallout.setVisibility(View.GONE);
}
};
private class StateHolder {
private Group<Venue> mVenues;
public StateHolder(Group<Venue> venues) {
mVenues = venues;
}
public Group<Venue> getVenues() {
return mVenues;
}
}
}