package mil.nga.giat.asam.map; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import mil.nga.giat.asam.Asam; import mil.nga.giat.asam.R; import mil.nga.giat.asam.connectivity.OfflineBannerFragment; import mil.nga.giat.asam.model.SubregionBean; import mil.nga.giat.asam.model.SubregionTextParser; import mil.nga.giat.asam.util.AsamConstants; import mil.nga.giat.asam.util.AsamLog; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.TextView; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMap.OnMapClickListener; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Polygon; import com.google.android.gms.maps.model.PolygonOptions; import com.vividsolutions.jts.geom.Geometry; public class SubregionMapActivity extends ActionBarActivity implements OnMapClickListener, Asam.OnOfflineFeaturesListener, OfflineBannerFragment.OnOfflineBannerClick { private static final int INITIAL_ZOOM_LEVEL = 2; private static final float OUTLINE_WIDTH = 1.0f; private static final int OUTLINE_COLOR = 0xffff8200; // ARGB 255, 255, 130, 0. private static final int SELECTED_FILL_COLOR = 0x50ff9600; // ARGB 128, 255, 150, 0. private static final int UNSELECTED_FILL_COLOR = 0x5000ff00; // ARGB 128, 0, 255, 0. private GoogleMap mMapUI; private int mMapType; private List<SubregionBean> mSubregions; private MenuItem mResetMenuItemUI; private MenuItem mQueryMenuItemUI; private MenuItem mSelectedSubregionsMenuItemUI; private boolean mLaunchedExpectingResultCode; private SharedPreferences mSharedPreferences; private OfflineMap offlineMap; private Collection<Geometry> offlineGeometries = null; private MenuItem offlineMap110mMenuItem; private OfflineBannerFragment offlineAlertFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); AsamLog.i(SubregionMapActivity.class.getName() + ":onCreate"); setContentView(R.layout.subregion_map); getSupportActionBar().setDisplayHomeAsUpEnabled(true); Bundle extras = getIntent().getExtras(); mLaunchedExpectingResultCode = false; if (extras != null) { mLaunchedExpectingResultCode = extras.getBoolean(AsamConstants.SUBREGION_MAP_EXPECTING_RESULT_CODE_KEY, false); } mMapUI = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.subregion_map_map_view_ui)).getMap(); mMapUI.setOnMapClickListener(this); offlineAlertFragment = new OfflineBannerFragment(); getSupportFragmentManager().beginTransaction() .add(android.R.id.content, offlineAlertFragment) .commit(); // Initialize subregions and place on map. mSubregions = new SubregionTextParser().parseSubregions(this); for (SubregionBean subregion : mSubregions) { PolygonOptions polygonOptions = new PolygonOptions().zIndex(100); polygonOptions.addAll(subregion.getMapCoordinates()).strokeColor(OUTLINE_COLOR).strokeWidth(OUTLINE_WIDTH).fillColor(UNSELECTED_FILL_COLOR); Polygon polygon = mMapUI.addPolygon(polygonOptions); subregion.setMapPolygon(polygon); } } @Override protected void onResume() { super.onResume(); AsamLog.i(SubregionMapActivity.class.getName() + ":onResume"); LatLng position = new LatLng(0.0, 0.0); CameraPosition cameraPosition = new CameraPosition.Builder().target(position).zoom(INITIAL_ZOOM_LEVEL).build(); mMapUI.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); ((Asam) getApplication()).registerOfflineMapListener(this); supportInvalidateOptionsMenu(); int mapType = mSharedPreferences.getInt(AsamConstants.MAP_TYPE_KEY, GoogleMap.MAP_TYPE_NORMAL); if (mapType != mMapType) onMapTypeChanged(mapType); } @Override public void onPause() { super.onPause(); ((Asam) getApplication()).unregisterOfflineMapListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.subregion_map_menu, menu); mResetMenuItemUI = menu.findItem(R.id.subregion_map_menu_reset_ui); mQueryMenuItemUI = menu.findItem(R.id.subregion_map_menu_query_ui); mSelectedSubregionsMenuItemUI = menu.findItem(R.id.subregion_map_menu_selected_subregions_ui); return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { int mapType = mSharedPreferences.getInt(AsamConstants.MAP_TYPE_KEY, 1); switch (mapType) { case GoogleMap.MAP_TYPE_SATELLITE: menu.findItem(R.id.map_type_satellite).setChecked(true); break; case GoogleMap.MAP_TYPE_HYBRID: menu.findItem(R.id.map_type_hybrid).setChecked(true); break; case AsamConstants.MAP_TYPE_OFFLINE_110M: menu.findItem(R.id.map_type_offline_110m).setChecked(true); break; default: menu.findItem(R.id.map_type_normal).setChecked(true); } offlineMap110mMenuItem = menu.findItem(R.id.map_type_offline_110m); if (offlineGeometries != null) offlineMap110mMenuItem.setVisible(true); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: if (mLaunchedExpectingResultCode) { Intent intent = getIntent(); setResult(Activity.RESULT_CANCELED, intent); } finish(); return true; case R.id.map_type_normal: item.setChecked(!item.isChecked()); onMapTypeChanged(GoogleMap.MAP_TYPE_NORMAL); return true; case R.id.map_type_satellite: item.setChecked(!item.isChecked()); onMapTypeChanged(GoogleMap.MAP_TYPE_SATELLITE); return true; case R.id.map_type_hybrid: item.setChecked(!item.isChecked()); onMapTypeChanged(GoogleMap.MAP_TYPE_HYBRID); return true; case R.id.map_type_offline_110m: item.setChecked(!item.isChecked()); onMapTypeChanged(AsamConstants.MAP_TYPE_OFFLINE_110M); return true; case R.id.subregion_map_menu_reset_ui: resetMenuClicked(); return true; case R.id.subregion_map_menu_selected_subregions_ui: showSelectedSubregionsPopup(); return true; case R.id.subregion_map_menu_60_days_ui: showQueryOnMap(AsamConstants.TIME_SPAN_60_DAYS); return true; case R.id.subregion_map_menu_90_days_ui: showQueryOnMap(AsamConstants.TIME_SPAN_90_DAYS); return true; case R.id.subregion_map_menu_180_days_ui: showQueryOnMap(AsamConstants.TIME_SPAN_180_DAYS); return true; case R.id.subregion_map_menu_1_year_ui: showQueryOnMap(AsamConstants.TIME_SPAN_1_YEAR); return true; case R.id.subregion_map_menu_5_years_ui: showQueryOnMap(AsamConstants.TIME_SPAN_5_YEARS); return true; case R.id.subregion_map_menu_all_ui: showQueryOnMap(AsamConstants.TIME_SPAN_ALL); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onMapClick(LatLng point) { AsamLog.v(SubregionMapActivity.class.getName() + ":onMapClick"); for (SubregionBean subregion : mSubregions) { if (isSubregionTapped(subregion, point)) { subregion.setSelected(!subregion.isSelected()); if (subregion.isSelected()) { subregion.getMapPolygon().setFillColor(SELECTED_FILL_COLOR); } else { subregion.getMapPolygon().setFillColor(UNSELECTED_FILL_COLOR); } int tappedSubregionId = subregion.getSubregionId(); // Some subregions are made up of more than one geometry. if (SubregionBean.MULTI_SUBREGION_IDS.contains(tappedSubregionId)) { boolean selectedStatus = subregion.isSelected(); for (SubregionBean multiSubregion : mSubregions) { if (multiSubregion.getSubregionId() == tappedSubregionId) { multiSubregion.setSelected(selectedStatus); if (multiSubregion.isSelected()) { multiSubregion.getMapPolygon().setFillColor(SELECTED_FILL_COLOR); } else { multiSubregion.getMapPolygon().setFillColor(UNSELECTED_FILL_COLOR); } } } } } } setMenuState(); } private void resetMenuClicked() { clearMap(); } private void clearMap() { for (SubregionBean subregion : mSubregions) { subregion.setSelected(false); subregion.getMapPolygon().setFillColor(UNSELECTED_FILL_COLOR); } setMenuState(); } private void setMenuState() { if (getSelectedSubregionIds().size() > 0) { mResetMenuItemUI.setEnabled(true); mQueryMenuItemUI.setEnabled(true); mSelectedSubregionsMenuItemUI.setEnabled(true); } else { mResetMenuItemUI.setEnabled(false); mQueryMenuItemUI.setEnabled(false); mSelectedSubregionsMenuItemUI.setEnabled(false); } } private void showSelectedSubregionsPopup() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.selected_subregions_popup_title_text)); View popupView = getLayoutInflater().inflate(R.layout.selected_subregions_popup, null); builder.setView(popupView); List<Integer> selectedSubregionIds = getSelectedSubregionIds(); TextView subregionsTextUI = (TextView)popupView.findViewById(R.id.selected_subregions_popup_subregions_text_ui); StringBuilder subregionsText = new StringBuilder(""); for (int i = 0; i < selectedSubregionIds.size(); i++) { subregionsText.append(selectedSubregionIds.get(i)); if (i < selectedSubregionIds.size() - 1) { subregionsText.append(", "); } } subregionsTextUI.setText(subregionsText.toString()); builder.setNegativeButton(getString(R.string.selected_subregions_popup_cancel_text), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); Dialog dialog = builder.create(); dialog.show(); } private ArrayList<Integer> getSelectedSubregionIds() { ArrayList<Integer> selectedSubregionIds = new ArrayList<Integer>(); for (SubregionBean subregion : mSubregions) { if (subregion.isSelected()) { selectedSubregionIds.add(subregion.getSubregionId()); } } Set<Integer> duplicatesRemoved = new HashSet<Integer>(selectedSubregionIds); selectedSubregionIds = new ArrayList<Integer>(duplicatesRemoved); Collections.sort(selectedSubregionIds); return selectedSubregionIds; } private void showQueryOnMap(int timeSpan) { Intent intent = null; if (mLaunchedExpectingResultCode) { intent = getIntent(); } else { intent = new Intent(this, AllAsamsMapActivity.class); } intent.putExtra(AsamConstants.QUERY_TYPE_KEY, AsamConstants.SUBREGION_QUERY); intent.putExtra(AsamConstants.SUBREGION_QUERY_TIME_SPAN_KEY, timeSpan); intent.putIntegerArrayListExtra(AsamConstants.SUBREGION_QUERY_SUBREGIONS_LIST_KEY, getSelectedSubregionIds()); if (mLaunchedExpectingResultCode) { setResult(Activity.RESULT_OK, intent); finish(); } else { startActivity(intent); clearMap(); // Reset everything to the initial state. } } private boolean isSubregionTapped(SubregionBean subregion, LatLng point) { List<SubregionBean.GeoPoint> geoPoints = subregion.getGeoPoints(); boolean contains = false; for (int i = 0, j = geoPoints.size() - 1; i < geoPoints.size() - 0; j = i++) { if (((geoPoints.get(i).latitude > point.latitude) != (geoPoints.get(j).latitude > point.latitude)) && (point.longitude < (geoPoints.get(j).longitude - geoPoints.get(i).longitude) * (point.latitude - geoPoints.get(i).latitude) / (geoPoints.get(j).latitude - geoPoints.get(i).latitude) + geoPoints.get(i).longitude)) { contains = !contains; } } return contains; } public void onMapTypeChanged(int mapType) { mMapType = mapType; // Show/hide the offline alert fragment based on map type if (mMapType == AsamConstants.MAP_TYPE_OFFLINE_110M) { getSupportFragmentManager() .beginTransaction() .hide(offlineAlertFragment) .commit(); } else { getSupportFragmentManager() .beginTransaction() .show(offlineAlertFragment) .commit(); } // Change the map if (mMapType == AsamConstants.MAP_TYPE_OFFLINE_110M) { if (offlineMap != null) offlineMap.clear(); offlineMap = new OfflineMap(this, mMapUI, offlineGeometries); } else { if (offlineMap != null) { offlineMap.clear(); offlineMap = null; } mMapUI.setMapType(mMapType); } // Update shared preferences SharedPreferences.Editor editor = mSharedPreferences.edit(); editor.putInt(AsamConstants.MAP_TYPE_KEY, mMapType); editor.commit(); } @Override public void onOfflineFeaturesLoaded(Collection<Geometry> offlineGeometries) { this.offlineGeometries = offlineGeometries; if (offlineMap110mMenuItem != null) offlineMap110mMenuItem.setVisible(true); if (offlineMap == null && mMapType == AsamConstants.MAP_TYPE_OFFLINE_110M) { if (offlineMap != null) offlineMap.clear(); offlineMap = new OfflineMap(this, mMapUI, offlineGeometries); } } @Override public void onOfflineBannerClick() { onMapTypeChanged(AsamConstants.MAP_TYPE_OFFLINE_110M); supportInvalidateOptionsMenu(); } }