├── .gitignore ├── LICENSE ├── README.md ├── android-easylocation ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── akhgupta │ │ └── easylocation │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── akhgupta │ │ │ └── easylocation │ │ │ ├── AppConstants.java │ │ │ ├── EasyLocation.java │ │ │ ├── EasyLocationActivity.java │ │ │ ├── EasyLocationAppCompatActivity.java │ │ │ ├── EasyLocationDelegate.java │ │ │ ├── EasyLocationListener.java │ │ │ ├── EasyLocationRequest.java │ │ │ ├── EasyLocationRequestBuilder.java │ │ │ ├── IntentKey.java │ │ │ ├── LocationBgService.java │ │ │ ├── LocationBroadcastReceiver.java │ │ │ └── PreferenceUtil.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── akhgupta │ └── easylocation │ └── ExampleUnitTest.java ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── akhgupta │ │ └── easylocation │ │ └── demo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── akhgupta │ │ │ └── easylocation │ │ │ └── demo │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.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 │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── akhgupta │ └── easylocation │ └── demo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | *.DS_Store 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | .idea 16 | .idea/** 17 | build/** 18 | # Gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # Intellij 38 | *.iml 39 | .idea/workspace.xml 40 | 41 | # Keystore files 42 | *.jks 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-EasyLocation 2 | 3 | Getting location updates requires lots of bolierplate code in Android, You need to take care of 4 | - Google Play services availablity Check, Update Google play Service Dialog 5 | - Creation of GoogleApiClient and its callbacks connected,disconnected etc. 6 | - Stopping and releasing resources for location updates 7 | - Handling Location permission scenarios 8 | - Checking Location services are On or Off 9 | - Getting lastknown location is not so easy either 10 | - Fallback to last known location if not getting location after certain duration 11 | 12 | **Android-EasyLocation** does all this stuff in background, so that you can concentrate on your business logic than handling all above 13 | 14 | ## Getting started 15 | 16 | In your `build.gradle`: 17 | 18 | **com.google.android.gms:play-services-location** dependency also needs to be added like this 19 | 20 | **x.x.x** can be replaced with google play service version your app is using [versions information available here](https://developers.google.com/android/guides/releases) 21 | 22 | ```gradle 23 | dependencies { 24 | compile 'com.akhgupta:android-easylocation:1.0.1' 25 | compile "com.google.android.gms:play-services-location:x.x.x" 26 | } 27 | ``` 28 | 29 | Extend your `Activity` from `EasyLocationAppCompatActivity` or `EasyLocationActivity`: 30 | 31 | *Create location request according to your needs* 32 | 33 | ```java 34 | LocationRequest locationRequest = new LocationRequest() 35 | .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) 36 | .setInterval(5000) 37 | .setFastestInterval(5000); 38 | ``` 39 | *Create EasyLocation request, and set locationRequest created* 40 | ```java 41 | EasyLocationRequest easyLocationRequest = new EasyLocationRequestBuilder() 42 | .setLocationRequest(locationRequest) 43 | .setFallBackToLastLocationTime(3000) 44 | .build(); 45 | } 46 | ``` 47 | **Request Single location update like this** 48 | ```java 49 | requestSingleLocationFix(easyLocationRequest); 50 | ``` 51 | **Or Request Multiple location updates like this** 52 | ```java 53 | requestLocationUpdates(easyLocationRequest); 54 | ``` 55 | 56 | **You're good to go!**, You will get below callbacks now in your activity 57 | 58 | ```java 59 | @Override 60 | public void onLocationPermissionGranted() { 61 | } 62 | 63 | @Override 64 | public void onLocationPermissionDenied() { 65 | } 66 | 67 | @Override 68 | public void onLocationReceived(Location location) { 69 | } 70 | 71 | @Override 72 | public void onLocationProviderEnabled() { 73 | } 74 | 75 | @Override 76 | public void onLocationProviderDisabled() { 77 | } 78 | ``` 79 | 80 | **Additional Options** 81 | 82 | Specify what messages you want to show to user using *EasyLocationRequestBuilder* 83 | ```java 84 | EasyLocationRequest easyLocationRequest = new EasyLocationRequestBuilder() 85 | .setLocationRequest(locationRequest) 86 | .setLocationPermissionDialogTitle(getString(R.string.location_permission_dialog_title)) 87 | .setLocationPermissionDialogMessage(getString(R.string.location_permission_dialog_message)) 88 | .setLocationPermissionDialogNegativeButtonText(getString(R.string.not_now)) 89 | .setLocationPermissionDialogPositiveButtonText(getString(R.string.yes)) 90 | .setLocationSettingsDialogTitle(getString(R.string.location_services_off)) 91 | .setLocationSettingsDialogMessage(getString(R.string.open_location_settings)) 92 | .setLocationSettingsDialogNegativeButtonText(getString(R.string.not_now)) 93 | .setLocationSettingsDialogPositiveButtonText(getString(R.string.yes)) 94 | .build(); 95 | ``` 96 | 97 | ## License 98 | 99 | Licensed under the Apache License, Version 2.0 (the "License"); 100 | you may not use this file except in compliance with the License. 101 | You may obtain a copy of the License at 102 | 103 | http://www.apache.org/licenses/LICENSE-2.0 104 | 105 | Unless required by applicable law or agreed to in writing, software 106 | distributed under the License is distributed on an "AS IS" BASIS, 107 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 108 | See the License for the specific language governing permissions and 109 | limitations under the License. -------------------------------------------------------------------------------- /android-easylocation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android-easylocation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | ext { 3 | bintrayRepo = 'com.akhgupta' 4 | bintrayName = 'Android-EasyLocation' 5 | 6 | publishedGroupId = 'com.akhgupta' 7 | libraryName = 'Android-EasyLocation' 8 | artifact = 'android-easylocation' 9 | 10 | libraryDescription = 'Library for requesting GPS,Network location using google play services on Android' 11 | 12 | siteUrl = 'https://github.com/akhgupta/Android-EasyLocation' 13 | gitUrl = 'https://github.com/akhgupta/Android-EasyLocation.git' 14 | 15 | libraryVersion = '1.0.1' 16 | 17 | developerId = 'akhgupta' 18 | developerName = 'Akhil Gupta' 19 | developerEmail = 'akhilgupta.me@gmail.com' 20 | 21 | licenseName = 'The Apache Software License, Version 2.0' 22 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 23 | allLicenses = ["Apache-2.0"] 24 | } 25 | //noinspection GroovyMissingReturnStatement 26 | android { 27 | compileSdkVersion 24 28 | buildToolsVersion "24.0.3" 29 | 30 | defaultConfig { 31 | minSdkVersion 15 32 | targetSdkVersion 24 33 | versionCode 1 34 | versionName "1.0.2" 35 | 36 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 37 | 38 | } 39 | buildTypes { 40 | release { 41 | minifyEnabled false 42 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 43 | } 44 | } 45 | } 46 | 47 | dependencies { 48 | compile fileTree(dir: 'libs', include: ['*.jar']) 49 | provided "com.google.android.gms:play-services-location:9.2.0" 50 | 51 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 52 | exclude group: 'com.android.support', module: 'support-annotations' 53 | }) 54 | compile 'com.android.support:appcompat-v7:24.2.1' 55 | testCompile 'junit:junit:4.12' 56 | } 57 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' 58 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle' -------------------------------------------------------------------------------- /android-easylocation/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/akhil/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /android-easylocation/src/androidTest/java/com/akhgupta/easylocation/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.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 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.akhgupta.easylocation.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android-easylocation/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/AppConstants.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | class AppConstants { 4 | public static final int SINGLE_FIX = 1; 5 | public static final int CONTINUOUS_LOCATION_UPDATES = 2; 6 | public static final String ACTION_LOCATION_FETCH_START = "location.fetch.start"; 7 | public static final String ACTION_LOCATION_FETCH_STOP = "location.fetch.stop"; 8 | public static final String INTENT_LOCATION_RECEIVED = "intent.location.received"; 9 | public static final String INTENT_NO_LOCATION_RECEIVED = "intent.no.location.received"; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocation.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.location.Location; 4 | 5 | class EasyLocation { 6 | private final Location location; 7 | 8 | public EasyLocation(Location location) { 9 | this.location = location; 10 | } 11 | 12 | @Override 13 | public boolean equals(Object o) { 14 | if (this == o) return true; 15 | if (o == null || getClass() != o.getClass()) return false; 16 | EasyLocation that = (EasyLocation) o; 17 | return location != null ? location.equals(that.location) : that.location == null; 18 | 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | return location != null ? location.hashCode() : 0; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return location.getLatitude() +","+location.getLongitude(); 29 | } 30 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationActivity.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.location.Location; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | 9 | 10 | public abstract class EasyLocationActivity extends Activity implements EasyLocationListener { 11 | private EasyLocationDelegate easyLocationDelegate; 12 | 13 | protected Location getLastKnownLocation() { 14 | return easyLocationDelegate.getLastKnownLocation(); 15 | } 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | easyLocationDelegate = new EasyLocationDelegate(this,this); 21 | easyLocationDelegate.onCreate(); 22 | } 23 | 24 | @Override 25 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 26 | super.onActivityResult(requestCode, resultCode, data); 27 | easyLocationDelegate.onActivityResult(requestCode); 28 | } 29 | 30 | @Override 31 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 32 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 33 | easyLocationDelegate.onRequestPermissionsResult(requestCode, grantResults); 34 | } 35 | 36 | @Override 37 | protected void onDestroy() { 38 | super.onDestroy(); 39 | easyLocationDelegate.onDestroy(); 40 | } 41 | 42 | protected void requestLocationUpdates(EasyLocationRequest easyLocationRequest) { 43 | easyLocationDelegate.requestLocationUpdates(easyLocationRequest); 44 | } 45 | 46 | 47 | protected void requestSingleLocationFix(EasyLocationRequest easyLocationRequest) { 48 | easyLocationDelegate.requestSingleLocationFix(easyLocationRequest); 49 | } 50 | 51 | protected void stopLocationUpdates() { 52 | easyLocationDelegate.stopLocationUpdates(); 53 | } 54 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationAppCompatActivity.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.content.Intent; 4 | import android.location.Location; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.app.AppCompatActivity; 8 | 9 | 10 | public abstract class EasyLocationAppCompatActivity extends AppCompatActivity implements EasyLocationListener { 11 | private EasyLocationDelegate easyLocationDelegate; 12 | 13 | protected Location getLastKnownLocation() { 14 | return easyLocationDelegate.getLastKnownLocation(); 15 | } 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | easyLocationDelegate = new EasyLocationDelegate(this,this); 21 | easyLocationDelegate.onCreate(); 22 | } 23 | 24 | @Override 25 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 26 | super.onActivityResult(requestCode, resultCode, data); 27 | easyLocationDelegate.onActivityResult(requestCode); 28 | } 29 | 30 | @Override 31 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 32 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 33 | easyLocationDelegate.onRequestPermissionsResult(requestCode, grantResults); 34 | } 35 | 36 | @Override 37 | protected void onDestroy() { 38 | super.onDestroy(); 39 | easyLocationDelegate.onDestroy(); 40 | } 41 | 42 | protected void requestLocationUpdates(EasyLocationRequest easyLocationRequest) { 43 | easyLocationDelegate.requestLocationUpdates(easyLocationRequest); 44 | } 45 | 46 | 47 | protected void requestSingleLocationFix(EasyLocationRequest easyLocationRequest) { 48 | easyLocationDelegate.requestSingleLocationFix(easyLocationRequest); 49 | } 50 | 51 | protected void stopLocationUpdates() { 52 | easyLocationDelegate.stopLocationUpdates(); 53 | } 54 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationDelegate.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | 4 | import android.Manifest; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.DialogInterface; 8 | import android.content.Intent; 9 | import android.content.IntentFilter; 10 | import android.content.pm.PackageManager; 11 | import android.location.Location; 12 | import android.location.LocationManager; 13 | import android.provider.Settings; 14 | import android.support.v4.app.ActivityCompat; 15 | import android.support.v4.content.ContextCompat; 16 | import android.support.v4.content.LocalBroadcastManager; 17 | import android.support.v7.app.AlertDialog; 18 | import android.text.TextUtils; 19 | 20 | import com.google.android.gms.common.ConnectionResult; 21 | import com.google.android.gms.common.GoogleApiAvailability; 22 | import com.google.android.gms.location.LocationRequest; 23 | 24 | import static com.akhgupta.easylocation.AppConstants.CONTINUOUS_LOCATION_UPDATES; 25 | import static com.akhgupta.easylocation.AppConstants.SINGLE_FIX; 26 | 27 | class EasyLocationDelegate { 28 | private static final int PERMISSIONS_REQUEST = 100; 29 | private static final int ENABLE_LOCATION_SERVICES_REQUEST = 101; 30 | private static final int GOOGLE_PLAY_SERVICES_ERROR_DIALOG = 102; 31 | 32 | 33 | private final Activity activity; 34 | private final EasyLocationListener easyLocationListener; 35 | private final LocationBroadcastReceiver locationReceiver; 36 | private LocationManager mLocationManager; 37 | private int mLocationFetchMode; 38 | private LocationRequest mLocationRequest; 39 | private GoogleApiAvailability googleApiAvailability; 40 | private EasyLocationRequest easyLocationRequest; 41 | 42 | EasyLocationDelegate(Activity activity, EasyLocationListener easyLocationListener) { 43 | this.activity = activity; 44 | this.easyLocationListener = easyLocationListener; 45 | locationReceiver = new LocationBroadcastReceiver(easyLocationListener); 46 | } 47 | 48 | 49 | private boolean isLocationEnabled() { 50 | return isGPSLocationEnabled() 51 | || isNetworkLocationEnabled(); 52 | } 53 | 54 | private boolean isGPSLocationEnabled() { 55 | return mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 56 | } 57 | 58 | private boolean isNetworkLocationEnabled() { 59 | return mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 60 | } 61 | 62 | private void openLocationSettings() { 63 | Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 64 | activity.startActivityForResult(intent, ENABLE_LOCATION_SERVICES_REQUEST); 65 | } 66 | 67 | void stopLocationUpdates() { 68 | Intent intent = new Intent(activity, LocationBgService.class); 69 | intent.setAction(AppConstants.ACTION_LOCATION_FETCH_STOP); 70 | activity.startService(intent); 71 | } 72 | 73 | private void isProperRequest(EasyLocationRequest easyLocationRequest) { 74 | if (easyLocationRequest == null) 75 | throw new IllegalStateException("easyLocationRequest can't be null"); 76 | 77 | if (easyLocationRequest.locationRequest == null) 78 | throw new IllegalStateException("locationRequest can't be null"); 79 | this.easyLocationRequest = easyLocationRequest; 80 | } 81 | 82 | private void startLocationBGService(LocationRequest locationRequest, long fallBackToLastLocationTime) { 83 | if (!isLocationEnabled()) 84 | showLocationServicesRequireDialog(); 85 | else { 86 | Intent intent = new Intent(activity, LocationBgService.class); 87 | intent.setAction(AppConstants.ACTION_LOCATION_FETCH_START); 88 | intent.putExtra(IntentKey.LOCATION_REQUEST, locationRequest); 89 | intent.putExtra(IntentKey.LOCATION_FETCH_MODE, mLocationFetchMode); 90 | intent.putExtra(IntentKey.FALLBACK_TO_LAST_LOCATION_TIME, fallBackToLastLocationTime); 91 | activity.startService(intent); 92 | } 93 | } 94 | 95 | private boolean hasLocationPermission() { 96 | return ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; 97 | } 98 | 99 | private void showPermissionRequireDialog() { 100 | String title = TextUtils.isEmpty(easyLocationRequest.locationPermissionDialogTitle) ? activity.getString(R.string.location_permission_dialog_title) : easyLocationRequest.locationPermissionDialogTitle; 101 | String message = TextUtils.isEmpty(easyLocationRequest.locationPermissionDialogMessage) ? activity.getString(R.string.location_permission_dialog_message) : easyLocationRequest.locationPermissionDialogMessage; 102 | String negativeButtonTitle = TextUtils.isEmpty(easyLocationRequest.locationPermissionDialogNegativeButtonText) ? activity.getString(android.R.string.cancel) : easyLocationRequest.locationPermissionDialogNegativeButtonText; 103 | String positiveButtonTitle = TextUtils.isEmpty(easyLocationRequest.locationPermissionDialogPositiveButtonText) ? activity.getString(android.R.string.ok) : easyLocationRequest.locationPermissionDialogPositiveButtonText; 104 | new AlertDialog.Builder(activity) 105 | .setCancelable(true) 106 | .setTitle(title) 107 | .setMessage(message) 108 | .setNegativeButton(negativeButtonTitle, new DialogInterface.OnClickListener() { 109 | @Override 110 | public void onClick(DialogInterface dialogInterface, int i) { 111 | easyLocationListener.onLocationPermissionDenied(); 112 | } 113 | }) 114 | .setPositiveButton(positiveButtonTitle, new DialogInterface.OnClickListener() { 115 | @Override 116 | public void onClick(DialogInterface dialogInterface, int i) { 117 | requestPermission(); 118 | } 119 | }).create().show(); 120 | } 121 | 122 | private void showLocationServicesRequireDialog() { 123 | String title = TextUtils.isEmpty(easyLocationRequest.locationSettingsDialogTitle) ? activity.getString(R.string.location_services_off) : easyLocationRequest.locationSettingsDialogTitle; 124 | String message = TextUtils.isEmpty(easyLocationRequest.locationSettingsDialogMessage) ? activity.getString(R.string.open_location_settings) : easyLocationRequest.locationSettingsDialogMessage; 125 | String negativeButtonText = TextUtils.isEmpty(easyLocationRequest.locationSettingsDialogNegativeButtonText) ? activity.getString(android.R.string.cancel) : easyLocationRequest.locationSettingsDialogNegativeButtonText; 126 | String positiveButtonText = TextUtils.isEmpty(easyLocationRequest.locationSettingsDialogPositiveButtonText) ? activity.getString(android.R.string.ok) : easyLocationRequest.locationSettingsDialogPositiveButtonText; 127 | new AlertDialog.Builder(activity) 128 | .setCancelable(true) 129 | .setTitle(title) 130 | .setMessage(message) 131 | .setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() { 132 | @Override 133 | public void onClick(DialogInterface dialogInterface, int i) { 134 | easyLocationListener.onLocationProviderDisabled(); 135 | } 136 | }) 137 | .setPositiveButton(positiveButtonText, new DialogInterface.OnClickListener() { 138 | @Override 139 | public void onClick(DialogInterface dialogInterface, int i) { 140 | openLocationSettings(); 141 | } 142 | }) 143 | .create().show(); 144 | } 145 | 146 | private void requestPermission() { 147 | ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST); 148 | } 149 | 150 | 151 | private void requestLocation(LocationRequest locationRequest, int locationMode) { 152 | if (isGoogleServiceAvailable()) { 153 | mLocationFetchMode = locationMode; 154 | mLocationRequest = locationRequest; 155 | checkForPermissionAndRequestLocation(locationRequest); 156 | } else 157 | showGooglePlayServicesErrorDialog(); 158 | } 159 | 160 | private void checkForPermissionAndRequestLocation(LocationRequest locationRequest) { 161 | if (!hasLocationPermission()) { 162 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, android.Manifest.permission.ACCESS_FINE_LOCATION)) 163 | showPermissionRequireDialog(); 164 | else 165 | requestPermission(); 166 | } else 167 | startLocationBGService(locationRequest,easyLocationRequest.fallBackToLastLocationTime); 168 | } 169 | 170 | private void unregisterLocationBroadcastReceiver() { 171 | LocalBroadcastManager.getInstance(activity).unregisterReceiver(locationReceiver); 172 | } 173 | 174 | private void registerLocationBroadcastReceiver() { 175 | IntentFilter intentFilter = new IntentFilter(); 176 | intentFilter.addAction(AppConstants.INTENT_LOCATION_RECEIVED); 177 | intentFilter.addAction(AppConstants.INTENT_NO_LOCATION_RECEIVED); 178 | 179 | LocalBroadcastManager.getInstance(activity).registerReceiver(locationReceiver, intentFilter); 180 | } 181 | 182 | private boolean isGoogleServiceAvailable() { 183 | return googleApiAvailability.isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS; 184 | } 185 | 186 | private void showGooglePlayServicesErrorDialog() { 187 | int errorCode = googleApiAvailability.isGooglePlayServicesAvailable(activity); 188 | if (googleApiAvailability.isUserResolvableError(errorCode)) 189 | googleApiAvailability.getErrorDialog(activity, errorCode, GOOGLE_PLAY_SERVICES_ERROR_DIALOG).show(); 190 | } 191 | 192 | 193 | void onCreate() { 194 | mLocationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); 195 | googleApiAvailability = GoogleApiAvailability.getInstance(); 196 | registerLocationBroadcastReceiver(); 197 | } 198 | 199 | void onActivityResult(int requestCode) { 200 | switch (requestCode) { 201 | case ENABLE_LOCATION_SERVICES_REQUEST: 202 | if (isLocationEnabled()) { 203 | requestLocation(mLocationRequest, mLocationFetchMode); 204 | easyLocationListener.onLocationProviderEnabled(); 205 | } else 206 | easyLocationListener.onLocationProviderDisabled(); 207 | break; 208 | } 209 | } 210 | 211 | void onRequestPermissionsResult(int requestCode, int[] grantResults) { 212 | switch (requestCode) { 213 | case PERMISSIONS_REQUEST: 214 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 215 | requestLocation(mLocationRequest, mLocationFetchMode); 216 | easyLocationListener.onLocationPermissionGranted(); 217 | } else 218 | easyLocationListener.onLocationPermissionDenied(); 219 | break; 220 | } 221 | } 222 | 223 | void onDestroy() { 224 | stopLocationUpdates(); 225 | unregisterLocationBroadcastReceiver(); 226 | } 227 | 228 | Location getLastKnownLocation() { 229 | return PreferenceUtil.getInstance(activity).getLastKnownLocation(); 230 | } 231 | 232 | void requestLocationUpdates(EasyLocationRequest easyLocationRequest) { 233 | isProperRequest(easyLocationRequest); 234 | requestLocation(easyLocationRequest.locationRequest, CONTINUOUS_LOCATION_UPDATES); 235 | } 236 | 237 | void requestSingleLocationFix(EasyLocationRequest easyLocationRequest) { 238 | isProperRequest(easyLocationRequest); 239 | requestLocation(easyLocationRequest.locationRequest, SINGLE_FIX); 240 | } 241 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationListener.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.location.Location; 4 | 5 | interface EasyLocationListener { 6 | void onLocationPermissionGranted(); 7 | void onLocationPermissionDenied(); 8 | void onLocationReceived(Location location); 9 | void noLocationReceived(); 10 | void onLocationProviderEnabled(); 11 | void onLocationProviderDisabled(); 12 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationRequest.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | 4 | import com.google.android.gms.location.LocationRequest; 5 | 6 | public class EasyLocationRequest { 7 | final LocationRequest locationRequest; 8 | final String locationSettingsDialogTitle; 9 | final String locationSettingsDialogMessage; 10 | final String locationSettingsDialogPositiveButtonText; 11 | final String locationSettingsDialogNegativeButtonText; 12 | final String locationPermissionDialogTitle; 13 | final String locationPermissionDialogMessage; 14 | final String locationPermissionDialogPositiveButtonText; 15 | final String locationPermissionDialogNegativeButtonText; 16 | final long fallBackToLastLocationTime; 17 | 18 | public EasyLocationRequest(LocationRequest locationRequest, String locationSettingsDialogTitle, String locationSettingsDialogMessage, String locationSettingsDialogPositiveButtonText, String locationSettingsDialogNegativeButtonText, String locationPermissionDialogTitle, String locationPermissionDialogMessage, String locationPermissionDialogPositiveButtonText, String locationPermissionDialogNegativeButtonText, long fallBackToLastLocationTime) { 19 | this.locationRequest = locationRequest; 20 | this.locationSettingsDialogTitle = locationSettingsDialogTitle; 21 | this.locationSettingsDialogMessage = locationSettingsDialogMessage; 22 | this.locationSettingsDialogPositiveButtonText = locationSettingsDialogPositiveButtonText; 23 | this.locationSettingsDialogNegativeButtonText = locationSettingsDialogNegativeButtonText; 24 | this.locationPermissionDialogTitle = locationPermissionDialogTitle; 25 | this.locationPermissionDialogMessage = locationPermissionDialogMessage; 26 | this.locationPermissionDialogPositiveButtonText = locationPermissionDialogPositiveButtonText; 27 | this.locationPermissionDialogNegativeButtonText = locationPermissionDialogNegativeButtonText; 28 | this.fallBackToLastLocationTime = fallBackToLastLocationTime; 29 | } 30 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/EasyLocationRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import com.google.android.gms.location.LocationRequest; 4 | 5 | public class EasyLocationRequestBuilder { 6 | private LocationRequest locationRequest; 7 | private String locationSettingsDialogTitle; 8 | private String locationSettingsDialogMessage; 9 | private String locationSettingsDialogPositiveButtonText; 10 | private String locationSettingsDialogNegativeButtonText; 11 | private String locationPermissionDialogTitle; 12 | private String locationPermissionDialogMessage; 13 | private String locationPermissionDialogPositiveButtonText; 14 | private String locationPermissionDialogNegativeButtonText; 15 | private long fallBackToLastLocationTime; 16 | 17 | public EasyLocationRequestBuilder setLocationRequest(LocationRequest locationRequest) { 18 | this.locationRequest = locationRequest; 19 | return this; 20 | } 21 | 22 | public EasyLocationRequestBuilder setLocationSettingsDialogTitle(String locationSettingsDialogTitle) { 23 | this.locationSettingsDialogTitle = locationSettingsDialogTitle; 24 | return this; 25 | } 26 | 27 | public EasyLocationRequestBuilder setLocationSettingsDialogMessage(String locationSettingsDialogMessage) { 28 | this.locationSettingsDialogMessage = locationSettingsDialogMessage; 29 | return this; 30 | } 31 | 32 | public EasyLocationRequestBuilder setLocationSettingsDialogPositiveButtonText(String locationSettingsDialogPositiveButtonText) { 33 | this.locationSettingsDialogPositiveButtonText = locationSettingsDialogPositiveButtonText; 34 | return this; 35 | } 36 | 37 | public EasyLocationRequestBuilder setLocationSettingsDialogNegativeButtonText(String locationSettingsDialogNegativeButtonText) { 38 | this.locationSettingsDialogNegativeButtonText = locationSettingsDialogNegativeButtonText; 39 | return this; 40 | } 41 | 42 | public EasyLocationRequestBuilder setLocationPermissionDialogTitle(String locationPermissionDialogTitle) { 43 | this.locationPermissionDialogTitle = locationPermissionDialogTitle; 44 | return this; 45 | } 46 | 47 | public EasyLocationRequestBuilder setLocationPermissionDialogMessage(String locationPermissionDialogMessage) { 48 | this.locationPermissionDialogMessage = locationPermissionDialogMessage; 49 | return this; 50 | } 51 | 52 | public EasyLocationRequestBuilder setLocationPermissionDialogPositiveButtonText(String locationPermissionDialogPositiveButtonText) { 53 | this.locationPermissionDialogPositiveButtonText = locationPermissionDialogPositiveButtonText; 54 | return this; 55 | } 56 | 57 | public EasyLocationRequestBuilder setLocationPermissionDialogNegativeButtonText(String locationPermissionDialogNegativeButtonText) { 58 | this.locationPermissionDialogNegativeButtonText = locationPermissionDialogNegativeButtonText; 59 | return this; 60 | } 61 | 62 | public EasyLocationRequestBuilder setFallBackToLastLocationTime(long fallBackToLastLocationTime) { 63 | this.fallBackToLastLocationTime = fallBackToLastLocationTime; 64 | return this; 65 | } 66 | 67 | public EasyLocationRequest build() { 68 | return new EasyLocationRequest(locationRequest, locationSettingsDialogTitle, locationSettingsDialogMessage, locationSettingsDialogPositiveButtonText, locationSettingsDialogNegativeButtonText, locationPermissionDialogTitle, locationPermissionDialogMessage, locationPermissionDialogPositiveButtonText, locationPermissionDialogNegativeButtonText, fallBackToLastLocationTime); 69 | } 70 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/IntentKey.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | class IntentKey { 4 | public static final String LOCATION_REQUEST = "location_request"; 5 | public static final String LOCATION_FETCH_MODE = "location_fetch_mode"; 6 | public static final String LOCATION = "location"; 7 | public static final String FALLBACK_TO_LAST_LOCATION_TIME = "fallback_to_last_location_time"; 8 | } 9 | -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/LocationBgService.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.location.Location; 6 | import android.os.Bundle; 7 | import android.os.Handler; 8 | import android.os.IBinder; 9 | import android.support.annotation.NonNull; 10 | import android.support.annotation.Nullable; 11 | import android.support.v4.content.LocalBroadcastManager; 12 | import android.util.Log; 13 | 14 | import com.google.android.gms.common.ConnectionResult; 15 | import com.google.android.gms.common.api.GoogleApiClient; 16 | import com.google.android.gms.location.LocationListener; 17 | import com.google.android.gms.location.LocationRequest; 18 | import com.google.android.gms.location.LocationServices; 19 | 20 | 21 | public class LocationBgService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,LocationListener { 22 | private static final long NO_FALLBACK = 0; 23 | private final String TAG = LocationBgService.class.getSimpleName(); 24 | private GoogleApiClient googleApiClient; 25 | private int mLocationMode; 26 | private LocationRequest mLocationRequest; 27 | private Handler handler; 28 | private long fallBackToLastLocationTime; 29 | 30 | 31 | @Nullable 32 | @Override 33 | public IBinder onBind(Intent intent) { 34 | return null; 35 | } 36 | 37 | @Override 38 | public void onCreate() { 39 | super.onCreate(); 40 | handler = new Handler(); 41 | googleApiClient = new GoogleApiClient.Builder(this) 42 | .addApi(LocationServices.API) 43 | .addConnectionCallbacks(this) 44 | .addOnConnectionFailedListener(this) 45 | .build(); 46 | Log.d(TAG,"googleApiClient created"); 47 | googleApiClient.connect(); 48 | } 49 | 50 | @SuppressWarnings("MissingPermission") 51 | @Override 52 | public int onStartCommand(Intent intent, int flags, int startId) { 53 | super.onStartCommand(intent,flags,startId); 54 | Log.d(TAG,"googleApiClient start command "+ intent.getAction()); 55 | if(intent.getAction().equals(AppConstants.ACTION_LOCATION_FETCH_START)) { 56 | mLocationMode = intent.getIntExtra(IntentKey.LOCATION_FETCH_MODE, AppConstants.SINGLE_FIX); 57 | mLocationRequest = intent.getParcelableExtra(IntentKey.LOCATION_REQUEST); 58 | fallBackToLastLocationTime = intent.getLongExtra(IntentKey.FALLBACK_TO_LAST_LOCATION_TIME,NO_FALLBACK); 59 | if (mLocationRequest == null) 60 | throw new IllegalStateException("Location request can't be null"); 61 | if(googleApiClient.isConnected()) 62 | requestLocationUpdates(); 63 | } 64 | else if(intent.getAction().equals(AppConstants.ACTION_LOCATION_FETCH_STOP)) { 65 | stopLocationService(); 66 | } 67 | return START_NOT_STICKY; 68 | } 69 | 70 | @SuppressWarnings("MissingPermission") 71 | private void requestLocationUpdates() { 72 | if (mLocationRequest != null) { 73 | startFallbackToLastLocationTimer(); 74 | LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, mLocationRequest, this); 75 | } 76 | } 77 | 78 | @SuppressWarnings("MissingPermission") 79 | private void startFallbackToLastLocationTimer() { 80 | if(fallBackToLastLocationTime!=NO_FALLBACK) { 81 | handler.removeCallbacksAndMessages(null); 82 | handler.postDelayed(new Runnable() { 83 | @Override 84 | public void run() { 85 | onLocationChanged(LocationServices.FusedLocationApi.getLastLocation(googleApiClient)); 86 | } 87 | }, fallBackToLastLocationTime); 88 | } 89 | } 90 | 91 | @SuppressWarnings("MissingPermission") 92 | @Override 93 | public void onConnected(@Nullable Bundle bundle) { 94 | Log.d(TAG,"googleApiClient connected"); 95 | requestLocationUpdates(); 96 | } 97 | 98 | @Override 99 | public void onConnectionSuspended(int i) { 100 | Log.d(TAG,"googleApiClient connection suspended"); 101 | stopLocationService(); 102 | } 103 | 104 | @Override 105 | public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 106 | Log.d(TAG,"googleApiClient connection failed"); 107 | stopLocationService(); 108 | } 109 | 110 | private void stopLocationService() { 111 | if(handler!=null) 112 | handler.removeCallbacksAndMessages(null); 113 | 114 | Log.d(TAG,"googleApiClient removing location updates"); 115 | if(googleApiClient!=null && googleApiClient.isConnected()) { 116 | LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient,this); 117 | Log.d(TAG,"googleApiClient disconnect"); 118 | googleApiClient.disconnect(); 119 | } 120 | Log.d(TAG,"googleApiClient stop service"); 121 | stopSelf(); 122 | } 123 | 124 | @Override 125 | public void onLocationChanged(Location location) { 126 | Log.d(TAG,"googleApiClient location received"); 127 | if(location!=null) { 128 | PreferenceUtil.getInstance(this).saveLastKnownLocation(location); 129 | Intent intent = new Intent(); 130 | intent.setAction(AppConstants.INTENT_LOCATION_RECEIVED); 131 | intent.putExtra(IntentKey.LOCATION,location); 132 | LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 133 | } else { 134 | Intent intent = new Intent(); 135 | intent.setAction(AppConstants.INTENT_NO_LOCATION_RECEIVED); 136 | LocalBroadcastManager.getInstance(this).sendBroadcast(intent); 137 | } 138 | if(mLocationMode == AppConstants.SINGLE_FIX) 139 | stopLocationService(); 140 | } 141 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/LocationBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.location.Location; 7 | 8 | class LocationBroadcastReceiver extends BroadcastReceiver { 9 | private final EasyLocationListener easyLocationListener; 10 | 11 | public LocationBroadcastReceiver(EasyLocationListener easyLocationListener) { 12 | this.easyLocationListener = easyLocationListener; 13 | } 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | if (intent.getAction().equals(AppConstants.INTENT_LOCATION_RECEIVED)) { 18 | Location location = intent.getParcelableExtra(IntentKey.LOCATION); 19 | easyLocationListener.onLocationReceived(location); 20 | } else if (AppConstants.INTENT_NO_LOCATION_RECEIVED.equals(intent.getAction())) { 21 | easyLocationListener.noLocationReceived(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/java/com/akhgupta/easylocation/PreferenceUtil.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.location.Location; 6 | import android.text.TextUtils; 7 | 8 | class PreferenceUtil { 9 | private static final String LAST_KNOWN_LOCATION = "last_known_location"; 10 | private static final String GPS = "GPS"; 11 | private static final String PREF_NAME = "easylocation"; 12 | private final SharedPreferences mPreferences; 13 | private static PreferenceUtil instance; 14 | 15 | public static PreferenceUtil getInstance(Context context) { 16 | if(instance ==null) { 17 | instance = new PreferenceUtil(context.getApplicationContext()); 18 | } 19 | return instance; 20 | } 21 | 22 | private PreferenceUtil(Context context) { 23 | mPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); 24 | } 25 | 26 | public Location getLastKnownLocation() { 27 | String locationString = mPreferences.getString(LAST_KNOWN_LOCATION, null); 28 | if(TextUtils.isEmpty(locationString)) 29 | return null; 30 | else { 31 | String[] latLong = locationString.split(","); 32 | Location location = new Location(GPS); 33 | location.setLatitude(Double.parseDouble(latLong[0])); 34 | location.setLongitude(Double.parseDouble(latLong[1])); 35 | return location; 36 | } 37 | } 38 | public void saveLastKnownLocation(Location location) { 39 | EasyLocation easyLocation= new EasyLocation(location); 40 | mPreferences.edit().putString(LAST_KNOWN_LOCATION,easyLocation.toString()).apply(); 41 | } 42 | } -------------------------------------------------------------------------------- /android-easylocation/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EasyLocation 3 | Location permission needed 4 | Enable Location permission now? 5 | Location services OFF 6 | Enable location services now? 7 | -------------------------------------------------------------------------------- /android-easylocation/src/test/java/com/akhgupta/easylocation/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation; 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 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-apt' 3 | 4 | //noinspection GroovyMissingReturnStatement,GroovyMissingReturnStatement 5 | android { 6 | compileSdkVersion 24 7 | buildToolsVersion "24.0.3" 8 | defaultConfig { 9 | applicationId "com.akhgupta.easylocation.demo" 10 | minSdkVersion 15 11 | targetSdkVersion 24 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(include: ['*.jar'], dir: 'libs') 26 | compile 'com.jakewharton:butterknife:8.4.0' 27 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 28 | compile "com.google.android.gms:play-services-location:9.6.0" 29 | 30 | 31 | 32 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 33 | exclude group: 'com.android.support', module: 'support-annotations' 34 | }) 35 | compile 'com.android.support:appcompat-v7:24.2.1' 36 | testCompile 'junit:junit:4.12' 37 | compile project(':android-easylocation') 38 | } 39 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/akhil/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/akhgupta/easylocation/demo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation.demo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.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 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.akhgupta.easylocation.demo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/akhgupta/easylocation/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.akhgupta.easylocation.demo; 2 | 3 | import android.location.Location; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.Toast; 8 | 9 | import com.akhgupta.easylocation.EasyLocationAppCompatActivity; 10 | import com.akhgupta.easylocation.EasyLocationRequest; 11 | import com.akhgupta.easylocation.EasyLocationRequestBuilder; 12 | import com.google.android.gms.location.LocationRequest; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import butterknife.OnClick; 17 | import butterknife.Unbinder; 18 | 19 | public class MainActivity extends EasyLocationAppCompatActivity { 20 | @BindView(R.id.requestSingleLocationButton) 21 | Button requestSingleLocationButton; 22 | @BindView(R.id.requestLocationUpdatesButton) 23 | Button requestLocationUpdatesButton; 24 | @BindView(R.id.stopLocationUpdatesButton) 25 | Button stopLocationUpdatesButton; 26 | private Unbinder unbinder; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | unbinder = ButterKnife.bind(this); 33 | } 34 | 35 | @Override 36 | public void onLocationPermissionGranted() { 37 | showToast("Location permission granted"); 38 | } 39 | 40 | private void showToast(String message) { 41 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); 42 | } 43 | 44 | @Override 45 | public void onLocationPermissionDenied() { 46 | showToast("Location permission denied"); 47 | } 48 | 49 | @Override 50 | public void onLocationReceived(Location location) { 51 | showToast(location.getProvider() + "," + location.getLatitude() + "," + location.getLongitude()); 52 | } 53 | 54 | @Override 55 | public void noLocationReceived() { 56 | showToast("No location received"); 57 | } 58 | 59 | @Override 60 | public void onLocationProviderEnabled() { 61 | showToast("Location services are now ON"); 62 | } 63 | 64 | @Override 65 | public void onLocationProviderDisabled() { 66 | showToast("Location services are still Off"); 67 | } 68 | 69 | @OnClick({R.id.requestSingleLocationButton, R.id.requestLocationUpdatesButton, R.id.stopLocationUpdatesButton}) 70 | public void onClick(View view) { 71 | switch (view.getId()) { 72 | case R.id.requestSingleLocationButton: { 73 | LocationRequest locationRequest = new LocationRequest() 74 | .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) 75 | .setInterval(5000) 76 | .setFastestInterval(5000); 77 | EasyLocationRequest easyLocationRequest = new EasyLocationRequestBuilder() 78 | .setLocationRequest(locationRequest) 79 | .setFallBackToLastLocationTime(3000) 80 | .build(); 81 | requestSingleLocationFix(easyLocationRequest); 82 | } 83 | break; 84 | case R.id.requestLocationUpdatesButton: { 85 | LocationRequest locationRequest = new LocationRequest() 86 | .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) 87 | .setInterval(5000) 88 | .setFastestInterval(5000); 89 | EasyLocationRequest easyLocationRequest = new EasyLocationRequestBuilder() 90 | .setLocationRequest(locationRequest) 91 | .setFallBackToLastLocationTime(3000) 92 | .build(); 93 | requestLocationUpdates(easyLocationRequest); 94 | } 95 | break; 96 | case R.id.stopLocationUpdatesButton: 97 | stopLocationUpdates(); 98 | break; 99 | } 100 | } 101 | 102 | @Override 103 | protected void onDestroy() { 104 | super.onDestroy(); 105 | unbinder.unbind(); 106 | } 107 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |