Java tutorial
/* * Project: Forest violations * Purpose: Mobile application for registering facts of the forest violations. * Author: Dmitry Baryshnikov (aka Bishop), bishop.dev@gmail.com * ***************************************************************************** * Copyright (c) 2015-2015. NextGIS, info@nextgis.com * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to <http://unlicense.org> */ package com.nextgis.forestinspector.fragment; import android.content.SharedPreferences; import android.location.Location; import android.location.LocationManager; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.getbase.floatingactionbutton.FloatingActionButton; import com.nextgis.forestinspector.MainApplication; import com.nextgis.forestinspector.R; import com.nextgis.forestinspector.activity.MainActivity; import com.nextgis.forestinspector.util.SettingsConstants; import com.nextgis.maplib.api.GpsEventListener; import com.nextgis.maplib.datasource.GeoPoint; import com.nextgis.maplib.location.GpsEventSource; import com.nextgis.maplib.map.MapDrawable; import com.nextgis.maplib.util.Constants; import com.nextgis.maplib.util.GeoConstants; import com.nextgis.maplib.util.LocationUtil; import com.nextgis.maplibui.api.MapViewEventListener; import com.nextgis.maplibui.mapui.MapViewOverlays; import com.nextgis.maplibui.overlay.CurrentLocationOverlay; import com.nextgis.maplibui.util.SettingsConstantsUI; public class MapFragment extends Fragment implements MapViewEventListener, GpsEventListener { protected MapViewOverlays mMap; protected FloatingActionButton mivZoomIn; protected FloatingActionButton mivZoomOut; protected RelativeLayout mMapRelativeLayout; protected TextView mStatusSource, mStatusAccuracy, mStatusSpeed, mStatusAltitude, mStatusLatitude, mStatusLongitude; protected FrameLayout mStatusPanel; protected GpsEventSource mGpsEventSource; protected CurrentLocationOverlay mCurrentLocationOverlay; protected boolean mShowStatusPanel; protected GeoPoint mCurrentCenter; protected int mCoordinatesFormat; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map, container, false); MainApplication app = (MainApplication) getActivity().getApplication(); mMap = new MapViewOverlays(getActivity(), (MapDrawable) app.getMap()); mMap.setId(999); mGpsEventSource = app.getGpsEventSource(); mCurrentLocationOverlay = new CurrentLocationOverlay(getActivity(), mMap); mCurrentLocationOverlay.setStandingMarker(R.drawable.ic_location_standing); mCurrentLocationOverlay.setMovingMarker(R.drawable.ic_location_moving); mMap.addOverlay(mCurrentLocationOverlay); //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)); } mMap.invalidate(); mivZoomIn = (FloatingActionButton) view.findViewById(R.id.action_zoom_in); if (null != mivZoomIn) { mivZoomIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mivZoomIn.isEnabled()) { mMap.zoomIn(); } } }); } mivZoomOut = (FloatingActionButton) view.findViewById(R.id.action_zoom_out); if (null != mivZoomOut) { mivZoomOut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mivZoomOut.isEnabled()) { mMap.zoomOut(); } } }); } final View addCurrentLocation = view.findViewById(R.id.add_indictment); if (null != addCurrentLocation) { addCurrentLocation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } final View addNewGeometry = view.findViewById(R.id.add_sheet); if (null != addNewGeometry) { addNewGeometry.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } final View addGeometryByWalk = view.findViewById(R.id.add_bookmark); if (null != addGeometryByWalk) { addGeometryByWalk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); } mStatusPanel = (FrameLayout) view.findViewById(R.id.fl_status_panel); return view; } @Override public void onDestroyView() { if (mMap != null) { mMap.removeListener(this); if (mMapRelativeLayout != null) { mMapRelativeLayout.removeView(mMap); } } super.onDestroyView(); } 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); } } rl.invalidate(); } @Override public void onPause() { if (null != mCurrentLocationOverlay) { mCurrentLocationOverlay.stopShowingCurrentLocation(); } if (null != mGpsEventSource) { mGpsEventSource.removeListener(this); } final SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit(); if (null != mMap) { edit.putFloat(SettingsConstants.KEY_PREF_ZOOM_LEVEL, mMap.getZoomLevel()); GeoPoint point = mMap.getMapCenter(); edit.putLong(SettingsConstants.KEY_PREF_SCROLL_X, Double.doubleToRawLongBits(point.getX())); edit.putLong(SettingsConstants.KEY_PREF_SCROLL_Y, Double.doubleToRawLongBits(point.getY())); mMap.removeListener(this); } edit.commit(); super.onPause(); } @Override public void onResume() { super.onResume(); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); boolean showControls = prefs.getBoolean(SettingsConstants.KEY_PREF_SHOW_ZOOM_CONTROLS, false); showMapButtons(showControls, mMapRelativeLayout); Log.d(Constants.TAG, "KEY_PREF_SHOW_ZOOM_CONTROLS: " + (showControls ? "ON" : "OFF")); if (null != mMap) { float mMapZoom; try { mMapZoom = prefs.getFloat(SettingsConstants.KEY_PREF_ZOOM_LEVEL, mMap.getMinZoom()); } catch (ClassCastException e) { mMapZoom = mMap.getMinZoom(); } double mMapScrollX; double mMapScrollY; try { mMapScrollX = Double.longBitsToDouble(prefs.getLong(SettingsConstants.KEY_PREF_SCROLL_X, 0)); mMapScrollY = Double.longBitsToDouble(prefs.getLong(SettingsConstants.KEY_PREF_SCROLL_Y, 0)); } catch (ClassCastException e) { mMapScrollX = 0; mMapScrollY = 0; } mMap.setZoomAndCenter(mMapZoom, new GeoPoint(mMapScrollX, mMapScrollY)); mMap.addListener(this); } mCoordinatesFormat = prefs.getInt(SettingsConstants.KEY_PREF_COORD_FORMAT + "_int", Location.FORMAT_DEGREES); if (null != mCurrentLocationOverlay) { mCurrentLocationOverlay.updateMode(PreferenceManager.getDefaultSharedPreferences(getActivity()) .getString(SettingsConstantsUI.KEY_PREF_SHOW_CURRENT_LOC, "3")); mCurrentLocationOverlay.startShowingCurrentLocation(); } if (null != mGpsEventSource) { mGpsEventSource.addListener(this); } mShowStatusPanel = prefs.getBoolean(SettingsConstantsUI.KEY_PREF_SHOW_STATUS_PANEL, true); if (null != mStatusPanel) { if (mShowStatusPanel) { mStatusPanel.setVisibility(View.VISIBLE); fillStatusPanel(null); } else { mStatusPanel.removeAllViews(); } } mCurrentCenter = null; } public void refresh() { if (null != mMap) { mMap.drawMapDrawable(); } } @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 onGpsStatusChanged(int event) { } @Override public void onLongPress(MotionEvent event) { } @Override public void onSingleTapUp(MotionEvent event) { } @Override public void panStart(MotionEvent e) { } @Override public void panMoveTo(MotionEvent e) { } @Override public void panStop() { } @Override public void onLayerAdded(int id) { } @Override public void onLayerDeleted(int id) { } @Override public void onLayerChanged(int id) { } @Override public void onExtentChanged(float zoom, GeoPoint center) { setZoomInEnabled(mMap.canZoomIn()); setZoomOutEnabled(mMap.canZoomOut()); } @Override public void onLayersReordered() { } @Override public void onLayerDrawFinished(int id, float percent) { } @Override public void onLayerDrawStarted() { } protected void setZoomInEnabled(boolean bEnabled) { if (mivZoomIn == null) { return; } mivZoomIn.setEnabled(bEnabled); } protected void setZoomOutEnabled(boolean bEnabled) { if (mivZoomOut == null) { return; } mivZoomOut.setEnabled(bEnabled); } protected void fillStatusPanel(Location location) { if (!mShowStatusPanel) //mStatusPanel.getVisibility() == FrameLayout.INVISIBLE) { return; } boolean needViewUpdate = true; boolean isCurrentOrientationOneLine = mStatusPanel.getChildCount() > 0 && ((LinearLayout) mStatusPanel.getChildAt(0)).getOrientation() == LinearLayout.HORIZONTAL; View panel; if (!isCurrentOrientationOneLine) { panel = getActivity().getLayoutInflater().inflate(R.layout.status_panel_land, mStatusPanel, false); defineTextViews(panel); } else { panel = mStatusPanel.getChildAt(0); needViewUpdate = false; } fillTextViews(location); if (!isFitOneLine()) { panel = getActivity().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); } } protected void fillTextViews(Location location) { if (null == location) { setDefaultTextViews(); } else { if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { int satellites = location.getExtras().getInt("satellites"); if (satellites < GpsEventSource.MIN_SATELLITES_IN_FIX) { mStatusSource.setText(""); mStatusSource.setCompoundDrawablesWithIntrinsicBounds( getResources().getDrawable(R.drawable.ic_location), null, null, null); } else { mStatusSource.setText(satellites + ""); mStatusSource.setCompoundDrawablesWithIntrinsicBounds( getResources().getDrawable(R.drawable.ic_location), null, null, null); } } else { mStatusSource.setText(""); mStatusSource.setCompoundDrawablesWithIntrinsicBounds( getResources().getDrawable(R.drawable.ic_signal_wifi), null, null, null); } mStatusAccuracy .setText(String.format("%.1f %s", location.getAccuracy(), getString(R.string.unit_meter))); mStatusAltitude .setText(String.format("%.1f %s", location.getAltitude(), getString(R.string.unit_meter))); mStatusSpeed.setText(String.format("%.1f %s/%s", location.getSpeed() * 3600 / 1000, getString(R.string.unit_kilometer), getString(R.string.unit_hour))); mStatusLatitude.setText(LocationUtil.formatCoordinate(location.getLatitude(), mCoordinatesFormat) + " " + getString(R.string.latitude_caption_short)); mStatusLongitude.setText(LocationUtil.formatCoordinate(location.getLongitude(), mCoordinatesFormat) + " " + getString(R.string.longitude_caption_short)); } } protected 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)); } protected 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(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); return totalWidth < metrics.widthPixels; } 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); } public void locateCurrentPosition() { if (mCurrentCenter != null) { mMap.panTo(mCurrentCenter); } else { Toast.makeText(getActivity(), R.string.error_no_location, Toast.LENGTH_SHORT).show(); } } }