Java tutorial
/* * Project: NextGIS Mobile * Purpose: Mobile GIS for Android. * Author: Dmitry Baryshnikov (aka Bishop), bishop.dev@gmail.com * Author: NikitaFeodonit, nfeodonit@yandex.com * Author: Stanislav Petriakov, becomeglory@gmail.com * ***************************************************************************** * Copyright (c) 2012-2017 NextGIS, info@nextgis.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.nextgis.mobile.fragment; import android.app.Activity; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.location.Location; import android.location.LocationManager; import android.net.Uri; import android.os.Bundle; import android.os.Vibrator; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.getbase.floatingactionbutton.FloatingActionButton; import com.nextgis.maplib.api.GpsEventListener; import com.nextgis.maplib.api.ILayer; import com.nextgis.maplib.api.ILayerView; import com.nextgis.maplib.datasource.Feature; import com.nextgis.maplib.datasource.GeoEnvelope; import com.nextgis.maplib.datasource.GeoGeometry; import com.nextgis.maplib.datasource.GeoGeometryFactory; import com.nextgis.maplib.datasource.GeoLineString; import com.nextgis.maplib.datasource.GeoLinearRing; import com.nextgis.maplib.datasource.GeoMultiLineString; import com.nextgis.maplib.datasource.GeoMultiPolygon; import com.nextgis.maplib.datasource.GeoPoint; import com.nextgis.maplib.datasource.GeoPolygon; import com.nextgis.maplib.location.GpsEventSource; import com.nextgis.maplib.map.MapDrawable; import com.nextgis.maplib.map.VectorLayer; import com.nextgis.maplib.util.Constants; import com.nextgis.maplib.util.FileUtil; import com.nextgis.maplib.util.GeoConstants; import com.nextgis.maplib.util.LocationUtil; import com.nextgis.maplibui.api.EditEventListener; import com.nextgis.maplibui.api.ILayerUI; import com.nextgis.maplibui.api.IVectorLayerUI; import com.nextgis.maplibui.api.MapViewEventListener; import com.nextgis.maplibui.dialog.ChooseLayerDialog; import com.nextgis.maplibui.fragment.BottomToolbar; import com.nextgis.maplibui.fragment.CompassFragment; import com.nextgis.maplibui.mapui.MapViewOverlays; import com.nextgis.maplibui.overlay.CurrentLocationOverlay; import com.nextgis.maplibui.overlay.CurrentTrackOverlay; import com.nextgis.maplibui.overlay.EditLayerOverlay; import com.nextgis.maplibui.overlay.RulerOverlay; import com.nextgis.maplibui.overlay.UndoRedoOverlay; import com.nextgis.maplibui.service.WalkEditService; import com.nextgis.maplibui.util.ConstantsUI; import com.nextgis.maplibui.util.ControlHelper; import com.nextgis.maplibui.util.NotificationHelper; import com.nextgis.maplibui.util.SettingsConstantsUI; import com.nextgis.mobile.MainApplication; import com.nextgis.mobile.R; import com.nextgis.mobile.activity.MainActivity; import java.io.IOException; import java.util.List; import java.util.Locale; import static com.nextgis.maplib.util.Constants.FIELD_GEOM; import static com.nextgis.maplib.util.Constants.FIELD_ID; import static com.nextgis.maplib.util.Constants.NOT_FOUND; import static com.nextgis.maplibui.util.ConstantsUI.GA_EDIT; import static com.nextgis.maplibui.util.ConstantsUI.GA_FAB; import static com.nextgis.maplibui.util.ConstantsUI.GA_LAYER; import static com.nextgis.mobile.util.SettingsConstants.KEY_PREF_SHOW_COMPASS; import static com.nextgis.mobile.util.SettingsConstants.KEY_PREF_SHOW_MEASURING; import static com.nextgis.mobile.util.SettingsConstants.KEY_PREF_SHOW_SCALE_RULER; import static com.nextgis.mobile.util.SettingsConstants.KEY_PREF_SHOW_ZOOM_CONTROLS; /** * Main map fragment */ public class MapFragment extends Fragment implements MapViewEventListener, GpsEventListener, EditEventListener, OnClickListener, RulerOverlay.OnRulerChanged { protected float mTolerancePX; protected SharedPreferences mPreferences; protected MainApplication mApp; protected MainActivity mActivity; protected MapViewOverlays mMap; protected FloatingActionButton mivZoomIn; protected FloatingActionButton mivZoomOut; protected FloatingActionButton mRuler; protected FloatingActionButton mAddNewGeometry; protected FloatingActionButton mAddPointButton; protected TextView mStatusSource, mStatusAccuracy, mStatusSpeed, mStatusAltitude, mStatusLatitude, mStatusLongitude; protected FrameLayout mStatusPanel; protected LinearLayout mScaleRulerLayout; protected TextView mScaleRulerText; protected ImageView mScaleRuler; protected RelativeLayout mMapRelativeLayout; protected GpsEventSource mGpsEventSource; protected View mMainButton; protected int mMode; protected CurrentLocationOverlay mCurrentLocationOverlay; protected CurrentTrackOverlay mCurrentTrackOverlay; protected EditLayerOverlay mEditLayerOverlay; protected UndoRedoOverlay mUndoRedoOverlay; protected RulerOverlay mRulerOverlay; protected GeoPoint mCurrentCenter; protected VectorLayer mSelectedLayer; protected int mCoordinatesFormat, mCoordinatesFraction; protected ChooseLayerDialog mChooseLayerDialog; protected AlertDialog mGPSDialog; protected Vibrator mVibrator; public static final int MODE_NORMAL = 0; public static final int MODE_SELECT_ACTION = 1; public static final int MODE_EDIT = 2; public static final int MODE_INFO = 3; public static final int MODE_EDIT_BY_WALK = 4; public static final int MODE_EDIT_BY_TOUCH = 5; protected static final String KEY_MODE = "mode"; protected static final String BUNDLE_KEY_LAYER = "layer"; protected static final String BUNDLE_KEY_FEATURE_ID = "feature"; protected static final String BUNDLE_KEY_SAVED_FEATURE = "feature_blob"; protected static final String BUNDLE_KEY_IS_MEASURING = "is_measuring"; protected boolean mIsCompassDragging; protected int mStatusPanelMode; protected onModeChange mModeListener; protected OnClickListener mFinishListener; protected final int ADD_CURRENT_LOC = 1; public static final int EDIT_LAYER = 2; protected final int ADD_GEOMETRY_BY_WALK = 3; protected final int ADD_POINT_BY_TAP = 4; private boolean mNeedSave = false; public interface onModeChange { void onModeChangeListener(); } public void setOnModeChangeListener(onModeChange listener) { mModeListener = listener; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mActivity = (MainActivity) getActivity(); mTolerancePX = mActivity.getResources().getDisplayMetrics().density * ConstantsUI.TOLERANCE_DP; mPreferences = PreferenceManager.getDefaultSharedPreferences(mActivity); mApp = (MainApplication) mActivity.getApplication(); mVibrator = (Vibrator) mActivity.getSystemService(Context.VIBRATOR_SERVICE); mGpsEventSource = mApp.getGpsEventSource(); mMap = new MapViewOverlays(mActivity, (MapDrawable) mApp.getMap()); mMap.setId(R.id.map_view); mEditLayerOverlay = new EditLayerOverlay(mActivity, mMap); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); if (mUndoRedoOverlay != null) mUndoRedoOverlay.defineUndoRedo(); if (mEditLayerOverlay != null) mEditLayerOverlay.setHasEdits(mEditLayerOverlay.hasEdits()); } public void restartGpsListener() { mGpsEventSource.removeListener(this); mGpsEventSource.addListener(this); } public EditLayerOverlay getEditLayerOverlay() { return mEditLayerOverlay; } public UndoRedoOverlay getUndoRedoOverlay() { return mUndoRedoOverlay; } public boolean isEditMode() { return mMode == MODE_EDIT || mMode == MODE_EDIT_BY_WALK || mMode == MODE_EDIT_BY_TOUCH; } public int getMode() { return mMode; } public boolean onOptionsItemSelected(int id) { boolean result; switch (id) { case android.R.id.home: cancelEdits(); return true; case 0: mMap.setLockMap(false); setMode(MODE_EDIT); return true; case R.id.menu_edit_by_touch: setMode(MODE_EDIT_BY_TOUCH); result = mEditLayerOverlay.onOptionsItemSelected(id); return result; case R.id.menu_edit_undo: case R.id.menu_edit_redo: result = mUndoRedoOverlay.onOptionsItemSelected(id); if (result) { Feature undoRedoFeature = mUndoRedoOverlay.getFeature(); Feature feature = mEditLayerOverlay.getSelectedFeature(); feature.setGeometry(undoRedoFeature.getGeometry()); mEditLayerOverlay.fillDrawItems(undoRedoFeature.getGeometry()); GeoGeometry original = mSelectedLayer.getGeometryForId(feature.getId()); boolean hasEdits = original != null && undoRedoFeature.getGeometry().equals(original); mEditLayerOverlay.setHasEdits(!hasEdits); mMap.buffer(); mMap.postInvalidate(); } return result; case R.id.menu_edit_by_walk: setMode(MODE_EDIT_BY_WALK); default: result = mEditLayerOverlay.onOptionsItemSelected(id); if (result) mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); return result; } } public boolean saveEdits() { Feature feature = mEditLayerOverlay.getSelectedFeature(); long featureId = NOT_FOUND; GeoGeometry geometry = null; if (feature != null) { geometry = feature.getGeometry(); featureId = feature.getId(); } if (!isGeometryValid(geometry)) return false; mMap.setLockMap(false); mEditLayerOverlay.setHasEdits(false); if (mMode == MODE_EDIT_BY_WALK) { mEditLayerOverlay.stopGeometryByWalk(); setMode(MODE_EDIT); mUndoRedoOverlay.clearHistory(); mUndoRedoOverlay.defineUndoRedo(); } if (mMode == MODE_EDIT_BY_TOUCH) { setMode(MODE_EDIT); mUndoRedoOverlay.clearHistory(); mUndoRedoOverlay.defineUndoRedo(); } if (mSelectedLayer != null) { if (featureId == NOT_FOUND) { //show attributes edit activity IVectorLayerUI vectorLayerUI = (IVectorLayerUI) mSelectedLayer; vectorLayerUI.showEditForm(mActivity, featureId, geometry); } else { Uri uri = Uri.parse("content://" + mApp.getAuthority() + "/" + mSelectedLayer.getPath().getName()); uri = ContentUris.withAppendedId(uri, featureId); ContentValues values = new ContentValues(); try { values.put(FIELD_GEOM, geometry.toBlob()); } catch (IOException e) { e.printStackTrace(); } mActivity.getContentResolver().update(uri, values, null, null); setMode(MODE_SELECT_ACTION); } } return true; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (mMode == MODE_INFO || resultCode != Activity.RESULT_OK) { mEditLayerOverlay.setHasEdits(true); return; } if (requestCode == IVectorLayerUI.MODIFY_REQUEST && data != null) { long id = data.getLongExtra(ConstantsUI.KEY_FEATURE_ID, NOT_FOUND); if (id != NOT_FOUND) { mEditLayerOverlay.setSelectedFeature(id); if (mSelectedLayer != null) mSelectedLayer.showFeature(id); setMode(MODE_SELECT_ACTION); } } else if (mEditLayerOverlay.getSelectedFeatureGeometry() != null) mEditLayerOverlay.setHasEdits(true); } protected boolean isGeometryValid(GeoGeometry geometry) { if (!hasMinimumPoints(geometry)) { Toast.makeText(getContext(), R.string.not_enough_points, Toast.LENGTH_SHORT).show(); return false; } if (geometry instanceof GeoPolygon) { if (((GeoPolygon) geometry).intersects()) { Toast.makeText(getContext(), R.string.self_intersection, Toast.LENGTH_SHORT).show(); return false; } if (!((GeoPolygon) geometry).isHolesInside()) { Toast.makeText(getContext(), R.string.ring_outside, Toast.LENGTH_SHORT).show(); return false; } if (((GeoPolygon) geometry).isHolesIntersect()) { Toast.makeText(getContext(), R.string.rings_intersection, Toast.LENGTH_SHORT).show(); return false; } } if (geometry instanceof GeoMultiPolygon) { if (((GeoMultiPolygon) geometry).isSelfIntersects()) { Toast.makeText(getContext(), R.string.self_intersection, Toast.LENGTH_SHORT).show(); return false; } if (!((GeoMultiPolygon) geometry).isHolesInside()) { Toast.makeText(getContext(), R.string.ring_outside, Toast.LENGTH_SHORT).show(); return false; } if (((GeoMultiPolygon) geometry).isHolesIntersect()) { Toast.makeText(getContext(), R.string.rings_intersection, Toast.LENGTH_SHORT).show(); return false; } } return true; } protected boolean hasMinimumPoints(GeoGeometry geometry) { if (null == geometry) return false; switch (geometry.getType()) { case GeoConstants.GTPoint: case GeoConstants.GTMultiPoint: return true; case GeoConstants.GTLineString: GeoLineString line = (GeoLineString) geometry; return line.getPointCount() > 1; case GeoConstants.GTMultiLineString: GeoMultiLineString multiLine = (GeoMultiLineString) geometry; for (int i = 0; i < multiLine.size(); i++) { GeoLineString subLine = multiLine.get(i); if (subLine.getPointCount() > 1) { return true; } } return false; case GeoConstants.GTPolygon: GeoPolygon polygon = (GeoPolygon) geometry; GeoLinearRing ring = polygon.getOuterRing(); return ring.getPointCount() > 2; case GeoConstants.GTMultiPolygon: GeoMultiPolygon multiPolygon = (GeoMultiPolygon) geometry; for (int i = 0; i < multiPolygon.size(); i++) { GeoPolygon subPolygon = multiPolygon.get(i); if (subPolygon.getOuterRing().getPointCount() > 2) { return true; } } return false; default: return false; } } public boolean hasEdits() { return mEditLayerOverlay != null && mEditLayerOverlay.hasEdits(); } public void cancelEdits() { // if (mEditLayerOverlay.hasEdits()) TODO prompt dialog // return; // restore mEditLayerOverlay.setHasEdits(false); if (mMode == MODE_EDIT_BY_WALK) { mEditLayerOverlay.stopGeometryByWalk(); // TODO toast? setMode(MODE_EDIT); mUndoRedoOverlay.clearHistory(); mUndoRedoOverlay.defineUndoRedo(); } long featureId = mEditLayerOverlay.getSelectedFeatureId(); mEditLayerOverlay.setSelectedFeature(featureId); setMode(MODE_SELECT_ACTION); } protected void setMode(int mode) { mMode = mode; hideMainButton(); hideAddByTapButton(); hideRulerButton(); final BottomToolbar toolbar = mActivity.getBottomToolbar(); toolbar.getBackground().setAlpha(128); toolbar.setVisibility(View.VISIBLE); mActivity.showDefaultToolbar(); if (mStatusPanelMode != 3) mStatusPanel.setVisibility(View.INVISIBLE); switch (mode) { case MODE_NORMAL: if (mSelectedLayer != null) mSelectedLayer.setLocked(false); mSelectedLayer = null; toolbar.setVisibility(View.GONE); showMainButton(); showRulerButton(); if (mStatusPanelMode != 0) mStatusPanel.setVisibility(View.VISIBLE); mEditLayerOverlay.showAllFeatures(); mEditLayerOverlay.setMode(EditLayerOverlay.MODE_NONE); mUndoRedoOverlay.clearHistory(); break; case MODE_EDIT: if (mSelectedLayer == null) { setMode(MODE_NORMAL); return; } mSelectedLayer.setLocked(true); mActivity.showEditToolbar(); mEditLayerOverlay.setMode(EditLayerOverlay.MODE_EDIT); toolbar.setOnMenuItemClickListener(new BottomToolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { return onOptionsItemSelected(menuItem.getItemId()); } }); break; case MODE_EDIT_BY_WALK: mSelectedLayer.setLocked(true); mActivity.showEditToolbar(); mEditLayerOverlay.setMode(EditLayerOverlay.MODE_EDIT_BY_WALK); mUndoRedoOverlay.clearHistory(); break; case MODE_EDIT_BY_TOUCH: mSelectedLayer.setLocked(true); mActivity.showEditToolbar(); mEditLayerOverlay.setMode(EditLayerOverlay.MODE_EDIT_BY_TOUCH); toolbar.setOnMenuItemClickListener(new BottomToolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { return onOptionsItemSelected(menuItem.getItemId()); } }); break; case MODE_SELECT_ACTION: if (mSelectedLayer == null) { setMode(MODE_NORMAL); return; } mSelectedLayer.setLocked(true); toolbar.setTitle(null); toolbar.getMenu().clear(); toolbar.inflateMenu(R.menu.select_action); toolbar.setNavigationIcon(R.drawable.ic_action_cancel_dark); mFinishListener = new View.OnClickListener() { @Override public void onClick(View view) { setMode(MODE_NORMAL); } }; toolbar.setNavigationOnClickListener(mFinishListener); toolbar.setOnMenuItemClickListener(new BottomToolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (mSelectedLayer == null) return false; switch (item.getItemId()) { case R.id.menu_feature_add: mEditLayerOverlay.setSelectedFeature(new Feature()); mEditLayerOverlay.createNewGeometry(); mUndoRedoOverlay.clearHistory(); setMode(MODE_EDIT); mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); mEditLayerOverlay.setHasEdits(true); break; case R.id.menu_feature_edit: setMode(MODE_EDIT); mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); mEditLayerOverlay.setHasEdits(false); break; case R.id.menu_feature_delete: deleteFeature(); break; case R.id.menu_feature_attributes: setMode(MODE_INFO); break; } return true; } }); mEditLayerOverlay.setMode(EditLayerOverlay.MODE_HIGHLIGHT); mUndoRedoOverlay.clearHistory(); break; case MODE_INFO: if (mSelectedLayer == null) { setMode(MODE_NORMAL); return; } mSelectedLayer.setLocked(true); boolean tabletSize = getResources().getBoolean(R.bool.isTablet); FragmentManager fragmentManager = mActivity.getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //get or create fragment final AttributesFragment attributesFragment = getAttributesFragment(fragmentManager); attributesFragment.setTablet(tabletSize); int container = R.id.mainview; if (attributesFragment.isTablet()) { container = R.id.fl_attributes; } else { Fragment hide = fragmentManager.findFragmentById(R.id.map); fragmentTransaction.hide(hide); } if (!attributesFragment.isAdded()) { fragmentTransaction.add(container, attributesFragment, "ATTRIBUTES") .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); if (!attributesFragment.isTablet()) fragmentTransaction.addToBackStack(null); } if (!attributesFragment.isVisible()) { fragmentTransaction.show(attributesFragment); } fragmentTransaction.commit(); attributesFragment.setSelectedFeature(mSelectedLayer, mEditLayerOverlay.getSelectedFeatureId()); attributesFragment.setToolbar(toolbar, mEditLayerOverlay); mFinishListener = new View.OnClickListener() { @Override public void onClick(View view) { ((MainActivity) getActivity()).finishFragment(); if (attributesFragment.isTablet()) getActivity().getSupportFragmentManager().beginTransaction().remove(attributesFragment) .commit(); if (view == null) setMode(MODE_NORMAL); } }; toolbar.setNavigationIcon(R.drawable.ic_action_cancel_dark); toolbar.setNavigationOnClickListener(mFinishListener); break; } if (mModeListener != null) mModeListener.onModeChangeListener(); setMarginsToPanel(); defineMenuItems(); } private AttributesFragment getAttributesFragment(FragmentManager fragmentManager) { AttributesFragment attributesFragment = (AttributesFragment) fragmentManager .findFragmentByTag("ATTRIBUTES"); if (null == attributesFragment) attributesFragment = new AttributesFragment(); return attributesFragment; } protected void defineMenuItems() { if (mMode == MODE_NORMAL || mMode == MODE_INFO) return; if (mSelectedLayer == null) { setMode(MODE_NORMAL); return; } boolean noFeature = mEditLayerOverlay.getSelectedFeatureGeometry() == null; long featureId = mEditLayerOverlay.getSelectedFeatureId(); String featureName = String.format(getString(R.string.feature_n), featureId); String labelField = mSelectedLayer.getPreferences().getString(SettingsConstantsUI.KEY_PREF_LAYER_LABEL, FIELD_ID); if (!labelField.equals(FIELD_ID) && !noFeature && featureId != NOT_FOUND) { Feature feature = mSelectedLayer.getFeature(featureId); if (feature != null) featureName = feature.getFieldValueAsString(labelField); } featureName = noFeature ? getString(R.string.nothing_selected) : featureId == Constants.NOT_FOUND ? getString(R.string.new_feature) : featureName; mActivity.setTitle(featureName); mActivity.setSubtitle(mSelectedLayer.getName()); boolean hasSelectedFeature = mEditLayerOverlay.getSelectedFeature() != null && !noFeature; BottomToolbar toolbar = mActivity.getBottomToolbar(); for (int i = 0; i < toolbar.getMenu().size(); i++) { MenuItem item = toolbar.getMenu().findItem(R.id.menu_feature_delete); if (item != null) ControlHelper.setEnabled(item, hasSelectedFeature); item = toolbar.getMenu().findItem(R.id.menu_feature_edit); if (item != null) ControlHelper.setEnabled(item, hasSelectedFeature); item = toolbar.getMenu().findItem(R.id.menu_feature_attributes); if (item != null) ControlHelper.setEnabled(item, hasSelectedFeature); } } public void deleteFeature() { final long selectedFeatureId = mEditLayerOverlay.getSelectedFeatureId(); mSelectedLayer.hideFeature(selectedFeatureId); mEditLayerOverlay.setSelectedFeature(null); defineMenuItems(); final VectorLayer layer = mSelectedLayer; Snackbar snackbar = Snackbar.make(getActivity().findViewById(R.id.mainview), getActivity().getString(R.string.delete_item_done), Snackbar.LENGTH_LONG) .setAction(R.string.undo, new OnClickListener() { @Override public void onClick(View v) { layer.showFeature(selectedFeatureId); mEditLayerOverlay.setSelectedFeature(selectedFeatureId); defineMenuItems(); } }).addCallback(new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { super.onDismissed(snackbar, event); if (event == DISMISS_EVENT_MANUAL) return; if (event != DISMISS_EVENT_ACTION) layer.deleteAddChanges(selectedFeatureId); } @Override public void onShown(Snackbar snackbar) { super.onShown(snackbar); } }); View view = snackbar.getView(); TextView textView = (TextView) view.findViewById(R.id.snackbar_text); textView.setTextColor(ContextCompat.getColor(mActivity, com.nextgis.maplibui.R.color.color_white)); snackbar.show(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map, container, false); mCurrentLocationOverlay = new CurrentLocationOverlay(mActivity, mMap); mCurrentLocationOverlay.setStandingMarker(R.mipmap.ic_location_standing); mCurrentLocationOverlay.setMovingMarker(R.mipmap.ic_location_moving); mCurrentLocationOverlay.setAutopanningEnabled(true); mCurrentTrackOverlay = new CurrentTrackOverlay(mActivity, mMap); mRulerOverlay = new RulerOverlay(mActivity, mMap); mUndoRedoOverlay = new UndoRedoOverlay(mActivity, mMap); mMap.addOverlay(mCurrentTrackOverlay); mMap.addOverlay(mCurrentLocationOverlay); mMap.addOverlay(mEditLayerOverlay); mMap.addOverlay(mUndoRedoOverlay); mMap.addOverlay(mRulerOverlay); //search relative view of map, if not found - add it mMapRelativeLayout = (RelativeLayout) view.findViewById(R.id.maprl); if (mMapRelativeLayout != null) { mMapRelativeLayout.addView(mMap, 0, new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); } float mapZoom; try { mapZoom = mPreferences.getFloat(SettingsConstantsUI.KEY_PREF_ZOOM_LEVEL, mMap.getMinZoom()); } catch (ClassCastException e) { mapZoom = mMap.getMinZoom(); } double mapScrollX; double mapScrollY; try { mapScrollX = Double.longBitsToDouble(mPreferences.getLong(SettingsConstantsUI.KEY_PREF_SCROLL_X, 0)); mapScrollY = Double.longBitsToDouble(mPreferences.getLong(SettingsConstantsUI.KEY_PREF_SCROLL_Y, 0)); } catch (ClassCastException e) { mapScrollX = 0; mapScrollY = 0; } mMap.setZoomAndCenter(mapZoom, new GeoPoint(mapScrollX, mapScrollY)); mMainButton = view.findViewById(R.id.multiple_actions); mAddPointButton = (FloatingActionButton) view.findViewById(R.id.add_point_by_tap); mAddPointButton.setOnClickListener(this); View addCurrentLocation = view.findViewById(R.id.add_current_location); addCurrentLocation.setOnClickListener(this); mAddNewGeometry = (FloatingActionButton) view.findViewById(R.id.add_new_geometry); mAddNewGeometry.setOnClickListener(this); mRuler = (FloatingActionButton) view.findViewById(R.id.action_ruler); mRuler.setOnClickListener(this); View addGeometryByWalk = view.findViewById(R.id.add_geometry_by_walk); addGeometryByWalk.setOnClickListener(this); mivZoomIn = (FloatingActionButton) view.findViewById(R.id.action_zoom_in); mivZoomIn.setOnClickListener(this); mivZoomOut = (FloatingActionButton) view.findViewById(R.id.action_zoom_out); mivZoomOut.setOnClickListener(this); mStatusPanel = (FrameLayout) view.findViewById(R.id.fl_status_panel); mScaleRuler = (ImageView) view.findViewById(R.id.iv_ruler); mScaleRulerText = (TextView) view.findViewById(R.id.tv_ruler); mScaleRulerText.setText(getRulerText()); mScaleRulerLayout = (LinearLayout) view.findViewById(R.id.ll_ruler); drawScaleRuler(); return view; } @Override public void onDestroyView() { if (mMap != null) { mMap.removeListener(this); if (mMapRelativeLayout != null) { mMapRelativeLayout.removeView(mMap); } } super.onDestroyView(); } protected void drawScaleRuler() { int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 10, getResources().getDisplayMetrics()); int notch = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1, getResources().getDisplayMetrics()); Bitmap ruler = Bitmap.createBitmap(px, px, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(ruler); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(ContextCompat.getColor(getActivity(), R.color.primary_dark)); paint.setStrokeWidth(4); paint.setStyle(Paint.Style.STROKE); canvas.drawLine(0, px, px, px, paint); canvas.drawLine(0, px, 0, 0, paint); canvas.drawLine(0, 0, notch, 0, paint); canvas.drawLine(px, px, px, px - notch, paint); mScaleRuler.setImageBitmap(ruler); } protected void showMapButtons(boolean show, RelativeLayout rl) { if (null == rl) { return; } View v = rl.findViewById(R.id.action_zoom_out); if (null != v) { if (show) { v.setVisibility(View.VISIBLE); } else { v.setVisibility(View.GONE); } } v = rl.findViewById(R.id.action_zoom_in); if (null != v) { if (show) { v.setVisibility(View.VISIBLE); } else { v.setVisibility(View.GONE); } } } @Override public void onLayerAdded(int id) { } @Override public void onLayerDeleted(int id) { setMode(MODE_NORMAL); } @Override public void onLayerChanged(int id) { } @Override public void onExtentChanged(float zoom, GeoPoint center) { setZoomInEnabled(mMap.canZoomIn()); setZoomOutEnabled(mMap.canZoomOut()); mScaleRulerText.setText(getRulerText()); } protected String getRulerText() { GeoPoint p1 = new GeoPoint(mScaleRuler.getLeft(), mScaleRuler.getBottom()); GeoPoint p2 = new GeoPoint(mScaleRuler.getRight(), mScaleRuler.getBottom()); p1 = mMap.getMap().screenToMap(p1); p2 = mMap.getMap().screenToMap(p2); p1.setCRS(GeoConstants.CRS_WEB_MERCATOR); p2.setCRS(GeoConstants.CRS_WEB_MERCATOR); GeoLineString s = new GeoLineString(); s.add(p1); s.add(p2); return LocationUtil.formatLength(getContext(), s.getLength(), 0); } @Override public void onLayersReordered() { } @Override public void onLayerDrawFinished(int id, float percent) { //Log.d(Constants.TAG, "onLayerDrawFinished: " + id + " percent " + percent); /*if (percent >= 1.0) mLayerDrawn++; MainActivity activity = (MainActivity) mActivity; if (null != activity){ if (percent >= 1.0) { if (id == mMap.getTopVisibleLayerId()) { activity.onRefresh(false, 0); } else { activity.onRefresh(true, (mLayerDrawn * 100) / mMap.getVisibleLayerCount()); } } }*/ if (percent >= 1.0 && id == mMap.getMap().getId()) { if (null != mActivity) { mActivity.onRefresh(false); } } } @Override public void onLayerDrawStarted() { if (null != mActivity) { mActivity.onRefresh(true); } } protected void setZoomInEnabled(boolean bEnabled) { if (mivZoomIn == null) { return; } mivZoomIn.setEnabled(bEnabled); } protected void setZoomOutEnabled(boolean bEnabled) { if (mivZoomOut == null) { return; } mivZoomOut.setEnabled(bEnabled); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(BUNDLE_KEY_IS_MEASURING, mRulerOverlay.isMeasuring()); outState.putInt(KEY_MODE, mMode); outState.putInt(BUNDLE_KEY_LAYER, null == mSelectedLayer ? Constants.NOT_FOUND : mSelectedLayer.getId()); Feature feature = mEditLayerOverlay.getSelectedFeature(); outState.putLong(BUNDLE_KEY_FEATURE_ID, null == feature ? Constants.NOT_FOUND : feature.getId()); if (null != feature && feature.getGeometry() != null) { try { outState.putByteArray(BUNDLE_KEY_SAVED_FEATURE, feature.getGeometry().toBlob()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); if (null == savedInstanceState) { mMode = MODE_NORMAL; } else { mMode = savedInstanceState.getInt(KEY_MODE); int layerId = savedInstanceState.getInt(BUNDLE_KEY_LAYER); ILayer layer = mMap.getLayerById(layerId); Feature feature = null; if (null != layer && layer instanceof VectorLayer) { mSelectedLayer = (VectorLayer) layer; if (savedInstanceState.containsKey(BUNDLE_KEY_SAVED_FEATURE)) { GeoGeometry geometry = null; try { geometry = GeoGeometryFactory .fromBlob(savedInstanceState.getByteArray(BUNDLE_KEY_SAVED_FEATURE)); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } feature = new Feature(); feature.setId(savedInstanceState.getLong(BUNDLE_KEY_FEATURE_ID)); feature.setGeometry(geometry); } } mEditLayerOverlay.setSelectedLayer(mSelectedLayer); mEditLayerOverlay.setSelectedFeature(feature); } if (WalkEditService.isServiceRunning(getContext())) { SharedPreferences preferences = getContext().getSharedPreferences(WalkEditService.TEMP_PREFERENCES, Constants.MODE_MULTI_PROCESS); int layerId = preferences.getInt(ConstantsUI.KEY_LAYER_ID, NOT_FOUND); long featureId = preferences.getLong(ConstantsUI.KEY_FEATURE_ID, NOT_FOUND); ILayer layer = mMap.getMap().getLayerById(layerId); if (layer != null && layer instanceof VectorLayer) { mSelectedLayer = (VectorLayer) layer; mEditLayerOverlay.setSelectedLayer(mSelectedLayer); if (featureId > NOT_FOUND) mEditLayerOverlay.setSelectedFeature(featureId); else mEditLayerOverlay.newGeometryByWalk(); GeoGeometry geometry = GeoGeometryFactory.fromWKT( preferences.getString(ConstantsUI.KEY_GEOMETRY, ""), GeoConstants.CRS_WEB_MERCATOR); if (geometry != null) mEditLayerOverlay.setGeometryFromWalkEdit(geometry); mMode = MODE_EDIT_BY_WALK; } } setMode(mMode); if (savedInstanceState != null && savedInstanceState.getBoolean(BUNDLE_KEY_IS_MEASURING, false)) startMeasuring(); } @Override public void onPause() { if (null != mCurrentLocationOverlay) { mCurrentLocationOverlay.stopShowingCurrentLocation(); } if (null != mGpsEventSource) { mGpsEventSource.removeListener(this); } if (null != mEditLayerOverlay) { mEditLayerOverlay.removeListener(this); } final SharedPreferences.Editor edit = mPreferences.edit(); if (null != mMap) { edit.putFloat(SettingsConstantsUI.KEY_PREF_ZOOM_LEVEL, mMap.getZoomLevel()); GeoPoint point = mMap.getMapCenter(); edit.putLong(SettingsConstantsUI.KEY_PREF_SCROLL_X, Double.doubleToRawLongBits(point.getX())); edit.putLong(SettingsConstantsUI.KEY_PREF_SCROLL_Y, Double.doubleToRawLongBits(point.getY())); mMap.removeListener(this); } edit.apply(); super.onPause(); } @Override public void onResume() { super.onResume(); boolean showControls = mPreferences.getBoolean(KEY_PREF_SHOW_ZOOM_CONTROLS, false); showMapButtons(showControls, mMapRelativeLayout); if (Constants.DEBUG_MODE) Log.d(Constants.TAG, "KEY_PREF_SHOW_ZOOM_CONTROLS: " + (showControls ? "ON" : "OFF")); showControls = mPreferences.getBoolean(KEY_PREF_SHOW_SCALE_RULER, true); if (showControls) mScaleRulerLayout.setVisibility(View.VISIBLE); else mScaleRulerLayout.setVisibility(View.GONE); showControls = mPreferences.getBoolean(KEY_PREF_SHOW_MEASURING, false); if (showControls) mRuler.setVisibility(View.VISIBLE); else mRuler.setVisibility(View.GONE); if (null != mMap) { mMap.getMap().setBackground(mApp.getMapBackground()); mMap.addListener(this); } String coordinatesFormat = mPreferences.getString(SettingsConstantsUI.KEY_PREF_COORD_FORMAT, Location.FORMAT_DEGREES + ""); if (FileUtil.isIntegerParseInt(coordinatesFormat)) mCoordinatesFormat = Integer.parseInt(coordinatesFormat); else mCoordinatesFormat = Location.FORMAT_DEGREES; mCoordinatesFraction = mPreferences.getInt(SettingsConstantsUI.KEY_PREF_COORD_FRACTION, 6); if (null != mCurrentLocationOverlay) { mCurrentLocationOverlay .updateMode(mPreferences.getString(SettingsConstantsUI.KEY_PREF_SHOW_CURRENT_LOC, "3")); mCurrentLocationOverlay.startShowingCurrentLocation(); } if (null != mGpsEventSource) { mGpsEventSource.addListener(this); if (mGPSDialog == null || !mGPSDialog.isShowing()) mGPSDialog = NotificationHelper.showLocationInfo(getActivity()); } if (null != mEditLayerOverlay) { mEditLayerOverlay.addListener(this); } try { String statusPanelModeStr = mPreferences.getString(SettingsConstantsUI.KEY_PREF_SHOW_STATUS_PANEL, "0"); if (FileUtil.isIntegerParseInt(statusPanelModeStr)) mStatusPanelMode = Integer.parseInt(statusPanelModeStr); else mStatusPanelMode = 0; } catch (ClassCastException e) { mStatusPanelMode = 0; if (Constants.DEBUG_MODE) Log.d(Constants.TAG, "Previous version of KEY_PREF_SHOW_STATUS_PANEL of bool type. Let set it to 0"); } if (null != mStatusPanel) { if (mStatusPanelMode != 0) { mStatusPanel.setVisibility(View.VISIBLE); fillStatusPanel(null); if (mMode != MODE_NORMAL && mStatusPanelMode != 3) mStatusPanel.setVisibility(View.INVISIBLE); } else { mStatusPanel.removeAllViews(); } setMarginsToPanel(); } boolean showCompass = mPreferences.getBoolean(KEY_PREF_SHOW_COMPASS, true); checkCompass(showCompass); mCurrentCenter = null; } protected void setMarginsToPanel() { final BottomToolbar toolbar = mActivity.getBottomToolbar(); toolbar.post(new Runnable() { @Override public void run() { boolean isToolbarVisible = toolbar.getVisibility() == View.VISIBLE; boolean isPanelVisible = mStatusPanel.getVisibility() == View.VISIBLE; int toolbarHeight = toolbar.getMeasuredHeight(); RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mStatusPanel.getLayoutParams(); int bottom; if (isToolbarVisible && isPanelVisible) bottom = toolbarHeight; else bottom = 0; lp.setMargins(lp.leftMargin, lp.topMargin, lp.rightMargin, bottom); mStatusPanel.setLayoutParams(lp); if (isToolbarVisible && !isPanelVisible) bottom = toolbarHeight; else bottom = 0; mStatusPanel.setMinimumHeight(bottom); mStatusPanel.requestLayout(); } }); } protected void checkCompass(boolean showCompass) { int compassContainer = R.id.fl_compass; final FrameLayout compass = (FrameLayout) mMapRelativeLayout.findViewById(compassContainer); if (!showCompass) { compass.setVisibility(View.GONE); return; } FragmentManager fragmentManager = mActivity.getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); //get or create fragment CompassFragment compassFragment = (CompassFragment) fragmentManager.findFragmentByTag("NEEDLE_COMPASS"); if (null == compassFragment) compassFragment = new CompassFragment(); compass.setClickable(false); compassFragment.setStyle(true); if (!compassFragment.isAdded()) fragmentTransaction.add(compassContainer, compassFragment, "NEEDLE_COMPASS") .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); if (!compassFragment.isVisible()) { fragmentTransaction.show(compassFragment); } fragmentTransaction.commit(); compass.setVisibility(View.VISIBLE); compass.setOnClickListener(this); compass.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { mIsCompassDragging = true; mVibrator.vibrate(5); return true; } }); // Thanks to http://javatechig.com/android/how-to-drag-a-view-in-android compass.setOnTouchListener(new View.OnTouchListener() { private int _xDelta; private int _yDelta; @Override public boolean onTouch(View v, MotionEvent event) { final int X = (int) event.getRawX(); final int Y = (int) event.getRawY(); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams(); _xDelta = X - lParams.leftMargin; _yDelta = Y - lParams.topMargin; return false; case MotionEvent.ACTION_UP: mIsCompassDragging = false; return false; case MotionEvent.ACTION_MOVE: if (!mIsCompassDragging) return false; RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v.getLayoutParams(); int width = v.getWidth(); int height = v.getHeight(); int toolbarHeight = 0; if (mActivity.getSupportActionBar() != null) toolbarHeight = mActivity.getSupportActionBar().getHeight(); if (X > width / 3 && X < v.getRootView().getWidth() - width / 3) layoutParams.leftMargin = X - _xDelta; if (Y > height / 2 + toolbarHeight && Y < v.getRootView().getHeight() - height / 2) layoutParams.topMargin = Y - _yDelta; v.setLayoutParams(layoutParams); break; } mMapRelativeLayout.invalidate(); return true; } }); } protected void addNewGeometry() { mApp.sendEvent(GA_LAYER, GA_EDIT, GA_FAB); //show select layer dialog if several layers, else start default or custom form List<ILayer> layers = mMap.getVectorLayersByType(GeoConstants.GTPointCheck | GeoConstants.GTMultiPointCheck | GeoConstants.GTLineStringCheck | GeoConstants.GTMultiLineStringCheck | GeoConstants.GTPolygonCheck | GeoConstants.GTMultiPolygonCheck); layers = removeHideLayers(layers); if (layers.isEmpty()) { Toast.makeText(mActivity, getString(R.string.warning_no_edit_layers), Toast.LENGTH_LONG).show(); } else if (layers.size() == 1) { //open form VectorLayer layer = (VectorLayer) layers.get(0); mSelectedLayer = layer; mEditLayerOverlay.setSelectedLayer(layer); setMode(MODE_SELECT_ACTION); Toast.makeText(mActivity, String.format(getString(R.string.edit_layer), layer.getName()), Toast.LENGTH_SHORT).show(); } else { if (isDialogShown()) return; //open choose edit layer dialog mChooseLayerDialog = new ChooseLayerDialog(); mChooseLayerDialog.setLayerList(layers).setCode(EDIT_LAYER).setTitle(getString(R.string.choose_layers)) .setTheme(mActivity.getThemeId()).show(mActivity.getSupportFragmentManager(), "choose_layer"); } } protected void addPointByTap() { if (mSelectedLayer != null) mSelectedLayer.setLocked(false); //show select layer dialog if several layers, else start default or custom form List<ILayer> layers = mMap .getVectorLayersByType(GeoConstants.GTPointCheck | GeoConstants.GTMultiPointCheck); layers = removeHideLayers(layers); if (layers.isEmpty()) { Toast.makeText(mActivity, getString(R.string.warning_no_edit_layers), Toast.LENGTH_LONG).show(); } else if (layers.size() == 1) { //open form VectorLayer layer = (VectorLayer) layers.get(0); mSelectedLayer = layer; mEditLayerOverlay.setSelectedLayer(layer); createPointFromOverlay(); Toast.makeText(mActivity, String.format(getString(R.string.edit_layer), layer.getName()), Toast.LENGTH_SHORT).show(); } else { if (isDialogShown()) return; //open choose edit layer dialog mChooseLayerDialog = new ChooseLayerDialog(); mChooseLayerDialog.setLayerList(layers).setCode(ADD_POINT_BY_TAP) .setTitle(getString(R.string.choose_layers)).setTheme(mActivity.getThemeId()) .show(mActivity.getSupportFragmentManager(), "choose_layer"); } } protected void createPointFromOverlay() { mEditLayerOverlay.setSelectedFeature(new Feature()); mEditLayerOverlay.getSelectedFeature().setGeometry(new GeoPoint()); setMode(MODE_EDIT); mUndoRedoOverlay.clearHistory(); mEditLayerOverlay.createPointFromOverlay(); mEditLayerOverlay.setHasEdits(true); mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); } protected void addCurrentLocation() { //show select layer dialog if several layers, else start default or custom form List<ILayer> layers = mMap .getVectorLayersByType(GeoConstants.GTMultiPointCheck | GeoConstants.GTPointCheck); layers = removeHideLayers(layers); if (layers.isEmpty()) { Toast.makeText(mActivity, getString(R.string.warning_no_edit_layers), Toast.LENGTH_LONG).show(); } else if (layers.size() == 1) { //open form ILayer vectorLayer = layers.get(0); if (vectorLayer instanceof ILayerUI) { mSelectedLayer = (VectorLayer) vectorLayer; mEditLayerOverlay.setSelectedLayer(mSelectedLayer); IVectorLayerUI vectorLayerUI = (IVectorLayerUI) vectorLayer; vectorLayerUI.showEditForm(mActivity, Constants.NOT_FOUND, null); Toast.makeText(mActivity, String.format(getString(R.string.edit_layer), vectorLayer.getName()), Toast.LENGTH_SHORT).show(); } else { Toast.makeText(mActivity, getString(R.string.warning_no_edit_layers), Toast.LENGTH_LONG).show(); } } else { if (isDialogShown()) return; //open choose dialog mChooseLayerDialog = new ChooseLayerDialog(); mChooseLayerDialog.setLayerList(layers).setCode(ADD_CURRENT_LOC) .setTitle(getString(R.string.choose_layers)).setTheme(mActivity.getThemeId()) .show(mActivity.getSupportFragmentManager(), "choose_layer"); } } protected List<ILayer> removeHideLayers(List<ILayer> layerList) { for (int i = 0; i < layerList.size(); i++) { ILayerView layerView = (ILayerView) layerList.get(i); if (null != layerView) { if (!layerView.isVisible()) { layerList.remove(i); i--; } } } return layerList; } protected void addGeometryByWalk() { //show select layer dialog if several layers, else start default or custom form List<ILayer> layers = mMap .getVectorLayersByType(GeoConstants.GTLineStringCheck | GeoConstants.GTPolygonCheck | GeoConstants.GTMultiLineStringCheck | GeoConstants.GTMultiPolygonCheck); layers = removeHideLayers(layers); if (layers.isEmpty()) { Toast.makeText(mActivity, getString(R.string.warning_no_edit_layers), Toast.LENGTH_LONG).show(); } else if (layers.size() == 1) { //open form VectorLayer layer = (VectorLayer) layers.get(0); mSelectedLayer = layer; mEditLayerOverlay.setSelectedLayer(layer); mEditLayerOverlay.newGeometryByWalk(); setMode(MODE_EDIT_BY_WALK); Toast.makeText(mActivity, String.format(getString(R.string.edit_layer), layer.getName()), Toast.LENGTH_SHORT).show(); } else { if (isDialogShown()) return; //open choose edit layer dialog mChooseLayerDialog = new ChooseLayerDialog(); mChooseLayerDialog.setLayerList(layers).setCode(ADD_GEOMETRY_BY_WALK) .setTitle(getString(R.string.choose_layers)).setTheme(mActivity.getThemeId()) .show(mActivity.getSupportFragmentManager(), "choose_layer"); } } public void onFinishChooseLayerDialog(int code, ILayer layer) { VectorLayer vectorLayer = (VectorLayer) layer; if (layer == null) return; // TODO toast? if (mSelectedLayer != null) mSelectedLayer.setLocked(false); mSelectedLayer = vectorLayer; mEditLayerOverlay.setSelectedLayer(vectorLayer); if (code == ADD_CURRENT_LOC) { if (layer instanceof ILayerUI) { IVectorLayerUI layerUI = (IVectorLayerUI) layer; layerUI.showEditForm(mActivity, Constants.NOT_FOUND, null); } } else if (code == EDIT_LAYER) { setMode(MODE_SELECT_ACTION); } else if (code == ADD_GEOMETRY_BY_WALK) { mEditLayerOverlay.newGeometryByWalk(); setMode(MODE_EDIT_BY_WALK); } else if (code == ADD_POINT_BY_TAP) { createPointFromOverlay(); } } @Override public void onLongPress(MotionEvent event) { if (!(mMode == MODE_NORMAL || mMode == MODE_SELECT_ACTION) || mRulerOverlay.isMeasuring()) { return; } double dMinX = event.getX() - mTolerancePX; double dMaxX = event.getX() + mTolerancePX; double dMinY = event.getY() - mTolerancePX; double dMaxY = event.getY() + mTolerancePX; GeoEnvelope mapEnv = mMap.screenToMap(new GeoEnvelope(dMinX, dMaxX, dMinY, dMaxY)); if (null == mapEnv) { return; } //show actions dialog List<ILayer> layers = mMap.getVectorLayersByType(GeoConstants.GTAnyCheck); List<Long> items = null; VectorLayer vectorLayer = null; boolean intersects = false; for (ILayer layer : layers) { if (!layer.isValid()) { continue; } ILayerView layerView = (ILayerView) layer; if (!layerView.isVisible()) { continue; } vectorLayer = (VectorLayer) layer; items = vectorLayer.query(mapEnv); if (!items.isEmpty()) { intersects = true; break; } } if (intersects) { if (mSelectedLayer != null) mSelectedLayer.setLocked(false); mSelectedLayer = vectorLayer; mEditLayerOverlay.setSelectedLayer(vectorLayer); for (int i = 0; i < items.size(); i++) { // FIXME hack for bad RTree cache long featureId = items.get(i); GeoGeometry geometry = mSelectedLayer.getGeometryForId(featureId); if (geometry != null) mEditLayerOverlay.setSelectedFeature(featureId); } setMode(MODE_SELECT_ACTION); } showOverlayPoint(event); //set select action mode mMap.postInvalidate(); } public void showAddByTapButton() { mAddPointButton.setVisibility(View.VISIBLE); } public void hideAddByTapButton() { mAddPointButton.setVisibility(View.GONE); } public void showRulerButton() { if (mPreferences.getBoolean(KEY_PREF_SHOW_MEASURING, false)) mRuler.setVisibility(View.VISIBLE); } public void hideRulerButton() { mRuler.setVisibility(View.GONE); } public void showMainButton() { if (mMode == MODE_EDIT_BY_WALK) return; mAddNewGeometry.getIconDrawable().setAlpha(255); mMainButton.setVisibility(View.VISIBLE); } public void hideMainButton() { mMainButton.setVisibility(View.GONE); } public void hideOverlayPoint() { mEditLayerOverlay.hideOverlayPoint(); mMap.postInvalidate(); hideAddByTapButton(); showMainButton(); } public void showOverlayPoint(MotionEvent event) { hideMainButton(); showAddByTapButton(); mEditLayerOverlay.setOverlayPoint(event); } @Override public void onSingleTapUp(MotionEvent event) { switch (mMode) { case MODE_EDIT: if (mEditLayerOverlay.selectGeometryInScreenCoordinates(event.getX(), event.getY())) mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); defineMenuItems(); break; case MODE_SELECT_ACTION: mEditLayerOverlay.selectGeometryInScreenCoordinates(event.getX(), event.getY()); defineMenuItems(); break; case MODE_INFO: mEditLayerOverlay.selectGeometryInScreenCoordinates(event.getX(), event.getY()); if (null != mEditLayerOverlay) { AttributesFragment attributesFragment = (AttributesFragment) mActivity.getSupportFragmentManager() .findFragmentByTag("ATTRIBUTES"); if (attributesFragment != null) { attributesFragment.setSelectedFeature(mSelectedLayer, mEditLayerOverlay.getSelectedFeatureId()); mMap.postInvalidate(); } } break; default: if (!mRulerOverlay.isMeasuring()) hideOverlayPoint(); break; } } @Override public void panStart(MotionEvent e) { if (mEditLayerOverlay.getMode() == EditLayerOverlay.MODE_CHANGE) mNeedSave = true; } @Override public void panMoveTo(MotionEvent e) { } @Override public void panStop() { if (mMode == MODE_EDIT_BY_TOUCH || mNeedSave) { mNeedSave = false; mUndoRedoOverlay.saveToHistory(mEditLayerOverlay.getSelectedFeature()); } } @Override public void onLocationChanged(Location location) { if (location != null) { if (mCurrentCenter == null) { mCurrentCenter = new GeoPoint(); } mCurrentCenter.setCoordinates(location.getLongitude(), location.getLatitude()); mCurrentCenter.setCRS(GeoConstants.CRS_WGS84); if (!mCurrentCenter.project(GeoConstants.CRS_WEB_MERCATOR)) { mCurrentCenter = null; } } fillStatusPanel(location); } @Override public void onBestLocationChanged(Location location) { } private void fillStatusPanel(Location location) { if (mStatusPanelMode == 0) return; boolean needViewUpdate = true; boolean isCurrentOrientationOneLine = mStatusPanel.getChildCount() > 0 && mStatusPanel.getChildAt(0).getId() == R.id.status_container_land; View panel; if (!isCurrentOrientationOneLine) { panel = mActivity.getLayoutInflater().inflate(R.layout.status_panel_land, mStatusPanel, false); defineTextViews(panel); } else { panel = mStatusPanel.getChildAt(0); needViewUpdate = false; } fillTextViews(location); if (!isFitOneLine()) { panel = mActivity.getLayoutInflater().inflate(R.layout.status_panel, mStatusPanel, false); defineTextViews(panel); fillTextViews(location); needViewUpdate = true; } if (needViewUpdate) { mStatusPanel.removeAllViews(); panel.getBackground().setAlpha(128); mStatusPanel.addView(panel); } } private void fillTextViews(Location location) { if (null == location) { setDefaultTextViews(); } else { if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { String text = ""; int satellites = location.getExtras() != null ? location.getExtras().getInt("satellites") : 0; if (satellites > 0) text += satellites; mStatusSource.setText(text); mStatusSource.setCompoundDrawablesWithIntrinsicBounds( ContextCompat.getDrawable(getActivity(), R.drawable.ic_location), null, null, null); } else { mStatusSource.setText(""); mStatusSource.setCompoundDrawablesWithIntrinsicBounds( ContextCompat.getDrawable(getActivity(), R.drawable.ic_signal_wifi), null, null, null); } mStatusAccuracy.setText(String.format(Locale.getDefault(), "%.1f %s", location.getAccuracy(), getString(R.string.unit_meter))); mStatusAltitude.setText(String.format(Locale.getDefault(), "%.1f %s", location.getAltitude(), getString(R.string.unit_meter))); mStatusSpeed.setText(String.format(Locale.getDefault(), "%.1f %s/%s", location.getSpeed() * 3600 / 1000, getString(R.string.unit_kilometer), getString(R.string.unit_hour))); mStatusLatitude.setText(formatCoordinate(location.getLatitude(), R.string.latitude_caption_short)); mStatusLongitude.setText(formatCoordinate(location.getLongitude(), R.string.longitude_caption_short)); } } private String formatCoordinate(double value, int appendix) { return LocationUtil.formatCoordinate(value, mCoordinatesFormat, mCoordinatesFraction) + " " + getString(appendix); } private void setDefaultTextViews() { mStatusSource.setCompoundDrawables(null, null, null, null); mStatusSource.setText(""); mStatusAccuracy.setText(getString(R.string.n_a)); mStatusAltitude.setText(getString(R.string.n_a)); mStatusSpeed.setText(getString(R.string.n_a)); mStatusLatitude.setText(getString(R.string.n_a)); mStatusLongitude.setText(getString(R.string.n_a)); } private boolean isFitOneLine() { mStatusLongitude.measure(0, 0); mStatusLatitude.measure(0, 0); mStatusAltitude.measure(0, 0); mStatusSpeed.measure(0, 0); mStatusAccuracy.measure(0, 0); mStatusSource.measure(0, 0); int totalWidth = mStatusSource.getMeasuredWidth() + mStatusLongitude.getMeasuredWidth() + mStatusLatitude.getMeasuredWidth() + mStatusAccuracy.getMeasuredWidth() + mStatusSpeed.getMeasuredWidth() + mStatusAltitude.getMeasuredWidth(); DisplayMetrics metrics = new DisplayMetrics(); mActivity.getWindowManager().getDefaultDisplay().getMetrics(metrics); return totalWidth < metrics.widthPixels; // return totalWidth < mStatusPanel.getWidth(); } private void defineTextViews(View panel) { mStatusSource = (TextView) panel.findViewById(R.id.tv_source); mStatusAccuracy = (TextView) panel.findViewById(R.id.tv_accuracy); mStatusSpeed = (TextView) panel.findViewById(R.id.tv_speed); mStatusAltitude = (TextView) panel.findViewById(R.id.tv_altitude); mStatusLatitude = (TextView) panel.findViewById(R.id.tv_latitude); mStatusLongitude = (TextView) panel.findViewById(R.id.tv_longitude); } @Override public void onGpsStatusChanged(int event) { } @Override public void onStartEditSession() { } @Override public void onFinishEditSession() { setMode(MODE_NORMAL); } @Override public void onFinishEditByWalkSession() { } public void hideBottomBar() { mActivity.getBottomToolbar().setVisibility(View.GONE); } public void restoreBottomBar(int mode) { setMode(mode != -1 ? mode : mMode); } public void addLocalTMSLayer(Uri uri) { if (null != mMap) { mMap.addLocalTMSLayer(uri); } } public void addLocalVectorLayer(Uri uri) { if (null != mMap) { mMap.addLocalVectorLayer(uri); } } public void addLocalVectorLayerWithForm(Uri uri) { if (null != mMap) { mMap.addLocalVectorLayerWithForm(uri); } } public void locateCurrentPosition() { if (mCurrentCenter != null) { mMap.panTo(mCurrentCenter); } else { Toast.makeText(mActivity, R.string.error_no_location, Toast.LENGTH_SHORT).show(); } } public void addNGWLayer() { if (null != mMap) { mMap.addNGWLayer(); } } public void addRemoteLayer() { if (null != mMap) { mMap.addRemoteLayer(); } } public void refresh() { if (null != mMap) { mMap.drawMapDrawable(); } } public boolean isDialogShown() { return mChooseLayerDialog != null && mChooseLayerDialog.isResumed(); } protected void showFullCompass() { FragmentManager fragmentManager = mActivity.getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FullCompassFragment compassFragment = new FullCompassFragment(); compassFragment.setClickable(true); int container = R.id.mainview; fragmentTransaction.add(container, compassFragment, "COMPASS_FULL") .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).addToBackStack(null).commit(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.fl_compass: showFullCompass(); break; case R.id.add_current_location: if (v.isEnabled()) addCurrentLocation(); break; case R.id.add_new_geometry: if (v.isEnabled()) addNewGeometry(); break; case R.id.add_geometry_by_walk: if (v.isEnabled()) addGeometryByWalk(); break; case R.id.action_zoom_in: if (v.isEnabled()) mMap.zoomIn(); break; case R.id.action_zoom_out: if (v.isEnabled()) mMap.zoomOut(); break; case R.id.add_point_by_tap: if (mRulerOverlay.isMeasuring()) { mRulerOverlay.stopMeasuring(); showMainButton(); showRulerButton(); hideAddByTapButton(); mAddPointButton.setIcon(R.drawable.ic_action_add_point); mActivity.setTitle(R.string.app_name); mActivity.setSubtitle(null); } else addPointByTap(); break; case R.id.action_ruler: startMeasuring(); Toast.makeText(getContext(), R.string.tap_to_measure, Toast.LENGTH_SHORT).show(); break; } } protected void startMeasuring() { mRulerOverlay.startMeasuring(this); hideOverlayPoint(); hideMainButton(); hideRulerButton(); showAddByTapButton(); mAddPointButton.setIcon(R.drawable.ic_action_apply_dark); } @Override public void onLengthChanged(double length) { mActivity.setTitle(LocationUtil.formatLength(getContext(), length, 3)); } @Override public void onAreaChanged(double area) { mActivity.setSubtitle(LocationUtil.formatArea(getContext(), area)); } }