123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- package com.example.meinwald.ui.map;
-
- import android.Manifest;
- import android.content.pm.PackageManager;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Color;
- import android.location.Location;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.preference.PreferenceManager;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ListView;
- import android.widget.Toast;
-
- import com.example.meinwald.BuildConfig;
- import com.example.meinwald.R;
- import com.example.meinwald.ui.area.AreaReference;
- import com.example.meinwald.ui.area.OwnArea;
- import com.example.meinwald.ui.task.OwnTask;
- import com.google.android.gms.common.util.Hex;
- import com.google.android.gms.dynamic.IObjectWrapper;
- import com.google.android.gms.location.FusedLocationProviderClient;
- import com.google.android.gms.location.LocationServices;
- import com.google.android.gms.maps.CameraUpdateFactory;
- import com.google.android.gms.maps.GoogleMap;
- import com.google.android.gms.maps.OnMapReadyCallback;
- import com.google.android.gms.maps.SupportMapFragment;
- import com.google.android.gms.maps.model.BitmapDescriptor;
- import com.google.android.gms.maps.model.CameraPosition;
- import com.google.android.gms.maps.model.LatLng;
- 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.google.android.gms.maps.model.Polyline;
- import com.google.android.gms.maps.model.PolylineOptions;
- import com.google.android.gms.tasks.OnCompleteListener;
- import com.google.android.gms.tasks.Task;
- import com.google.maps.android.SphericalUtil;
-
- import org.json.JSONArray;
- import org.json.JSONException;
-
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileReader;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
-
- import androidx.annotation.NonNull;
- import androidx.core.app.ActivityCompat;
- import androidx.core.content.ContextCompat;
- import androidx.fragment.app.Fragment;
- import androidx.fragment.app.FragmentTransaction;
-
- import static com.example.meinwald.R.layout.fragment_map;
-
- public class MapsFragment extends Fragment implements OnMapReadyCallback {
-
- /**
- * ______________________________________________________________________________________________
- * MAPS
- */
- // A default location and default zoom to use when location permission is not granted.
- private static final LatLng M_DEFAULT_LOCATION = new LatLng(49.5, 11.0); //Nuremberg
- private static final int DEFAULT_ZOOM = 1;
- private static final float MAX_ZOOM = (float) 20.0;
-
-
- private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
- private static final String TAG = MapsFragment.class.getSimpleName();
- // Keys for storing activity state.
- private static final String KEY_CAMERA_POSITION = "camera_position";
- private static final String KEY_LOCATION = "location";
-
- private GoogleMap mMap;
- private CameraPosition mCameraPosition;
-
- /**
- * The entry point to the Fused Location Provider.
- */
- private FusedLocationProviderClient mFusedLocationProviderClient;
- private boolean mLocationPermissionGranted;
- /**
- * The geographical location where the device is currently located.
- * That is the last-known location retrieved by the Fused Location Provider.
- */
- private Location mLastKnownLocation;
-
- /**
- * ______________________________________________________________________________________________
- * TASKS
- */
- private List<OwnTask> allTasks;
- private static final String KEY_ALL_TASKS = "allTasks";
-
- /**
- * ______________________________________________________________________________________________
- * STORAGEE
- */
- private static final int READ_EXTERNAL_STORAGE_CODE = 200;
- private static final int WRITE_EXTERNAL_STORAGE_CODE = 201;
- private boolean mReadStorageGranted;
- private boolean mWriteStorageGranted;
-
- /**
- * ______________________________________________________________________________________________
- * AREA
- */
- private List<OwnArea> allAreas;
- private static final String KEY_AREA_REFERENCES = "areaReferences";
- private List<AreaReference> areaReferences;
-
- @Override
- public void onCreate (Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- areaReferences = new ArrayList<>();
- areaReferences = readAreaReferencesFromPreferences();
- }
-
- /**
- * Is called when the MapsFragment view is created. Initializes all service connections, the location client and map itself.
- * @param inflater Calling LayoutInflater
- * @param container ViewGroup
- * @param savedInstanceState Applications savedInstanceState
- * @return
- */
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- //get view to inflate
- View root = inflater.inflate(fragment_map, container, false);
-
- //get storage permission
- getReadStoragePermission();
-
- //get tasks
- allTasks = readTasksFromPreferences();
-
- //get areas
- //instantiate area lists
- allAreas = new ArrayList<>();
-
- //get saved areas
- allAreas = loadAreasFromPreferences();
-
- //display map fragment
- SupportMapFragment mapFragment = new SupportMapFragment();
- FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
- transaction.add(R.id.map, mapFragment).commit();
-
- //construct a FusedLocationProviderClient.
- mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
-
- //wait for map is ready
- mapFragment.getMapAsync(new OnMapReadyCallback()
- {
- @Override
- public void onMapReady(GoogleMap googleMap) {
- //save map instance locally
- mMap = googleMap;
- //set max zoom level
- mMap.setMaxZoomPreference(MAX_ZOOM);
- mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
- mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
- @Override
- public boolean onMarkerClick(Marker marker) {
-
- if (mMap.getCameraPosition().zoom < 17.5)
- {
- mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(marker.getPosition().latitude, marker.getPosition().longitude),(float)17.5));
- }
- else
- {
- mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(marker.getPosition().latitude, marker.getPosition().longitude),mMap.getCameraPosition().zoom));
- }
-
- return false;
- }
- });
-
- //retrieve saved instance state
- mCameraPosition = parseCameraPosition(PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_CAMERA_POSITION, new CameraPosition(new LatLng(45.0,11.0), (float) 1.0, (float) 0.0,(float) 0.0).toString()));
- mLastKnownLocation = new Location(PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_LOCATION, new LatLng(45.0,11.0).toString()));
- mCameraPosition = parseCameraPosition(PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_CAMERA_POSITION, new CameraPosition(new LatLng(45.0,11.0), (float) 1.0, (float) 0.0,(float) 0.0).toString()));
-
- //move camera to last position
- mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
-
- //get permission
- getLocationPermission();
-
- //turn on the My Location layer and the related control on the map.
- updateLocationUI();
-
- // Get the current location of the device and set the position of the map.
- getDeviceLocation();
- }
- });
-
- return root;
- }
-
- @Override
- public void onPause() {
-
- //save current location and camera position to shared preferences
- if (mMap.getCameraPosition() != null && mLastKnownLocation != null) {
- PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_CAMERA_POSITION, mMap.getCameraPosition().toString()).commit();
- PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_LOCATION, mLastKnownLocation.toString()).commit();
- }
-
- super.onPause();
- }
-
- private void drawAreas()
- {
- for (OwnArea area: allAreas)
- {
- if (area.getLocations() != null && area.getLocations().size()>0)
- {
- PolygonOptions options = new PolygonOptions().clickable(true);
-
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "Color: " + getAreaColor(area.getLastChecked()));
- Log.d(TAG, "Color: " + String.valueOf(getAreaColor(area.getLastChecked() & 0x00FFFFFF) | 0x60000000));
- Log.d(TAG, "Area: " + SphericalUtil.computeArea(area.getLocations()));
- }
- options.strokeColor(getAreaColor(area.getLastChecked()));
- options.fillColor((options.getStrokeColor() & 0x00FFFFFF) | 0x60000000);
-
- for (LatLng location: area.getLocations())
- {
- options.add(location);
-
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "Position: " + location.toString());
- }
- }
-
- options.add(area.getLocations().get(0));
-
- mMap.addPolygon(options);
- }
- }
- }
-
- /**
- * Reads areaReferences saved in preferences as jsonStrings
- *
- * @return list of AreaReferences
- */
- private List<AreaReference> readAreaReferencesFromPreferences() {
-
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "readAreaReferencesFromPreferences()");
- }
-
- List<AreaReference> areas = new ArrayList<>();
-
- try {
- String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_AREA_REFERENCES, "error");
- if(!"error".equalsIgnoreCase(jsonString)) {
- JSONArray jsonObjects = new JSONArray(jsonString);
- for (int i = 0; i<jsonObjects.length();i++) {
- areas.add(new AreaReference(jsonObjects.getJSONObject(i)));
- }
- }
- else
- {
- if (BuildConfig.DEBUG)
- {
- Log.e(TAG, "read area reference error");
- }
- }
- } catch (JSONException e) {
- if (BuildConfig.DEBUG) {
- Log.e(TAG, "Error while parsing area references as jsonObjects from preferences");
- e.printStackTrace();
- }
- }
-
- for (AreaReference reference: areas)
- {
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "read reference: " + reference.toString());
- }
- }
-
- return areas;
- }
-
- /**
- * Get OwnAreas from a JSONString.
- * @return
- */
- private List<OwnArea> loadAreasFromPreferences()
- {
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "loadAreasFromPreferences() reference size: " + areaReferences.size());
- }
-
- List<OwnArea> areas = new ArrayList<>();
- Integer i = 0;
-
- for (AreaReference reference: areaReferences)
- {
- String jsonString = readAreaFromExternalStorage(reference.getPath());
-
- areas.add(new OwnArea(jsonString));
-
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "load area from preferences: " + areas.get(i).toString());
- }
-
- i++;
- }
-
- return areas;
- }
-
- /**
- * Read OwnArea from file in external storage and return as a string.
- *
- * @param path File path where the OwnArea is saved.
- * @return
- */
- private String readAreaFromExternalStorage(String path)
- {
- if (BuildConfig.DEBUG)
- {
- Log.d(TAG, "readAreaFromExternalStorage()");
- }
-
- //Get the text file
- File file = new File(path);
-
- //Read text from file
- StringBuilder text = new StringBuilder();
-
- try {
- BufferedReader br = new BufferedReader(new FileReader(file));
- String line;
-
- while ((line = br.readLine()) != null) {
- text.append(line);
- }
- br.close();
- }
- catch (IOException e) {
- if (BuildConfig.DEBUG)
- {
- Log.e(TAG, "Failed read from external storage: " + e.toString());
- }
- }
-
- return text.toString();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- /**
- * Parses a string and creates a new CameraPosition from it.
- * Use CameraPosition.toString() to get corresponding string.
- * @param posString String which includes a camera position.
- * @return The parsed position of type CameraPosition.
- */
- private CameraPosition parseCameraPosition(String posString) {
- //parse string from shared preferences (CameraPosition.toString())
- String[] stringsplit = posString.split(" ");
- float lat = Float.parseFloat(stringsplit[1].split(",")[0].substring(1));
- float lng = Float.parseFloat(stringsplit[1].split(",")[1].substring(0,stringsplit[1].split(",")[1].length()-1));
- float zoom = Float.parseFloat(stringsplit[2].split("=")[1].substring(0,stringsplit[2].split("=")[1].length()-1));
- float tilt = Float.parseFloat(stringsplit[3].split("=")[1].substring(0,stringsplit[3].split("=")[1].length()-1));
- float bearing = Float.parseFloat(stringsplit[4].split("=")[1].substring(0,stringsplit[4].split("=")[1].length()-1));
-
- return new CameraPosition(new LatLng(lat,lng),zoom,tilt,bearing);
- }
-
- /**
- * Request location permission, so that we can get the location of the device.
- * The result of the permission request is handled by a callback,
- * onRequestPermissionsResult.
- *
- */
- private void getLocationPermission() {
- if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
- android.Manifest.permission.ACCESS_FINE_LOCATION)
- == PackageManager.PERMISSION_GRANTED) {
- mLocationPermissionGranted = true;
- } else {
- ActivityCompat.requestPermissions(getActivity(),
- new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
- PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
- }
- }
-
- /**
- * DOCU ME!
- * TOOD: What are grant results etc for?
- * @param requestCode
- * @param permissions
- * @param grantResults
- */
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
- {
- mLocationPermissionGranted = false;
- switch (requestCode) {
- case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
- // If request is cancelled, the result arrays are empty.
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED)
- {
- updateLocationUI();
- mLocationPermissionGranted = true;
- }
- }
- case READ_EXTERNAL_STORAGE_CODE: {
-
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- mReadStorageGranted = true;
- }
- }
- }
- }
-
- /**
- * Get the best and most recent location of the device, which may be null in rare
- * cases when a location is not available.
- *
- */
- private void getDeviceLocation() {
- try {
- if (mLocationPermissionGranted) {
- Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
- locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
- @Override
- public void onComplete(@NonNull Task<Location> task) {
- if (task.isSuccessful()) {
- // Set the last known position to the current location of the device.
- mLastKnownLocation = task.getResult();
- if (BuildConfig.DEBUG) {
-
- if (task.getResult() != null)
- {
- Log.d(TAG, "getDeviceLocation " + task.getResult().toString());
-
- }
- }
- } else {
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Current location is null. Using defaults.");
- Log.e(TAG, "Exception: %s", task.getException());
- }
- mMap.moveCamera(CameraUpdateFactory
- .newLatLngZoom(M_DEFAULT_LOCATION, DEFAULT_ZOOM));
- //mMap.getUiSettings().setMyLocationButtonEnabled(false);
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "getDeviceLocation: task not successful");
- }
- }
- }
- });
- }
- } catch (SecurityException e) {
- if (BuildConfig.DEBUG) {
- Log.e(TAG, "Exception occurred: ");
- e.printStackTrace();
- }
- }
- }
-
- private void updateLocationUI() {
- if (mMap == null) {
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Permission: Map not ready!");
- }
- return;
- }
- try {
- if (mLocationPermissionGranted) {
- mMap.setMyLocationEnabled(true);
- mMap.getUiSettings().setMapToolbarEnabled(true);
- mMap.getUiSettings().setMyLocationButtonEnabled(true);
- mMap.getUiSettings().setCompassEnabled(true);
- mMap.getUiSettings().setZoomControlsEnabled(true);
-
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Permission: Granted!");
- }
- } else {
- mMap.setMyLocationEnabled(false);
- mMap.getUiSettings().setMyLocationButtonEnabled(false);
- mMap.getUiSettings().setZoomControlsEnabled(false);
- mMap.getUiSettings().setCompassEnabled(false);
- mMap.getUiSettings().setMapToolbarEnabled(false);
- mLastKnownLocation = null;
-
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Permission: Denied!");
- }
-
- getLocationPermission();
- }
- } catch (SecurityException e) {
- if (BuildConfig.DEBUG) {
- Log.e(TAG, "Exception occurred: ");
- e.printStackTrace();
- }
- }
-
- for (OwnTask task: allTasks)
- {
- MarkerOptions marker = new MarkerOptions();
-
- //set options
- marker.position(new LatLng(task.getLocation().getLatitude(), task.getLocation().getLongitude()));
- marker.title(task.getTitle());
-
- mMap.addMarker(marker);
- }
-
- drawAreas();
- }
-
- /**
- * Decides color of area based on the time passed since last ckeck update.
- *
- * @param time difference in milliseconds between last check and now
- * @return color number
- */
- private int getAreaColor(long time) {
- //set transparency related to time difference
- if(time > -1)
- {
- long timeDiff = new Date().getTime() - time;
-
- //less than a week
- if (timeDiff < 7*24*60*60*1000L)
- {
- return Color.parseColor("#57a639");
- }
- //less than two weeks
- else if (timeDiff < 14*24*60*60*1000L)
- {
- return Color.parseColor("#819b45");
- }
- //less than three weeks
- else if (timeDiff < 21*24*60*60*1000L)
- {
- return Color.parseColor("#d3d30c");
- }
- //less than four weeks
- else if (timeDiff < 28*24*60*60*1000L)
- {
- return Color.parseColor("#df9600");
- }
- //less than 6 weeks
- else if (timeDiff < 42*24*60*60*1000L)
- {
- return Color.parseColor("#df3d00");
- }
- //longer than four weeks
- else
- {
- return Color.parseColor("#f70000");
- }
- }
- else
- {
- return Color.parseColor("#f70000");
- }
- }
-
- /**
- * Request read external storage permission, so that we can get saved images from external storage.
- * The result of the permission request is handled by a callback,
- * onRequestPermissionsResult.
- *
- */
- private void getReadStoragePermission() {
- if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
- Manifest.permission.READ_EXTERNAL_STORAGE)
- == PackageManager.PERMISSION_GRANTED) {
- mReadStorageGranted = true;
- } else {
- ActivityCompat.requestPermissions(getActivity(),
- new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
- READ_EXTERNAL_STORAGE_CODE);
- }
- }
-
- /**
- * Reads tasks saved in preferences as jsonStrings
- *
- * @return list of OwnTask
- */
- private List<OwnTask> readTasksFromPreferences() {
- List<OwnTask> tasks = new ArrayList<>();
-
- try {
- String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_ALL_TASKS, "error");
- if(!"error".equalsIgnoreCase(jsonString)) {
- JSONArray jsonObjects = new JSONArray(jsonString);
-
- for (int i = 0; i<jsonObjects.length();i++) {
- tasks.add(new OwnTask(jsonObjects.getJSONObject(i)));
-
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Task loaded from shared preferences: " + tasks.get(i).toString());
- }
-
- Bitmap image = BitmapFactory.decodeFile(tasks.get(i).getPathImage() + File.separator + tasks.get(i).getId() + ".jpeg");
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "Image loaded from shared preferences: " + image.getByteCount());
- }
- tasks.get(i).setImage(image);
- }
- }
- } catch (JSONException e) {
- if (BuildConfig.DEBUG) {
- Log.e(TAG, "Error while parsing tasks as jsonObjects from preferences");
- e.printStackTrace();
- }
- }
-
- return tasks;
- }
-
- @Override
- public void onMapReady(GoogleMap googleMap) { }
- }
|