Created
December 28, 2021 19:50
-
-
Save SurajBahadur/4539f7fea562b7307e46b54d20e3ebf4 to your computer and use it in GitHub Desktop.
Fetch current location in kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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