You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MapsFragment.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. package com.example.meinwald.ui.main.map;
  2. import android.Manifest;
  3. import android.content.pm.PackageManager;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.location.Location;
  7. import android.os.Bundle;
  8. import android.os.IBinder;
  9. import android.preference.PreferenceManager;
  10. import android.util.Log;
  11. import android.view.LayoutInflater;
  12. import android.view.View;
  13. import android.view.ViewGroup;
  14. import android.widget.ListView;
  15. import com.example.meinwald.BuildConfig;
  16. import com.example.meinwald.R;
  17. import com.example.meinwald.ui.task.OwnTask;
  18. import com.google.android.gms.dynamic.IObjectWrapper;
  19. import com.google.android.gms.location.FusedLocationProviderClient;
  20. import com.google.android.gms.location.LocationServices;
  21. import com.google.android.gms.maps.CameraUpdateFactory;
  22. import com.google.android.gms.maps.GoogleMap;
  23. import com.google.android.gms.maps.OnMapReadyCallback;
  24. import com.google.android.gms.maps.SupportMapFragment;
  25. import com.google.android.gms.maps.model.BitmapDescriptor;
  26. import com.google.android.gms.maps.model.CameraPosition;
  27. import com.google.android.gms.maps.model.LatLng;
  28. import com.google.android.gms.maps.model.MarkerOptions;
  29. import com.google.android.gms.tasks.OnCompleteListener;
  30. import com.google.android.gms.tasks.Task;
  31. import org.json.JSONArray;
  32. import org.json.JSONException;
  33. import java.io.File;
  34. import java.util.ArrayList;
  35. import java.util.List;
  36. import androidx.annotation.NonNull;
  37. import androidx.core.app.ActivityCompat;
  38. import androidx.core.content.ContextCompat;
  39. import androidx.fragment.app.Fragment;
  40. import androidx.fragment.app.FragmentTransaction;
  41. import static com.example.meinwald.R.layout.fragment_map;
  42. public class MapsFragment extends Fragment implements OnMapReadyCallback {
  43. /**
  44. * ______________________________________________________________________________________________
  45. * MAPS
  46. */
  47. // A default location and default zoom to use when location permission is not granted.
  48. private static final LatLng M_DEFAULT_LOCATION = new LatLng(49.5, 11.0); //Nuremberg
  49. private static final int DEFAULT_ZOOM = 1;
  50. private static final float MAX_ZOOM = (float) 20.0;
  51. private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
  52. private static final String TAG = MapsFragment.class.getSimpleName();
  53. // Keys for storing activity state.
  54. private static final String KEY_CAMERA_POSITION = "camera_position";
  55. private static final String KEY_LOCATION = "location";
  56. private GoogleMap mMap;
  57. private CameraPosition mCameraPosition;
  58. /**
  59. * The entry point to the Fused Location Provider.
  60. */
  61. private FusedLocationProviderClient mFusedLocationProviderClient;
  62. private boolean mLocationPermissionGranted;
  63. /**
  64. * The geographical location where the device is currently located.
  65. * That is the last-known location retrieved by the Fused Location Provider.
  66. */
  67. private Location mLastKnownLocation;
  68. /**
  69. * ______________________________________________________________________________________________
  70. * TASKS
  71. */
  72. private List<OwnTask> allTasks;
  73. private static final String KEY_ALL_TASKS = "allTasks";
  74. /**
  75. * ______________________________________________________________________________________________
  76. * STORAGEE
  77. */
  78. private static final int READ_EXTERNAL_STORAGE_CODE = 200;
  79. private static final int WRITE_EXTERNAL_STORAGE_CODE = 201;
  80. private boolean mReadStorageGranted;
  81. private boolean mWriteStorageGranted;
  82. /**
  83. * Is called when the MapsFragment view is created. Initializes all service connections, the location client and map itself.
  84. * @param inflater Calling LayoutInflater
  85. * @param container ViewGroup
  86. * @param savedInstanceState Applications savedInstanceState
  87. * @return
  88. */
  89. public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  90. //get view to inflate
  91. View root = inflater.inflate(fragment_map, container, false);
  92. //get storage permission
  93. getReadStoragePermission();
  94. //get tasks
  95. allTasks = readTasksFromPreferences();
  96. //display map fragment
  97. SupportMapFragment mapFragment = new SupportMapFragment();
  98. FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
  99. transaction.add(R.id.map, mapFragment).commit();
  100. //construct a FusedLocationProviderClient.
  101. mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
  102. //wait for map is ready
  103. mapFragment.getMapAsync(new OnMapReadyCallback() {
  104. @Override
  105. public void onMapReady(GoogleMap googleMap) {
  106. //save map instance locally
  107. mMap = googleMap;
  108. //set max zoom level
  109. mMap.setMaxZoomPreference(MAX_ZOOM);
  110. //retrieve saved instance state
  111. 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()));
  112. mLastKnownLocation = new Location(PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_LOCATION, new LatLng(45.0,11.0).toString()));
  113. 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()));
  114. //move camera to last position
  115. mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
  116. //get permission
  117. getLocationPermission();
  118. //turn on the My Location layer and the related control on the map.
  119. updateLocationUI();
  120. // Get the current location of the device and set the position of the map.
  121. getDeviceLocation();
  122. }
  123. });
  124. return root;
  125. }
  126. @Override
  127. public void onPause() {
  128. //save current location and camera position to shared preferences
  129. if (mMap.getCameraPosition() != null && mLastKnownLocation != null) {
  130. PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_CAMERA_POSITION, mMap.getCameraPosition().toString()).commit();
  131. PreferenceManager.getDefaultSharedPreferences(getContext()).edit().putString(KEY_LOCATION, mLastKnownLocation.toString()).commit();
  132. }
  133. super.onPause();
  134. }
  135. @Override
  136. public void onResume() {
  137. super.onResume();
  138. }
  139. /**
  140. * Parses a string and creates a new CameraPosition from it.
  141. * Use CameraPosition.toString() to get corresponding string.
  142. * @param posString String which includes a camera position.
  143. * @return The parsed position of type CameraPosition.
  144. */
  145. private CameraPosition parseCameraPosition(String posString) {
  146. //parse string from shared preferences (CameraPosition.toString())
  147. String[] stringsplit = posString.split(" ");
  148. float lat = Float.parseFloat(stringsplit[1].split(",")[0].substring(1));
  149. float lng = Float.parseFloat(stringsplit[1].split(",")[1].substring(0,stringsplit[1].split(",")[1].length()-1));
  150. float zoom = Float.parseFloat(stringsplit[2].split("=")[1].substring(0,stringsplit[2].split("=")[1].length()-1));
  151. float tilt = Float.parseFloat(stringsplit[3].split("=")[1].substring(0,stringsplit[3].split("=")[1].length()-1));
  152. float bearing = Float.parseFloat(stringsplit[4].split("=")[1].substring(0,stringsplit[4].split("=")[1].length()-1));
  153. return new CameraPosition(new LatLng(lat,lng),zoom,tilt,bearing);
  154. }
  155. /**
  156. * Request location permission, so that we can get the location of the device.
  157. * The result of the permission request is handled by a callback,
  158. * onRequestPermissionsResult.
  159. *
  160. */
  161. private void getLocationPermission() {
  162. if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
  163. android.Manifest.permission.ACCESS_FINE_LOCATION)
  164. == PackageManager.PERMISSION_GRANTED) {
  165. mLocationPermissionGranted = true;
  166. } else {
  167. ActivityCompat.requestPermissions(getActivity(),
  168. new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
  169. PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
  170. }
  171. }
  172. /**
  173. * DOCU ME!
  174. * TOOD: What are grant results etc for?
  175. * @param requestCode
  176. * @param permissions
  177. * @param grantResults
  178. */
  179. @Override
  180. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
  181. {
  182. mLocationPermissionGranted = false;
  183. switch (requestCode) {
  184. case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
  185. // If request is cancelled, the result arrays are empty.
  186. if (grantResults.length > 0
  187. && grantResults[0] == PackageManager.PERMISSION_GRANTED)
  188. {
  189. updateLocationUI();
  190. mLocationPermissionGranted = true;
  191. }
  192. }
  193. case READ_EXTERNAL_STORAGE_CODE: {
  194. if (grantResults.length > 0
  195. && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  196. mReadStorageGranted = true;
  197. }
  198. }
  199. }
  200. }
  201. /**
  202. * Get the best and most recent location of the device, which may be null in rare
  203. * cases when a location is not available.
  204. *
  205. */
  206. private void getDeviceLocation() {
  207. try {
  208. if (mLocationPermissionGranted) {
  209. Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
  210. locationResult.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
  211. @Override
  212. public void onComplete(@NonNull Task<Location> task) {
  213. if (task.isSuccessful()) {
  214. // Set the last known position to the current location of the device.
  215. mLastKnownLocation = task.getResult();
  216. if (BuildConfig.DEBUG) {
  217. if (task.getResult() != null)
  218. {
  219. Log.d(TAG, "getDeviceLocation " + task.getResult().toString());
  220. }
  221. }
  222. } else {
  223. if (BuildConfig.DEBUG) {
  224. Log.d(TAG, "Current location is null. Using defaults.");
  225. Log.e(TAG, "Exception: %s", task.getException());
  226. }
  227. mMap.moveCamera(CameraUpdateFactory
  228. .newLatLngZoom(M_DEFAULT_LOCATION, DEFAULT_ZOOM));
  229. //mMap.getUiSettings().setMyLocationButtonEnabled(false);
  230. if (BuildConfig.DEBUG) {
  231. Log.d(TAG, "getDeviceLocation: task not successful");
  232. }
  233. }
  234. }
  235. });
  236. }
  237. } catch (SecurityException e) {
  238. if (BuildConfig.DEBUG) {
  239. Log.e(TAG, "Exception occurred: ");
  240. e.printStackTrace();
  241. }
  242. }
  243. }
  244. private void updateLocationUI() {
  245. if (mMap == null) {
  246. if (BuildConfig.DEBUG) {
  247. Log.d(TAG, "Permission: Map not ready!");
  248. }
  249. return;
  250. }
  251. try {
  252. if (mLocationPermissionGranted) {
  253. mMap.setMyLocationEnabled(true);
  254. mMap.getUiSettings().setMapToolbarEnabled(true);
  255. mMap.getUiSettings().setMyLocationButtonEnabled(true);
  256. mMap.getUiSettings().setCompassEnabled(true);
  257. mMap.getUiSettings().setZoomControlsEnabled(true);
  258. if (BuildConfig.DEBUG) {
  259. Log.d(TAG, "Permission: Granted!");
  260. }
  261. } else {
  262. mMap.setMyLocationEnabled(false);
  263. mMap.getUiSettings().setMyLocationButtonEnabled(false);
  264. mMap.getUiSettings().setZoomControlsEnabled(false);
  265. mMap.getUiSettings().setCompassEnabled(false);
  266. mMap.getUiSettings().setMapToolbarEnabled(false);
  267. mLastKnownLocation = null;
  268. if (BuildConfig.DEBUG) {
  269. Log.d(TAG, "Permission: Denied!");
  270. }
  271. getLocationPermission();
  272. }
  273. } catch (SecurityException e) {
  274. if (BuildConfig.DEBUG) {
  275. Log.e(TAG, "Exception occurred: ");
  276. e.printStackTrace();
  277. }
  278. }
  279. for (OwnTask task: allTasks)
  280. {
  281. MarkerOptions marker = new MarkerOptions();
  282. //set options
  283. marker.position(new LatLng(task.getLocation().getLatitude(), task.getLocation().getLongitude()));
  284. marker.title(task.getTitle());
  285. mMap.addMarker(marker);
  286. }
  287. }
  288. /**
  289. * Request read external storage permission, so that we can get saved images from external storage.
  290. * The result of the permission request is handled by a callback,
  291. * onRequestPermissionsResult.
  292. *
  293. */
  294. private void getReadStoragePermission() {
  295. if (ContextCompat.checkSelfPermission(getActivity().getApplicationContext(),
  296. Manifest.permission.READ_EXTERNAL_STORAGE)
  297. == PackageManager.PERMISSION_GRANTED) {
  298. mReadStorageGranted = true;
  299. } else {
  300. ActivityCompat.requestPermissions(getActivity(),
  301. new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
  302. READ_EXTERNAL_STORAGE_CODE);
  303. }
  304. }
  305. /**
  306. * Reads tasks saved in preferences as jsonStrings
  307. *
  308. * @return list of OwnTask
  309. */
  310. private List<OwnTask> readTasksFromPreferences() {
  311. List<OwnTask> tasks = new ArrayList<>();
  312. try {
  313. String jsonString = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(KEY_ALL_TASKS, "error");
  314. if(!"error".equalsIgnoreCase(jsonString)) {
  315. JSONArray jsonObjects = new JSONArray(jsonString);
  316. for (int i = 0; i<jsonObjects.length();i++) {
  317. tasks.add(new OwnTask(jsonObjects.getJSONObject(i)));
  318. if (BuildConfig.DEBUG) {
  319. Log.d(TAG, "Task loaded from shared preferences: " + tasks.get(i).toString());
  320. }
  321. Bitmap image = BitmapFactory.decodeFile(tasks.get(i).getPathImage() + File.separator + tasks.get(i).getId() + ".jpeg");
  322. if (BuildConfig.DEBUG) {
  323. Log.d(TAG, "Image loaded from shared preferences: " + image.getByteCount());
  324. }
  325. tasks.get(i).setImage(image);
  326. }
  327. }
  328. } catch (JSONException e) {
  329. if (BuildConfig.DEBUG) {
  330. Log.e(TAG, "Error while parsing tasks as jsonObjects from preferences");
  331. e.printStackTrace();
  332. }
  333. }
  334. return tasks;
  335. }
  336. @Override
  337. public void onMapReady(GoogleMap googleMap) { }
  338. }