Skip to content

Instantly share code, notes, and snippets.

@rakshakhegde
Last active May 30, 2017 07:23
Show Gist options
  • Save rakshakhegde/3d1952817d42c76aa0f1e053cc465030 to your computer and use it in GitHub Desktop.
Save rakshakhegde/3d1952817d42c76aa0f1e053cc465030 to your computer and use it in GitHub Desktop.
If GPS disabled, show dialog to enable GPS and provide location updates: FusedLocationEnabler using Lifecycle from Arch Components
package me.rakshakhegde.locationapp
import android.app.Activity
import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleObserver
import android.arch.lifecycle.OnLifecycleEvent
import android.content.IntentSender
import android.location.Location
import android.os.Bundle
import android.util.Log
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.api.GoogleApiClient
import com.google.android.gms.common.api.ResultCallback
import com.google.android.gms.location.*
/**
* Created by rakshakhegde on 29/05/17.
*/
class FusedLocationEnabler(val act: Activity, lifecycle: Lifecycle) :
LifecycleObserver,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<LocationSettingsResult> {
private val TAG = "FusedLocationEnabler"
/**
* Constant used in the location settings dialog.
*/
val REQUEST_CHECK_SETTINGS = 0x1
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
private val UPDATE_INTERVAL_IN_MILLISECONDS: Long = 60 * 1000
/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
private val FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2
private val mGoogleApiClient by lazy {
GoogleApiClient.Builder(act)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build()
}
private val mLocationRequest: LocationRequest by lazy {
LocationRequest().apply {
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
interval = UPDATE_INTERVAL_IN_MILLISECONDS
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
fastestInterval = FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
}
private val mLocationSettingsRequest: LocationSettingsRequest by lazy {
LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest)
.build()
}
init {
lifecycle.addObserver(this@FusedLocationEnabler)
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
mGoogleApiClient.connect()
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
if (mGoogleApiClient.isConnected) {
startLocationUpdates()
checkLocationSettings()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
// Stop location updates to save battery, but don't disconnect the GoogleApiClient object.
if (mGoogleApiClient.isConnected) {
stopLocationUpdates()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
mGoogleApiClient.disconnect()
}
private fun checkLocationSettings() {
val result = LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient,
mLocationSettingsRequest
)
result.setResultCallback(this)
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
override fun onConnected(connectionHint: Bundle?) {
Log.i(TAG, "Connected to GoogleApiClient")
startLocationUpdates()
checkLocationSettings()
}
override fun onConnectionSuspended(cause: Int) {
Log.i(TAG, "Connection suspended")
}
override fun onConnectionFailed(result: ConnectionResult) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.errorCode)
}
/**
* Callback that fires when the location changes.
*/
override fun onLocationChanged(location: Location?) {
Log.i(TAG, "onLocationChanged $location")
}
/**
* The callback invoked when
* [com.google.android.gms.location.SettingsApi.checkLocationSettings] is called. Examines the
* [com.google.android.gms.location.LocationSettingsResult] object and determines if
* location settings are adequate. If they are not, begins the process of presenting a location
* settings dialog to the user.
*/
override fun onResult(locationSettingsResult: LocationSettingsResult) {
val status = locationSettingsResult.status
when (status.statusCode) {
LocationSettingsStatusCodes.SUCCESS -> {
Log.i(TAG, "All location settings are satisfied.")
startLocationUpdates()
}
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
Log.i(TAG, "Location settings are not satisfied. Show the user a dialog to" +
" upgrade location settings.")
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(act, REQUEST_CHECK_SETTINGS)
} catch (e: IntentSender.SendIntentException) {
Log.i(TAG, "Location status PendingIntent unable to execute request")
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE ->
Log.i(TAG, "Location settings are inadequate, and cannot be fixed here. Dialog not created.")
}
}
/**
* Requests location updates from the FusedLocationApi.
*/
fun startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient,
mLocationRequest,
this
).setResultCallback { status ->
println("startLocationUpdates() ${status.statusMessage}")
}
}
/**
* Removes location updates from the FusedLocationApi.
*/
private fun stopLocationUpdates() {
// It is a good practice to remove location requests when the activity is in a paused or
// stopped state. Doing so helps battery performance and is especially
// recommended in applications that request frequent location updates.
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this@FusedLocationEnabler)
.setResultCallback { status ->
println("stopLocationUpdates() ${status.statusMessage}")
}
}
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
when (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
REQUEST_CHECK_SETTINGS -> when (resultCode) {
Activity.RESULT_OK -> {
Log.i(TAG, "User agreed to make required location settings changes")
startLocationUpdates()
}
Activity.RESULT_CANCELED ->
Log.i(TAG, "User chose not to make required location settings changes")
}
}
}
}
package me.rakshakhegde.locationapp
import android.app.Activity
import android.arch.lifecycle.LifecycleActivity
class LocationMapActivity : LifecycleActivity() {
private val fusedLocationEnabler = FusedLocationEnabler(this@LocationMapActivity, lifecycle)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
fusedLocationEnabler.onActivityResult(requestCode, resultCode, data)
}
}
// In case you cannot use LifecycleActivity directly, implement interface LifecycleRegistryOwner
package me.rakshakhegde.locationapp
import android.arch.lifecycle.LifecycleRegistry
import android.arch.lifecycle.LifecycleRegistryOwner
abstract class SuperActivity : LifecycleRegistryOwner {
private val mRegistry = LifecycleRegistry(this@SuperActivity)
override fun getLifecycle() = mRegistry
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment