├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── layout
│ │ │ │ ├── dummy.xml
│ │ │ │ ├── constraint.xml
│ │ │ │ ├── loader_layout.xml
│ │ │ │ ├── activity_maps.xml
│ │ │ │ ├── fragment_favourite_locations.xml
│ │ │ │ └── card_address.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable
│ │ │ │ ├── ic_star_defualt_24dp.xml
│ │ │ │ ├── ic_star_favourites_24dp.xml
│ │ │ │ ├── ic_drive_eta_black_24dp.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ └── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ ├── java
│ │ │ └── lingaraj
│ │ │ │ └── hourglass
│ │ │ │ └── in
│ │ │ │ └── letswalk
│ │ │ │ ├── Constants.java
│ │ │ │ ├── letswalkscreen
│ │ │ │ ├── LocationRequestCallback.java
│ │ │ │ ├── GeoDecoderCallback.java
│ │ │ │ ├── RepoCallbacks.java
│ │ │ │ ├── di
│ │ │ │ │ ├── LetsWalkActivityComponent.java
│ │ │ │ │ ├── MainScreenBindingModule.java
│ │ │ │ │ └── FavouriteLocationsComponent.java
│ │ │ │ ├── FusedLocationCallback.java
│ │ │ │ ├── LetsWalkViewModel.java
│ │ │ │ ├── AddressAdapter.java
│ │ │ │ ├── parser
│ │ │ │ │ └── PolyLineParser.java
│ │ │ │ ├── FavouriteLocationsFragment.java
│ │ │ │ ├── Repository.java
│ │ │ │ ├── AppLocationManager.java
│ │ │ │ └── LetsWalkActivity.java
│ │ │ │ ├── GoogleAPIStatusException.java
│ │ │ │ ├── di
│ │ │ │ ├── ActivityScope.java
│ │ │ │ ├── ForScreen.java
│ │ │ │ ├── FragmentScope.java
│ │ │ │ ├── components
│ │ │ │ │ ├── ScreenComponent.java
│ │ │ │ │ └── ApplicationComponent.java
│ │ │ │ ├── DisposableManager.java
│ │ │ │ ├── ViewModelKey.java
│ │ │ │ ├── modules
│ │ │ │ │ ├── ScreenModule.java
│ │ │ │ │ ├── ApplicationModule.java
│ │ │ │ │ ├── ActivityBindingModule.java
│ │ │ │ │ ├── ViewModelBindingModule.java
│ │ │ │ │ └── NetworkModule.java
│ │ │ │ ├── injectors
│ │ │ │ │ ├── Injector.java
│ │ │ │ │ ├── ActivityInjector.java
│ │ │ │ │ └── FragmentInjector.java
│ │ │ │ └── BaseViewModelFactory.java
│ │ │ │ ├── rest
│ │ │ │ ├── response
│ │ │ │ │ ├── Location.java
│ │ │ │ │ ├── Legs.java
│ │ │ │ │ ├── distanceresponse
│ │ │ │ │ │ ├── Row.java
│ │ │ │ │ │ ├── Distance.java
│ │ │ │ │ │ ├── Element.java
│ │ │ │ │ │ └── DistanceResult.java
│ │ │ │ │ ├── OverviewPolyLine.java
│ │ │ │ │ ├── Route.java
│ │ │ │ │ ├── DirectionResults.java
│ │ │ │ │ └── Steps.java
│ │ │ │ ├── di
│ │ │ │ │ └── RestAPISModule.java
│ │ │ │ └── DirectionAPIEndpoints.java
│ │ │ │ ├── utils
│ │ │ │ ├── DistanceCalculator.java
│ │ │ │ └── MarshmallowPermissions.java
│ │ │ │ └── BaseApplication.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── lingaraj
│ │ │ └── hourglass
│ │ │ └── in
│ │ │ ├── ridegmap
│ │ │ └── ExampleUnitTest.java
│ │ │ └── letswalk
│ │ │ └── letswalkscreen
│ │ │ └── LetsWalkViewModelTest.java
│ ├── androidTest
│ │ └── java
│ │ │ └── lingaraj
│ │ │ └── hourglass
│ │ │ └── in
│ │ │ └── ridegmap
│ │ │ └── ExampleInstrumentedTest.java
│ ├── release
│ │ └── res
│ │ │ └── values
│ │ │ └── google_maps_api.xml
│ └── debug
│ │ └── res
│ │ └── values
│ │ └── google_maps_api.xml
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gmap.iml
├── .gitignore
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lingarajsankaravelu/letswalk/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/Constants.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk;
2 |
3 | public class Constants {
4 | public static final String INSTANCE_ID = "instance_id";
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/LocationRequestCallback.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | public interface LocationRequestCallback {
4 | void onLocationRequestCancelled();
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 20sp
5 | 8dp
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/GeoDecoderCallback.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Address;
4 |
5 | public interface GeoDecoderCallback {
6 | void decodedAddressDetails(Address address);
7 | }
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 04 12:33:12 IST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dummy.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/GoogleAPIStatusException.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk;
2 |
3 | public class GoogleAPIStatusException extends Exception {
4 | public GoogleAPIStatusException() {
5 | super("GOOGLE MAPS API Status does not return okay");
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 | #9E9E9E
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/ActivityScope.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import javax.inject.Scope;
6 |
7 | @Scope
8 | @Retention(RetentionPolicy.RUNTIME)
9 | public @interface ActivityScope {
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/ForScreen.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import javax.inject.Qualifier;
6 |
7 | @Qualifier
8 | @Retention(RetentionPolicy.RUNTIME)
9 | public @interface ForScreen {
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/FragmentScope.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import javax.inject.Scope;
6 |
7 | @Scope
8 | @Retention(RetentionPolicy.RUNTIME)
9 | public @interface FragmentScope {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/Location.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | public class Location {
4 | private double lat;
5 | private double lng;
6 |
7 | public double getLat() {
8 | return lat;
9 | }
10 |
11 | public double getLng() {
12 | return lng;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/Legs.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | public class Legs implements Serializable {
7 | private List steps;
8 |
9 | public List getSteps() {
10 | return steps;
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/constraint.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/RepoCallbacks.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Address;
4 | import com.google.android.gms.maps.model.PolylineOptions;
5 | import java.util.List;
6 |
7 | public interface RepoCallbacks {
8 | void onSuccess(List polyLines);
9 | void onFailure();
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/distanceresponse/Row.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response.distanceresponse;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | public class Row implements Serializable {
7 | private List elements;
8 |
9 | public List getElements() {
10 | return elements;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_defualt_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_favourites_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/OverviewPolyLine.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import java.io.Serializable;
5 |
6 | public class OverviewPolyLine implements Serializable {
7 |
8 | @SerializedName("points")
9 | public String points;
10 |
11 | public String getPoints() {
12 | return points;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/distanceresponse/Distance.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response.distanceresponse;
2 |
3 | import java.io.Serializable;
4 |
5 | class Distance implements Serializable {
6 | private String text;
7 | private long value;
8 |
9 | public String getText() {
10 | return text;
11 | }
12 |
13 | public long getValue() {
14 | return value;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/components/ScreenComponent.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.components;
2 |
3 | import dagger.android.AndroidInjector;
4 | import lingaraj.hourglass.in.letswalk.di.DisposableManager;
5 | import lingaraj.hourglass.in.letswalk.di.ForScreen;
6 |
7 | public interface ScreenComponent extends AndroidInjector {
8 |
9 | @ForScreen
10 | DisposableManager disposableManager();
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/test/java/lingaraj/hourglass/in/ridegmap/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.ridegmap;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test public void addition_isCorrect() {
14 | assertEquals(4, 2 + 2);
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/Route.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import java.util.List;
5 |
6 | public class Route {
7 | @SerializedName("overview_polyline") private OverviewPolyLine overviewPolyLine;
8 |
9 | private List legs;
10 |
11 | public OverviewPolyLine getOverviewPolyLine() {
12 | return overviewPolyLine;
13 | }
14 |
15 | public List getLegs() {
16 | return legs;
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/DisposableManager.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 | import io.reactivex.disposables.CompositeDisposable;
4 | import io.reactivex.disposables.Disposable;
5 |
6 | public class DisposableManager {
7 |
8 | private final CompositeDisposable compositeDisposable = new CompositeDisposable();
9 |
10 | public void add(Disposable... disposables) {
11 | compositeDisposable.addAll(disposables);
12 | }
13 |
14 | public void dispose() {
15 | compositeDisposable.clear();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/ViewModelKey.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 | import androidx.lifecycle.ViewModel;
4 | import dagger.MapKey;
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 | import java.lang.annotation.Target;
10 |
11 | @Documented
12 | @Target(ElementType.METHOD)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @MapKey
15 | public @interface ViewModelKey {
16 | Class extends ViewModel> value();
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/di/RestAPISModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.di;
2 |
3 | import dagger.Module;
4 | import dagger.Provides;
5 | import javax.inject.Singleton;
6 | import lingaraj.hourglass.in.letswalk.rest.DirectionAPIEndpoints;
7 | import retrofit2.Retrofit;
8 |
9 | @Module
10 | public abstract class RestAPISModule {
11 |
12 |
13 | @Provides @Singleton
14 | static DirectionAPIEndpoints providesDirectionsAPIEndpoints(Retrofit retrofit) {
15 | return retrofit.create(DirectionAPIEndpoints.class);
16 | }
17 |
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/distanceresponse/Element.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response.distanceresponse;
2 |
3 | import java.io.Serializable;
4 |
5 | public class Element implements Serializable {
6 |
7 | private Distance distance;
8 | private Distance duration;
9 | private String status;
10 |
11 | public Distance getDistance() {
12 | return distance;
13 | }
14 |
15 | public Distance getDuration() {
16 | return duration;
17 | }
18 |
19 | public String getStatus() {
20 | return status;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/DirectionResults.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import java.io.Serializable;
5 | import java.util.List;
6 |
7 | public class DirectionResults implements Serializable {
8 |
9 | private String status;
10 | @SerializedName("routes")
11 | private List routes;
12 |
13 | public String getStatus() {
14 | return status;
15 | }
16 |
17 |
18 | public List getRoutes() {
19 | return routes;
20 | }}
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/Steps.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response;
2 |
3 | import java.io.Serializable;
4 |
5 | public class Steps implements Serializable {
6 | private Location start_location;
7 | private Location end_location;
8 | private OverviewPolyLine polyline;
9 |
10 | public Location getStart_location() {
11 | return start_location;
12 | }
13 |
14 | public Location getEnd_location() {
15 | return end_location;
16 | }
17 |
18 | public OverviewPolyLine getPolyline() {
19 | return polyline;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/modules/ScreenModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.modules;
2 | import dagger.Module;
3 | import dagger.Provides;
4 | import lingaraj.hourglass.in.letswalk.di.DisposableManager;
5 | import lingaraj.hourglass.in.letswalk.di.ForScreen;
6 | import lingaraj.hourglass.in.letswalk.di.FragmentScope;
7 |
8 | @Module
9 | public abstract class ScreenModule {
10 |
11 | @Provides
12 | @FragmentScope
13 | @ForScreen
14 | static DisposableManager provideDisposableManager() {
15 | return new DisposableManager();
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_drive_eta_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/response/distanceresponse/DistanceResult.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest.response.distanceresponse;
2 |
3 | import java.io.Serializable;
4 | import java.util.List;
5 |
6 | public class DistanceResult implements Serializable {
7 | private String status;
8 | private List destination_address;
9 | private List origin_addresses;
10 | private List rows;
11 |
12 | public String getStatus() {
13 | return status;
14 | }
15 |
16 | public List getDestination_address() {
17 | return destination_address;
18 | }
19 |
20 | public List getOrigin_addresses() {
21 | return origin_addresses;
22 | }
23 |
24 | public List getRows() {
25 | return rows;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/di/LetsWalkActivityComponent.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen.di;
2 |
3 | import dagger.Subcomponent;
4 | import dagger.android.AndroidInjector;
5 | import lingaraj.hourglass.in.letswalk.di.ActivityScope;
6 | import lingaraj.hourglass.in.letswalk.letswalkscreen.LetsWalkActivity;
7 |
8 | @ActivityScope
9 | @Subcomponent(modules = {
10 | MainScreenBindingModule.class,
11 |
12 | })
13 | public interface LetsWalkActivityComponent extends AndroidInjector {
14 |
15 | @Subcomponent.Builder
16 | abstract class Builder extends AndroidInjector.Builder {
17 |
18 | @Override
19 | public void seedInstance(LetsWalkActivity instance) {
20 |
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/utils/DistanceCalculator.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.utils;
2 |
3 | public class DistanceCalculator {
4 | public static double distance(double lat1, double lon1, double lat2, double lon2) {
5 | double theta = lon1 - lon2;
6 | double dist = Math.sin(deg2rad(lat1))
7 | * Math.sin(deg2rad(lat2))
8 | + Math.cos(deg2rad(lat1))
9 | * Math.cos(deg2rad(lat2))
10 | * Math.cos(deg2rad(theta));
11 | dist = Math.acos(dist);
12 | dist = rad2deg(dist);
13 | dist = dist * 60 * 1.1515;
14 | return (dist);
15 | }
16 |
17 | private static double deg2rad(double deg) {
18 | return (deg * Math.PI / 180.0);
19 | }
20 |
21 | private static double rad2deg(double rad) {
22 | return (rad * 180.0 / Math.PI);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/modules/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.modules;
2 |
3 | import com.patloew.rxlocation.RxLocation;
4 | import dagger.Module;
5 | import dagger.Provides;
6 | import lingaraj.hourglass.in.letswalk.BaseApplication;
7 |
8 | @Module
9 | public class ApplicationModule {
10 |
11 | private final BaseApplication baseApplication;
12 | private final RxLocation rxLocation;
13 |
14 | public ApplicationModule(BaseApplication baseApplication) {
15 | this.baseApplication = baseApplication;
16 | this.rxLocation = new RxLocation(baseApplication);
17 | }
18 |
19 | @Provides
20 | BaseApplication providesApplicationContext(){
21 | return baseApplication;
22 | }
23 |
24 | @Provides
25 | RxLocation providesRxLocation(){ return rxLocation;}
26 | }
27 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/di/MainScreenBindingModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen.di;
2 |
3 | import androidx.fragment.app.Fragment;
4 | import dagger.Binds;
5 | import dagger.Module;
6 | import dagger.android.AndroidInjector;
7 | import dagger.android.support.FragmentKey;
8 | import dagger.multibindings.IntoMap;
9 | import lingaraj.hourglass.in.letswalk.letswalkscreen.FavouriteLocationsFragment;
10 |
11 | @Module(subcomponents = {
12 | FavouriteLocationsComponent.class
13 |
14 | })
15 | public abstract class MainScreenBindingModule {
16 |
17 | @Binds
18 | @IntoMap
19 | @FragmentKey(FavouriteLocationsFragment.class)
20 | abstract AndroidInjector.Factory extends Fragment> bindSplashController(FavouriteLocationsComponent.Builder builder);
21 |
22 |
23 |
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/modules/ActivityBindingModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.modules;
2 |
3 | import android.app.Activity;
4 | import dagger.Binds;
5 | import dagger.Module;
6 | import dagger.android.ActivityKey;
7 | import dagger.android.AndroidInjector;
8 | import dagger.multibindings.IntoMap;
9 | import lingaraj.hourglass.in.letswalk.letswalkscreen.LetsWalkActivity;
10 | import lingaraj.hourglass.in.letswalk.letswalkscreen.di.LetsWalkActivityComponent;
11 |
12 | @Module(subcomponents = {
13 | LetsWalkActivityComponent.class
14 | })
15 | public abstract class ActivityBindingModule {
16 |
17 | @Binds
18 | @IntoMap
19 | @ActivityKey(LetsWalkActivity.class)
20 | abstract AndroidInjector.Factory extends Activity> provideMainActivityInjector(LetsWalkActivityComponent.Builder builder);
21 |
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/lingaraj/hourglass/in/ridegmap/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.ridegmap;
2 |
3 | import android.content.Context;
4 | import androidx.test.InstrumentationRegistry;
5 | import androidx.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest {
18 | @Test public void useAppContext() {
19 | // Context of the app under test.
20 | Context appContext = InstrumentationRegistry.getTargetContext();
21 |
22 | assertEquals("lingaraj.hourglass.in.ridegmap", appContext.getPackageName());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | android.enableAapt2=false
12 | org.gradle.jvmargs=-Xmx1536m
13 | # When configured, Gradle will run in incubating parallel mode.
14 | # This option should only be used with decoupled projects. More details, visit
15 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
16 | # org.gradle.parallel=true
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/modules/ViewModelBindingModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.modules;
2 |
3 | import androidx.lifecycle.ViewModel;
4 | import androidx.lifecycle.ViewModelProvider;
5 | import dagger.Binds;
6 | import dagger.Module;
7 | import dagger.multibindings.IntoMap;
8 | import lingaraj.hourglass.in.letswalk.di.BaseViewModelFactory;
9 | import lingaraj.hourglass.in.letswalk.di.ViewModelKey;
10 | import lingaraj.hourglass.in.letswalk.letswalkscreen.LetsWalkViewModel;
11 |
12 | @Module
13 | public abstract class ViewModelBindingModule {
14 |
15 | @Binds
16 | @IntoMap
17 | @ViewModelKey(LetsWalkViewModel.class)
18 | abstract ViewModel providesLetsWalkViewModel(LetsWalkViewModel letsWalkViewModel);
19 |
20 | @Binds
21 | abstract ViewModelProvider.Factory bindsViewModelFactory(BaseViewModelFactory baseViewModelFactory);
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/rest/DirectionAPIEndpoints.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.rest;
2 |
3 | import io.reactivex.Single;
4 | import lingaraj.hourglass.in.letswalk.rest.response.DirectionResults;
5 | import lingaraj.hourglass.in.letswalk.rest.response.distanceresponse.DistanceResult;
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Query;
8 |
9 | public interface DirectionAPIEndpoints {
10 |
11 | @GET("/maps/api/directions/json")
12 | Single getJson(@Query("origin") String origin,@Query("destination") String destination,@Query("waypoints") String waypoints,@Query("mode") String mode, @Query("key") String Key);
13 |
14 | @GET("/maps/api/distancematrix/json")
15 | Single getDistance(@Query("origins") String origin,@Query("destinations") String destination,@Query("mode") String mode, @Query("key") String Key);
16 | }
17 |
--------------------------------------------------------------------------------
/gmap.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/release/res/values/google_maps_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 | YOUR_KEY_HERE
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Let\'s Walk
3 | Map
4 | Sorry, you cannot mark more than four locations in map
5 | Loading
6 | Please Provide Necessary Permissions to Continue!
7 | Grant Permissions
8 | Favourites
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vitae nunc et sapien tristique ornare ut in diam. Etiam non sapien vitae turpis pulvinar ullamcorper nec vitae justo. Donec convallis porttitor sem, eu semper arcu faucibus in. Nunc ligula erat, ornare vitae odio vel, interdum elementum neque.
10 | California
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/components/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.components;
2 |
3 | import dagger.Component;
4 | import javax.inject.Singleton;
5 | import lingaraj.hourglass.in.letswalk.BaseApplication;
6 | import lingaraj.hourglass.in.letswalk.di.modules.ActivityBindingModule;
7 | import lingaraj.hourglass.in.letswalk.di.modules.ApplicationModule;
8 | import lingaraj.hourglass.in.letswalk.di.modules.NetworkModule;
9 | import lingaraj.hourglass.in.letswalk.di.modules.ViewModelBindingModule;
10 | import lingaraj.hourglass.in.letswalk.rest.di.RestAPISModule;
11 |
12 | @Singleton
13 | @Component(modules = {
14 | ApplicationModule.class,
15 | ViewModelBindingModule.class,
16 | NetworkModule.class,
17 | RestAPISModule.class,
18 | ActivityBindingModule.class
19 | })
20 | public interface ApplicationComponent {
21 | void inject(BaseApplication baseApplication);
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/di/FavouriteLocationsComponent.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen.di;
2 |
3 | import dagger.Subcomponent;
4 | import dagger.android.AndroidInjector;
5 | import lingaraj.hourglass.in.letswalk.di.FragmentScope;
6 | import lingaraj.hourglass.in.letswalk.di.components.ScreenComponent;
7 | import lingaraj.hourglass.in.letswalk.di.modules.ScreenModule;
8 | import lingaraj.hourglass.in.letswalk.letswalkscreen.FavouriteLocationsFragment;
9 |
10 |
11 | @FragmentScope
12 | @Subcomponent(modules ={ ScreenModule.class } )
13 | public interface FavouriteLocationsComponent extends ScreenComponent {
14 |
15 | @Subcomponent.Builder
16 | abstract class Builder extends AndroidInjector.Builder {
17 |
18 | @Override
19 | public void seedInstance(FavouriteLocationsFragment instance) {
20 |
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | /*/build/
3 |
4 | # Crashlytics configuations
5 | com_crashlytics_export_strings.xml
6 |
7 | # Local configuration file (sdk path, etc)
8 | local.properties
9 |
10 | # Gradle generated files
11 | .gradle/
12 |
13 | # Signing files
14 | .signing/
15 |
16 | # User-specific configurations
17 | .idea/
18 | .idea/libraries/
19 | .idea/workspace.xml
20 | .idea/tasks.xml
21 | .idea/.name
22 | .idea/compiler.xml
23 | .idea/copyright/profiles_settings.xml
24 | .idea/encodings.xml
25 | .idea/misc.xml
26 | .idea/modules.xml
27 | .idea/scopes/scope_settings.xml
28 | .idea/vcs.xml
29 | .idea/caches/
30 | .idea/codeStyles/
31 |
32 | # OS-specific files
33 | .DS_Store
34 | .DS_Store?
35 | ._*
36 | .Spotlight-V100
37 | .Trashes
38 | ehthumbs.db
39 | Thumbs.db
40 |
41 | app/.idea/workspace.xml
42 | build/intermediates/dex-cache/cache.xml
43 | build/android-profile/*
44 | build/generated/*
45 | build/intermediates/progurad-files/*
46 |
47 | /openCVLibrary310
48 | openCVLibrary310/build.gradle
49 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/injectors/Injector.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.injectors;
2 |
3 | import android.app.Activity;
4 | import androidx.fragment.app.Fragment;
5 | import lingaraj.hourglass.in.letswalk.letswalkscreen.FavouriteLocationsFragment;
6 | import lingaraj.hourglass.in.letswalk.letswalkscreen.LetsWalkActivity;
7 |
8 | public class Injector {
9 |
10 | private Injector() {
11 |
12 | }
13 |
14 | public static void inject(Activity activity) {
15 | ActivityInjector.get(activity).inject(activity);
16 | }
17 |
18 | public static void clearComponent(Activity activity) {
19 | ActivityInjector.get(activity).clear(activity);
20 | }
21 |
22 | public static void inject(Fragment fragment) {
23 | FragmentInjector.get(fragment.getActivity()).inject(fragment);
24 | }
25 |
26 | public static void clearComponent(Fragment fragment) {
27 | FragmentInjector.get(fragment.getActivity()).clear(fragment);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/loader_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
21 |
26 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/debug/res/values/google_maps_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 | AIzaSyCtAxMqGpvZg_blHrub0Ke5_WADxDRBjUk
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/BaseApplication.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import javax.inject.Inject;
6 | import lingaraj.hourglass.in.letswalk.di.components.ApplicationComponent;
7 | import lingaraj.hourglass.in.letswalk.di.components.DaggerApplicationComponent;
8 | import lingaraj.hourglass.in.letswalk.di.injectors.ActivityInjector;
9 | import lingaraj.hourglass.in.letswalk.di.modules.ApplicationModule;
10 |
11 | public class BaseApplication extends Application {
12 |
13 | private ApplicationComponent component;
14 | @Inject ActivityInjector activityInjector;
15 |
16 | @Override
17 | public void onCreate() {
18 | super.onCreate();
19 | component = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
20 | component.inject(this);
21 |
22 | }
23 |
24 | public ApplicationComponent getComponent() {
25 | return component;
26 | }
27 |
28 | public static BaseApplication get(Context context) {
29 | return (BaseApplication) context.getApplicationContext();
30 | }
31 |
32 | public ActivityInjector getActivityInjector() {
33 | return activityInjector;
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_maps.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
12 |
13 |
17 |
18 |
24 |
25 |
26 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/FusedLocationCallback.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Location;
4 | import com.google.android.gms.location.LocationAvailability;
5 | import com.google.android.gms.location.LocationCallback;
6 | import com.google.android.gms.location.LocationResult;
7 |
8 | public class FusedLocationCallback extends LocationCallback {
9 |
10 | private final LocationResultCallbacks callbacks;
11 |
12 |
13 | public FusedLocationCallback(LocationResultCallbacks callbacks) {
14 | this.callbacks = callbacks;
15 | }
16 |
17 | @Override public void onLocationResult(LocationResult locationResult) {
18 | super.onLocationResult(locationResult);
19 | this.callbacks.onLocationResult(locationResult);
20 | }
21 |
22 | @Override
23 | public void onLocationAvailability(LocationAvailability locationAvailability) {
24 | super.onLocationAvailability(locationAvailability);
25 | this.callbacks.onLocationAvailability(locationAvailability);
26 | }
27 |
28 | interface LocationResultCallbacks {
29 | void onLocationChanged(Location location);
30 |
31 | void onLocationResult(LocationResult locationResult);
32 | void onLocationAvailability(LocationAvailability locationAvailability);
33 | }
34 |
35 |
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favourite_locations.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
24 |
25 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/modules/NetworkModule.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.modules;
2 |
3 | import android.location.Geocoder;
4 | import dagger.Module;
5 | import dagger.Provides;
6 | import java.util.concurrent.TimeUnit;
7 | import javax.inject.Singleton;
8 | import okhttp3.OkHttpClient;
9 | import okhttp3.logging.HttpLoggingInterceptor;
10 | import retrofit2.Retrofit;
11 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
12 | import retrofit2.converter.gson.GsonConverterFactory;
13 |
14 | @Module
15 | public class NetworkModule {
16 |
17 | static final String BASE_URL = "https://maps.googleapis.com/";
18 |
19 | @Provides
20 | @Singleton
21 | static OkHttpClient providesOkhttpClient() {
22 | HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
23 | logging.setLevel(HttpLoggingInterceptor.Level.BODY);
24 | OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
25 | httpClient.addInterceptor(logging);
26 | httpClient.readTimeout(1, TimeUnit.MINUTES);
27 | httpClient.connectTimeout(1, TimeUnit.MINUTES);
28 | return httpClient.build();
29 | }
30 |
31 | @Provides
32 | @Singleton
33 | static Retrofit providesRetrofit(){
34 | return new Retrofit.Builder()
35 | .addConverterFactory(GsonConverterFactory.create())
36 | .client(providesOkhttpClient())
37 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
38 | .baseUrl(BASE_URL)
39 | .build();
40 |
41 | }
42 |
43 |
44 |
45 |
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/utils/MarshmallowPermissions.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.utils;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.pm.PackageManager;
6 | import android.widget.Toast;
7 | import androidx.core.app.ActivityCompat;
8 | import androidx.core.content.ContextCompat;
9 |
10 | public class MarshmallowPermissions {
11 |
12 | public static final int LOCATION_PERMISSION_REQUEST_CODE = 103;
13 | private static final String[] LOCATIONS_PERMISSIONS = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION };
14 |
15 | public static boolean arePermissionsGranted(Activity activity){
16 | int result1 = ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION);
17 | int result2 = ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION);
18 | return result1 == PackageManager.PERMISSION_GRANTED
19 | && result2 == PackageManager.PERMISSION_GRANTED;
20 | }
21 |
22 | public static void requestPermissions(Activity activity){
23 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity,Manifest.permission.ACCESS_COARSE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale(activity,Manifest.permission.ACCESS_FINE_LOCATION)){
24 | Toast.makeText(activity, "Please Provided Location Permission. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
25 | }
26 | else {
27 | ActivityCompat.requestPermissions(activity, LOCATIONS_PERMISSIONS,
28 | LOCATION_PERMISSION_REQUEST_CODE);
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/injectors/ActivityInjector.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.injectors;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import dagger.android.AndroidInjector;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import javax.inject.Inject;
9 | import javax.inject.Provider;
10 | import lingaraj.hourglass.in.letswalk.BaseApplication;
11 |
12 | public class ActivityInjector {
13 |
14 | private final Map, Provider>> activityInjectors;
15 | private final Map> cache = new HashMap<>();
16 | private final String instanceId = "1";
17 |
18 | @Inject
19 | ActivityInjector(Map, Provider>> activityInjectors) {
20 |
21 | this.activityInjectors = activityInjectors;
22 | }
23 |
24 | void inject(Activity activity) {
25 | if(cache.containsKey(instanceId)) {
26 | ((AndroidInjector) cache.get(instanceId)).inject(activity);
27 | return;
28 | }
29 |
30 | AndroidInjector.Factory injectorFactory = (AndroidInjector.Factory) activityInjectors.get(activity.getClass()).get();
31 | AndroidInjector injector = injectorFactory.create(activity);
32 | cache.put(instanceId, injector);
33 | injector.inject(activity);
34 | }
35 |
36 | void clear(Activity activity) {
37 | cache.remove(instanceId);
38 | }
39 |
40 | static ActivityInjector get(Context context) {
41 | return ((BaseApplication) context.getApplicationContext()).getActivityInjector();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/BaseViewModelFactory.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di;
2 |
3 |
4 | import android.util.Log;
5 | import androidx.annotation.NonNull;
6 | import androidx.lifecycle.ViewModel;
7 | import androidx.lifecycle.ViewModelProvider;
8 | import java.util.Map;
9 | import javax.inject.Inject;
10 | import javax.inject.Provider;
11 | import javax.inject.Singleton;
12 |
13 | @Singleton
14 | public class BaseViewModelFactory implements ViewModelProvider.Factory {
15 |
16 | private final String TAG = "BaseViewModelFact";
17 | private final Map, Provider> mProviderMap;
18 |
19 |
20 | @Inject
21 | BaseViewModelFactory(Map, Provider> providerMap) {
22 | mProviderMap = providerMap;
23 | }
24 |
25 | @SuppressWarnings("unchecked")
26 | @NonNull
27 | @Override
28 | public T create(@NonNull Class modelClass) {
29 | Provider extends ViewModel> creator = mProviderMap.get(modelClass);
30 | if (creator == null) {
31 | Log.d(TAG,"No previous model found in map:"+modelClass.getSimpleName());
32 | for (Map.Entry, Provider> entry : mProviderMap.entrySet()) {
33 | if (modelClass.isAssignableFrom(entry.getKey())) {
34 | creator = entry.getValue();
35 | Log.d(TAG,"Created key for model in map:"+modelClass.getSimpleName()+"->"+entry.getKey());
36 | break;
37 | }
38 | }
39 | }
40 | if (creator == null) {
41 | Log.d(TAG,"Unkown model class:"+modelClass.getSimpleName());
42 | throw new IllegalArgumentException("unknown model class " + modelClass);
43 | }
44 | try {
45 | return (T) creator.get();
46 | } catch (Exception e) {
47 | Log.e(TAG,e.toString());
48 | throw new RuntimeException(e);
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
31 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
25 |
26 |
38 |
39 |
45 |
46 |
47 | 16dp
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/di/injectors/FragmentInjector.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.di.injectors;
2 |
3 | import android.app.Activity;
4 | import android.util.Log;
5 | import androidx.fragment.app.Fragment;
6 | import dagger.android.AndroidInjector;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import java.util.Objects;
10 | import javax.inject.Inject;
11 | import javax.inject.Provider;
12 | import lingaraj.hourglass.in.letswalk.di.ActivityScope;
13 | import lingaraj.hourglass.in.letswalk.letswalkscreen.FavouriteLocationsFragment;
14 | import lingaraj.hourglass.in.letswalk.letswalkscreen.LetsWalkActivity;
15 |
16 | @ActivityScope
17 | public class FragmentInjector {
18 |
19 | private final String TAG = "Screen Injector";
20 | private final Map, Provider>> screenInjectors;
21 | private final Map> cache = new HashMap<>();
22 | private final String instanceId = "2";
23 |
24 | @Inject FragmentInjector(Map, Provider>> screenInjectors) {
25 | this.screenInjectors = screenInjectors;
26 | }
27 |
28 | void inject(Fragment fragment) {
29 | if (cache.containsKey(instanceId)) {
30 | Objects.requireNonNull(cache.get(instanceId)).inject(fragment);
31 | return;
32 | }
33 |
34 | //noinspection unchecked
35 | Log.d(TAG,"Injecting Fragment:" + fragment.getClass());
36 | AndroidInjector.Factory injectorFactory =
37 | (AndroidInjector.Factory) Objects.requireNonNull(screenInjectors.get(fragment.getClass())).get();
38 | if(injectorFactory != null) {
39 | AndroidInjector injector = injectorFactory.create(fragment);
40 | cache.put(instanceId, injector);
41 | injector.inject(fragment);
42 | }
43 | }
44 |
45 | void clear(Fragment fragment) {
46 | cache.remove(instanceId);
47 | }
48 |
49 | static FragmentInjector get(Activity activity) {
50 | return ((LetsWalkActivity) activity).getFragmentInjector();
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/LetsWalkViewModel.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Address;
4 | import android.util.Log;
5 | import androidx.lifecycle.MutableLiveData;
6 | import com.google.android.gms.maps.model.Marker;
7 | import com.google.android.gms.maps.model.PolylineOptions;
8 | import com.google.gson.Gson;
9 | import java.util.List;
10 | import java.util.Map;
11 | import javax.inject.Inject;
12 |
13 | public class LetsWalkViewModel extends androidx.lifecycle.ViewModel {
14 |
15 |
16 | private final Repository repository;
17 | private MutableLiveData decodedAddress = new MutableLiveData();
18 | private MutableLiveData network_loader = new MutableLiveData<>();
19 | private MutableLiveData messages = new MutableLiveData<>();
20 | private MutableLiveData> poly_lines = new MutableLiveData<>();
21 |
22 | public MutableLiveData getDecodedAddress() {
23 | return decodedAddress;
24 | }
25 |
26 | public MutableLiveData getNetwork_loader() {
27 | return network_loader;
28 | }
29 |
30 | public MutableLiveData getMessages() {
31 | return messages;
32 | }
33 |
34 | public MutableLiveData> getPoly_lines() {
35 | return poly_lines;
36 | }
37 |
38 | @Inject
39 | public LetsWalkViewModel(Repository repository) {
40 | this.repository = repository;
41 | }
42 |
43 |
44 |
45 |
46 | public void drawRoute(Map markerMap,String apiKey){
47 | network_loader.postValue(true);
48 | repository.parseRouteInformation(markerMap,apiKey ,new RepoCallbacks() {
49 | @Override public void onSuccess(List polyLines) {
50 | poly_lines.postValue(polyLines);
51 | network_loader.postValue(false);
52 | }
53 |
54 | @Override public void onFailure() {
55 | network_loader.postValue(false);
56 | messages.postValue( "Error Connecting to network! Try again");
57 |
58 | }
59 | });
60 | }
61 |
62 | public void decodeMarkerLocation(double latitude, double longitude) {
63 | repository.reverseGeocode(latitude, longitude, new GeoDecoderCallback() {
64 | @Override
65 | public void decodedAddressDetails(Address address) {
66 | Log.d("ViewModel:",new Gson().toJson(address));
67 | decodedAddress.postValue(address);
68 | }
69 | });
70 |
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/card_address.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
17 |
18 |
33 |
34 |
47 |
48 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/AddressAdapter.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.content.Context;
4 | import android.location.Address;
5 | import android.view.LayoutInflater;
6 | import android.view.ViewGroup;
7 | import androidx.annotation.NonNull;
8 | import androidx.databinding.DataBindingUtil;
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 |
12 | import android.view.View;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import lingaraj.hourglass.in.ridegmap.R;
16 | import lingaraj.hourglass.in.ridegmap.databinding.CardAddressBinding;
17 |
18 | public class AddressAdapter extends RecyclerView.Adapter {
19 |
20 | private final Context mcontext;
21 | private final List addresses = new ArrayList();
22 | private final List favourites = new ArrayList<>();
23 | private final FavouriteLocationsFragment.FavouriteClick mclick;
24 |
25 | public AddressAdapter(Context context, FavouriteLocationsFragment.FavouriteClick favouriteClick){
26 | this.mcontext = context;
27 | this.mclick = favouriteClick;
28 | }
29 |
30 | @NonNull @Override
31 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
32 | View view = LayoutInflater.from(mcontext).inflate(R.layout.card_address,parent);
33 | view.setOnClickListener(this.mclick);
34 | return new ViewHolder(view);
35 | }
36 |
37 | @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
38 | int image_resource = favourites.contains(position)?R.drawable.ic_star_favourites_24dp:R.drawable.ic_star_defualt_24dp;
39 | Address address = this.addresses.get(position);
40 | holder.binding.streetDetails.setText(address.getFeatureName());
41 | holder.binding.country.setText(address.getLocality()+" "+address.getCountryName());
42 | holder.binding.star.setImageResource(image_resource);
43 | }
44 |
45 | public class ViewHolder extends RecyclerView.ViewHolder{
46 |
47 | public CardAddressBinding binding;
48 | public ViewHolder(@NonNull View itemView) {
49 | super(itemView);
50 | binding = DataBindingUtil.bind(itemView);
51 | }
52 | }
53 |
54 | @Override public int getItemCount() {
55 | return addresses.size();
56 | }
57 |
58 | public void notifySelection(Integer position){
59 | if (favourites.contains(position)){
60 | favourites.remove(position);
61 | }
62 | else {
63 | favourites.add(position);
64 | }
65 | notifyDataSetChanged();
66 |
67 | }
68 |
69 | public void addLocation(Address address){
70 | this.addresses.add(address);
71 | notifyDataSetChanged();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/parser/PolyLineParser.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen.parser;
2 |
3 | import android.graphics.Color;
4 | import com.google.android.gms.maps.model.LatLng;
5 | import com.google.android.gms.maps.model.PolylineOptions;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import lingaraj.hourglass.in.letswalk.GoogleAPIStatusException;
9 | import lingaraj.hourglass.in.letswalk.rest.response.DirectionResults;
10 |
11 | public class PolyLineParser {
12 |
13 |
14 | private final String TAG = this.getClass().getSimpleName();
15 | private List poly_lines = new ArrayList<>();
16 |
17 | public List getPolyLines() {
18 | return poly_lines;
19 | }
20 |
21 | public PolyLineParser(DirectionResults directionResults) throws GoogleAPIStatusException {
22 | String STATUS_OK = "OK";
23 | if (directionResults.getStatus().equals(STATUS_OK)){
24 | parse(directionResults);
25 | }
26 | else {
27 | throw new GoogleAPIStatusException();
28 | }
29 |
30 | }
31 |
32 | private void parse(DirectionResults directionResults) {
33 | if (directionResults.getRoutes().size()>=1){
34 | String poly_line_points = directionResults.getRoutes().get(0).getOverviewPolyLine().getPoints();
35 | List latLngs = decodePoly(poly_line_points);
36 | for (int z = 0; z < latLngs.size() - 1; z++) {
37 | LatLng src = latLngs.get(z);
38 | LatLng dest = latLngs.get(z + 1);
39 | PolylineOptions poly_line_option =new PolylineOptions()
40 | .add(new LatLng(src.latitude, src.longitude),
41 | new LatLng(dest.latitude, dest.longitude))
42 | .width(5).color(Color.GREEN).geodesic(true);
43 | poly_lines.add(poly_line_option);
44 | }
45 | }
46 | }
47 |
48 | private List decodePoly(String encoded) {
49 |
50 | List poly = new ArrayList();
51 | int index = 0, len = encoded.length();
52 | int lat = 0, lng = 0;
53 |
54 | while (index < len) {
55 | int b, shift = 0, result = 0;
56 | do {
57 | b = encoded.charAt(index++) - 63;
58 | result |= (b & 0x1f) << shift;
59 | shift += 5;
60 | } while (b >= 0x20);
61 | int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
62 | lat += dlat;
63 |
64 | shift = 0;
65 | result = 0;
66 | do {
67 | b = encoded.charAt(index++) - 63;
68 | result |= (b & 0x1f) << shift;
69 | shift += 5;
70 | } while (b >= 0x20);
71 | int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
72 | lng += dlng;
73 |
74 | LatLng p = new LatLng((((double) lat / 1E5)),
75 | (((double) lng / 1E5)));
76 | poly.add(p);
77 | }
78 |
79 | return poly;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/FavouriteLocationsFragment.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.content.Context;
4 | import android.location.Address;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 | import androidx.databinding.DataBindingUtil;
13 | import androidx.fragment.app.Fragment;
14 | import androidx.lifecycle.Observer;
15 | import androidx.recyclerview.widget.LinearLayoutManager;
16 | import com.google.gson.Gson;
17 | import javax.inject.Inject;
18 | import lingaraj.hourglass.in.letswalk.di.BaseViewModelFactory;
19 | import lingaraj.hourglass.in.letswalk.di.injectors.Injector;
20 | import lingaraj.hourglass.in.ridegmap.R;
21 | import lingaraj.hourglass.in.ridegmap.databinding.FragmentFavouriteLocationsBinding;
22 |
23 | public class FavouriteLocationsFragment extends Fragment {
24 |
25 | @Inject BaseViewModelFactory view_model_factory;
26 | FragmentFavouriteLocationsBinding binding;
27 | private LetsWalkViewModel view_model;
28 | private final String TAG = "FAVLocationFrags";
29 | private Context mContext;
30 | private AddressAdapter mAdapter;
31 |
32 |
33 |
34 | @Override
35 | public void onAttach(Context context) {
36 | super.onAttach(context);
37 | this.mContext = context;
38 | Injector.inject(this);
39 | view_model = view_model_factory.create(LetsWalkViewModel.class);
40 |
41 | }
42 |
43 | private void setLiveDataObservers() {
44 |
45 | view_model.getDecodedAddress().observe(this, new Observer() {
46 | @Override
47 | public void onChanged(Address address) {
48 | Log.d(TAG,"Address Recieved:\n"+new Gson().toJson(address));
49 | mAdapter.addLocation(address);
50 | }
51 | });
52 | }
53 |
54 | @Nullable @Override
55 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
56 | @Nullable Bundle savedInstanceState) {
57 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_favourite_locations,container,false);
58 | return binding.getRoot();
59 | }
60 |
61 | @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
62 | super.onActivityCreated(savedInstanceState);
63 | binding.locationList.setHasFixedSize(true);
64 | binding.locationList.setLayoutManager(new LinearLayoutManager(mContext,LinearLayoutManager.VERTICAL,false));
65 | mAdapter = new AddressAdapter(mContext,new FavouriteClick());
66 | binding.locationList.setAdapter(mAdapter);
67 | setLiveDataObservers();
68 | }
69 |
70 | public class FavouriteClick implements View.OnClickListener{
71 |
72 | @Override public void onClick(View v) {
73 | int position = binding.locationList.getChildAdapterPosition(v);
74 | mAdapter.notifySelection(position);
75 |
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/test/java/lingaraj/hourglass/in/letswalk/letswalkscreen/LetsWalkViewModelTest.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Address;
4 | import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
5 | import com.google.android.gms.maps.model.Marker;
6 | import io.reactivex.Single;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import lingaraj.hourglass.in.letswalk.letswalkscreen.parser.PolyLineParser;
10 | import lingaraj.hourglass.in.letswalk.rest.DirectionAPIEndpoints;
11 | import lingaraj.hourglass.in.letswalk.rest.response.DirectionResults;
12 | import lingaraj.hourglass.in.letswalk.rest.response.distanceresponse.DistanceResult;
13 | import org.junit.Before;
14 | import org.junit.Rule;
15 | import org.junit.Test;
16 | import org.mockito.ArgumentCaptor;
17 | import org.mockito.Captor;
18 | import org.mockito.Mock;
19 | import org.mockito.MockitoAnnotations;
20 |
21 | import static org.hamcrest.core.Is.is;
22 | import static org.junit.Assert.assertThat;
23 | import static org.mockito.ArgumentMatchers.eq;
24 | import static org.mockito.Mockito.verify;
25 | import static org.mockito.Mockito.when;
26 |
27 | public class LetsWalkViewModelTest {
28 |
29 | private LetsWalkViewModel view_model;
30 | @Rule
31 | public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
32 |
33 | @Captor
34 | private ArgumentCaptor repo_callback;
35 |
36 |
37 |
38 | String origin= "1.0,2.0";
39 | String destination = "10.0,11.9";
40 | String way_points="20.13,30.12";
41 | String mode = "walk";
42 | double latitude = 20.9999;
43 | double longitude = 35.0875;
44 | @Mock DirectionAPIEndpoints endpoints;
45 | @Mock Repository repository;
46 | @Mock PolyLineParser polyLineParser;
47 | @Mock private Map marker_map = new HashMap<>();
48 | @Mock Address address;
49 | private String api_key = "api_key";
50 | @Mock DistanceResult distance_result_response;
51 | @Mock DirectionResults direction_result_response;
52 |
53 |
54 | @Before
55 | public void setUp() throws Exception {
56 | MockitoAnnotations.initMocks(this);
57 | view_model = new LetsWalkViewModel(repository);
58 | distance_result_response = new DistanceResult();
59 | }
60 |
61 |
62 | @Test
63 | public void testRetrofit(){
64 | when(endpoints.getDistance(origin,destination,mode,api_key)).thenReturn(Single.just(distance_result_response));
65 | when(endpoints.getJson(origin,destination,way_points,mode,api_key)).thenReturn(Single.just(direction_result_response));
66 | }
67 |
68 |
69 | @Test
70 | public void testDrawRoute(){
71 | view_model.drawRoute(marker_map,api_key);
72 | setUpDirectionsCallback();
73 | repo_callback.getValue().onSuccess(polyLineParser.getPolyLines());
74 | assertThat(view_model.getPoly_lines().getValue(),is(polyLineParser.getPolyLines()));
75 | assertThat(view_model.getNetwork_loader().getValue(),is(false));
76 | }
77 |
78 | private void setUpDirectionsCallback(){
79 | verify(repository).parseRouteInformation(eq(marker_map),eq(api_key),repo_callback.capture());
80 | }
81 |
82 |
83 |
84 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android-extensions'
3 | apply plugin: 'kotlin-android'
4 |
5 | android {
6 | compileSdkVersion 28
7 | defaultConfig {
8 | applicationId "lingaraj.hourglass.in.ridegmap"
9 | minSdkVersion 19
10 | targetSdkVersion 28
11 | versionCode 1
12 | versionName "1.0"
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 | dataBinding.enabled = true
15 | vectorDrawables.useSupportLibrary = true
16 |
17 | }
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility = '1.8'
26 | targetCompatibility = '1.8'
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation fileTree(dir: 'libs', include: ['*.jar'])
32 | implementation 'androidx.appcompat:appcompat:1.1.0'
33 | implementation 'com.pnikosis:materialish-progress:1.7'
34 | implementation 'com.google.android.gms:play-services-maps:17.0.0'
35 | androidTestImplementation 'androidx.test:runner:1.1.0'
36 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
37 | implementation 'com.google.android.gms:play-services-location:17.0.0'
38 | implementation "android.arch.lifecycle:extensions:$archComponentsVersion"
39 | implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
40 | implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
41 | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
42 | implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
43 | implementation "com.google.code.gson:gson:$gsonVersion"
44 | implementation "com.squareup.retrofit2:converter-gson:$gsonConverterVersion"
45 | implementation "com.squareup.okhttp3:logging-interceptor:$loggingInterceptorVersion"
46 | implementation 'com.android.support:design:28.0.0'
47 | implementation "androidx.core:core-ktx:+"
48 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0"
49 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
50 | implementation "com.google.dagger:dagger:$daggerVersion"
51 | implementation "com.google.dagger:dagger-android-support:$daggerVersion"
52 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
53 | implementation 'com.patloew.rxlocation:rxlocation:1.0.5'
54 | annotationProcessor "com.google.dagger:dagger-android-processor:$daggerVersion"
55 | annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
56 | implementation 'com.google.code.findbugs:jsr305:3.0.2'
57 | testImplementation "android.arch.core:core-testing:$archComponentsVersion"
58 | testImplementation "org.mockito:mockito-core:$mockitoVersion"
59 | testImplementation 'junit:junit:4.12'
60 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
61 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
62 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
63 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
64 |
65 |
66 |
67 |
68 | }
69 | repositories {
70 | mavenCentral()
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/Repository.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.location.Address;
4 | import android.location.Geocoder;
5 | import android.util.Log;
6 | import com.google.android.gms.maps.model.LatLng;
7 | import com.google.android.gms.maps.model.Marker;
8 | import com.google.gson.Gson;
9 | import com.patloew.rxlocation.RxLocation;
10 | import io.reactivex.Completable;
11 | import io.reactivex.Scheduler;
12 | import io.reactivex.Single;
13 | import io.reactivex.android.schedulers.AndroidSchedulers;
14 | import io.reactivex.disposables.Disposable;
15 | import io.reactivex.functions.Action;
16 | import io.reactivex.observers.DisposableSingleObserver;
17 | import io.reactivex.schedulers.Schedulers;
18 | import io.reactivex.subjects.BehaviorSubject;
19 | import java.io.IOException;
20 | import java.util.ArrayList;
21 | import java.util.Collections;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.Observable;
25 | import javax.inject.Inject;
26 | import lingaraj.hourglass.in.letswalk.letswalkscreen.parser.PolyLineParser;
27 | import lingaraj.hourglass.in.letswalk.rest.DirectionAPIEndpoints;
28 |
29 | public class Repository {
30 |
31 | private final String TAG = this.getClass().getSimpleName();
32 | private RxLocation rxLocation;
33 | private final String MODE = "walking";
34 | private Disposable disposable;
35 | private final DirectionAPIEndpoints maps_api;
36 |
37 | @Inject
38 | public Repository(RxLocation rxLocation,DirectionAPIEndpoints endpoints) {
39 | this.rxLocation = rxLocation;
40 | this.maps_api = endpoints;
41 | }
42 |
43 |
44 |
45 |
46 | public void parseRouteInformation(Map markerMap, String apiKey,final RepoCallbacks repoCallbacks){
47 |
48 | List markers = new ArrayList(markerMap.keySet());
49 | Collections.sort(markers);
50 | int size = markers.size();
51 | String origin = latLngToString(markerMap.get(markers.get(0)).getPosition());
52 | String destination = latLngToString(markerMap.get(markers.get(size-1)).getPosition());
53 | StringBuilder way_points_builder = new StringBuilder();
54 | for (int i = 1; i < size - 1; i++) {
55 | LatLng latLng = markerMap.get(markers.get(i)).getPosition();
56 | /* if (i>1) {
57 | way_points_builder.append(",");
58 | }
59 | else {
60 | way_points_builder.append("\"").append(latLng.latitude).append(",").append(latLng.longitude).append("\"");
61 |
62 | }*/
63 | way_points_builder.append(latLng.toString());
64 |
65 | }
66 |
67 | Log.d(TAG,"Way Points:\n"+way_points_builder.toString());
68 | disposable = maps_api.getJson(origin, destination, way_points_builder.toString(), MODE,apiKey)
69 | .map(PolyLineParser::new)
70 | .subscribeOn(Schedulers.io())
71 | .observeOn(AndroidSchedulers.mainThread())
72 | .subscribeWith(new DisposableSingleObserver() {
73 | @Override public void onSuccess(PolyLineParser polyLineParser) {
74 | repoCallbacks.onSuccess(polyLineParser.getPolyLines());
75 | }
76 |
77 | @Override public void onError(Throwable e) {
78 | repoCallbacks.onFailure();
79 | }
80 | });
81 |
82 | }
83 |
84 |
85 |
86 | public void reverseGeocode(double lat, double lng,final GeoDecoderCallback callback) {
87 | Log.d(TAG,"Preparing to reverse geo Decode:"+"Lat/Lng"+lat+"/"+lng);
88 |
89 | disposable = rxLocation.geocoding()
90 | .fromLocation(lat,lng)
91 | .observeOn(Schedulers.io())
92 | .subscribeOn(AndroidSchedulers.mainThread())
93 | .subscribe(address -> {
94 | Log.d(TAG,"Address recieved for lat lng");
95 | callback.decodedAddressDetails(address);},throwable -> {
96 | Log.d(TAG,"Unable to process address for lat lng:"+throwable.toString());
97 | });
98 | /*
99 | disposable = Completable.fromAction(new Action() {
100 | @Override
101 | public void run() throws Exception {
102 | List addresses = geo_coder.getFromLocation(lat, lng, 1);
103 | int len = addresses.size();
104 | Address address = addresses.get(len-1);
105 | Log.d(TAG,new Gson().toJson(address));
106 | callback.decodedAddressDetails(address);
107 | }
108 | }).observeOn(Schedulers.io())
109 | .subscribeOn(AndroidSchedulers.mainThread())
110 | .subscribe(()->{Log.d(TAG,"Reverse GeoCode ran to completion");},throwable -> {
111 | Log.d(TAG,throwable.toString());
112 | }); */
113 | }
114 |
115 |
116 | private String latLngToString(LatLng latLng){
117 | return String.valueOf(latLng.latitude+","+latLng.longitude);
118 |
119 | }
120 |
121 | public void clear(){
122 | if (this.disposable!=null){
123 | this.disposable.dispose();
124 | }
125 | }
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/AppLocationManager.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.app.Activity;
4 | import android.location.Location;
5 | import android.os.Bundle;
6 | import android.os.Looper;
7 | import android.util.Log;
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.lifecycle.LiveData;
11 | import com.google.android.gms.common.api.ApiException;
12 | import com.google.android.gms.common.api.GoogleApiClient;
13 | import com.google.android.gms.common.api.ResolvableApiException;
14 | import com.google.android.gms.location.FusedLocationProviderClient;
15 | import com.google.android.gms.location.LocationAvailability;
16 | import com.google.android.gms.location.LocationRequest;
17 | import com.google.android.gms.location.LocationResult;
18 | import com.google.android.gms.location.LocationServices;
19 | import com.google.android.gms.location.LocationSettingsRequest;
20 | import com.google.android.gms.location.LocationSettingsResponse;
21 | import com.google.android.gms.location.LocationSettingsStatusCodes;
22 | import com.google.android.gms.tasks.OnCanceledListener;
23 | import com.google.android.gms.tasks.OnCompleteListener;
24 | import com.google.android.gms.tasks.OnFailureListener;
25 | import com.google.android.gms.tasks.Task;
26 | import lingaraj.hourglass.in.letswalk.utils.MarshmallowPermissions;
27 |
28 | public class AppLocationManager extends LiveData
29 | implements
30 | GoogleApiClient.ConnectionCallbacks,
31 | FusedLocationCallback.LocationResultCallbacks {
32 |
33 |
34 | private Activity activity;
35 | private final String TAG = "FUSED_LOC";
36 | private final LocationRequest location_request;
37 | private final LocationRequestCallback loc_request_callback;
38 | private final FusedLocationCallback fusedLocationCallback;
39 | private final GoogleApiClient google_api_client;
40 | private FusedLocationProviderClient fused_loc_provider = null;
41 | private final LocationSettingsRequest.Builder builder;
42 | private boolean is_loc_available = false;
43 |
44 |
45 | public AppLocationManager(Activity activity,LocationRequestCallback locationRequestCallback){
46 | this.activity = activity;
47 | this.loc_request_callback = locationRequestCallback;
48 | this.fusedLocationCallback = new FusedLocationCallback(this);
49 | this.google_api_client = new GoogleApiClient.Builder(activity)
50 | .addApi(LocationServices.API)
51 | .addConnectionCallbacks(this)
52 | .build();
53 | this.location_request = LocationRequest.create()
54 | .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
55 | .setInterval(30 * 1000)
56 | .setFastestInterval(5 * 1000);
57 | this.builder = new LocationSettingsRequest.Builder()
58 | .addLocationRequest(location_request)
59 | .setAlwaysShow(true);
60 | Log.d(TAG,"Constructor called");
61 |
62 | }
63 |
64 |
65 |
66 |
67 | @Override
68 | protected void onActive() {
69 | if (!google_api_client.isConnected()){
70 | google_api_client.connect();
71 | }
72 | else {
73 | requestLocationUpdate();
74 | }
75 | }
76 |
77 |
78 |
79 | @Override
80 | protected void onInactive() {
81 | if (google_api_client.isConnected()) {
82 | this.is_loc_available = false;
83 | if (this.fused_loc_provider!=null){
84 | this.fused_loc_provider.removeLocationUpdates(fusedLocationCallback);
85 | this.fused_loc_provider = null;
86 | }
87 | this.google_api_client.disconnect();
88 | }
89 | }
90 | @Override
91 | public void onConnected(@Nullable Bundle connectionHint) {
92 | Log.d(TAG, "connected to google api client");
93 | if (is_loc_available){
94 | requestLocationUpdate();
95 | }
96 | else {
97 | promptUserLocationRequest();
98 | }
99 | }
100 |
101 | public void requestLocationUpdate() {
102 | if(is_loc_available && hasActiveObservers() && google_api_client.isConnected() && fused_loc_provider==null) {
103 | fused_loc_provider = new FusedLocationProviderClient(activity);
104 | fused_loc_provider.requestLocationUpdates(location_request,fusedLocationCallback, Looper.myLooper());
105 | }
106 |
107 | }
108 |
109 | @Override
110 | public void onLocationChanged(Location location) {
111 | Log.d(TAG,"Location Changed:"+"Lat/Lng:"+location.getLatitude()+"/"+location.getLongitude());
112 | setValue(location);
113 | }
114 |
115 |
116 | @Override
117 | public void onConnectionSuspended(int cause) {
118 | Log.w(TAG, "On Connection suspended " + cause);
119 | }
120 |
121 | @Override public void onLocationResult(LocationResult locationResult) {
122 | //Fused Location Callback
123 | Location location = locationResult.getLastLocation();
124 | if (location!=null){
125 | Log.d(TAG,"Last Know Location");
126 | setValue(location);
127 | }
128 |
129 | }
130 |
131 | @Override public void onLocationAvailability(LocationAvailability locationAvailability) {
132 | is_loc_available = locationAvailability.isLocationAvailable();
133 | if (!is_loc_available){
134 | promptUserLocationRequest();
135 |
136 | }
137 | else {
138 | requestLocationUpdate();
139 | }
140 | Log.d(TAG,"Location Availability:"+is_loc_available);
141 | }
142 |
143 | private void promptUserLocationRequest() {
144 | if (!MarshmallowPermissions.arePermissionsGranted(activity)){
145 | Log.d(TAG,"Location Access Permission yet to be provided by user, discarding user location request");
146 | return;
147 | }
148 |
149 | Task task = LocationServices.getSettingsClient(this.activity).checkLocationSettings(builder.build());
150 | task.addOnFailureListener(new OnFailureListener() {
151 | @Override public void onFailure(@NonNull Exception e) {
152 | Log.d(TAG,"Location request failed");
153 | loc_request_callback.onLocationRequestCancelled();
154 | onInactive();
155 | }
156 | });
157 | task.addOnCanceledListener(new OnCanceledListener() {
158 | @Override public void onCanceled() {
159 | Log.d(TAG,"Location request cancelled by user");
160 | loc_request_callback.onLocationRequestCancelled();
161 | onInactive();
162 | }
163 | });
164 | task.addOnCompleteListener(new OnCompleteListener() {
165 | @Override public void onComplete(@NonNull Task task) {
166 | try {
167 | LocationSettingsResponse response = task.getResult(ApiException.class);
168 | if (response!=null && response.getLocationSettingsStates().isLocationUsable()){
169 | is_loc_available = response.getLocationSettingsStates().isLocationUsable();
170 | requestLocationUpdate();
171 | }
172 | else {
173 | is_loc_available = false;
174 | loc_request_callback.onLocationRequestCancelled();
175 | }
176 | }
177 | catch (ApiException exception){
178 | if (exception.getStatusCode() == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {
179 | try {
180 | ResolvableApiException resolvable = (ResolvableApiException) exception;
181 | resolvable.startResolutionForResult(activity, LetsWalkActivity.REQUEST_LOCATION);
182 | }
183 | catch (Exception e){
184 | Log.d(TAG,e.toString());
185 | }
186 | }
187 | onInactive();
188 | }
189 | }
190 | });
191 |
192 | Log.d(TAG,"Prompted User Location");
193 |
194 | }
195 | }
--------------------------------------------------------------------------------
/app/src/main/java/lingaraj/hourglass/in/letswalk/letswalkscreen/LetsWalkActivity.java:
--------------------------------------------------------------------------------
1 | package lingaraj.hourglass.in.letswalk.letswalkscreen;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.app.ProgressDialog;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.content.pm.PackageManager;
9 | import android.location.Location;
10 | import android.os.Bundle;
11 | import android.util.Log;
12 | import android.view.View;
13 | import android.widget.Button;
14 | import android.widget.FrameLayout;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 | import android.widget.ViewSwitcher;
18 | import androidx.annotation.NonNull;
19 | import androidx.annotation.Nullable;
20 | import androidx.core.app.ActivityCompat;
21 | import androidx.fragment.app.FragmentActivity;
22 | import androidx.fragment.app.FragmentTransaction;
23 | import androidx.lifecycle.Observer;
24 | import com.google.android.gms.maps.CameraUpdateFactory;
25 | import com.google.android.gms.maps.GoogleMap;
26 | import com.google.android.gms.maps.OnMapReadyCallback;
27 | import com.google.android.gms.maps.SupportMapFragment;
28 | import com.google.android.gms.maps.model.BitmapDescriptorFactory;
29 | import com.google.android.gms.maps.model.LatLng;
30 | import com.google.android.gms.maps.model.Marker;
31 | import com.google.android.gms.maps.model.MarkerOptions;
32 | import com.google.android.gms.maps.model.PolylineOptions;
33 | import com.pnikosis.materialishprogress.ProgressWheel;
34 | import java.util.HashMap;
35 | import java.util.List;
36 | import java.util.Map;
37 | import java.util.UUID;
38 | import javax.inject.Inject;
39 | import lingaraj.hourglass.in.letswalk.Constants;
40 | import lingaraj.hourglass.in.letswalk.di.BaseViewModelFactory;
41 | import lingaraj.hourglass.in.letswalk.di.injectors.Injector;
42 | import lingaraj.hourglass.in.letswalk.di.injectors.FragmentInjector;
43 | import lingaraj.hourglass.in.letswalk.utils.MarshmallowPermissions;
44 | import lingaraj.hourglass.in.ridegmap.R;
45 |
46 | public class LetsWalkActivity extends FragmentActivity implements
47 | LocationRequestCallback,
48 | OnMapReadyCallback,
49 | GoogleMap.OnMapLongClickListener,
50 | GoogleMap.OnMarkerDragListener,
51 | ActivityCompat.OnRequestPermissionsResultCallback {
52 |
53 | public static final int REQUEST_LOCATION = 199;
54 | private final String TAG = "MAPSACT";
55 | private int marker_count = 1;
56 | private Map marker_map = new HashMap<>();
57 | private SupportMapFragment map_fragment;
58 | private GoogleMap mMap;
59 | private LatLng previous_know_loc = null;
60 | private LetsWalkViewModel view_model;
61 | private String map_api_key = null;
62 | private ProgressDialog progress;
63 | private AppLocationManager loc_manager;
64 | private ViewSwitcher view_switcher;
65 | private ProgressWheel wheel;
66 | private TextView error;
67 | private Button retry;
68 | private FrameLayout bottom_sheet;
69 | @Inject FragmentInjector fragmentInjector;
70 | @Inject BaseViewModelFactory view_model_factory;
71 |
72 |
73 | @Override protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | setContentView(R.layout.activity_maps);
76 | Injector.inject(this);
77 | loc_manager = new AppLocationManager(this, this);
78 | map_api_key = this.getString(R.string.google_maps_key);
79 | view_model = view_model_factory.create(LetsWalkViewModel.class);
80 | init();
81 | setMapFragment();
82 | setBottomSheet();
83 | showLoader();
84 | showMap();
85 | setLiveDataRelays();
86 | setViewModelRelays();
87 | }
88 |
89 | private void showMap() {
90 | if (view_switcher.getDisplayedChild()==0){
91 | view_switcher.showNext();
92 |
93 | Log.d(TAG,"Showing Map");
94 |
95 |
96 | }
97 |
98 | }
99 |
100 | private void setLiveDataRelays() {
101 | loc_manager.observe(this, new Observer() {
102 | @Override public void onChanged(Location location) {
103 | if (location==null){
104 | Log.d(TAG,"Recieved Null as response");
105 | }
106 | else {
107 | showMap();
108 | setLastKnowLocation(location);
109 | }
110 | }
111 | });
112 | }
113 |
114 | private void setViewModelRelays() {
115 | view_model.getMessages().observe(this, new Observer() {
116 | @Override public void onChanged(String message) {
117 | displayMessage(message);
118 | }
119 | });
120 |
121 | view_model.getNetwork_loader().observe(this, new Observer() {
122 | @Override public void onChanged(Boolean showNetworkLoader) {
123 | if (showNetworkLoader){
124 | showDefaultProgressLoader();
125 | }
126 | else {
127 | hideDefaultProgressLoader();
128 | }
129 | }
130 | });
131 | view_model.getPoly_lines().observe(this, new Observer>() {
132 | @Override public void onChanged(List polylineOptions) {
133 | drawPathOnMap(polylineOptions);
134 | }
135 |
136 | });
137 |
138 | }
139 |
140 | private void displayMessage(String message) {
141 | Toast.makeText(LetsWalkActivity.this,message,Toast.LENGTH_SHORT).show();
142 | }
143 |
144 | private void hideDefaultProgressLoader() {
145 | this.progress.dismiss();
146 | }
147 |
148 | private void showDefaultProgressLoader() {
149 | if (this.progress!=null){
150 | this.progress.show();
151 | }
152 | Log.d(TAG,"Showing Progress Loader");
153 | }
154 |
155 | private void drawPathOnMap(List polylineOptions) {
156 | for (PolylineOptions path :polylineOptions ) {
157 | mMap.addPolyline(path);
158 | }
159 | }
160 |
161 | private void init() {
162 | map_fragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_for_ride);
163 | view_switcher = findViewById(R.id.view_switcher);
164 | wheel = findViewById(R.id.wheel);
165 | error = findViewById(R.id.error);
166 | retry = findViewById(R.id.retry);
167 | bottom_sheet = findViewById(R.id.bottom_sheet_frame);
168 | progress = new ProgressDialog(this);
169 | progress.setMessage("Getting things ready");
170 | progress.setCancelable(false); // disable dismiss by tapping outside of the dialog
171 |
172 | }
173 |
174 | private void showLoader(){
175 | wheel.setVisibility(View.VISIBLE);
176 | error.setVisibility(View.GONE);
177 | retry.setVisibility(View.GONE);
178 | if (view_switcher.getDisplayedChild()==1){
179 | view_switcher.showPrevious();
180 | }
181 | Log.d(TAG,"Show Loader");
182 | }
183 |
184 | private void checkRequiredPermission() {
185 | if (MarshmallowPermissions.arePermissionsGranted(this)) {
186 | loc_manager.onActive();
187 | }
188 | else {
189 | MarshmallowPermissions.requestPermissions(this);
190 | }
191 | }
192 |
193 |
194 | @Override
195 | public void onMapReady(GoogleMap googleMap) {
196 | mMap = googleMap;
197 | mMap.setOnMapLongClickListener(this);
198 | mMap.setOnMarkerDragListener(this);
199 | checkRequiredPermission();
200 | }
201 |
202 | private void setLastKnowLocation(Location location) {
203 | this.previous_know_loc = new LatLng(location.getLatitude(),location.getLongitude());
204 | if (mMap!=null){
205 | mMap.setMyLocationEnabled(true);
206 | mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(previous_know_loc,16f));
207 | Log.d(TAG,"Last Known location updated");
208 | }
209 | }
210 |
211 |
212 | @Override public void onMarkerDragStart(Marker marker) {
213 |
214 | }
215 |
216 | @Override public void onMarkerDrag(Marker marker) {
217 |
218 | }
219 |
220 | @Override public void onMarkerDragEnd(Marker marker) {
221 | Integer marker_no = (Integer) marker.getTag();
222 | if (marker_no!=null){
223 | marker_map.put(marker_no,marker);
224 | Log.d(TAG,"Marker Dragged Ended and map updated for Marker:"+marker_no);
225 | }
226 | }
227 |
228 | private void calculateWalkingRoute() {
229 | if (marker_count>2){
230 | AlertDialog.Builder builder = new AlertDialog.Builder(LetsWalkActivity.this);
231 |
232 | builder.setMessage("Do you wish to get Walking Direction?");
233 |
234 | builder.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
235 | @Override
236 | public void onClick(DialogInterface dialog, int which){
237 | view_model.drawRoute(marker_map,map_api_key);
238 | dialog.dismiss();
239 | }
240 | });
241 |
242 | builder.setNegativeButton("No", new DialogInterface.OnClickListener(){
243 | @Override
244 | public void onClick(DialogInterface dialog, int which){
245 | dialog.dismiss();
246 | }
247 | });
248 | builder.show();
249 | }
250 | }
251 |
252 | @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
253 | @NonNull int[] grantResults) {
254 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
255 | // If request is cancelled, the result arrays are empty.
256 | if (requestCode == MarshmallowPermissions.LOCATION_PERMISSION_REQUEST_CODE) {
257 | if (grantResults.length > 0
258 | && grantResults[0] == PackageManager.PERMISSION_GRANTED
259 | && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
260 | loc_manager.onInactive();
261 | loc_manager.onActive();
262 | }
263 | else {
264 | showPermissionError();
265 | }
266 | }
267 |
268 | }
269 |
270 | private void setMapFragment(){
271 | if (map_fragment!=null){
272 | map_fragment.getMapAsync(this);
273 | }
274 |
275 |
276 | }
277 |
278 | private void showPermissionError(){
279 | wheel.setVisibility(View.GONE);
280 | error.setVisibility(View.VISIBLE);
281 | retry.setVisibility(View.VISIBLE);
282 | if (view_switcher.getDisplayedChild()==1){
283 | view_switcher.showPrevious();
284 | }
285 | Log.d(TAG,"Showing Error");
286 | }
287 |
288 | public void retry(View view) {
289 | Log.d(TAG,"Retry");
290 | checkRequiredPermission();
291 | }
292 |
293 | @Override
294 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
295 | super.onActivityResult(requestCode, resultCode, data);
296 | if (requestCode == REQUEST_LOCATION) {
297 | switch (resultCode) {
298 | case Activity.RESULT_OK: {
299 | loc_manager.onActive();
300 | break;
301 | }
302 | case Activity.RESULT_CANCELED: {
303 | showPermissionError();
304 | break;
305 | }
306 | default: {
307 | break;
308 | }
309 | }
310 | }
311 | }
312 |
313 | @Override
314 | public void onLocationRequestCancelled() {
315 | showPermissionError();
316 | }
317 |
318 | @Override
319 | public void onMapLongClick(LatLng latLng) {
320 | marker_count++;
321 | Marker marker = mMap.addMarker(new MarkerOptions()
322 | .position(new LatLng(latLng.latitude,latLng.longitude))
323 | .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
324 | .draggable(true));
325 | marker.showInfoWindow();
326 | marker.setTag(marker_count);
327 | marker_map.put(marker_count,marker);
328 | view_model.decodeMarkerLocation(latLng.latitude,latLng.longitude);
329 | calculateWalkingRoute();
330 | Log.d(TAG,"Lat/Lng:"+marker.getPosition());
331 |
332 | }
333 |
334 | private void setBottomSheet() {
335 | FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
336 | FavouriteLocationsFragment favourites_frag = new FavouriteLocationsFragment();
337 | fragmentTransaction.add(bottom_sheet.getId(),favourites_frag).commit();
338 | Log.d(TAG,"Frag loaded to bottom sheet");
339 | bottom_sheet.setVisibility(View.VISIBLE);
340 |
341 | }
342 |
343 | public FragmentInjector getFragmentInjector() {
344 | return fragmentInjector;
345 | }
346 |
347 |
348 | }
349 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | generateDebugSources
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
--------------------------------------------------------------------------------