Skip to content

Instantly share code, notes, and snippets.

@SurajBahadur
Created December 28, 2021 19:50
Show Gist options
  • Save SurajBahadur/4539f7fea562b7307e46b54d20e3ebf4 to your computer and use it in GitHub Desktop.
Save SurajBahadur/4539f7fea562b7307e46b54d20e3ebf4 to your computer and use it in GitHub Desktop.
Fetch current location in kotlin
/*
* Copyright (C) 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.location.currentlocationkotlin
import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.example.android.location.currentlocationkotlin.databinding.ActivityMainBinding
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationRequest.PRIORITY_HIGH_ACCURACY
import com.google.android.gms.location.LocationServices
import com.google.android.gms.tasks.CancellationTokenSource
import com.google.android.gms.tasks.Task
import com.google.android.material.snackbar.Snackbar
/**
* Demonstrates how to easily get the current location via the [FusedLocationProviderClient.getCurrentLocation].
* The main code is in this class's requestCurrentLocation() method.
*/
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
// The Fused Location Provider provides access to location APIs.
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(applicationContext)
}
// Allows class to cancel the location request if it exits the activity.
// Typically, you use one cancellation source per lifecycle.
private var cancellationTokenSource = CancellationTokenSource()
// If the user denied a previous permission request, but didn't check "Don't ask again", this
// Snackbar provides an explanation for why user should approve, i.e., the additional rationale.
private val fineLocationRationalSnackbar by lazy {
Snackbar.make(
binding.container,
R.string.fine_location_permission_rationale,
Snackbar.LENGTH_LONG
).setAction(R.string.ok) {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE
)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
override fun onStop() {
super.onStop()
// Cancels location request (if in flight).
cancellationTokenSource.cancel()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
Log.d(TAG, "onRequestPermissionResult()")
if (requestCode == REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE) {
when {
grantResults.isEmpty() ->
// If user interaction was interrupted, the permission request
// is cancelled and you receive an empty array.
Log.d(TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED ->
Snackbar.make(
binding.container,
R.string.permission_approved_explanation,
Snackbar.LENGTH_LONG
)
.show()
else -> {
Snackbar.make(
binding.container,
R.string.fine_permission_denied_explanation,
Snackbar.LENGTH_LONG
)
.setAction(R.string.settings) {
// Build intent that displays the App settings screen.
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID,
null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
.show()
}
}
}
}
fun locationRequestOnClick(view: View) {
Log.d(TAG, "locationRequestOnClick()")
val permissionApproved =
applicationContext.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
if (permissionApproved) {
requestCurrentLocation()
} else {
requestPermissionWithRationale(
Manifest.permission.ACCESS_FINE_LOCATION,
REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE,
fineLocationRationalSnackbar
)
}
}
/**
* Gets current location.
* Note: The code checks for permission before calling this method, that is, it's never called
* from a method with a missing permission. Also, I include a second check with my extension
* function in case devs just copy/paste this code.
*/
@SuppressLint("MissingPermission")
private fun requestCurrentLocation() {
Log.d(TAG, "requestCurrentLocation()")
if (applicationContext.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
// Returns a single current location fix on the device. Unlike getLastLocation() that
// returns a cached location, this method could cause active location computation on the
// device. A single fresh location will be returned if the device location can be
// determined within reasonable time (tens of seconds), otherwise null will be returned.
//
// Both arguments are required.
// PRIORITY type is self-explanatory. (Other options are PRIORITY_BALANCED_POWER_ACCURACY,
// PRIORITY_LOW_POWER, and PRIORITY_NO_POWER.)
// The second parameter, [CancellationToken] allows the activity to cancel the request
// before completion.
val currentLocationTask: Task<Location> = fusedLocationClient.getCurrentLocation(
PRIORITY_HIGH_ACCURACY,
cancellationTokenSource.token
)
currentLocationTask.addOnCompleteListener { task: Task<Location> ->
val result = if (task.isSuccessful && task.result != null) {
val result: Location = task.result
"Location (success): ${result.latitude}, ${result.longitude}"
} else {
val exception = task.exception
"Location (failure): $exception"
}
Log.d(TAG, "getCurrentLocation() result: $result")
logOutputToScreen(result)
}
}
}
private fun logOutputToScreen(outputString: String) {
val finalOutput = binding.outputTextView.text.toString() + "\n" + outputString
binding.outputTextView.text = finalOutput
}
companion object {
private const val TAG = "MainActivity"
private const val REQUEST_FINE_LOCATION_PERMISSIONS_REQUEST_CODE = 34
}
}
/*
* Copyright (C) 2020 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.location.currentlocationkotlin
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import com.google.android.material.snackbar.Snackbar
/**
* Helper functions to simplify permission checks/requests.
*/
fun Context.hasPermission(permission: String): Boolean {
// Background permissions didn't exit prior to Q, so it's approved by default.
if (permission == Manifest.permission.ACCESS_BACKGROUND_LOCATION &&
android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q) {
return true
}
return ActivityCompat.checkSelfPermission(this, permission) ==
PackageManager.PERMISSION_GRANTED
}
/**
* Requests permission and if the user denied a previous request, but didn't check
* "Don't ask again", we provide additional rationale.
*
* Note: The [Snackbar] should have an action to request the permission.
*/
fun Activity.requestPermissionWithRationale(
permission: String,
requestCode: Int,
snackbar: Snackbar
) {
val provideRationale = shouldShowRequestPermissionRationale(permission)
if (provideRationale) {
snackbar.show()
} else {
requestPermissions(arrayOf(permission), requestCode)
}
}
© 2021 GitHub, Inc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment