├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── dimens.xml │ │ │ ├── colors.xml │ │ │ └── styles.xml │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ └── layout │ │ │ ├── activity_sample_fragment.xml │ │ │ ├── location_display_layout.xml │ │ │ └── activity_main.xml │ │ ├── java │ │ └── com │ │ │ └── yayandroid │ │ │ └── locationmanager │ │ │ └── sample │ │ │ ├── SampleApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── fragment │ │ │ ├── SampleFragmentActivity.java │ │ │ └── SampleFragment.java │ │ │ ├── service │ │ │ ├── SampleService.java │ │ │ └── SampleServiceActivity.java │ │ │ ├── activity │ │ │ └── SampleActivity.java │ │ │ └── SamplePresenter.java │ │ └── AndroidManifest.xml └── build.gradle ├── library ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── yayandroid │ │ │ └── locationmanager │ │ │ ├── listener │ │ │ ├── FallbackListener.java │ │ │ ├── DialogListener.java │ │ │ ├── PermissionListener.java │ │ │ └── LocationListener.java │ │ │ ├── helper │ │ │ ├── logging │ │ │ │ ├── Logger.java │ │ │ │ └── DefaultLogger.java │ │ │ ├── StringUtils.java │ │ │ ├── UpdateRequest.java │ │ │ ├── continuoustask │ │ │ │ ├── ContinuousTaskScheduler.java │ │ │ │ └── ContinuousTask.java │ │ │ └── LogUtils.java │ │ │ ├── constants │ │ │ ├── RequestCode.java │ │ │ ├── ProviderType.java │ │ │ ├── FailType.java │ │ │ └── ProcessType.java │ │ │ ├── providers │ │ │ ├── permissionprovider │ │ │ │ ├── StubPermissionProvider.java │ │ │ │ ├── PermissionCompatSource.java │ │ │ │ ├── PermissionProvider.java │ │ │ │ └── DefaultPermissionProvider.java │ │ │ ├── dialogprovider │ │ │ │ ├── DialogProvider.java │ │ │ │ └── SimpleMessageDialogProvider.java │ │ │ └── locationprovider │ │ │ │ ├── DispatcherLocationSource.java │ │ │ │ ├── DefaultLocationSource.java │ │ │ │ ├── LocationProvider.java │ │ │ │ ├── GooglePlayServicesLocationSource.java │ │ │ │ └── DispatcherLocationProvider.java │ │ │ ├── base │ │ │ ├── SimpleLocationListener.java │ │ │ ├── LocationBaseService.java │ │ │ ├── LocationBaseFragment.java │ │ │ └── LocationBaseActivity.java │ │ │ ├── configuration │ │ │ ├── Defaults.java │ │ │ ├── Configurations.java │ │ │ ├── PermissionConfiguration.java │ │ │ ├── LocationConfiguration.java │ │ │ ├── GooglePlayServicesConfiguration.java │ │ │ └── DefaultProviderConfiguration.java │ │ │ ├── view │ │ │ └── ContextProcessor.java │ │ │ └── LocationManager.java │ └── test │ │ └── java │ │ └── com │ │ └── yayandroid │ │ └── locationmanager │ │ ├── fakes │ │ ├── MockDialogProvider.java │ │ ├── FakePermissionProvider.java │ │ └── FakeSimpleTask.java │ │ ├── providers │ │ └── permissionprovider │ │ │ ├── PermissionProviderTest.java │ │ │ └── DefaultPermissionProviderTest.java │ │ ├── helper │ │ ├── LogUtilsTest.java │ │ └── continuoustask │ │ │ └── ContinuousTaskSchedulerTest.java │ │ ├── configuration │ │ ├── ConfigurationsTest.java │ │ ├── GooglePlayServicesConfigurationTest.java │ │ ├── LocationConfigurationTest.java │ │ ├── PermissionConfigurationTest.java │ │ └── DefaultProviderConfigurationTest.java │ │ └── LocationManagerTest.java ├── build.gradle ├── gradle.properties └── maven_push.gradle ├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github ├── issue_template.md └── workflows │ └── android.yml ├── LocationManager.iml ├── gradle.properties ├── .travis.yml ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | .DS_Store 4 | /local.properties 5 | /build 6 | /captures 7 | *.iml -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LocationManager 3 | 4 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yayaa/LocationManager/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 5 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ...DEFINE YOUR ISSUE... 2 | 3 | ### Configuration 4 | ```java 5 | PLEASE SHARE YOUR CONFIGURATION OBJECT HERE 6 | ``` 7 | 8 | ### Logs 9 | PLEASE SHARE YOUR LOGS 10 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/listener/FallbackListener.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.listener; 2 | 3 | public interface FallbackListener { 4 | void onFallback(); 5 | } -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/listener/DialogListener.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.listener; 2 | 3 | public interface DialogListener { 4 | 5 | void onPositiveButtonClick(); 6 | 7 | void onNegativeButtonClick(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 01 14:17:05 CET 2020 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.4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_sample_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/java/com/yayandroid/locationmanager/sample/SampleApplication.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.sample; 2 | 3 | import android.app.Application; 4 | 5 | import com.yayandroid.locationmanager.LocationManager; 6 | 7 | public class SampleApplication extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | LocationManager.enableLog(true); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/listener/PermissionListener.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.listener; 2 | 3 | public interface PermissionListener { 4 | 5 | /** 6 | * Notify when user is granted all required permissions 7 | */ 8 | void onPermissionsGranted(); 9 | 10 | /** 11 | * Notify when user is denied any one of required permissions 12 | */ 13 | void onPermissionsDenied(); 14 | } 15 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/logging/Logger.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper.logging; 2 | 3 | public interface Logger { 4 | void logD(String className, String message); 5 | 6 | void logE(String className, String message); 7 | 8 | void logI(String className, String message); 9 | 10 | void logV(String className, String message); 11 | 12 | void logW(String className, String message); 13 | } 14 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/constants/RequestCode.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.constants; 2 | 3 | public final class RequestCode { 4 | 5 | public static final int RUNTIME_PERMISSION = 23; 6 | public static final int GOOGLE_PLAY_SERVICES = 24; 7 | public static final int GPS_ENABLE = 25; 8 | public static final int SETTINGS_API = 26; 9 | 10 | private RequestCode() { 11 | // No instance 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | public final class StringUtils { 6 | 7 | private StringUtils() { 8 | // no instance 9 | } 10 | 11 | public static boolean isEmpty(@Nullable CharSequence str) { 12 | return str == null || str.length() == 0; 13 | } 14 | 15 | public static boolean isNotEmpty(@Nullable CharSequence str) { 16 | return str != null && str.length() > 0; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/location_display_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion versions.compileSdkVersion 5 | buildToolsVersion versions.buildToolsVersion 6 | 7 | defaultConfig { 8 | applicationId "com.yayandroid.locationmanager.sample" 9 | minSdkVersion versions.minSdkVersion 10 | targetSdkVersion versions.targetSdkVersion 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | } 15 | 16 | dependencies { 17 | implementation project(':library') 18 | implementation libraries.appCompat 19 | 20 | debugImplementation libraries.leakcanary 21 | } -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Check 21 | run: ./gradlew clean check --stacktrace --no-daemon 22 | - name: Build with Gradle 23 | run: ./gradlew build jacocoTestReport assembleAndroidTest 24 | - name: Codecov 25 | uses: codecov/codecov-action@v1.0.7 26 | 27 | 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/constants/ProviderType.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.constants; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | @IntDef({ProviderType.NONE, ProviderType.GOOGLE_PLAY_SERVICES, 9 | ProviderType.GPS, ProviderType.NETWORK, ProviderType.DEFAULT_PROVIDERS}) 10 | @Retention(RetentionPolicy.SOURCE) 11 | public @interface ProviderType { 12 | 13 | int NONE = 0; 14 | int GOOGLE_PLAY_SERVICES = 1; 15 | int GPS = 2; 16 | int NETWORK = 3; 17 | int DEFAULT_PROVIDERS = 4; // Covers both GPS and NETWORK 18 | 19 | } 20 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/providers/permissionprovider/StubPermissionProvider.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.providers.permissionprovider; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.yayandroid.locationmanager.configuration.Defaults; 6 | 7 | public class StubPermissionProvider extends PermissionProvider { 8 | 9 | public StubPermissionProvider() { 10 | super(Defaults.LOCATION_PERMISSIONS, null); 11 | } 12 | 13 | @Override 14 | public boolean requestPermissions() { 15 | return false; 16 | } 17 | 18 | @Override 19 | public void onRequestPermissionsResult(int requestCode, String[] permissions, @NonNull int[] grantResults) { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/logging/DefaultLogger.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper.logging; 2 | 3 | import android.util.Log; 4 | 5 | public class DefaultLogger implements Logger { 6 | public void logD(String className, String message) { 7 | Log.d(className, message); 8 | } 9 | 10 | public void logE(String className, String message) { 11 | Log.e(className, message); 12 | } 13 | 14 | public void logI(String className, String message) { 15 | Log.i(className, message); 16 | } 17 | 18 | public void logV(String className, String message) { 19 | Log.v(className, message); 20 | } 21 | 22 | public void logW(String className, String message) { 23 | Log.w(className, message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /library/src/test/java/com/yayandroid/locationmanager/fakes/MockDialogProvider.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.fakes; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.yayandroid.locationmanager.providers.dialogprovider.DialogProvider; 9 | 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | public final class MockDialogProvider extends DialogProvider { 14 | 15 | private String message; 16 | @Mock Dialog dialog; 17 | 18 | public MockDialogProvider(String message) { 19 | this.message = message; 20 | MockitoAnnotations.initMocks(this); 21 | } 22 | 23 | public String message() { 24 | return message; 25 | } 26 | 27 | @Override 28 | public Dialog getDialog(@NonNull Context context) { 29 | return dialog; 30 | } 31 | } -------------------------------------------------------------------------------- /LocationManager.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'jacoco-android' 3 | 4 | android { 5 | compileSdkVersion versions.compileSdkVersion 6 | buildToolsVersion versions.buildToolsVersion 7 | 8 | defaultConfig { 9 | minSdkVersion versions.minSdkVersion 10 | targetSdkVersion versions.targetSdkVersion 11 | versionCode = Integer.parseInt(VERSION_CODE) 12 | versionName = VERSION_NAME 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | } 19 | debug { 20 | testCoverageEnabled true 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation libraries.appCompat 27 | implementation libraries.googlePlayServices 28 | 29 | testImplementation libraries.junit 30 | testImplementation libraries.assertJ 31 | testImplementation libraries.mockito 32 | } 33 | 34 | apply from: 'maven_push.gradle' -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | org.gradle.jvmargs=-Xmx1536M 15 | 16 | # When configured, Gradle will run in incubating parallel mode. 17 | # This option should only be used with decoupled projects. More details, visit 18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 19 | # org.gradle.parallel=true 20 | android.useAndroidX=true -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | # installing Java 8 JDK is required to prevent getting "Unsupported major.minor version 52.0" error 4 | jdk: 5 | - oraclejdk8 6 | 7 | # Travis now has Xenial builds as default -> https://blog.travis-ci.com/2019-04-15-xenial-default-build-environment 8 | # Though, Android builds are not yet supported on Xenial 9 | dist: trusty 10 | 11 | android: 12 | components: 13 | - tools 14 | - platform-tools 15 | - build-tools-29.0.0 16 | - android-29 17 | 18 | - extra-google-google_play_services 19 | - extra-google-m2repository 20 | - extra-android-m2repository 21 | 22 | licenses: 23 | - 'android-sdk-license-.+' 24 | 25 | before_install: 26 | - yes | sdkmanager "platforms;android-29" 27 | 28 | script: 29 | - ./gradlew clean check --stacktrace --no-daemon 30 | - ./gradlew build jacocoTestReport assembleAndroidTest 31 | 32 | after_success: 33 | - bash <(curl -s https://codecov.io/bash) 34 | 35 | sudo: 36 | false 37 | 38 | notifications: 39 | email: false -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/constants/FailType.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.constants; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | @IntDef({FailType.UNKNOWN, FailType.TIMEOUT, FailType.PERMISSION_DENIED, FailType.NETWORK_NOT_AVAILABLE, 9 | FailType.GOOGLE_PLAY_SERVICES_NOT_AVAILABLE, 10 | FailType.GOOGLE_PLAY_SERVICES_SETTINGS_DIALOG, FailType.GOOGLE_PLAY_SERVICES_SETTINGS_DENIED, 11 | FailType.VIEW_DETACHED, FailType.VIEW_NOT_REQUIRED_TYPE}) 12 | @Retention(RetentionPolicy.SOURCE) 13 | public @interface FailType { 14 | 15 | int UNKNOWN = -1; 16 | int TIMEOUT = 1; 17 | int PERMISSION_DENIED = 2; 18 | int NETWORK_NOT_AVAILABLE = 3; 19 | int GOOGLE_PLAY_SERVICES_NOT_AVAILABLE = 4; 20 | int GOOGLE_PLAY_SERVICES_SETTINGS_DIALOG = 6; 21 | int GOOGLE_PLAY_SERVICES_SETTINGS_DENIED = 7; 22 | int VIEW_DETACHED = 8; 23 | int VIEW_NOT_REQUIRED_TYPE = 9; 24 | 25 | } -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/providers/permissionprovider/PermissionCompatSource.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.providers.permissionprovider; 2 | 3 | import android.app.Activity; 4 | 5 | import androidx.core.app.ActivityCompat; 6 | import androidx.fragment.app.Fragment; 7 | 8 | class PermissionCompatSource { 9 | 10 | boolean shouldShowRequestPermissionRationale(Fragment fragment, String permission) { 11 | return fragment.shouldShowRequestPermissionRationale(permission); 12 | } 13 | 14 | void requestPermissions(Fragment fragment, String[] requiredPermissions, int requestCode) { 15 | fragment.requestPermissions(requiredPermissions, requestCode); 16 | } 17 | 18 | boolean shouldShowRequestPermissionRationale(Activity activity, String permission) { 19 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission); 20 | } 21 | 22 | void requestPermissions(Activity activity, String[] requiredPermissions, int requestCode) { 23 | ActivityCompat.requestPermissions(activity, requiredPermissions, requestCode); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/yayandroid/locationmanager/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import com.yayandroid.locationmanager.sample.activity.SampleActivity; 11 | import com.yayandroid.locationmanager.sample.fragment.SampleFragmentActivity; 12 | import com.yayandroid.locationmanager.sample.service.SampleServiceActivity; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | } 21 | 22 | public void inActivityClick(View view) { 23 | startActivity(new Intent(this, SampleActivity.class)); 24 | } 25 | 26 | public void inFragmentClick(View view) { 27 | startActivity(new Intent(this, SampleFragmentActivity.class)); 28 | } 29 | 30 | public void inServiceClick(View view) { 31 | startActivity(new Intent(this, SampleServiceActivity.class)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/base/SimpleLocationListener.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.base; 2 | 3 | import android.location.Location; 4 | import android.os.Bundle; 5 | 6 | import com.yayandroid.locationmanager.constants.ProcessType; 7 | import com.yayandroid.locationmanager.listener.LocationListener; 8 | 9 | /** 10 | * Empty Location Listener in case you need only some of the methods from {@linkplain LocationListener} 11 | * Only {@linkplain LocationListener#onLocationChanged(Location)} and {@linkplain LocationListener#onLocationFailed(int)} 12 | * need to be overridden. 13 | */ 14 | public abstract class SimpleLocationListener implements LocationListener { 15 | 16 | @Override 17 | public void onProcessTypeChanged(@ProcessType int processType) { 18 | 19 | } 20 | 21 | @Override 22 | public void onPermissionGranted(boolean alreadyHadPermission) { 23 | 24 | } 25 | 26 | @Override 27 | public void onStatusChanged(String provider, int status, Bundle extras) { 28 | 29 | } 30 | 31 | @Override 32 | public void onProviderEnabled(String provider) { 33 | 34 | } 35 | 36 | @Override 37 | public void onProviderDisabled(String provider) { 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/UpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper; 2 | 3 | import android.location.LocationListener; 4 | import android.location.LocationManager; 5 | 6 | public class UpdateRequest { 7 | 8 | private final LocationManager locationManager; 9 | private final LocationListener locationListener; 10 | 11 | private String provider; 12 | private long minTime; 13 | private float minDistance; 14 | 15 | public UpdateRequest(LocationManager locationManager, LocationListener locationListener) { 16 | this.locationManager = locationManager; 17 | this.locationListener = locationListener; 18 | } 19 | 20 | public void run(String provider, long minTime, float minDistance) { 21 | this.provider = provider; 22 | this.minTime = minTime; 23 | this.minDistance = minDistance; 24 | run(); 25 | } 26 | 27 | @SuppressWarnings("ResourceType") 28 | public void run() { 29 | if(StringUtils.isNotEmpty(provider)) { 30 | locationManager.requestLocationUpdates(provider, minTime, minDistance, locationListener); 31 | } 32 | } 33 | 34 | @SuppressWarnings("ResourceType") 35 | public void release() { 36 | if (locationManager != null) locationManager.removeUpdates(locationListener); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/providers/dialogprovider/DialogProvider.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.providers.dialogprovider; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import com.yayandroid.locationmanager.listener.DialogListener; 10 | import com.yayandroid.locationmanager.providers.permissionprovider.DefaultPermissionProvider; 11 | 12 | import java.lang.ref.WeakReference; 13 | 14 | public abstract class DialogProvider { 15 | 16 | private WeakReference weakDialogListener; 17 | 18 | /** 19 | * Create a dialog object on given context 20 | * 21 | * @param context in which the dialog should run 22 | * @return dialog object to display 23 | */ 24 | public abstract Dialog getDialog(@NonNull Context context); 25 | 26 | /** 27 | * Sets a {@linkplain DialogListener} to provide pre-defined actions to the component which uses this dialog 28 | * 29 | * This method will be called by {@linkplain DefaultPermissionProvider} internally, if it is in use. 30 | * 31 | * @param dialogListener will be used to notify on specific actions 32 | */ 33 | public void setDialogListener(@Nullable DialogListener dialogListener) { 34 | this.weakDialogListener = new WeakReference<>(dialogListener); 35 | } 36 | 37 | @Nullable public DialogListener getDialogListener() { 38 | return weakDialogListener.get(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /library/src/test/java/com/yayandroid/locationmanager/fakes/FakePermissionProvider.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.fakes; 2 | 3 | import android.content.pm.PackageManager; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | 8 | import com.yayandroid.locationmanager.providers.dialogprovider.DialogProvider; 9 | import com.yayandroid.locationmanager.providers.permissionprovider.PermissionProvider; 10 | 11 | public class FakePermissionProvider extends PermissionProvider { 12 | 13 | private boolean requestPermissions = false; 14 | private boolean isPermissionGranted = false; 15 | 16 | public FakePermissionProvider(String[] requiredPermissions, @Nullable DialogProvider rationaleDialogProvider) { 17 | super(requiredPermissions, rationaleDialogProvider); 18 | } 19 | 20 | public void shouldSuccessOnRequest(boolean success) { 21 | this.requestPermissions = success; 22 | } 23 | 24 | public void grantPermission(boolean granted) { 25 | this.isPermissionGranted = granted; 26 | } 27 | 28 | @Override 29 | protected int checkSelfPermission(String permission) { 30 | return isPermissionGranted ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED; 31 | } 32 | 33 | @Override 34 | public boolean requestPermissions() { 35 | return requestPermissions; 36 | } 37 | 38 | @Override 39 | public void onRequestPermissionsResult(int requestCode, @Nullable String[] permissions, @NonNull int[] grantResults) { 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/yayandroid/locationmanager/sample/fragment/SampleFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.sample.fragment; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import androidx.annotation.Nullable; 7 | import androidx.appcompat.app.AppCompatActivity; 8 | 9 | import com.yayandroid.locationmanager.sample.R; 10 | 11 | public class SampleFragmentActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_sample_fragment); 17 | } 18 | 19 | @Override 20 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 21 | super.onActivityResult(requestCode, resultCode, data); 22 | dispatchToFragment(requestCode, resultCode, data); 23 | } 24 | 25 | /** 26 | * This is required because GooglePlayServicesApi and SettingsApi requires Activity, 27 | * and they call startActivityForResult from the activity, not fragment, 28 | * fragment doesn't receive onActivityResult callback. We need to call/redirect manually. 29 | */ 30 | private void dispatchToFragment(int requestCode, int resultCode, Intent data) { 31 | SampleFragment sampleFragment = (SampleFragment) getSupportFragmentManager() 32 | .findFragmentById(R.id.sample_fragment); 33 | if (sampleFragment != null) { 34 | sampleFragment.onActivityResult(requestCode, resultCode, data); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/providers/dialogprovider/SimpleMessageDialogProvider.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.providers.dialogprovider; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.appcompat.app.AlertDialog; 9 | 10 | public class SimpleMessageDialogProvider extends DialogProvider implements DialogInterface.OnClickListener { 11 | 12 | private String message; 13 | 14 | public SimpleMessageDialogProvider(String message) { 15 | this.message = message; 16 | } 17 | 18 | public String message() { 19 | return message; 20 | } 21 | 22 | @Override 23 | public Dialog getDialog(@NonNull Context context) { 24 | return new AlertDialog.Builder(context) 25 | .setMessage(message) 26 | .setCancelable(false) 27 | .setPositiveButton(android.R.string.ok, this) 28 | .setNegativeButton(android.R.string.cancel, this) 29 | .create(); 30 | } 31 | 32 | @Override 33 | public void onClick(DialogInterface dialog, int which) { 34 | switch (which) { 35 | case DialogInterface.BUTTON_POSITIVE: { 36 | if (getDialogListener() != null) getDialogListener().onPositiveButtonClick(); 37 | break; 38 | } 39 | case DialogInterface.BUTTON_NEGATIVE: { 40 | if (getDialogListener() != null) getDialogListener().onNegativeButtonClick(); 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/continuoustask/ContinuousTaskScheduler.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper.continuoustask; 2 | 3 | class ContinuousTaskScheduler { 4 | 5 | private final static long NONE = Long.MIN_VALUE; 6 | 7 | private final ContinuousTask task; 8 | 9 | private long requiredDelay = NONE; 10 | private long initialTime = NONE; 11 | private long remainingTime = NONE; 12 | 13 | private boolean isSet = false; 14 | 15 | ContinuousTaskScheduler(ContinuousTask task) { 16 | this.task = task; 17 | } 18 | 19 | boolean isSet() { 20 | return isSet; 21 | } 22 | 23 | void delayed(long delay) { 24 | requiredDelay = delay; 25 | remainingTime = requiredDelay; 26 | initialTime = task.getCurrentTime(); 27 | 28 | set(delay); 29 | } 30 | 31 | void onPause() { 32 | if (requiredDelay != NONE) { 33 | release(); 34 | remainingTime = requiredDelay - (task.getCurrentTime() - initialTime); 35 | } 36 | } 37 | 38 | void onResume() { 39 | if (remainingTime != NONE) { 40 | set(remainingTime); 41 | } 42 | } 43 | 44 | void onStop() { 45 | release(); 46 | clean(); 47 | } 48 | 49 | void set(long delay) { 50 | if (!isSet) { 51 | task.schedule(delay); 52 | isSet = true; 53 | } 54 | } 55 | 56 | void release() { 57 | task.unregister(); 58 | isSet = false; 59 | } 60 | 61 | void clean() { 62 | requiredDelay = NONE; 63 | initialTime = NONE; 64 | remainingTime = NONE; 65 | isSet = false; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | POM_NAME=LocationManager Library 21 | POM_ARTIFACT_ID=LocationManager 22 | POM_PACKAGING=aar 23 | VERSION_NAME=2.4.1 24 | VERSION_CODE=29 25 | GROUP=com.yayandroid 26 | 27 | POM_DESCRIPTION=LocationManager Library 28 | POM_URL=https://github.com/yayaa/LocationManager 29 | POM_SCM_URL=https://github.com/yayaa/LocationManager 30 | POM_SCM_CONNECTION=scm:https://github.com/yayaa/LocationManager.git 31 | POM_SCM_DEV_CONNECTION=scm:https://github.com/yayaa/LocationManager.git 32 | POM_LICENCE_NAME=Apache License, Version 2.0 33 | POM_LICENCE_URL=https://opensource.org/licenses/Apache-2.0 34 | POM_LICENCE_DIST=repo 35 | POM_DEVELOPER_ID=yayaa 36 | POM_DEVELOPER_NAME=Yahya BAYRAMOGLU 37 | 38 | SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots 39 | RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2 -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/helper/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.helper; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.yayandroid.locationmanager.helper.logging.DefaultLogger; 6 | import com.yayandroid.locationmanager.helper.logging.Logger; 7 | 8 | public final class LogUtils { 9 | 10 | private static boolean isEnabled = false; 11 | 12 | private static Logger activeLogger = new DefaultLogger(); 13 | 14 | private LogUtils() { 15 | // No instance 16 | } 17 | 18 | public static void enable(boolean isEnabled) { 19 | LogUtils.isEnabled = isEnabled; 20 | } 21 | 22 | public static void setLogger(@NonNull Logger logger) { 23 | activeLogger = logger; 24 | } 25 | 26 | public static void logD(String message) { 27 | if (isEnabled) activeLogger.logD(getClassName(), message); 28 | } 29 | 30 | public static void logE(String message) { 31 | if (isEnabled) activeLogger.logE(getClassName(), message); 32 | } 33 | 34 | public static void logI(String message) { 35 | if (isEnabled) activeLogger.logI(getClassName(), message); 36 | } 37 | 38 | public static void logV(String message) { 39 | if (isEnabled) activeLogger.logV(getClassName(), message); 40 | } 41 | 42 | public static void logW(String message) { 43 | if (isEnabled) activeLogger.logW(getClassName(), message); 44 | } 45 | 46 | private static String getClassName() { 47 | StackTraceElement[] trace = Thread.currentThread().getStackTrace(); 48 | StackTraceElement relevantTrace = trace[4]; 49 | String className = relevantTrace.getClassName(); 50 | int lastIndex = className.lastIndexOf('.'); 51 | return className.substring(lastIndex + 1); 52 | } 53 | } -------------------------------------------------------------------------------- /library/src/main/java/com/yayandroid/locationmanager/constants/ProcessType.java: -------------------------------------------------------------------------------- 1 | package com.yayandroid.locationmanager.constants; 2 | 3 | import androidx.annotation.IntDef; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | @IntDef({ProcessType.ASKING_PERMISSIONS, ProcessType.GETTING_LOCATION_FROM_GOOGLE_PLAY_SERVICES, 9 | ProcessType.GETTING_LOCATION_FROM_GPS_PROVIDER, ProcessType.GETTING_LOCATION_FROM_NETWORK_PROVIDER, 10 | ProcessType.GETTING_LOCATION_FROM_CUSTOM_PROVIDER}) 11 | @Retention(RetentionPolicy.SOURCE) 12 | public @interface ProcessType { 13 | 14 | /** 15 | * This type will be emitted when application doesn't have required permissions yet, 16 | * and library starts the process to ask for them. If application already has the permissions, 17 | * this will not be emitted. 18 | */ 19 | int ASKING_PERMISSIONS = 1; 20 | 21 | /** 22 | * This type will be emitted when GooglePlayServices is available on device and possible to ask for location update, 23 | * otherwise it will not be emitted. 24 | */ 25 | int GETTING_LOCATION_FROM_GOOGLE_PLAY_SERVICES = 2; 26 | 27 | /** 28 | * This type will be emitted as soon as library asks Location update with GPS provider, 29 | * otherwise it will not be emitted. 30 | */ 31 | int GETTING_LOCATION_FROM_GPS_PROVIDER = 3; 32 | 33 | /** 34 | * This type will be emitted as soon as library asks Location update with Network provider, 35 | * otherwise it will not be emitted. 36 | */ 37 | int GETTING_LOCATION_FROM_NETWORK_PROVIDER = 4; 38 | 39 | /** 40 | * This type will never be emitted by the library. 41 | * It is defined in case of a custom Location Provider set to LocationManager. 42 | */ 43 | int GETTING_LOCATION_FROM_CUSTOM_PROVIDER = 5; 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |