diff --git a/app/build.gradle b/app/build.gradle index 9d6f2cc..003cd15 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,6 +26,9 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + repositories { + maven { url "https://jitpack.io" } + } } dependencies { @@ -47,6 +50,10 @@ dependencies { //osm implementation 'org.osmdroid:osmdroid-android:6.1.8' + //osm bonus pack + implementation 'com.github.MKergall:osmbonuspack:6.6.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + testImplementation 'org.mockito:mockito-core:2.7.22' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f5def4b..d82a8f3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,8 @@ + + fileIO = new FileIO<>(); + fileIO.writeFileData(new Route("TERSTSET"), getApplicationContext()); + Log.d(TAG, "onCreate: " + "FILE GESCHREVENN!!!!!");*/ + LocationListManager.INSTANCE.setContext(this); LocationListManager.INSTANCE.load(); CouponListManager.INSTANCE.setContext(this); diff --git a/app/src/main/java/com/a1/nextlocation/data/FileIO.java b/app/src/main/java/com/a1/nextlocation/data/FileIO.java index a47f76e..33fd03e 100644 --- a/app/src/main/java/com/a1/nextlocation/data/FileIO.java +++ b/app/src/main/java/com/a1/nextlocation/data/FileIO.java @@ -2,17 +2,26 @@ package com.a1.nextlocation.data; import android.content.Context; import android.content.res.AssetManager; +import android.os.Environment; import android.util.Log; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import org.json.JSONArray; + import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -50,7 +59,45 @@ public class FileIO { return res; } - public void writeFileData(T objectToWrite) { - //TODO make - } +// public void writeFileData(T objectToWrite, Context context) { +// //TODO make +// //object naar jsonobject +// //jsonarray toevoegen/maken +// //filewriter naar file +// +// String filename = ""; +// if (objectToWrite instanceof Coupon){ +// filename = "coupons.json"; +// } +// +// if (objectToWrite instanceof Route){ +// filename = "routes.json"; +// } +// +// if (objectToWrite instanceof Location){ +// filename = "locations.json"; +// } +// +// try (FileOutputStream fileOutputStream = context.openFileOutput(filename, Context.MODE_PRIVATE)){ +// String json = new Gson().toJson(objectToWrite); +// +// fileOutputStream.write(json.getBytes(StandardCharsets.UTF_8)); +// +// } catch (FileNotFoundException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// +// /*try (FileWriter fileWriter = new FileWriter(filename)){ +// +// String json = new Gson().toJson(objectToWrite); +// +// fileWriter.append(json); +// fileWriter.flush(); +// +// } catch (IOException e) { +// e.printStackTrace(); +// }*/ +// } } diff --git a/app/src/main/java/com/a1/nextlocation/data/Location.java b/app/src/main/java/com/a1/nextlocation/data/Location.java index f7d2362..ed4ccc8 100644 --- a/app/src/main/java/com/a1/nextlocation/data/Location.java +++ b/app/src/main/java/com/a1/nextlocation/data/Location.java @@ -35,6 +35,10 @@ public class Location implements Parcelable { this(name,getStringFromCoordinates(latCoord,longCoord),description,imageUrl); } + public Location(String name, android.location.Location loc, String description, String imageUrl) { + this(name,getStringFromCoordinates(loc.getLatitude(),loc.getLongitude()),description,imageUrl); + } + protected Location(Parcel in) { name = in.readString(); coordinates = in.readString(); @@ -90,8 +94,8 @@ public class Location implements Parcelable { public double[] getCoordinatesAsDoubles() { double[] res = new double[2]; - res[0] = getLat(); - res[1] = getLong(); + res[1] = getLat(); + res[0] = getLong(); return res; } @@ -105,7 +109,45 @@ public class Location implements Parcelable { } public static String getStringFromCoordinates(double lat1, double long1) { - return lat1 + "," + long1; + return long1 + "," + lat1; + } + + public double getDistance(Location other) { + double dlon = other.getLong() - getLong(); + double dlat = other.getLat() - getLong(); + double a = Math.pow(Math.sin(dlat / 2), 2) + + Math.cos(getLat()) * Math.cos(other.getLong()) + * Math.pow(Math.sin(dlon / 2),2); + + double c = 2 * Math.asin(Math.sqrt(a)); + + // Radius of earth in kilometers. Use 3956 + // for miles + double r = 6371; + + // calculate the result + double distance = c * r; + + return Math.floor(distance); + } + + public static double getDistance(double lat1, double lon1, double lat2, double lon2) { + double dlon = lon2 - lon1; + double dlat = lat2 - lat1; + double a = Math.pow(Math.sin(dlat / 2), 2) + + Math.cos(lat1) * Math.cos(lat2) + * Math.pow(Math.sin(dlon / 2),2); + + double c = 2 * Math.asin(Math.sqrt(a)); + + // Radius of earth in kilometers. Use 3956 + // for miles + double r = 6371; + + // calculate the result + double distance = c * r; + + return Math.floor(distance); } public GeoPoint convertToGeoPoint() { diff --git a/app/src/main/java/com/a1/nextlocation/data/RouteHandler.java b/app/src/main/java/com/a1/nextlocation/data/RouteHandler.java new file mode 100644 index 0000000..0075475 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/RouteHandler.java @@ -0,0 +1,69 @@ +package com.a1.nextlocation.data; + +import org.osmdroid.views.overlay.Polyline; + +/** + * singleton to track the current route that is being followed + */ +public enum RouteHandler { + INSTANCE; + + private boolean isFollowingRoute = false; + private Route currentRoute; + private int stepCount = 0; + private RouteFinishedListener routeFinishedListener; + + private Polyline currentRouteLine; + + public void setCurrentRouteLine(Polyline currentRouteLine) { + this.currentRouteLine = currentRouteLine; + } + + public Polyline getCurrentRouteLine() { + return currentRouteLine; + } + + public void setRouteFinishedListener(RouteFinishedListener routeFinishedListener) { + this.routeFinishedListener = routeFinishedListener; + } + + public int getStepCount() { + return stepCount; + } + + public void addStep() { + stepCount++; + } + + public void finishRoute() { + stepCount = 0; + isFollowingRoute = false; + currentRoute = null; + currentRouteLine = null; + } + + public void followRoute(Route route) { + this.currentRoute = route; + setFollowingRoute(true); + } + + public boolean isFollowingRoute(Route route) { + return isFollowingRoute && route.equals(currentRoute); + } + public void setFollowingRoute(boolean followingRoute) { + isFollowingRoute = followingRoute; + } + + public boolean isFollowingRoute() { + return isFollowingRoute; + } + + public Route getCurrentRoute() { + return currentRoute; + } + + @FunctionalInterface + public interface RouteFinishedListener { + void onRouteFinish(); + } +} diff --git a/app/src/main/java/com/a1/nextlocation/data/StaticData.java b/app/src/main/java/com/a1/nextlocation/data/StaticData.java new file mode 100644 index 0000000..d347d42 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/data/StaticData.java @@ -0,0 +1,39 @@ +package com.a1.nextlocation.data; + +import org.osmdroid.views.overlay.Polyline; + +import java.util.ArrayList; + +/** + * singleton to keep track of different global data + */ +public enum StaticData { + INSTANCE; + private double distanceTraveled = 0; + private int locationsVisited = 0; + + private ArrayList visitedNames = new ArrayList<>(); + + public void addDistance(double d) { + distanceTraveled += d; + } + + + public double getDistanceTraveled() { + return distanceTraveled; + } + + public void visitLocation(Location location) { + if (!visitedNames.contains(location.getName())) { + locationsVisited++; + visitedNames.add(location.getName()); + } + } + + public int getLocationsVisited() { + return locationsVisited; + } + + + +} diff --git a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java index bbc3a60..1b8f2e6 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/HomeFragment.java @@ -1,11 +1,12 @@ package com.a1.nextlocation.fragments; - import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.location.Location; +import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.util.Log; @@ -13,6 +14,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -22,27 +24,41 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import com.a1.nextlocation.R; -import com.a1.nextlocation.recyclerview.CustomOverlay; +import com.a1.nextlocation.data.RouteHandler; +import com.a1.nextlocation.data.StaticData; +import com.a1.nextlocation.json.DirectionsResult; +import com.a1.nextlocation.network.ApiHandler; import com.a1.nextlocation.recyclerview.LocationListManager; import org.osmdroid.api.IMapController; import org.osmdroid.config.Configuration; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.ItemizedIconOverlay; +import org.osmdroid.views.overlay.Overlay; import org.osmdroid.views.overlay.OverlayItem; +import org.osmdroid.views.overlay.Polyline; import org.osmdroid.views.overlay.compass.CompassOverlay; import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider; import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider; import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay; import java.util.ArrayList; +import java.util.List; -public class HomeFragment extends Fragment { +public class HomeFragment extends Fragment implements LocationListener { private final String userAgent = "com.ai.nextlocation.fragments"; + public final static String MAPQUEST_API_KEY = "vuyXjqnAADpjeL9QwtgWGleIk95e36My"; private ImageButton imageButton; + private ImageButton stopButton; private MapView mapView; private final int REQUEST_PERMISSIONS_REQUEST_CODE = 1; private final String TAG = HomeFragment.class.getCanonicalName(); + // private RoadManager roadManager; + private Polyline roadOverlay; + private int color; + private Location currentLocation; + private Overlay allLocationsOverlay; @Override public void onCreate(Bundle savedInstanceState) { @@ -53,6 +69,7 @@ public class HomeFragment extends Fragment { // WRITE_EXTERNAL_STORAGE is required in order to show the map Manifest.permission.WRITE_EXTERNAL_STORAGE); + color = requireContext().getColor(R.color.red); } @Override @@ -61,15 +78,52 @@ public class HomeFragment extends Fragment { View view = inflater.inflate(R.layout.fragment_home, container, false); + // set up the location list button this.imageButton = view.findViewById(R.id.location_list_button); this.imageButton.setOnClickListener(v -> { LocationFragment locationFragment = new LocationFragment(); ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit(); }); + // set up the route stop button + stopButton = view.findViewById(R.id.home_stop_route_button); + stopButton.setOnClickListener(v -> { + RouteHandler.INSTANCE.finishRoute(); + stopButton.setVisibility(View.GONE); + Toast.makeText(requireContext(),getResources().getString(R.string.route_stop_toast),Toast.LENGTH_SHORT).show(); + mapView.getOverlays().remove(roadOverlay); + mapView.getOverlays().remove(allLocationsOverlay); + addLocations(); + mapView.invalidate(); + roadOverlay = null; + }); + + if (RouteHandler.INSTANCE.isFollowingRoute()) { + stopButton.setVisibility(View.VISIBLE); + } else { + stopButton.setVisibility(View.GONE); + } + ApiHandler.INSTANCE.addListener(this::onDirectionsAvailable); return view; } + /** + * callback method that gets called when there are new directions available in the form of a {@link DirectionsResult} object. + * @param directionsResult the directions received from the api + */ + private void onDirectionsAvailable(DirectionsResult directionsResult) { + Log.d(TAG, "onDirectionsAvailable: got result! " + directionsResult); + ArrayList geoPoints = directionsResult.getGeoPoints(); + roadOverlay = new Polyline(); + roadOverlay.setPoints(geoPoints); + roadOverlay.setColor(color); + + + RouteHandler.INSTANCE.setCurrentRouteLine(roadOverlay); + Log.d(TAG, "onDirectionsAvailable: successfully added road!"); + + } + @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -77,6 +131,11 @@ public class HomeFragment extends Fragment { initMap(view); } + /** + * This method initializes the map and all the things it needs + * + * @param view the view the map is on + */ private void initMap(@NonNull View view) { // set the user agent Configuration.getInstance().setUserAgentValue(userAgent); @@ -91,31 +150,18 @@ public class HomeFragment extends Fragment { GpsMyLocationProvider gpsMyLocationProvider = new GpsMyLocationProvider(this.requireContext()); // add the compass overlay - CompassOverlay compassOverlay = new CompassOverlay(requireContext(),new InternalCompassOrientationProvider(requireContext()),mapView); + CompassOverlay compassOverlay = new CompassOverlay(requireContext(), new InternalCompassOrientationProvider(requireContext()), mapView); compassOverlay.enableCompass(); mapView.getOverlays().add(compassOverlay); + addLocations(); + // add the location overlay MyLocationNewOverlay mLocationOverlay = new MyLocationNewOverlay(gpsMyLocationProvider, mapView); mLocationOverlay.enableFollowLocation(); mLocationOverlay.enableMyLocation(); mapView.getOverlays().add(mLocationOverlay); - CustomOverlay customOverlay = new CustomOverlay(getResources().getDrawable(R.drawable.ic_baseline_location_on_24),mapView); - - for (com.a1.nextlocation.data.Location l : LocationListManager.INSTANCE.getLocationList()) { - GeoPoint p = new GeoPoint(l.getLat(), l.getLong()); - OverlayItem overlayItem = new OverlayItem(l.getName(),l.getDescription(), p); - - customOverlay.addOverlayItem(overlayItem); - Log.d(TAG, "initMap: " + "succes"); - } - - - mapView.getOverlays().add(customOverlay); - - - // add the zoom controller IMapController mapController = mapView.getController(); mapController.setZoom(15.0); @@ -125,9 +171,19 @@ public class HomeFragment extends Fragment { try { + + // request location updates for the distance checking + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); + + // get the current location and set it as center Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - GeoPoint startPoint = new GeoPoint(location.getLatitude(), location.getLongitude()); - mapController.setCenter(startPoint); + if (currentLocation == null) currentLocation = location; + + if (location != null) { + GeoPoint start = new GeoPoint(location.getLatitude(), location.getLongitude()); + mapController.setCenter(start); + } } catch (SecurityException e) { Log.d(TAG, "onViewCreated: exception while getting location: " + e.getLocalizedMessage()); @@ -140,7 +196,99 @@ public class HomeFragment extends Fragment { } + + displayRoute(); + } + + /** + * displays the route that is currently being followed as a red line + */ + private void displayRoute() { + + if (RouteHandler.INSTANCE.isFollowingRoute()) { + if (roadOverlay == null) { + if (RouteHandler.INSTANCE.getCurrentRouteLine() != null) { + roadOverlay = RouteHandler.INSTANCE.getCurrentRouteLine(); + mapView.getOverlays().add(roadOverlay); + mapView.invalidate(); + Log.d(TAG, "initMap: successfully added road!"); + } + } else { + mapView.getOverlays().add(roadOverlay); + mapView.invalidate(); + Log.d(TAG, "initMap: successfully added road!"); + } + } + } + + /** + * adds the locations of the current route to the map. If there is no current route, show all locations + */ + private void addLocations() { + // get the locations of the current route or all locations + List locations = RouteHandler.INSTANCE.isFollowingRoute() ? RouteHandler.INSTANCE.getCurrentRoute().getLocations() : LocationListManager.INSTANCE.getLocationList(); + final ArrayList items = new ArrayList<>(locations.size()); + // marker icon + Drawable marker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_baseline_location_on_24); + marker.setAlpha(255); + marker.setTint(getResources().getColor(R.color.primaryColour)); + + // add all locations to the overlay itemss + for (com.a1.nextlocation.data.Location location : locations) { + OverlayItem item = new OverlayItem(location.getName(), location.getDescription(), location.convertToGeoPoint()); + item.setMarker(marker); + items.add(item); + } + + // create the overlay that will hold all locations and add listeners + allLocationsOverlay = new ItemizedIconOverlay(items, + new ItemizedIconOverlay.OnItemGestureListener() { + /** + * on sinlge click, navigate to that location's detail fragment + * @param index the index in the location list + * @param item the item that was clicked + * @return true + */ + @Override + public boolean onItemSingleTapUp(int index, OverlayItem item) { + com.a1.nextlocation.data.Location clicked = locations.get(index); + requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, new LocationDetailFragment(clicked)).commit(); + return true; + } + + /** + * on item long press, show that location's name in a toast message + * @param index the index in the location list + * @param item the item that was clicked + * @return true + */ + @Override + public boolean onItemLongPress(int index, OverlayItem item) { + com.a1.nextlocation.data.Location clicked = locations.get(index); + Toast.makeText(requireContext(), clicked.getName(), Toast.LENGTH_SHORT).show(); + + // create a route to the clicked location, didn't work and didn't have enough time to make it work ¯\_(ツ)_/¯ + +// Route route = new Route("Route to " + clicked.getName()); +// route.addLocation(new com.a1.nextlocation.data.Location("Current location",currentLocation.getLatitude(),currentLocation.getLongitude(),"your location",null)); +// route.addLocation(clicked); +// ApiHandler.INSTANCE.getDirections(route); + return true; + } + }, requireContext()); + + // add the overlay to the map + mapView.getOverlays().add(allLocationsOverlay); + Log.d(TAG, "addLocations: successfully added locations"); + + } + + /** + * @author Ricky + * request the permissions needed for location and network, made by Ricky + * @param permissions tbe permissions we want to ask + */ private void requestPermissionsIfNecessary(String... permissions) { ArrayList permissionsToRequest = new ArrayList<>(); if (this.getContext() != null) @@ -158,4 +306,62 @@ public class HomeFragment extends Fragment { REQUEST_PERMISSIONS_REQUEST_CODE); } } + + /** + * location callback that gets called each time the location is updated. It is used for updating the distance walked and checking if there are locations you have visited + * @param location the new location + */ + @Override + public void onLocationChanged(@NonNull Location location) { + // calculate the distance walked + double distance = currentLocation.distanceTo(location); // in meters + StaticData.INSTANCE.addDistance(distance); + currentLocation = location; + + //new thread because we don't want the main thread to hang, this method gets called a lot + Thread t = new Thread(() -> { + for (com.a1.nextlocation.data.Location l : LocationListManager.INSTANCE.getLocationList()) { + if (com.a1.nextlocation.data.Location.getDistance(currentLocation.getLatitude(), currentLocation.getLongitude(), l.getLat(), l.getLong()) < 10) { + StaticData.INSTANCE.visitLocation(l); + } + } + }); + + t.start(); + } + + // empty override methods for the LocationListener + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + + } + + @Override + public void onProviderEnabled(@NonNull String provider) { + + } + + @Override + public void onProviderDisabled(@NonNull String provider) { + + } + + /** + * method that gets called when the app gets paused + */ + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + /** + * method that gets called when the app gets resumed + */ + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java index 2be60ce..19f73cd 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/LocationDetailFragment.java @@ -1,30 +1,33 @@ package com.a1.nextlocation.fragments; -import android.content.Context; +import android.content.Intent; import android.os.Bundle; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; import com.a1.nextlocation.R; import com.a1.nextlocation.data.Location; public class LocationDetailFragment extends Fragment { + private static final String TAG = LocationDetailFragment.class.getCanonicalName(); private ImageButton imageButton; - private ImageView locationImage; private Location location; - private TextView titelText; - private TextView detailText; - public LocationDetailFragment(){} + public LocationDetailFragment() { + + } + + public LocationDetailFragment(Location location) { + this.location = location; + } @Override public void onCreate(Bundle savedInstanceState) { @@ -33,29 +36,17 @@ public class LocationDetailFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_location_detail, container, false); - - this.titelText = view.findViewById(R.id.detail_location_name); - this.titelText.setText(location.getName()); - - this.detailText = view.findViewById(R.id.detail_location_text); - this.detailText.setText(location.getDescription()); - this.imageButton = view.findViewById(R.id.detail_location_back_button); this.imageButton.setOnClickListener(v -> { LocationFragment locationFragment = new LocationFragment(); ((FragmentActivity) view.getContext()).getSupportFragmentManager().beginTransaction().replace(R.id.fragment_layout, locationFragment).addToBackStack(null).commit(); }); - this.locationImage = view.findViewById(R.id.detail_location_image); - Context context = this.locationImage.getContext(); - int id = context.getResources().getIdentifier(this.location.getImageUrl(), "drawable", context.getPackageName()); - this.locationImage.setImageResource(id); - + if (location != null) { + Log.d(TAG, "onCreateView: the location has a name of: " + location.getName()); + } return view; } - - public void setLocation(Location location){ - this.location = location; - } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java index 9ddf728..2369e6d 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/RouteFragment.java @@ -2,11 +2,14 @@ package com.a1.nextlocation.fragments; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -18,8 +21,14 @@ import com.a1.nextlocation.recyclerview.RouteAdapter; import com.a1.nextlocation.recyclerview.RouteListManager; import java.util.List; +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.json.DirectionsResult; +import com.a1.nextlocation.network.ApiHandler; +import com.a1.nextlocation.network.DirectionsListener; public class RouteFragment extends Fragment { + private static final String TAG = RouteFragment.class.getCanonicalName(); private RecyclerView routeRecyclerView; private RecyclerView.LayoutManager layoutManager; @@ -63,4 +72,21 @@ public class RouteFragment extends Fragment { this.routeRecyclerView.setAdapter(this.routeAdapter); return view; } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + +// ApiHandler.INSTANCE.getDirections(51.49017262451581, 4.289038164073164,51.47337383133509, 4.303535222390562); +// Route r = new Route("test"); +// r.addLocation(new Location("test",51.574473766034046, 4.7628379328055175,"route",null)); +// r.addLocation(new Location("test",51.577354223919876, 4.771120593941968,"route",null)); +// r.addLocation(new Location("test",51.573033468635174, 4.782750651807139,"route",null)); +// r.addLocation(new Location("test",51.56519104881196, 4.748246716295709,"route",null)); +// r.addLocation(new Location("test",51.57367360644676, 4.74404101271347,"route",null)); +// r.addLocation(new Location("test",51.57852769146427, 4.739878224473907,"route",null)); +//// r.addLocation(new Location("test",51.489063681658145, 4.289596063527951,"route",null)); +//// r.addLocation(new Location("test",51.483012677667766, 4.28003245468457,"route",null)); +// ApiHandler.INSTANCE.getDirections(r); + } } \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java b/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java index 707b719..a2cc87a 100644 --- a/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java +++ b/app/src/main/java/com/a1/nextlocation/fragments/StatisticFragment.java @@ -16,6 +16,7 @@ import android.widget.Toast; import com.a1.nextlocation.R; import com.a1.nextlocation.data.Coupon; +import com.a1.nextlocation.data.StaticData; import com.a1.nextlocation.recyclerview.CouponAdapter; import com.a1.nextlocation.recyclerview.CouponListManager; @@ -37,6 +38,13 @@ public class StatisticFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_statistic, container, false); + TextView distance = view.findViewById(R.id.statistics_km); + TextView locs = view.findViewById(R.id.statistics_locations_visited); + double dist = StaticData.INSTANCE.getDistanceTraveled()/1000; + distance.setText("" + String.format("%.1f",dist) + " km"); + locs.setText("" + StaticData.INSTANCE.getLocationsVisited()); + + this.couponList = CouponListManager.INSTANCE.getCouponList(); CouponAdapter adapter = new CouponAdapter(this.getContext(), this.couponList); TextView couponNumber = view.findViewById(R.id.couponAmount); diff --git a/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java b/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java new file mode 100644 index 0000000..7f52783 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/json/DirectionsResult.java @@ -0,0 +1,190 @@ +package com.a1.nextlocation.json; + +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; + +import org.json.JSONArray; +import org.osmdroid.util.GeoPoint; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DirectionsResult { + private static final String TAG = DirectionsResult.class.getCanonicalName(); + private List steps = new ArrayList<>(); + private double distance; + private double duration; + private double[][] wayPointCoordinates; + private GeoPoint[] startAndEndPoint = new GeoPoint[2]; + + public List getSteps() { + return steps; + } + + public void setSteps(List steps) { + this.steps = steps; + } + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public double getDuration() { + return duration; + } + + public void setDuration(double duration) { + this.duration = duration; + } + + public void addStep(DirectionsStep step) { + this.steps.add(step); + } + + public GeoPoint[] getStartAndEndPoint() { + return startAndEndPoint; + } + + /** + * converts all the geopoints in all the steps into an arraylist to display it on the map + * @return the list of geopoints + */ + public ArrayList getGeoPoints() { + int size = 0; + // we'll have a lot of waypoints, so calculate the size first so that the list won't have to be extended (o p t i m i z e) + for (int i = 0; i < this.getSteps().size(); i++) { + size += this.getSteps().get(i).getWaypoints().length; + } + + ArrayList res = new ArrayList<>(size); + for (DirectionsStep step : this.getSteps()) { + Collections.addAll(res, step.getWaypoints()); + } + return res; + } + + /** + * parses a given json string into this object. It gets all the waypoints and steps and combines them so that every step also has the correct coordinates associated with it + * + * @param json the json string to parse. + */ + public void parse(String json) { + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + JsonObject feature = JsonParser.parseString(json).getAsJsonObject().get("features").getAsJsonArray().get(0).getAsJsonObject(); + JsonObject properties = feature.get("properties").getAsJsonObject(); + JsonArray wayPointCoordinates = feature.get("geometry").getAsJsonObject().getAsJsonArray("coordinates"); + this.wayPointCoordinates = new double[wayPointCoordinates.size()][2]; + + + // fill the way point coordinates list for later use + for (int i = 0; i < wayPointCoordinates.size(); i++) { + JsonElement j = wayPointCoordinates.get(i); + JsonArray arr = j.getAsJsonArray(); + this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble(); + this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble(); + } + + + JsonArray segments = properties.getAsJsonArray("segments"); + + for (JsonElement element : segments) { + JsonObject segment = element.getAsJsonObject(); + + setDistance(segment.get("distance").getAsDouble()); + setDuration(segment.get("duration").getAsDouble()); + + JsonArray steps = segment.getAsJsonArray("steps"); + + for (JsonElement j : steps) { + + DirectionsStep step = gson.fromJson(j, DirectionsStep.class); + double lat; + double longl; + + // kinda stinky but it works + for (int i = 0; i < 2; i++) { + lat = this.wayPointCoordinates[step.getWay_points().get(i)][0]; + longl = this.wayPointCoordinates[step.getWay_points().get(i)][1]; + step.getWaypoints()[i] = new GeoPoint(lat, longl); + } + + addStep(step); + Log.d(TAG, "parse: added step" + step); + } + } + + startAndEndPoint[0] = this.getSteps().get(0).getWaypoints()[0]; + startAndEndPoint[1] = this.getSteps().get(this.getSteps().size()-1).getWaypoints()[1]; + + } + + public void parseRoute(String json) { + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + JsonArray routes = JsonParser.parseString(json).getAsJsonObject().getAsJsonArray("routes"); + for (JsonElement element : routes) { + JsonObject route = element.getAsJsonObject(); + JsonObject summary = route.getAsJsonObject("summary"); + this.distance = summary.get("distance").getAsDouble(); + this.duration = summary.get("duration").getAsDouble(); + + JsonPrimitive geometry = route.getAsJsonPrimitive("geometry"); + JsonArray wayPointCoordinates = GeometryDecoder.decodeGeometry(geometry.getAsString(), false); + this.wayPointCoordinates = new double[wayPointCoordinates.size()][2]; + + + // fill the way point coordinates list for later use + for (int i = 0; i < wayPointCoordinates.size(); i++) { + JsonElement j = wayPointCoordinates.get(i); + JsonArray arr = j.getAsJsonArray(); + this.wayPointCoordinates[i][0] = arr.get(0).getAsDouble(); + this.wayPointCoordinates[i][1] = arr.get(1).getAsDouble(); + } + + + JsonArray segments = route.getAsJsonArray("segments"); + + for (JsonElement e : segments) { + JsonObject segment = e.getAsJsonObject(); + + setDistance(segment.get("distance").getAsDouble()); + setDuration(segment.get("duration").getAsDouble()); + + JsonArray steps = segment.getAsJsonArray("steps"); + + for (JsonElement j : steps) { + + DirectionsStep step = gson.fromJson(j, DirectionsStep.class); + double lat; + double longl; + + // kinda stinky but it works + for (int i = 0; i < 2; i++) { + lat = this.wayPointCoordinates[step.getWay_points().get(i)][0]; + longl = this.wayPointCoordinates[step.getWay_points().get(i)][1]; + step.getWaypoints()[i] = new GeoPoint(lat, longl); + } + + addStep(step); + Log.d(TAG, "parse: added step" + step); + } + } + + } + + } +} diff --git a/app/src/main/java/com/a1/nextlocation/json/DirectionsStep.java b/app/src/main/java/com/a1/nextlocation/json/DirectionsStep.java new file mode 100644 index 0000000..c495cef --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/json/DirectionsStep.java @@ -0,0 +1,72 @@ +package com.a1.nextlocation.json; + +import org.osmdroid.util.GeoPoint; + +import java.util.ArrayList; + +/** + * pojo class that holds the step object from the api response + */ +public class DirectionsStep { + private double distance; + private double duration; + private String instruction; + private String name; + /** + * these are the actual waypoints that the step refers to. The first is the beginning of the step, and the second is what it leads to. + * The second geopoint is always the first geopoint of the next step in the list of the {@link DirectionsResult} object. + */ + private GeoPoint[] waypoints = new GeoPoint[2]; + /** + * this is a list of the waypoints that are in the response, it is called way_points so it can be automatically serialized with gson + */ + private ArrayList way_points; + + public double getDistance() { + return distance; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public double getDuration() { + return duration; + } + + public void setDuration(double duration) { + this.duration = duration; + } + + public String getInstruction() { + return instruction; + } + + public void setInstruction(String instruction) { + this.instruction = instruction; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ArrayList getWay_points() { + return way_points; + } + + public void setWay_points(ArrayList way_points) { + this.way_points = way_points; + } + + public GeoPoint[] getWaypoints() { + return waypoints; + } + + public void setWaypoints(GeoPoint[] waypoints) { + this.waypoints = waypoints; + } +} diff --git a/app/src/main/java/com/a1/nextlocation/json/GeometryDecoder.java b/app/src/main/java/com/a1/nextlocation/json/GeometryDecoder.java new file mode 100644 index 0000000..3884e52 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/json/GeometryDecoder.java @@ -0,0 +1,63 @@ +package com.a1.nextlocation.json; + +import com.google.gson.JsonArray; + +import org.json.JSONArray; +import org.json.JSONException; + +/** + * source: https://github.com/GIScience/openrouteservice-docs#geometry-decoding + */ +public class GeometryDecoder { + + public static JsonArray decodeGeometry(String encodedGeometry, boolean inclElevation) { + JsonArray geometry = new JsonArray(); + int len = encodedGeometry.length(); + int index = 0; + int lat = 0; + int lng = 0; + int ele = 0; + + while (index < len) { + int result = 1; + int shift = 0; + int b; + do { + b = encodedGeometry.charAt(index++) - 63 - 1; + result += b << shift; + shift += 5; + } while (b >= 0x1f); + lat += (result & 1) != 0 ? ~(result >> 1) : (result >> 1); + + result = 1; + shift = 0; + do { + b = encodedGeometry.charAt(index++) - 63 - 1; + result += b << shift; + shift += 5; + } while (b >= 0x1f); + lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1); + + + if(inclElevation){ + result = 1; + shift = 0; + do { + b = encodedGeometry.charAt(index++) - 63 - 1; + result += b << shift; + shift += 5; + } while (b >= 0x1f); + ele += (result & 1) != 0 ? ~(result >> 1) : (result >> 1); + } + + JsonArray location = new JsonArray(); + location.add(lat / 1E5); + location.add(lng / 1E5); + if(inclElevation){ + location.add((float) (ele / 100)); + } + geometry.add(location); + } + return geometry; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java b/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java index af34416..46d3830 100644 --- a/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java +++ b/app/src/main/java/com/a1/nextlocation/network/ApiHandler.java @@ -4,14 +4,20 @@ import android.util.Log; import com.a1.nextlocation.data.Location; import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.json.DirectionsResult; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.RequestBody; import okhttp3.Response; public enum ApiHandler { @@ -22,21 +28,22 @@ public enum ApiHandler { public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private final String BASE_URL = "https://api.openrouteservice.org/v2/directions/"; private final String API_KEY = "5b3ce3597851110001cf6248d4eee2099f724255918adc71cc502b2a"; - private final String DIRECTIONS_MODE = "foot_walking"; + private final String DIRECTIONS_MODE = "foot-walking"; + private List listeners = new ArrayList<>(); private OkHttpClient client = new OkHttpClient(); - public Route getDirections(Location startLocation, Location endLocation) { - return getDirections(startLocation.getCoordinates(),endLocation.getCoordinates()); + public void getDirections(Location startLocation, Location endLocation) { + getDirections(startLocation.getCoordinates(),endLocation.getCoordinates()); } - public Route getDirections(double startLat, double startLong, double endLat, double endLong) { - return getDirections(startLat + "," + startLong, endLat + "," + endLong); + public void getDirections(double startLat, double startLong, double endLat, double endLong) { + getDirections(startLong + "," + startLat, endLong + "," + endLat); } - public Route getDirections(String startLocation, String endLocation) { + public void getDirections(String startLocation, String endLocation) { + String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY + "&start=" +startLocation + "&end=" + endLocation; - AtomicReference res = null; Thread t = new Thread(() -> { Request request = new Request.Builder().url(requestUrl).build(); @@ -45,6 +52,14 @@ public enum ApiHandler { if (response.body() != null) { String responseString = Objects.requireNonNull(response.body()).string(); Log.d(TAG, "getDirections: got response: " + responseString); + + DirectionsResult result = new DirectionsResult(); + result.parse(responseString); + Log.d(TAG, "getDirections: " + result.getSteps().size()); + + for (DirectionsListener listener : listeners) { + listener.onDirectionsAvailable(result); + } } } catch (IOException e) { @@ -54,12 +69,76 @@ public enum ApiHandler { t.start(); +// try { +// t.join(); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } + + } + + public void addListener(DirectionsListener listener) { + this.listeners.add(listener); + } + + public void getDirections(Route route) { +// for (int i = 0; i < route.getLocations().size()-1; i+= 2) { +// Location start = route.getLocations().get(i); +// Location end = route.getLocations().get(i+1); +// getDirections(start,end); +// } + + ArrayList allCoords = new ArrayList<>(); + for (Location location : route.getLocations()) { + allCoords.add(location.getCoordinatesAsDoubles()); + } + + String body = "{\"coordinates\":" + new Gson().toJson(allCoords) + "}"; + + + String requestUrl = BASE_URL + DIRECTIONS_MODE + "?api_key=" + API_KEY; + + Thread t = new Thread(() -> { + + RequestBody requestBody = RequestBody.create(body,JSON); + Request request = new Request.Builder() + .url(requestUrl) + .post(requestBody) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (response.body() != null) { + String responseString = Objects.requireNonNull(response.body()).string(); + Log.d(TAG, "getDirections: got response: " + responseString); + if (responseString.startsWith("{\"error")) { + Log.e(TAG, "getDirections: ERROR IN REQUEST!"); + return; + } + + DirectionsResult result = new DirectionsResult(); + result.parseRoute(responseString); + Log.d(TAG, "getDirections: " + result.getSteps().size()); + + for (DirectionsListener listener : listeners) { + listener.onDirectionsAvailable(result); + } + } + + } catch (IOException e) { + Log.d(TAG, "getDirections: caught exception: " + e.getLocalizedMessage()); + } + + }); + + t.start(); + try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } - return res.get(); + + } diff --git a/app/src/main/java/com/a1/nextlocation/network/DirectionsListener.java b/app/src/main/java/com/a1/nextlocation/network/DirectionsListener.java new file mode 100644 index 0000000..28f2305 --- /dev/null +++ b/app/src/main/java/com/a1/nextlocation/network/DirectionsListener.java @@ -0,0 +1,8 @@ +package com.a1.nextlocation.network; + +import com.a1.nextlocation.data.Route; +import com.a1.nextlocation.json.DirectionsResult; + +public interface DirectionsListener { + void onDirectionsAvailable(DirectionsResult result); +} diff --git a/app/src/main/res/drawable-anydpi/ic_stop_icon.xml b/app/src/main/res/drawable-anydpi/ic_stop_icon.xml new file mode 100644 index 0000000..addfeb0 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_stop_icon.xml @@ -0,0 +1,12 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_stop_icon.png b/app/src/main/res/drawable-hdpi/ic_stop_icon.png new file mode 100644 index 0000000..10f865c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stop_icon.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_stop_icon.png b/app/src/main/res/drawable-mdpi/ic_stop_icon.png new file mode 100644 index 0000000..eec2a0b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stop_icon.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_stop_icon.png b/app/src/main/res/drawable-xhdpi/ic_stop_icon.png new file mode 100644 index 0000000..e8ee9f5 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stop_icon.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_stop_icon.png b/app/src/main/res/drawable-xxhdpi/ic_stop_icon.png new file mode 100644 index 0000000..b844819 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stop_icon.png differ diff --git a/app/src/main/res/drawable/stop_icon.png b/app/src/main/res/drawable/stop_icon.png new file mode 100644 index 0000000..7d72917 Binary files /dev/null and b/app/src/main/res/drawable/stop_icon.png differ diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 5a55efa..bebf806 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -27,6 +27,17 @@ android:src="@drawable/ic_baseline_outlined_flag_24" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_statistic.xml b/app/src/main/res/layout/fragment_statistic.xml index 8935a83..ede8e82 100644 --- a/app/src/main/res/layout/fragment_statistic.xml +++ b/app/src/main/res/layout/fragment_statistic.xml @@ -54,6 +54,7 @@ app:layout_constraintTop_toTopOf="parent" /> #FF115571 #FF31AFB4 #FF14212D + #FF0000 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bfbd17f..cac68cf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,25 +1,21 @@ Next Location - Locaties + + Hello blank fragment + Locaties Routes - Statistieken - Instellingen + Statistieken + Instellingen Taal Imperiaal systeem 65+ stand Kleurenblind + Statistieken Totale afstand: Bezochte locaties: Totale tijd: Coupons gespaard: Coupons Start Route - Naam - Terug - Locatie Detail - Detail tekst - Titel - Kilometer - Getal - Minuten + Route stopped! \ No newline at end of file diff --git a/app/src/test/java/com/a1/nextlocation/CouponTestClass.java b/app/src/test/java/com/a1/nextlocation/CouponTestClass.java new file mode 100644 index 0000000..068b814 --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/CouponTestClass.java @@ -0,0 +1,32 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.data.Coupon; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + +public class CouponTestClass { + private Coupon testCoupon; + + @Before + public void init(){ + testCoupon = new Coupon("TESTCODE", "REWARDISTRUE"); + } + + @Test + public void testSetCode() { + testCoupon.setCode("testing"); + String expected = "testing"; + assertEquals(expected, testCoupon.getCode()); + } + + @Test + public void testSetReward() { + testCoupon.setReward("testreward"); + String expected = "testreward"; + assertNotNull(testCoupon.getReward()); + assertEquals(expected, testCoupon.getReward()); + } +} diff --git a/app/src/test/java/com/a1/nextlocation/DataTestClass.java b/app/src/test/java/com/a1/nextlocation/DataTestClass.java new file mode 100644 index 0000000..576f00a --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/DataTestClass.java @@ -0,0 +1,81 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.data.Coupon; +import com.a1.nextlocation.data.Data; +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.Route; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +public class DataTestClass { + private Data data; + + @Before + public void init(){ + data = new Data(); + } + + + @Test + public void testSetDistanceTraveled() { + data.setDistanceTraveled(100); + + int expected = 100; + assertEquals(expected, data.getDistanceTraveled(), 0.1); + } + + @Test + public void testSetLocationsVisited() { + data.setLocationsVisited(16); + + int expected = 16; + assertEquals(expected, data.getLocationsVisited()); + } + + @Test + public void testSetTotalTime() { + data.setTotalTime(120); + + int expected = 120; + assertEquals(expected, data.getTotalTime()); + } + + @Test + public void testSetCouponList() { + List expected = new ArrayList<>(); + expected.add(new Coupon("CODE1", "REWARD1")); + expected.add(new Coupon("CODE2", "REWARD2")); + expected.add(new Coupon("CODE3", "REWARD3")); + + data.setCouponList(expected); + assertEquals(expected, data.getCouponList()); + } + + @Test + public void testNextLocation() { + Location expected = new Location("name1", "cord1", "desc1", null); + data.setNextLocation(expected); + assertEquals(expected, data.getNextLocation()); + } + + @Test + public void testLastLocation() { + Location expected = new Location("name2", "cord2", "desc2", null); + data.setLastLocation(expected); + assertEquals(expected, data.getLastLocation()); + } + + @Test + public void testCurrentRoute() { + Route expected = new Route("testRoute1"); + data.setCurrentRoute(expected); + assertEquals(expected, data.getCurrentRoute()); + } + + +} \ No newline at end of file diff --git a/app/src/test/java/com/a1/nextlocation/FileIOTest.java b/app/src/test/java/com/a1/nextlocation/FileIOTest.java new file mode 100644 index 0000000..1f2894f --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/FileIOTest.java @@ -0,0 +1,57 @@ +package com.a1.nextlocation; + +import android.app.Instrumentation; +import android.content.Context; +import android.content.pm.InstrumentationInfo; +import android.widget.ArrayAdapter; + +import com.a1.nextlocation.data.FileIO; +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.Route; +import com.google.gson.reflect.TypeToken; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Mock; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +public class FileIOTest { + +// @Test +// public void testReadFileIO() { +// //System.out.println(Arrays.toString(mMockContext.fileList())); +// Context mMockContext = mock(MainActivity.class); +// List expected = new ArrayList<>(); +// Route testRoute = new Route("rondje stad"); +// testRoute.addLocation(new Location("kees kroket", "2.4654645,6.2342323", "lekkere patatjes", null)); +// testRoute.setTotalDistance(2.3434f); +// testRoute.setTotalTime(342342); +// expected.add(testRoute); +// +// /* +// FileIO> fileIO = new FileIO<>(); +// ArrayList res = fileIO.readFileData(context, "routes.json",new TypeToken>(){}.getType()); +// */ +// +// if (mMockContext.getAssets() == null) +// System.out.println("daar ga je"); +// +// FileIO> fileIO = new FileIO<>(); +// ArrayList res = fileIO.readFileData(mMockContext, "routes.json", new TypeToken>(){}.getType()); +// +// assertEquals(expected, res); +// +// } + +} diff --git a/app/src/test/java/com/a1/nextlocation/LocationTest.java b/app/src/test/java/com/a1/nextlocation/LocationTest.java new file mode 100644 index 0000000..5a3921f --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/LocationTest.java @@ -0,0 +1,97 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.data.Location; + +import org.junit.Before; +import org.junit.Test; +import org.osmdroid.util.GeoPoint; + +import static org.junit.Assert.*; + +public class LocationTest { + private Location testLocation; + @Before + public void init(){ + testLocation = new Location("testName", "15.4,27.5", "testDesc", null); + } + + @Test + public void nameTest(){ + String testName = "nameTestName"; + + String expectedBefore = "testName"; + String expectedAfter = "nameTestName"; + + assertEquals(expectedBefore, testLocation.getName()); + testLocation.setName(testName); + assertEquals(expectedAfter, testLocation.getName()); + } + + @Test + public void coordinatesTest(){ + String testCoordinaates = "32.4,15.7"; + + String expectedBefore = "15.4,27.5"; + String expectedAfter = "32.4,15.7"; + + assertEquals(expectedBefore, testLocation.getCoordinates()); + testLocation.setCoordinates(testCoordinaates); + assertEquals(expectedAfter, testLocation.getCoordinates()); + } + + @Test + public void descriptionTest(){ + String testDescription = "This description is a test!"; + + String expectedBefore = "testDesc"; + String expectedAfter = "This description is a test!"; + + assertEquals(expectedBefore, testLocation.getDescription()); + testLocation.setDescription(testDescription); + assertEquals(expectedAfter, testLocation.getDescription()); + } + + @Test + public void ImageURLTest(){ + String testURL = "https://i.imgur.com/FvohwaS.png"; + + String expectedBefore = null; + String expectedAfter = "https://i.imgur.com/FvohwaS.png"; + + assertEquals(expectedBefore ,testLocation.getImageUrl()); + testLocation.setImageUrl(testURL); + assertEquals(expectedAfter, testLocation.getImageUrl()); + } + + @Test + public void coordinateDoublesTest(){ + double[] testDoubles = new double[2]; + testDoubles[0] = 15.4; + testDoubles[1] = 27.5; + + double [] expectedCoordAsDouble = testDoubles; + String expectedStringFromDouble = "15.4,27.5"; + + assertArrayEquals(expectedCoordAsDouble, testLocation.getCoordinatesAsDoubles(), 0.1); + assertEquals(expectedStringFromDouble, testLocation.getStringFromCoordinates(testDoubles[0], testDoubles[1])); + } + + @Test + public void geoPointTest(){ + String testGeoPointCoords = "30.3,55.5"; + + GeoPoint expectedBefore = new GeoPoint(15.4, 27.5); + GeoPoint expectedAfter = new GeoPoint(30.3, 55.5); + + assertEquals(expectedBefore, testLocation.convertToGeoPoint()); + testLocation.setCoordinates(testGeoPointCoords); + assertEquals(expectedAfter, testLocation.convertToGeoPoint()); + } + + @Test + public void AlternateConstructorTest(){ + Location alternateTestLocation = new Location("testName", 15.4, 27.5, "testDesc", null); + + assertNotNull(alternateTestLocation); + } +} diff --git a/app/src/test/java/com/a1/nextlocation/RouteTest.java b/app/src/test/java/com/a1/nextlocation/RouteTest.java new file mode 100644 index 0000000..9b07a4e --- /dev/null +++ b/app/src/test/java/com/a1/nextlocation/RouteTest.java @@ -0,0 +1,93 @@ +package com.a1.nextlocation; + +import com.a1.nextlocation.data.Location; +import com.a1.nextlocation.data.Route; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +public class RouteTest { + private Route route; + + @Before + public void init(){ + route = new Route("testName"); + } + + @Test + public void nameTest(){ + String testName = "secondTestName"; + + String expectedBefore = "testName"; + String expectedAfter = "secondTestName"; + + assertEquals(expectedBefore, route.getName()); + route.setName(testName); + assertEquals(expectedAfter, route.getName()); + } + + @Test + public void getLocationsTest(){ + List expected = new ArrayList<>(); + + assertEquals(expected, route.getLocations()); + } + + @Test + public void SetLocationsTest(){ + List testList = new ArrayList<>(); + testList.add(new Location("name1", "coord1", "desc1", null)); + testList.add(new Location("name2", "coord2", "desc2", null)); + testList.add(new Location("name3", "coord3", "desc3", null)); + + List expectedBefore = new ArrayList<>(); + List expectedAfter = testList; + + assertEquals(expectedBefore, route.getLocations()); + route.setLocations(testList); + assertEquals(expectedAfter, route.getLocations()); + } + + @Test + public void AddLocationTest(){ + Location testLocation = new Location("testLocationName", "testCoordinates", "testDescription", null); + + List expectedBefore = new ArrayList<>(); + List expectedAfter = new ArrayList<>(); + expectedAfter.add(testLocation); + + assertEquals(expectedBefore, route.getLocations()); + route.addLocation(testLocation); + assertEquals(expectedAfter, route.getLocations()); + } + + @Test + public void totalDistanceTest(){ + float testDistance = 523; + + float expectedBefore = 0; + float expectedAfter = 523; + + assertEquals(expectedBefore, route.getTotalDistance(), 0.01); + route.setTotalDistance(testDistance); + assertEquals(expectedAfter, route.getTotalDistance(), 0.01); + } + + @Test + public void totalTimeTest(){ + int testTime = 36; + + int expectedBefore = 0; + int expectedAfter = 36; + + assertEquals(expectedBefore, route.getTotalTime()); + route.setTotalTime(testTime); + assertEquals(expectedAfter, route.getTotalTime()); + } + +}