I am working in kotlin and my fragment lies inside an activity. So when I run my app and as soon as the location fragment opens up it asks me for the permission but immediately crashes, so I'm unable to allow or deny the permission.
Here's my code for location fragment:
package com.example.atry.MakeComplaint
import android.app.Activity
import android.app.Activity.RESULT_OK
import com.example.atry.Retrofit.INodeJS
import com.example.atry.Retrofit.Observables
import com.example.atry.Retrofit.RetrofitClient
import android.content.Context
import android.content.IntentSender
import android.content.pm.PackageManager
import android.location.*
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.Toast
import com.google.android.gms.maps.MapView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.atry.R
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.*
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.*
import kotlinx.android.synthetic.main.fragment_location.view.*
import retrofit2.Call
import retrofit2.Response
class LocationFragment : Fragment(), OnMapReadyCallback, GoogleMap.OnMarkerClickListener {
override fun onMarkerClick(p0: Marker?)= false
private lateinit var map: GoogleMap
private lateinit var mapView : MapView
private lateinit var restrict:LatLngBounds
lateinit var myAPI: INodeJS
var MyCategory: Observables.Complainttype?=null
private var listener: OnLocationFragmentInteractionListener? = null
var makeComplaintobject1:Observables.final?=null
lateinit var typename:String
var objectComplaint =
Observables.Complaint(
1 , "dummy problem" ,
"url" ,
Observables.Location("78.4","17.4"),
Observables.ComplaintTypes("Smell" ),
Observables.Status( "Unresolved")
)
//for updating user's location/ for current location
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var locationRequest: LocationRequest
private lateinit var locationCallback: LocationCallback
// private lateinit var lastLocation: Location
var lastLocation:Location?=null
private var locationUpdateState = false
companion object {
private const val LOCATION_PERMISSION_REQUEST_CODE = 1
private const val REQUEST_CHECK_SETTINGS = 2 //For updating user's location as they move
}
fun sendCategoryItem(category: Observables.Complainttype) {
//receiving the category selected from Category Fragment
this.MyCategory = category
Log.d("here", "i am here 1")
Log.d("here", MyCategory.toString())
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
locationResult ?: return
if (locationResult.locations.isNotEmpty()) {
// get latest location and sets it on the map
lastLocation = locationResult.lastLocation
Log.d("lastlocation", lastLocation.toString())
placeMarkerOnMap(LatLng(lastLocation!!.latitude, lastLocation!!.longitude))
} } }
getLocationUpdates()
//INIT API
val retrofit = RetrofitClient.instanc
myAPI = retrofit.create(INodeJS::class.java)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val v = inflater.inflate(R.layout.fragment_location, container, false)
mapView = v.findViewById(R.id.maps)
mapView.onCreate(savedInstanceState)
mapView.onResume()
try {
MapsInitializer.initialize(getActivity()!!.getApplicationContext())
} catch (sendEx: IntentSender.SendIntentException) {
sendEx.printStackTrace()
}
mapView.getMapAsync(this)
v.backToList.setOnClickListener {
backFragment()
}
v.forwardToDescription.setOnClickListener{
//will proceed to the Category Description fragment only if the lastLocation isn't null
getAllData()
}
return v
}
private fun setUpMap() {
if (activity!!.checkSelfPermission(
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
return
}
}
private fun checkForPermissions(){
if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
}
startLocationUpdates()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(grantResults.size >0){
if(requestCode== LOCATION_PERMISSION_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED){
locationUpdateState=true
checkForPermissions()
}
}
}
/**
* call this method in onCreate
* onLocationResult call when location is changed
*/
private fun getLocationUpdates() {
//with fusedLocationClient
// fusedLocationClient = LocationServices.getFusedLocationProviderClient(context!!)
locationRequest = LocationRequest()
locationRequest.interval = 1000
locationRequest.fastestInterval = 5000
locationRequest.smallestDisplacement = 170f // 170 m = 0.1 mile
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //set according to your app function
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest)
val client = LocationServices.getSettingsClient(context!!)
val task = client.checkLocationSettings(builder.build())
//can update the map if location services on
task.addOnSuccessListener {
locationUpdateState=true
checkForPermissions()
}
task.addOnFailureListener { e ->
//check if the location settings is on yet
if(e is ResolvableApiException){
try{
e.startResolutionForResult(activity, REQUEST_CHECK_SETTINGS)
}catch (sendEx : IntentSender.SendIntentException){
}
}
}
}
//Places the marker on the map and changes its style.
private fun placeMarkerOnMap(location: LatLng) {
// 1
val markerOptions = MarkerOptions().position(location)
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED))
// 2
map.addMarker(markerOptions)
}
//start location updates
private fun startLocationUpdates() {
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
null /* Looper */
)
}
// stop location updates
private fun stopLocationUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback)
}
// start receiving location update when activity visible/foreground
override fun onResume() {
super.onResume()
mapView.onResume()
checkForPermissions()
// startLocationUpdates()
}
// stop receiving location update when activity not visible/foreground
override fun onPause() {
super.onPause()
mapView.onPause()
stopLocationUpdates()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override public fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onMapReady(googleMap: GoogleMap?) {
map = googleMap!!
map.uiSettings?.isZoomControlsEnabled = true
setUpMap()
map.isMyLocationEnabled = true
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
//updating the map with user's current location
if (location !=null){
lastLocation = location
val currentLatLng = LatLng(location.latitude,location.longitude)
placeMarkerOnMap(currentLatLng)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng,12f))
}
}
}
private fun backFragment() {
val manager = (context as AppCompatActivity).supportFragmentManager
manager.popBackStackImmediate()
}
fun getAllData(){
//
// val latitude = 17.4
// val longitude = 78.4
// LocationUtils().getInstance(appContext)
// LocationUtils().getLocation().observe(this, Observer {loc: Location? ->
// location = loc!!
// // Yay! location recived. Do location related work here
// Log.i(TAG,"Location: ${location.latitude} ${location.longitude}")
//
// })
if(lastLocation!=null){
makeComplaintobject1 = Observables.final(
Observables.ComplaintTypes(MyCategory!!.typeName),
// Observables.Location(lastLocation.longitude.toString(),lastLocation.latitude.toString()) //lateinit wala
Observables.Location(lastLocation!!.longitude.toString(),lastLocation!!.latitude.toString())
)
}
else{
makeComplaintobject1 = Observables.final(
Observables.ComplaintTypes(MyCategory!!.typeName),
// Observables.Location(lastLocation.longitude.toString(),lastLocation.latitude.toString()) //lateinit wala
Observables.Location("","")
)
}
typename = MyCategory!!.typeName
val call = myAPI.checkExistingComplain(typename,makeComplaintobject1!!.finalLocation.longitude, makeComplaintobject1!!.finalLocation.latitude ) //new
Log.d("T", typename)
Log.d("Lo", makeComplaintobject1!!.finalLocation.longitude)
Log.d("La", makeComplaintobject1!!.finalLocation.latitude)
call.enqueue(object : retrofit2.Callback<Observables.checkExistingResult> {
override fun onFailure(call: Call<Observables.checkExistingResult>?, t: Throwable?) {
Log.d("NO", t!!.message)
}
override fun onResponse(call: Call<Observables.checkExistingResult>?, response: Response<Observables.checkExistingResult>?) {
Log.d("response popup", response!!.code().toString())
//
if(response.code() == 200){
Log.d("YES", response.code().toString())
Log.d("response", response.body().toString())
if(response.body()!!.Complain === null){
//if type and location are in db but does not match
Log.d("null",response.body()!!.Complain.toString())
var item1 = makeComplaintobject1
Log.d("wohoooooo",makeComplaintobject1.toString())
listener!!.onLocationFragmentInteraction1(item1!!) // typeName and location going to category description
}
else{
//if location or type matched
objectComplaint = response.body()!!.Complain!!
Log.d("got the complaint",objectComplaint.toString())
setExistingData(objectComplaint)
val item = objectComplaint
listener!!.onLocationFragmentInteraction(item) // all complaint going to popup
}
}
else if(response.code() == 500){
//if location or type is not in db
Log.d("response error", response.body().toString())
var item1 = makeComplaintobject1
Log.d("NOT IN DB",makeComplaintobject1.toString())
listener!!.onLocationFragmentInteraction1(item1!!) // typeName and location going to category description
}
else{
var item1 = makeComplaintobject1
Log.d("wohoooooo!1111",makeComplaintobject1.toString())
listener!!.onLocationFragmentInteraction1(item1!!) // typeName and location going to category description
//descriptionFragment()
}
}
})
}
interface OnLocationFragmentInteractionListener {
fun onLocationFragmentInteraction(item: Observables.Complaint?) // all complaint going to popup
fun onLocationFragmentInteraction1(item1: Observables.final) // typeName and location going to category description
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is OnLocationFragmentInteractionListener) {
listener = context
}
else {
throw RuntimeException("$context must implement OnLocationFragmentInteractionListener")
}
}
fun setExistingData(test: Observables.Complaint) {
objectComplaint = test
}
}
I have already asked for the ACCESS_FINE_LOCATION permission in the manifest and my min sdk version is 23 while targetsdk is 26.
After a lot of tries I am still getting the following error.
java.lang.SecurityException: my location requires permission ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION
Please if anyone could help me with this I'd really appreciate it!!
If you are running on Marshmallow
or greater version then you need to check permission of ACCESS_FINE_LOCATION
if user has granted or not if not then you will get SecurityException
when you try to access location without user consent. so before accessing location You check like this -
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// you can access LOCATION
}
else
{
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 411);
}
}
else
{
// you can access LOCATION
}
Get Result of the Permission dialog,
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 411) {
if (grantResults.length == 0 || grantResults == null) {
// show dialog that you need access to go ahead
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Your code here permission granted
} else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// show dialog that you need access to go ahead
}
}
}
Now coming to your code
private fun checkForPermissions(){
if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
}
startLocationUpdates()
}
Right after
if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
this if condition
end you are calling
startLocationUpdates()
so that's why after permission dialog system call this method and try to get location updates without user consent and app crash with SecurityException
.
Your updates method could like below -
private fun checkForPermissions(){
if(activity!!.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
requestPermissions( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
}else{
startLocationUpdates()
}
}
Hope this will help you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.