package com.nbs.client.assassins.views; import java.io.IOException; import java.util.Arrays; import java.util.List; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Color; import android.location.Address; import android.location.Geocoder; import android.location.Location; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.actionbarsherlock.app.SherlockMapFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.CancelableCallback; import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener; import com.google.android.gms.maps.GoogleMap.OnMyLocationChangeListener; import com.google.android.gms.maps.UiSettings; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.maps.model.Polygon; import com.google.android.gms.maps.model.PolygonOptions; import com.googlecode.androidannotations.annotations.Background; import com.googlecode.androidannotations.annotations.EFragment; import com.googlecode.androidannotations.annotations.UiThread; import com.nbs.client.assassins.utils.LocationUtils; @EFragment public class MatchBoundsFragment extends SherlockMapFragment { private static final String TAG = "MatchBoundsFragment"; // Container Activity must implement this interface public interface OnBoundsSelectedListener { public void onBoundsSelected(String description, List<LatLng> points); } private OnBoundsSelectedListener mListener; private static final double DEFAULT_BOUNDS_HALF_WIDTH = 0.05; private static final int LATLNG_BOUNDS_PADDING = 80; private Marker corner1; private Marker corner2; private static final int RED = Color.argb(100, Color.red(Color.RED), Color.green(Color.RED), Color.blue(Color.RED)); private static final int DONE_ID = 1; private Polygon matchBounds; private ProgressDialog progress; public MatchBoundsFragment(){ } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnBoundsSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnBoundsSelectedListener"); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); setMenuVisibility(true); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { getMap().setMapType(GoogleMap.MAP_TYPE_NORMAL); UiSettings uiSettings = getMap().getUiSettings(); uiSettings.setCompassEnabled(true); uiSettings.setZoomGesturesEnabled(true); uiSettings.setZoomControlsEnabled(true); getMap().setMyLocationEnabled(true); progress = ProgressDialog.show(getSherlockActivity(), "Please Wait","Waiting for GPS...", true, false); getMap().setOnMarkerDragListener(new OnMarkerDragListener(){ @Override public void onMarkerDrag(Marker m) { drawBounds(); } @Override public void onMarkerDragEnd(Marker m) {} @Override public void onMarkerDragStart(Marker m) {} }); getMap().setOnMyLocationChangeListener(new OnMyLocationChangeListener() { @Override public void onMyLocationChange(Location myLocation) { final double lat = myLocation.getLatitude(); final double lng = myLocation.getLongitude(); //default bounds are a 5 mile box around the user's location final LatLng cornerA = new LatLng(lat-DEFAULT_BOUNDS_HALF_WIDTH,lng-DEFAULT_BOUNDS_HALF_WIDTH); final LatLng cornerB = new LatLng(lat+DEFAULT_BOUNDS_HALF_WIDTH,lng+DEFAULT_BOUNDS_HALF_WIDTH); getMap().setOnMyLocationChangeListener(null); CameraUpdate camUpdate = CameraUpdateFactory .newLatLngBounds(new LatLngBounds(cornerA, cornerB), LATLNG_BOUNDS_PADDING); dismissGpsProgress(); getMap().animateCamera(camUpdate, 1000, new CancelableCallback(){ @Override public void onCancel() { dismissGpsProgress(); } @Override public void onFinish() { corner1 = getMap().addMarker(new MarkerOptions() .draggable(true) .position(cornerA)); corner2 = getMap().addMarker(new MarkerOptions() .draggable(true) .position(cornerB)); drawBounds(); } }); }}); super.onViewCreated(view, savedInstanceState); } private void dismissGpsProgress() { if(progress != null) progress.dismiss(); } private void drawBounds() { LatLng corner3 = new LatLng(corner2.getPosition().latitude, corner1.getPosition().longitude); LatLng corner4 = new LatLng(corner1.getPosition().latitude, corner2.getPosition().longitude); if(matchBounds == null) { matchBounds = getMap().addPolygon(new PolygonOptions() .add(corner1.getPosition(), corner3, corner2.getPosition(), corner4) .strokeColor(RED)); } else { matchBounds.setPoints(Arrays.asList(corner1.getPosition(), corner3, corner2.getPosition(), corner4)); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { Log.d(TAG, "onCreateOptionsMenu()"); menu.add(Menu.NONE, DONE_ID, Menu.FIRST, "Done") .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case DONE_ID: reverseGeocodeMatchArea( LocationUtils.midPoint(corner1.getPosition(), corner2.getPosition()), ProgressDialog.show(getActivity(), "Please wait", "Computing bounds...", true, false)); return true; } return super.onOptionsItemSelected(item); } @Background public void reverseGeocodeMatchArea(LatLng center, ProgressDialog progress) { Geocoder geo = new Geocoder(this.getSherlockActivity()); List<Address> addresses = null; if(Geocoder.isPresent()) { try{ addresses = geo.getFromLocation(center.latitude, center.longitude, 1); } catch (IOException e) { Log.e(TAG, e.getMessage()); } } onGeocodeFinished(addresses, progress); } @UiThread public void onGeocodeFinished(List<Address> addresses, ProgressDialog progress) { progress.dismiss(); String description = null; if(addresses != null && addresses.size() > 0) { String admin = addresses.get(0).getAdminArea(); String locality = addresses.get(0).getLocality(); description = locality + ", " + admin; Log.d(TAG, description); } List<LatLng> s2N = LocationUtils.sortSouthToNorth(matchBounds.getPoints()); //TODO: may need to change how we determine what is the 'most west/east' //if your gameplay bounds cross the middle of the atlantic ocean, you will //experience unsatisfactory results! List<LatLng> e2W = LocationUtils.sortEastToWest(matchBounds.getPoints()); //match bounds are stored as upper left and lower right corner LatLng n = s2N.get(s2N.size()-1); LatLng w = e2W.get(e2W.size()-1); LatLng s = s2N.get(0); LatLng e = e2W.get(0); mListener.onBoundsSelected(description, Arrays.asList( new LatLng(n.latitude, w.longitude), new LatLng(s.latitude, e.longitude))); } }