Here's my code:
private var longitude = ""
private var latitude = ""
In the oncreateView, I have to do a api call with my latitude and longitude data. But the value of latitude and longitude never change!
//location
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(requireActivity())
// getCurrentLocation
checkPermissions()
//CALL API
val request = Request.Builder()
.url(" API_PATH?latitude=$latitude&longitude=$longitude")
.build()
val client = OkHttpClient()
...
private fun checkPermissions(){
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_DENIED){
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 1)
}
else{
getLocations()
}
}
private fun getLocations() {
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
fusedLocationProviderClient.lastLocation.addOnCompleteListener {
if(it == null){
Toast.makeText(requireContext(), "sorry can't get the location", Toast.LENGTH_SHORT).show()
}else it.apply {
latitude = it.result.latitude.toString()
longitude = it.result.longitude.toString()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== 1){
if(grantResults.isNotEmpty() && grantResults[0]==PackageManager.PERMISSION_GRANTED){
//permission granted
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED){
Toast.makeText(requireContext(), "Permission granted", Toast.LENGTH_SHORT).show()
getLocations()
}
}else{
Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show()
//denied permission
}
}
}
First, I enter always in th first condition in checkPermissions(). I don't know why. Secondly, I also try to write getLocations() in the first condition in the first if in checkPermissions(). But longitude and latitude are never update.
Can you help me please, I am on this case for a long time and I have no idea.
I think you always enter the first condition in checkPermissions() because you haven't yet granted the permissions.
I think you need to request the permissions where the TODO code is commented out.
It will be something like:
// You can directly ask for the permission.
requestPermissions(CONTEXT,
arrayOf(Manifest.permission.REQUESTED_PERMISSION),
REQUEST_CODE)
Found from https://developer.android.com/training/permissions/requesting
I hope that steers you in the right direction.
If you want to cheat for testing, you can go to Settings -> Apps -> Your app -> Permissions and enable the permissions and then re-test. Of course, you'll have to do the request in code for the users of your app before you release the app.
Related
I need to access the IMEI number of android device. I'm not going to publish this android app on playstore. It's for personal use in the organization. Is there any workaround to fetch the IMEI number? Right now I'm geting security exception while fetching IMEI. I have made device admin app. Though I'm not able to access IMEI number.
class MainActivity : AppCompatActivity() {
val REQUEST_CODE = 101
var imei: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// in the below line, we are initializing our variables.
// in the below line, we are initializing our variables.
val telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager
val imeiTextView = findViewById<TextView>(R.id.idTVIMEI)
// in the below line, we are checking for permissions
// in the below line, we are checking for permissions
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.READ_PHONE_STATE
) != PackageManager.PERMISSION_GRANTED
) {
// if permissions are not provided we are requesting for permissions.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_PHONE_STATE),
REQUEST_CODE
)
}
// in the below line, we are setting our imei to our text view.
// in the below line, we are setting our imei to our text view.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
imei = telephonyManager.imei
}
imeiTextView.setText(imei)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String?>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE) {
// in the below line, we are checking if permission is granted.
if (grantResults.size != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// if permissions are granted we are displaying below toast message.
Toast.makeText(this, "Permission granted.", Toast.LENGTH_SHORT).show()
} else {
// in the below line, we are displaying toast message
// if permissions are not granted.
Toast.makeText(this, "Permission denied.", Toast.LENGTH_SHORT).show()
}
}
}
}
It will be a great help if someone can give a bit working demonstration with proper code. I want to fetch the background location every 2-3 minutes.
I have tried this below code, but it is showing toast message Permission Denied every time.
I have written this code inside a fragment,I have tried to search on medium, other sites, and youtube, all are showing the demonstration for foreground location,please help me.
private var mFusedLocationClient: FusedLocationProviderClient? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mFusedLocationClient=LocationServices.getFusedLocationProviderClient(requireContext())
if(ActivityCompat.checkSelfPermission(requireContext(),Manifest.permission.ACCESS_BACKGROUND_LOCATION)==PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(requireContext(),"IF",Toast.LENGTH_SHORT).show()
getTheCurrentLocation()
}
else
{
Toast.makeText(requireContext(),"Else",Toast.LENGTH_SHORT).show()
requestPermissions(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
,100)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if(requestCode==100 && grantResults.size>0 && (grantResults[0]==PackageManager.PERMISSION_GRANTED))
getTheCurrentLocation()
else
{
Toast.makeText(requireContext(),"Permission Denied",Toast.LENGTH_SHORT).show()
}
}
private fun getTheCurrentLocation()
{
Toast.makeText(requireContext(),"In GetCurrentLocation Fun",Toast.LENGTH_SHORT).show()
var locationManager:LocationManager?=null
locationManager = requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
{
//when location service is enabled
//Get the last location
if (ActivityCompat.checkSelfPermission(
requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
mFusedLocationClient?.lastLocation?.addOnCompleteListener(OnCompleteListener {
var location:android.location.Location?=null
location=it.result
if(location!=null)
{
println("Location is ${location.latitude} ${location.longitude}")
}
else
{
var locationRequest:LocationRequest=LocationRequest().
setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(1000)
.setFastestInterval(100)
.setNumUpdates(1)
var locationCallback:LocationCallback=object:LocationCallback()
{
override fun onLocationResult(locationResult: LocationResult) {
var location1:android.location.Location?=null
location1=locationResult.lastLocation
println("else Location is ${location1.latitude} ${location1.longitude}")
}
}
mFusedLocationClient!!.requestLocationUpdates(locationRequest,locationCallback,
Looper.myLooper())
}
})
}
}
Problem:
I have done this LocationPermission task with activity but I want to do it with the fragment. In Fragment method onRequestPermissionsResult() is not being called.
There are many answers to this question but unfortunately non of them worked for me. Some of those answers are in java which is not applicable in kotlin, for instance, one answer says using 'FragmentCompat' this problem can be solved but we don't have FragmentCompat in Kotlin.
What I did so far?
I followed this question and many others.
Before ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
After:
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
though requestPermissions is depricated But nothing worked so far.
PLEASE DO CONSIDER KOTLIN LANGUAGE FOR ANSWERS
Code in Fragment:
fun RequestLocationPermission()
{
Log.d(TAG, "RequestLocationPermission: ")
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
if(ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION)){
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
}
else{
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
Toast.makeText(requireContext(), "Request Permission Called", Toast.LENGTH_SHORT).show()
Log.d(TAG, "onRequestPermissionResult Called ")
when (requestCode) {
1 -> when {
grantResults.isEmpty() ->
// If user interaction was interrupted, the permission request
// is cancelled and you receive empty arrays.
Log.d(TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED ->{
// Permission was granted.
locationPermission = true
fetchLocation()
}
else -> {
// Permission denied.
Toast.makeText(requireContext(), "Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
}
I'm using google maps so I need to ask some permissions.
I'm requesting the user during the onStart() of the Fragment
I'm calling requestPermissions because I'm in a fragment and I also have called super.onRequestPermissionsResult as recommended in this answer and as you can see in the code below.
I have put some breakpoint and Log to be 100% sure that onRequestPermissionsResult is not called.
class FindLessonFragment : BaseFragment(), OnMapReadyCallback, OnClusterItemClickListener<ClusterLesson>, OnClusterClickListener<ClusterLesson> {
override fun onStart() {
super.onStart()
checkPermissions()
}
private fun checkPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (activity!!.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| activity!!.checkSelfPermission(permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| activity!!.checkSelfPermission(permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val builder = AlertDialog.Builder(activity!!)
builder.setTitle("This app needs location access")
builder.setMessage("Please grant location access so this app can work normally.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener {
requestPermissions(
arrayOf(permission.ACCESS_COARSE_LOCATION, permission.READ_EXTERNAL_STORAGE, permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_LOCATION)
}
builder.show()
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, #NonNull permissions: Array<String>, #NonNull grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Log.e("PERMISSIONRESULT", "PASS PERMISSION RESULT")
when (requestCode) {
BaseActivity.PERMISSION_REQUEST_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d("BaseActivity", "coarse location permission granted")
onMapReady(mMap)
} else {
val builder = AlertDialog.Builder(context!!)
builder.setTitle("Functionality limited")
builder.setMessage(
"Since location access has not been granted, this app will not be able to work correctly.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener { dialog -> dialog.dismiss() }
builder.show()
}
}
}
}
companion object {
fun create() = FindLessonFragment()
internal const val PERMISSION_REQUEST_LOCATION = 1
}
}
minSdkVersion 23
Any kind of help is welcome
The onRequestPermissionsResult has to be catch in the activty.
I have implemented Runtime Permission. For testing purpose I have denied location permission and then again I have denied the permission with "Never to ask again" checkbox.
Now there is the problem. OnRequestPermissionResult is being called again and again from the system. For this, I can't show a dialog or snackbar on the screen properly. Here is my implementation. Where is the problem?
Checking location permission
override fun onResume() {
super.onResume()
if (checkLocationPermission())
startLocationUpdates()
updateUI()
}
This is my location update call
#SuppressLint("MissingPermission")
private fun startLocationUpdates() {
// Begin by checking if the device has the necessary location settings.
mLocationSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this, {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
updateUI()
})
.addOnFailureListener(this, {
handlingLocationClientSettingsFailure(it)
});
}
private fun handlingLocationClientSettingsFailure(it: Exception) {
val apiException = it as ApiException
when (apiException.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
Lg.d(TAG, "Inside start location update method FAILURE: REQUIRED")
// Show the dialog by calling startResolutionForResult(), and check the
// result in onActivityResult().
val rae = it as ResolvableApiException
rae.startResolutionForResult(this#MainActivity, REQUEST_CHECK_SETTINGS);
} catch (sie: IntentSender.SendIntentException) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
val errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
mRequestingLocationUpdates = false;
}
}
updateUI()
}
override fun onStop() {
super.onStop()
stopLocationUpdates()
}
private fun stopLocationUpdates() {
if (!mRequestingLocationUpdates) {
Lg.d(TAG, "Permission Denied! So No op!!!")
return
}
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(this) { mRequestingLocationUpdates = false }
}
private val MY_PERMISSIONS_REQUEST_LOCATION = 99;
private fun startLocationPermissionRequest() {
ActivityCompat.requestPermissions(this#MainActivity,
arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION);
}
private fun checkLocationPermission(): Boolean {
if (ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
showSnackbar(R.string.location_permission_rationale,
android.R.string.ok,
View.OnClickListener {
startLocationPermissionRequest()
})
} else {
// No explanation needed, we can request the permission.
startLocationPermissionRequest()
}
return false
} else {
// Permission has already been granted
return true
}
}
#SuppressLint("NeedOnRequestPermissionsResult")
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_LOCATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
setLocationEnabled()
startLocationUpdates()
}
} else {
val showRationale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
shouldShowRequestPermissionRationale(permissions[0])
} else {
TODO("VERSION.SDK_INT < M")
}
if (!showRationale) {
// user also CHECKED "never ask again"
// you can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting
showingNecessaryMsgForLocationPermissionDenied()
} else {
// user did NOT check "never ask again"
// this is a good place to explain the user
// why you need the permission and ask if he wants
// to accept it (the rationale)
}
}
return
}
// other 'case' lines to check for other
// permissions this app might request
}
}
private fun showingNecessaryMsgForLocationPermissionDenied() {
Lg.d("TestTag", "Called")
MaterialDialog.Builder(this)
.title("Permission")
.content(R.string.permission_denied_explanation)
.onPositive { dialog, which ->
// Build intent that displays the App settings screen.
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
.positiveText(R.string.ok)
.show()
}
In this showingNecessaryMsgForLocationPermissionDenied() function I put a log, in my logcat I see that this function called again and again. How to stop it? Here is the logcat screentshot
I want to show this dialog when user denied permission. But I can't draw this smoothly for the above problem.
Note: I have tested the google repository of location update project. Same problem
Based on the documentation of Activity.requestPermissions
This method may start an activity allowing the user to choose which permissions to grant and which to reject. Hence, you should be prepared that your activity may be paused and resumed. Further, granting some permissions may require a restart of your application.
In this code, you are calling checkLocationPermission() in onResume(). Then from checkLocationPermission() call goes to requestPermissions which takes Activity in onPasue(). After onRequestPermissionsResult(), onResume() gets called again, creating infinte loop.
I would suggest having a boolean variable to decide if to call to checkLocationPermission() required.
var isRequestRequired = true;
override fun onResume() {
super.onResume()
if (isRequestRequired && checkLocationPermission())
startLocationUpdates()
updateUI()
}
then update isRequestRequired to false before showingNecessaryMsgForLocationPermissionDenied()
isRequestRequired = false
showingNecessaryMsgForLocationPermissionDenied()
This will stop onResume() from calling checkLocationPermission() again and again