How to request Location Permission at runtime - java
In the manifest file I added permissions coarse and fine, and when I run on device with Android 6, nothing happens! I try
everything but no way to get location updates...
What am I doing wrong?
public class MainActivity extends AppCompatActivity implements LocationListener {
LocationManager locationManager;
String provider;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
provider = locationManager.getBestProvider(new Criteria(), false);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
Log.i("Location Info", "Location achieved!");
} else {
Log.i("Location Info", "No location :(");
}
}
#Override
protected void onResume() {
super.onResume();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
#Override
protected void onPause() {
super.onPause();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
locationManager.removeUpdates(this);
}
#Override
public void onLocationChanged(Location location) {
Double lat = location.getLatitude();
Double lng = location.getLongitude();
Log.i("Location info: Lat", lat.toString());
Log.i("Location info: Lng", lng.toString());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
public void getLocation(View view) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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;
}
Location location = locationManager.getLastKnownLocation(provider);
onLocationChanged(location);
}
}
You need to actually request the Location permission at runtime (notice the comments in your code stating this).
Updated with Kotlin and background location for API 31 (Android 12):
Starting with API 30 background location must be requested separately.
This example is using targetSdk 31 and compileSdk 31.
Note that it's possible to bundle the background location request along with the main location request on API 29, however to do that you would need to maintain three separate code paths.
It's easier to just break it out to separate requests for 29 and above.
Be sure to include the latest location services in the app level gradle (18.0.0 at the time of writing):
implementation "com.google.android.gms:play-services-location:18.0.0"
Include the location permissions in the manifest:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
This is a simplified example that does handle most cases, but in a simplified way. In the case where a user chooses "Don't ask again", on the next app launch it will open up the settings for the user to manually enable the permission.
Full activity code:
import android.Manifest
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Looper
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.*
class MainActivity : AppCompatActivity() {
private var fusedLocationProvider: FusedLocationProviderClient? = null
private val locationRequest: LocationRequest = LocationRequest.create().apply {
interval = 30
fastestInterval = 10
priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
maxWaitTime = 60
}
private var locationCallback: LocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val locationList = locationResult.locations
if (locationList.isNotEmpty()) {
//The last location in the list is the newest
val location = locationList.last()
Toast.makeText(
this#MainActivity,
"Got Location: " + location.toString(),
Toast.LENGTH_LONG
)
.show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this)
checkLocationPermission()
}
override fun onResume() {
super.onResume()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
}
override fun onPause() {
super.onPause()
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.removeLocationUpdates(locationCallback)
}
}
private fun checkLocationPermission() {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton(
"OK"
) { _, _ ->
//Prompt the user once explanation has been shown
requestLocationPermission()
}
.create()
.show()
} else {
// No explanation needed, we can request the permission.
requestLocationPermission()
}
} else {
checkBackgroundLocation()
}
}
private fun checkBackgroundLocation() {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
requestBackgroundLocationPermission()
}
}
private fun requestLocationPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
),
MY_PERMISSIONS_REQUEST_LOCATION
)
}
private fun requestBackgroundLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_BACKGROUND_LOCATION
),
MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION
)
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_LOCATION -> {
// If request is cancelled, the result arrays are empty.
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,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
// Now check background location
checkBackgroundLocation()
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show()
// Check if we are in a state where the user has denied the permission and
// selected Don't ask again
if (!ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
startActivity(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", this.packageName, null),
),
)
}
}
return
}
MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION -> {
// If request is cancelled, the result arrays are empty.
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,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
Toast.makeText(
this,
"Granted Background Location Permission",
Toast.LENGTH_LONG
).show()
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show()
}
return
}
}
}
companion object {
private const val MY_PERMISSIONS_REQUEST_LOCATION = 99
private const val MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 66
}
}
On Android 10 (API 29) it will give the user the choice to grant background location after the initial location request:
On Android 12 (API 31) it will do the same, but the interface is different:
Original Answer in Java:
Here is tested and working code to request the Location permission.
Put this code in the Activity:
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle(R.string.title_location_permission)
.setMessage(R.string.text_location_permission)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Request location updates:
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
}
}
Then call the checkLocationPermission() method in onCreate():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//.........
checkLocationPermission();
}
You can then use onResume() and onPause() exactly as it is in the question.
Here is a condensed version that is a bit more clean:
#Override
protected void onResume() {
super.onResume();
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
}
#Override
protected void onPause() {
super.onPause();
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.removeUpdates(this);
}
}
Google has created a library for easy Permissions management. Its called EasyPermissions
Here is a simple example on requesting Location permission using this library.
public class MainActivity extends AppCompatActivity {
private final int REQUEST_LOCATION_PERMISSION = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestLocationPermission();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
#AfterPermissionGranted(REQUEST_LOCATION_PERMISSION)
public void requestLocationPermission() {
String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION};
if(EasyPermissions.hasPermissions(this, perms)) {
Toast.makeText(this, "Permission already granted", Toast.LENGTH_SHORT).show();
}
else {
EasyPermissions.requestPermissions(this, "Please grant the location permission", REQUEST_LOCATION_PERMISSION, perms);
}
}
}
#AfterPermissionsGranted(REQUEST_CODE) is used to indicate the method that needs to be executed after a permission request with the request code REQUEST_CODE has been granted.
This above case, the method requestLocationPermission() method is called if the user grants the permission to access location services. So, that method acts as both a callback and a method to request the permissions.
You can implement separate callbacks for permission granted and permission denied as well. It is explained in the github page.
Location permission privacy change in Android 10 or Android Q.
We have to define additional ACCESS_BACKGROUND_LOCATION permission if user wants to access their current location in background so user needs to granted permission runtime also in requestPermission()
If we are using lower than Android 10 device then ACCESS_BACKGROUND_LOCATION permission allow automatically with ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission
This tabular format might be easy to understand what if we don't specify ACCESS_BACKGROUND_LOCATION in manifest file.
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> // here we defined ACCESS_BACKGROUND_LOCATION for Android 10 device
MainActivity.java
Call checkRunTimePermission() in onCreate() or onResume()
public void checkRunTimePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
gpsTracker = new GPSTracker(context);
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
10);
}
} else {
gpsTracker = new GPSTracker(context); //GPSTracker is class that is used for retrieve user current location
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 10) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
gpsTracker = new GPSTracker(context);
} else {
if (!ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) {
// If User Checked 'Don't Show Again' checkbox for runtime permission, then navigate user to Settings
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Permission Required");
dialog.setCancelable(false);
dialog.setMessage("You have to Allow permission to access user location");
dialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package",
context.getPackageName(), null));
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(i, 1001);
}
});
AlertDialog alertDialog = dialog.create();
alertDialog.show();
}
//code for deny
}
}
}
#Override
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
switch (requestCode) {
case 1001:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
gpsTracker = new GPSTracker(context);
if (gpsTracker.canGetLocation()) {
latitude = gpsTracker.getLatitude();
longitude = gpsTracker.getLongitude();
}
} else {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION},10);
}
}
break;
default:
break;
}
}
build.gradle (app level)
android {
compileSdkVersion 29 //should be >= 29
buildToolsVersion "29.0.2"
useLibrary 'org.apache.http.legacy'
defaultConfig {
applicationId "com.example.runtimepermission"
minSdkVersion 21
targetSdkVersion 29 //should be >= 29
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
}
Here you can find GPSTracker.java file code
Below is my solution to requesting foreground and background location permissions on 28 and below, 29, and 30. The differences between the APIs are subtle but important.
API 28 and below, the system treats foreground and background location permissions as the same. If you grant location permissions, then the application is granted both implicitly.
API 29, you can request both foreground and background permissions at the same time.
API 30, you must request foreground location permissions and then only request background location permissions after the foreground location permissions have been granted. If you ask for both foreground and background permissions at the same time, then the system will ignore the request. Another difference is that the user must allow background location permissions within the application location permission settings rather than through a system dialog.
The solution below only starts the specified action (e.g. background location tracking) only after the user has accepted both foreground and background location tracking:
LocationPermissionUtil.kt
private const val REQUEST_CODE_FOREGROUND = 1
private const val REQUEST_CODE_FOREGROUND_AND_BACKGROUND = 2
object LocationPermissionUtil {
private fun Context.isPermissionGranted(permission: String): Boolean = ActivityCompat
.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
private val Context.isFineLocationPermissionGranted
get() = isPermissionGranted(
Manifest.permission.ACCESS_FINE_LOCATION
)
private val Context.isBackgroundPermissionGranted
get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) == PackageManager.PERMISSION_GRANTED
else -> isFineLocationPermissionGranted
}
private val Context.isFineAndBackgroundLocationPermissionsGranted
get() = isFineLocationPermissionGranted && isBackgroundPermissionGranted
private fun Activity.checkFineLocationPermission() {
if (isFineLocationPermissionGranted) return
val shouldShowFineLocationPermissionRationale = ActivityCompat
.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
if (shouldShowFineLocationPermissionRationale) {
presentAlertDialog(
R.string.dialog_fine_location_rationale_title,
R.string.dialog_fine_location_rationale_description,
R.string.yes,
) {
requestLocationPermissions()
}
} else {
requestLocationPermissions()
}
}
private fun Activity.requestLocationPermissions() =
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
requestFineLocationAndBackground()
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE_FOREGROUND
)
}
#TargetApi(29)
private fun Activity.requestFineLocationAndBackground() {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
),
REQUEST_CODE_FOREGROUND_AND_BACKGROUND
)
}
#TargetApi(29)
private fun Activity.checkBackgroundLocationPermission() {
if (isFineAndBackgroundLocationPermissionsGranted) return
val shouldShowBackgroundPermissionRationale = ActivityCompat
.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
if (shouldShowBackgroundPermissionRationale) {
presentAlertDialog(
R.string.dialog_background_location_rationale_title,
R.string.dialog_background_location_rationale_description,
R.string.yes,
) {
requestFineLocationAndBackground()
}
} else {
requestFineLocationAndBackground()
}
}
fun checkLocationPermissions(activity: Activity, action: () -> Unit) = with(activity) {
if (isFineAndBackgroundLocationPermissionsGranted) {
action()
return
}
checkFineLocationPermission()
}
fun onRequestPermissionsResult(
activity: Activity,
requestCode: Int,
action: () -> Unit
) = with(activity) {
when (requestCode) {
REQUEST_CODE_FOREGROUND -> {
if (!isFineLocationPermissionGranted) {
checkFineLocationPermission()
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
checkBackgroundLocationPermission()
} else {
action()
}
}
REQUEST_CODE_FOREGROUND_AND_BACKGROUND -> {
if (!isFineLocationPermissionGranted) {
checkFineLocationPermission()
return
}
if (isBackgroundPermissionGranted) {
action()
} else {
checkBackgroundLocationPermission()
}
}
}
}
}
Activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
LocationPermissionUtil.checkLocationPermissions(this, this::onLocationPermissionsGranted)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
LocationPermissionUtil.onRequestPermissionsResult(
this,
requestCode,
this::onLocationPermissionsGranted
)
}
private fun onLocationPermissionsGranted() {
Toast.makeText(
this,
"Background location permitted, starting location tracking...",
Toast.LENGTH_LONG
).show()
}
}
check this code from MainActivity
// Check location permission is granted - if it is, start
// the service, otherwise request the permission
fun checkOrAskLocationPermission(callback: () -> Unit) {
// Check GPS is enabled
val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show()
buildAlertMessageNoGps(this)
return
}
// Check location permission is granted - if it is, start
// the service, otherwise request the permission
val permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
if (permission == PackageManager.PERMISSION_GRANTED) {
callback.invoke()
} else {
// callback will be inside the activity's onRequestPermissionsResult(
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST
)
}
}
plus
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSIONS_REQUEST) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
// Permission ok. Do work.
}
}
}
plus
fun buildAlertMessageNoGps(context: Context) {
val builder = AlertDialog.Builder(context);
builder.setMessage("Your GPS is disabled. Do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes") { _, _ -> context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) }
.setNegativeButton("No") { dialog, _ -> dialog.cancel(); }
val alert = builder.create();
alert.show();
}
usage
checkOrAskLocationPermission() {
// Permission ok. Do work.
}
This code work for me. I also handled case "Never Ask Me"
In AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
In build.gradle (Module: app)
dependencies {
....
implementation "com.google.android.gms:play-services-location:16.0.0"
}
This is CurrentLocationManager.kt
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.IntentSender
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.os.CountDownTimer
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.LocationSettingsRequest
import com.google.android.gms.location.LocationSettingsStatusCodes
import java.lang.ref.WeakReference
object CurrentLocationManager : LocationListener {
const val REQUEST_CODE_ACCESS_LOCATION = 123
fun checkLocationPermission(activity: Activity) {
if (ContextCompat.checkSelfPermission(
activity,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_CODE_ACCESS_LOCATION
)
} else {
Thread(Runnable {
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND)
//
requestLocationUpdates(activity)
}).start()
}
}
/**
* be used in HomeActivity.
*/
const val REQUEST_CHECK_SETTINGS = 55
/**
* The number of millis in the future from the call to start().
* until the countdown is done and onFinish() is called.
*
*
* It is also the interval along the way to receive onTick(long) callbacks.
*/
private const val TWENTY_SECS: Long = 20000
/**
* Timer to get location from history when requestLocationUpdates don't return result.
*/
private var mCountDownTimer: CountDownTimer? = null
/**
* WeakReference of current activity.
*/
private var mWeakReferenceActivity: WeakReference<Activity>? = null
/**
* user's location.
*/
var currentLocation: Location? = null
#Synchronized
fun requestLocationUpdates(activity: Activity) {
if (mWeakReferenceActivity == null) {
mWeakReferenceActivity = WeakReference(activity)
} else {
mWeakReferenceActivity?.clear()
mWeakReferenceActivity = WeakReference(activity)
}
//create location request: https://developer.android.com/training/location/change-location-settings.html#prompt
val mLocationRequest = LocationRequest()
// Which your app prefers to receive location updates. Note that the location updates may be
// faster than this rate, or slower than this rate, or there may be no updates at all
// (if the device has no connectivity)
mLocationRequest.interval = 20000
//This method sets the fastest rate in milliseconds at which your app can handle location updates.
// You need to set this rate because other apps also affect the rate at which updates are sent
mLocationRequest.fastestInterval = 10000
mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
//Get Current Location Settings
val builder = LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest)
//Next check whether the current location settings are satisfied
val client = LocationServices.getSettingsClient(activity)
val task = client.checkLocationSettings(builder.build())
//Prompt the User to Change Location Settings
task.addOnSuccessListener(activity) {
Log.d("CurrentLocationManager", "OnSuccessListener")
// All location settings are satisfied. The client can initialize location requests here.
// If it's failed, the result after user updated setting is sent to onActivityResult of HomeActivity.
val activity1 = mWeakReferenceActivity?.get()
if (activity1 != null) {
startRequestLocationUpdate(activity1.applicationContext)
}
}
task.addOnFailureListener(activity) { e ->
Log.d("CurrentLocationManager", "addOnFailureListener")
val statusCode = (e as ApiException).statusCode
when (statusCode) {
CommonStatusCodes.RESOLUTION_REQUIRED ->
// Location settings are not satisfied, but this can be fixed
// by showing the user a dialog.
try {
val activity1 = mWeakReferenceActivity?.get()
if (activity1 != null) {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
val resolvable = e as ResolvableApiException
resolvable.startResolutionForResult(
activity1, REQUEST_CHECK_SETTINGS
)
}
} catch (sendEx: IntentSender.SendIntentException) {
// Ignore the error.
sendEx.printStackTrace()
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
// Location settings are not satisfied. However, we have no way
// to fix the settings so we won't show the dialog.
}
}
}
}
fun startRequestLocationUpdate(appContext: Context) {
val mLocationManager = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (ActivityCompat.checkSelfPermission(
appContext.applicationContext,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
//Utilities.showProgressDialog(mWeakReferenceActivity.get());
if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 10000, 0f, this
)
} else {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 10000, 0f, this
)
}
}
/*Timer to call getLastKnownLocation() when requestLocationUpdates don 't return result*/
countDownUpdateLocation()
}
override fun onLocationChanged(location: Location?) {
if (location != null) {
stopRequestLocationUpdates()
currentLocation = location
}
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {
}
override fun onProviderEnabled(provider: String) {
}
override fun onProviderDisabled(provider: String) {
}
/**
* Init CountDownTimer to to get location from history when requestLocationUpdates don't return result.
*/
#Synchronized
private fun countDownUpdateLocation() {
mCountDownTimer?.cancel()
mCountDownTimer = object : CountDownTimer(TWENTY_SECS, TWENTY_SECS) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
if (mWeakReferenceActivity != null) {
val activity = mWeakReferenceActivity?.get()
if (activity != null && ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
val location = (activity.applicationContext
.getSystemService(Context.LOCATION_SERVICE) as LocationManager)
.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER)
stopRequestLocationUpdates()
onLocationChanged(location)
} else {
stopRequestLocationUpdates()
}
} else {
mCountDownTimer?.cancel()
mCountDownTimer = null
}
}
}.start()
}
/**
* The method must be called in onDestroy() of activity to
* removeUpdateLocation and cancel CountDownTimer.
*/
fun stopRequestLocationUpdates() {
val activity = mWeakReferenceActivity?.get()
if (activity != null) {
/*if (ActivityCompat.checkSelfPermission(activity,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {*/
(activity.applicationContext
.getSystemService(Context.LOCATION_SERVICE) as LocationManager).removeUpdates(this)
/*}*/
}
mCountDownTimer?.cancel()
mCountDownTimer = null
}
}
In MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
CurrentLocationManager.checkLocationPermission(this#LoginActivity)
}
override fun onDestroy() {
CurrentLocationManager.stopRequestLocationUpdates()
super.onDestroy()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CurrentLocationManager.REQUEST_CODE_ACCESS_LOCATION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
//denied
val builder = AlertDialog.Builder(this)
builder.setMessage("We need permission to use your location for the purpose of finding friends near you.")
.setTitle("Device Location Required")
.setIcon(com.eswapp.R.drawable.ic_info)
.setPositiveButton("OK") { _, _ ->
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
//only deny
CurrentLocationManager.checkLocationPermission(this#LoginActivity)
} else {
//never ask again
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivityForResult(intent, CurrentLocationManager.REQUEST_CHECK_SETTINGS)
}
}
.setNegativeButton("Ask Me Later") { _, _ ->
}
// Create the AlertDialog object and return it
val dialog = builder.create()
dialog.show()
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
CurrentLocationManager.requestLocationUpdates(this)
}
}
}
//Forward Login result to the CallBackManager in OnActivityResult()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
//case 1. After you allow the app access device location, Another dialog will be displayed to request you to turn on device location
//case 2. Or You chosen Never Ask Again, you open device Setting and enable location permission
CurrentLocationManager.REQUEST_CHECK_SETTINGS -> when (resultCode) {
RESULT_OK -> {
Log.d("REQUEST_CHECK_SETTINGS", "RESULT_OK")
//case 1. You choose OK
CurrentLocationManager.startRequestLocationUpdate(applicationContext)
}
RESULT_CANCELED -> {
Log.d("REQUEST_CHECK_SETTINGS", "RESULT_CANCELED")
//case 1. You choose NO THANKS
//CurrentLocationManager.requestLocationUpdates(this)
//case 2. In device Setting screen: user can enable or not enable location permission,
// so when user back to this activity, we should re-call checkLocationPermission()
CurrentLocationManager.checkLocationPermission(this#LoginActivity)
}
else -> {
//do nothing
}
}
else -> {
super.onActivityResult(requestCode, resultCode, data)
}
}
}
After having it defined in your manifest file, a friendlier alternative to the native solution would be using Aaper: https://github.com/LikeTheSalad/aaper like so:
#EnsurePermissions(permissions = [Manifest.permission.ACCESS_FINE_LOCATION])
private fun scanForLocation() {
// Your code that needs the location permission granted.
}
Disclaimer, I'm the creator of Aaper.
Looking for a simpler code? Try this!
if (ContextCompat.checkSelfPermission(LoginActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(LoginActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CALL);
}
Also, don't forget to ask for permissions obviously
Related
Android TelephonyManager Permissions
I am trying to code a quick application which gives me the needed 3G values, when I click a button. But first I need to check if I am connected to 3G network. However I am having some issues with my Permissions. I am having the following code: public void calculate(View view) { TextView rscp = (TextView) findViewById(R.id.RSCP); TextView rssi = (TextView) findViewById(R.id.RSSI); TextView ecno = (TextView) findViewById(R.id.EcNo); TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (Arrays.stream(values_3G).anyMatch(n -> n == tm.getDataNetworkType())) { for (CellInfo cellInfo : tm.getAllCellInfo()) { if (cellInfo instanceof CellInfoWcdma) { CellSignalStrengthWcdma cellSignalStrength = ((CellInfoWcdma) cellInfo).getCellSignalStrength(); rscp.setText(cellSignalStrength.getDbm()); ecno.setText(cellSignalStrength.getEcNo()); int rssiValue = -113 + 2 * cellSignalStrength.getAsuLevel(); rssi.setText(rssiValue); } } } else { rscp.setText(0); rssi.setText(0); ecno.setText(0); Log.i(TAG, "No 3G Mobile connection detected!"); Toast.makeText(getApplicationContext(), "Connect to 3G", Toast.LENGTH_SHORT).show(); } } tm.getDataNetworkType() is giving me the following issue with READ_PHONE_STATE: Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException If I follow the instructions to check permission in Android Studio I get the following: if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != 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; } What do I need to fill in between the brackets?
Create a global final int of the permission request code final int PHONE_REQUEST_CODE = 101; And request the permission if not granted if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, PHONE_REQUEST_CODE); // triggers onRequestPermissionsResult() } else { // calculate(myView); // Do whatever you want as the permission is already granted } And override onRequestPermissionsResult() in activity #Override public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults.length == 0) return; if (requestCode == PHONE_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // calculate(myView); // Do whatever you want after the permission is granted } And add the permission in manifest.xml as well. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
App closed when it asks permission to user for read write
I am facing issues in my app, My app needs read write permission but whenever my app opens first time my app crashes and closed then it asks for permission in background then i need to start it again then it works fine. I am getting issues only first time run. This is my code Main Activity if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { checkPermissions(); } #RequiresApi(api = Build.VERSION_CODES.M) private void checkPermissions(){ if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (shouldShowRequestPermissionRationale( Manifest.permission.READ_EXTERNAL_STORAGE)) { // Explain to the user why we need to read the contacts } requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1052); // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an // app-defined int constant that should be quite unique return; } /* if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != android.content.pm.PackageManager.PERMISSION_GRANTED|| ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != android.content.pm.PackageManager.PERMISSION_GRANTED) ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE, }, 1052);*/ } public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1052: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED && grantResults[1] == android.content.pm.PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Enjoy This app", Toast.LENGTH_SHORT).show(); } else { android.widget.Toast.makeText(this, "Permission Denied, without your permission we cant share or download images to your device", android.widget.Toast.LENGTH_LONG).show(); // Permission denied - Show a message to inform the user that this app only works // with these permissions granted } } } }
You need to ask for permission by starting a new activity and writing all the above code in that new activity. I replicated this problem in a new android project and verified this. What you need to do is create another activity, one that is specifically created to ask for permissions. Let it be Main2Activity.java. Your MainActivity.java would be public class MainActivity extends AppCompatActivity { #RequiresApi(api = Build.VERSION_CODES.M) #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { startActivity(new Intent(MainActivity.this, Main2Activity.class)); } } } Then your Main2Activity.java would be public class Main2Activity extends AppCompatActivity { #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { checkPermissions(); } } #RequiresApi(api = Build.VERSION_CODES.M) private void checkPermissions(){ if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (shouldShowRequestPermissionRationale( Manifest.permission.READ_EXTERNAL_STORAGE)) { // Explain to the user why we need to read the contacts } requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1052); // MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an // app-defined int constant that should be quite unique return; } /* if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != android.content.pm.PackageManager.PERMISSION_GRANTED|| ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != android.content.pm.PackageManager.PERMISSION_GRANTED) ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE, }, 1052);*/ } public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1052: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && (grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED || grantResults[1] == android.content.pm.PackageManager.PERMISSION_GRANTED)) { Toast.makeText(this, "Enjoy This app", Toast.LENGTH_SHORT).show(); startActivity(new Intent(Main2Activity.this, MainActivity.class)); finish(); } else { android.widget.Toast.makeText(this, "Permission Denied, without your permission we cant share or download images to your device", android.widget.Toast.LENGTH_LONG).show(); // Permission denied - Show a message to inform the user that this app only works // with these permissions granted } } } } } Notice that in Main2Activity.java, i made edits if (grantResults.length > 0 && (grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED || grantResults[1] == android.content.pm.PackageManager.PERMISSION_GRANTED)) { Toast.makeText(this, "Enjoy This app", Toast.LENGTH_SHORT).show(); startActivity(new Intent(Main2Activity.this, MainActivity.class)); finish(); } For the Toast to appear, android.content.pm.PackageManager.PERMISSION_GRANTED will be either in grantResults[0] or grantResults[1] but not both. I used functions startActivity() and finish() because after getting permission this activity made specifically for permission will close and open the MainActivity.java.
Android is asking each permission three times and app closes after permissions are granted
I am creating a simple applications in which I need READ_CONTACT and CALL_PHONE permissions. I have written below code. After installation app asks permissions 3 times like this - 1 of 2 read contacts 2 of 2 call and manage phone 1 of 2 read contacts 2 of 2 call and manage phone 1 of 2 read contacts 2 of 2 call and manage phone Also After granting these permissions app does't open. But when I open app again, it works fine and does not ask permissions again. I have following code #Override public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) { switch (requestCode) { case MULTIPLE_REQUESTS: { if (grantResults.length > 0) { boolean contactPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED; boolean phonePermission = grantResults[0] == PackageManager.PERMISSION_GRANTED; if (contactPermission && phonePermission) { // write your logic here } else { Toast.makeText(this, "Read Contact & Call phone permissions are required", Toast.LENGTH_SHORT).show(); closeNow(); } } break; } } } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) + ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.READ_CONTACTS) || ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CALL_PHONE)) { } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE}, MULTIPLE_REQUESTS); } } setContentView(R.layout.activity_contact_app_bar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); toolbar.setTitle(getTitle()); }
The permission should be asked when you invoke respective functionality . I am suspecting the app is getting closed due to closeNow is called . You need to debug below code . if (grantResults.length > 0) { boolean contactPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED; boolean phonePermission = grantResults[0] == PackageManager.PERMISSION_GRANTED; if (contactPermission && phonePermission) { // write your logic here } else { Toast.makeText(this, "Read Contact & Call phone permissions are required", Toast.LENGTH_SHORT).show(); closeNow(); } }
try This Code if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE}, MULTIPLE_REQUESTS); } add above code where you want permission #Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MULTIPLE_REQUESTS: { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { // Permission has been denied by user } else { // Permission has been granted by user } return; } } } }
Android 6.0+: how to catch click on 'accept' or 'refused' button of geolocation authorization alert? [duplicate]
In the manifest file I added permissions coarse and fine, and when I run on device with Android 6, nothing happens! I try everything but no way to get location updates... What am I doing wrong? public class MainActivity extends AppCompatActivity implements LocationListener { LocationManager locationManager; String provider; #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); provider = locationManager.getBestProvider(new Criteria(), false); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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; } Location location = locationManager.getLastKnownLocation(provider); if (location != null) { Log.i("Location Info", "Location achieved!"); } else { Log.i("Location Info", "No location :("); } } #Override protected void onResume() { super.onResume(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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; } locationManager.requestLocationUpdates(provider, 400, 1, this); } #Override protected void onPause() { super.onPause(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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; } locationManager.removeUpdates(this); } #Override public void onLocationChanged(Location location) { Double lat = location.getLatitude(); Double lng = location.getLongitude(); Log.i("Location info: Lat", lat.toString()); Log.i("Location info: Lng", lng.toString()); } #Override public void onStatusChanged(String provider, int status, Bundle extras) { } #Override public void onProviderEnabled(String provider) { } #Override public void onProviderDisabled(String provider) { } public void getLocation(View view) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, 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; } Location location = locationManager.getLastKnownLocation(provider); onLocationChanged(location); } }
You need to actually request the Location permission at runtime (notice the comments in your code stating this). Updated with Kotlin and background location for API 31 (Android 12): Starting with API 30 background location must be requested separately. This example is using targetSdk 31 and compileSdk 31. Note that it's possible to bundle the background location request along with the main location request on API 29, however to do that you would need to maintain three separate code paths. It's easier to just break it out to separate requests for 29 and above. Be sure to include the latest location services in the app level gradle (18.0.0 at the time of writing): implementation "com.google.android.gms:play-services-location:18.0.0" Include the location permissions in the manifest: <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> This is a simplified example that does handle most cases, but in a simplified way. In the case where a user chooses "Don't ask again", on the next app launch it will open up the settings for the user to manually enable the permission. Full activity code: import android.Manifest import android.app.AlertDialog import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Looper import android.provider.Settings import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.google.android.gms.location.* class MainActivity : AppCompatActivity() { private var fusedLocationProvider: FusedLocationProviderClient? = null private val locationRequest: LocationRequest = LocationRequest.create().apply { interval = 30 fastestInterval = 10 priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY maxWaitTime = 60 } private var locationCallback: LocationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult) { val locationList = locationResult.locations if (locationList.isNotEmpty()) { //The last location in the list is the newest val location = locationList.last() Toast.makeText( this#MainActivity, "Got Location: " + location.toString(), Toast.LENGTH_LONG ) .show() } } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this) checkLocationPermission() } override fun onResume() { super.onResume() if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) } } override fun onPause() { super.onPause() if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.removeLocationUpdates(locationCallback) } } private fun checkLocationPermission() { if (ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) ) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. AlertDialog.Builder(this) .setTitle("Location Permission Needed") .setMessage("This app needs the Location permission, please accept to use location functionality") .setPositiveButton( "OK" ) { _, _ -> //Prompt the user once explanation has been shown requestLocationPermission() } .create() .show() } else { // No explanation needed, we can request the permission. requestLocationPermission() } } else { checkBackgroundLocation() } } private fun checkBackgroundLocation() { if (ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_BACKGROUND_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { requestBackgroundLocationPermission() } } private fun requestLocationPermission() { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, ), MY_PERMISSIONS_REQUEST_LOCATION ) } private fun requestBackgroundLocationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_BACKGROUND_LOCATION ), MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION ) } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), MY_PERMISSIONS_REQUEST_LOCATION ) } } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray ) { when (requestCode) { MY_PERMISSIONS_REQUEST_LOCATION -> { // If request is cancelled, the result arrays are empty. 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, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) // Now check background location checkBackgroundLocation() } } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show() // Check if we are in a state where the user has denied the permission and // selected Don't ask again if (!ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) ) { startActivity( Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", this.packageName, null), ), ) } } return } MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION -> { // If request is cancelled, the result arrays are empty. 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, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { fusedLocationProvider?.requestLocationUpdates( locationRequest, locationCallback, Looper.getMainLooper() ) Toast.makeText( this, "Granted Background Location Permission", Toast.LENGTH_LONG ).show() } } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show() } return } } } companion object { private const val MY_PERMISSIONS_REQUEST_LOCATION = 99 private const val MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 66 } } On Android 10 (API 29) it will give the user the choice to grant background location after the initial location request: On Android 12 (API 31) it will do the same, but the interface is different: Original Answer in Java: Here is tested and working code to request the Location permission. Put this code in the Activity: public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; public boolean checkLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. new AlertDialog.Builder(this) .setTitle(R.string.title_location_permission) .setMessage(R.string.text_location_permission) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { #Override public void onClick(DialogInterface dialogInterface, int i) { //Prompt the user once explanation has been shown ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } }) .create() .show(); } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION); } return false; } else { return true; } } #Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // location-related task you need to do. if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { //Request location updates: locationManager.requestLocationUpdates(provider, 400, 1, this); } } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } } } Then call the checkLocationPermission() method in onCreate(): #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //......... checkLocationPermission(); } You can then use onResume() and onPause() exactly as it is in the question. Here is a condensed version that is a bit more clean: #Override protected void onResume() { super.onResume(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.requestLocationUpdates(provider, 400, 1, this); } } #Override protected void onPause() { super.onPause(); if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.removeUpdates(this); } }
Google has created a library for easy Permissions management. Its called EasyPermissions Here is a simple example on requesting Location permission using this library. public class MainActivity extends AppCompatActivity { private final int REQUEST_LOCATION_PERMISSION = 1; #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestLocationPermission(); } #Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // Forward results to EasyPermissions EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } #AfterPermissionGranted(REQUEST_LOCATION_PERMISSION) public void requestLocationPermission() { String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION}; if(EasyPermissions.hasPermissions(this, perms)) { Toast.makeText(this, "Permission already granted", Toast.LENGTH_SHORT).show(); } else { EasyPermissions.requestPermissions(this, "Please grant the location permission", REQUEST_LOCATION_PERMISSION, perms); } } } #AfterPermissionsGranted(REQUEST_CODE) is used to indicate the method that needs to be executed after a permission request with the request code REQUEST_CODE has been granted. This above case, the method requestLocationPermission() method is called if the user grants the permission to access location services. So, that method acts as both a callback and a method to request the permissions. You can implement separate callbacks for permission granted and permission denied as well. It is explained in the github page.
Location permission privacy change in Android 10 or Android Q. We have to define additional ACCESS_BACKGROUND_LOCATION permission if user wants to access their current location in background so user needs to granted permission runtime also in requestPermission() If we are using lower than Android 10 device then ACCESS_BACKGROUND_LOCATION permission allow automatically with ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission This tabular format might be easy to understand what if we don't specify ACCESS_BACKGROUND_LOCATION in manifest file. AndroidManifest.xml <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> // here we defined ACCESS_BACKGROUND_LOCATION for Android 10 device MainActivity.java Call checkRunTimePermission() in onCreate() or onResume() public void checkRunTimePermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED|| ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) { gpsTracker = new GPSTracker(context); } else { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 10); } } else { gpsTracker = new GPSTracker(context); //GPSTracker is class that is used for retrieve user current location } } #Override public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 10) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { gpsTracker = new GPSTracker(context); } else { if (!ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) { // If User Checked 'Don't Show Again' checkbox for runtime permission, then navigate user to Settings AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle("Permission Required"); dialog.setCancelable(false); dialog.setMessage("You have to Allow permission to access user location"); dialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() { #Override public void onClick(DialogInterface dialog, int which) { Intent i = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", context.getPackageName(), null)); //i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(i, 1001); } }); AlertDialog alertDialog = dialog.create(); alertDialog.show(); } //code for deny } } } #Override public void startActivityForResult(Intent intent, int requestCode) { super.startActivityForResult(intent, requestCode); switch (requestCode) { case 1001: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) { gpsTracker = new GPSTracker(context); if (gpsTracker.canGetLocation()) { latitude = gpsTracker.getLatitude(); longitude = gpsTracker.getLongitude(); } } else { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION},10); } } break; default: break; } } build.gradle (app level) android { compileSdkVersion 29 //should be >= 29 buildToolsVersion "29.0.2" useLibrary 'org.apache.http.legacy' defaultConfig { applicationId "com.example.runtimepermission" minSdkVersion 21 targetSdkVersion 29 //should be >= 29 versionCode 1 versionName "1.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } } Here you can find GPSTracker.java file code
Below is my solution to requesting foreground and background location permissions on 28 and below, 29, and 30. The differences between the APIs are subtle but important. API 28 and below, the system treats foreground and background location permissions as the same. If you grant location permissions, then the application is granted both implicitly. API 29, you can request both foreground and background permissions at the same time. API 30, you must request foreground location permissions and then only request background location permissions after the foreground location permissions have been granted. If you ask for both foreground and background permissions at the same time, then the system will ignore the request. Another difference is that the user must allow background location permissions within the application location permission settings rather than through a system dialog. The solution below only starts the specified action (e.g. background location tracking) only after the user has accepted both foreground and background location tracking: LocationPermissionUtil.kt private const val REQUEST_CODE_FOREGROUND = 1 private const val REQUEST_CODE_FOREGROUND_AND_BACKGROUND = 2 object LocationPermissionUtil { private fun Context.isPermissionGranted(permission: String): Boolean = ActivityCompat .checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED private val Context.isFineLocationPermissionGranted get() = isPermissionGranted( Manifest.permission.ACCESS_FINE_LOCATION ) private val Context.isBackgroundPermissionGranted get() = when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> ActivityCompat.checkSelfPermission( this, Manifest.permission.ACCESS_BACKGROUND_LOCATION ) == PackageManager.PERMISSION_GRANTED else -> isFineLocationPermissionGranted } private val Context.isFineAndBackgroundLocationPermissionsGranted get() = isFineLocationPermissionGranted && isBackgroundPermissionGranted private fun Activity.checkFineLocationPermission() { if (isFineLocationPermissionGranted) return val shouldShowFineLocationPermissionRationale = ActivityCompat .shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) if (shouldShowFineLocationPermissionRationale) { presentAlertDialog( R.string.dialog_fine_location_rationale_title, R.string.dialog_fine_location_rationale_description, R.string.yes, ) { requestLocationPermissions() } } else { requestLocationPermissions() } } private fun Activity.requestLocationPermissions() = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { requestFineLocationAndBackground() } else { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_CODE_FOREGROUND ) } #TargetApi(29) private fun Activity.requestFineLocationAndBackground() { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION ), REQUEST_CODE_FOREGROUND_AND_BACKGROUND ) } #TargetApi(29) private fun Activity.checkBackgroundLocationPermission() { if (isFineAndBackgroundLocationPermissionsGranted) return val shouldShowBackgroundPermissionRationale = ActivityCompat .shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_BACKGROUND_LOCATION ) if (shouldShowBackgroundPermissionRationale) { presentAlertDialog( R.string.dialog_background_location_rationale_title, R.string.dialog_background_location_rationale_description, R.string.yes, ) { requestFineLocationAndBackground() } } else { requestFineLocationAndBackground() } } fun checkLocationPermissions(activity: Activity, action: () -> Unit) = with(activity) { if (isFineAndBackgroundLocationPermissionsGranted) { action() return } checkFineLocationPermission() } fun onRequestPermissionsResult( activity: Activity, requestCode: Int, action: () -> Unit ) = with(activity) { when (requestCode) { REQUEST_CODE_FOREGROUND -> { if (!isFineLocationPermissionGranted) { checkFineLocationPermission() return } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { checkBackgroundLocationPermission() } else { action() } } REQUEST_CODE_FOREGROUND_AND_BACKGROUND -> { if (!isFineLocationPermissionGranted) { checkFineLocationPermission() return } if (isBackgroundPermissionGranted) { action() } else { checkBackgroundLocationPermission() } } } } } Activity: class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) LocationPermissionUtil.checkLocationPermissions(this, this::onLocationPermissionsGranted) } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) LocationPermissionUtil.onRequestPermissionsResult( this, requestCode, this::onLocationPermissionsGranted ) } private fun onLocationPermissionsGranted() { Toast.makeText( this, "Background location permitted, starting location tracking...", Toast.LENGTH_LONG ).show() } }
check this code from MainActivity // Check location permission is granted - if it is, start // the service, otherwise request the permission fun checkOrAskLocationPermission(callback: () -> Unit) { // Check GPS is enabled val lm = getSystemService(Context.LOCATION_SERVICE) as LocationManager if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { Toast.makeText(this, "Please enable location services", Toast.LENGTH_SHORT).show() buildAlertMessageNoGps(this) return } // Check location permission is granted - if it is, start // the service, otherwise request the permission val permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) if (permission == PackageManager.PERMISSION_GRANTED) { callback.invoke() } else { // callback will be inside the activity's onRequestPermissionsResult( ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSIONS_REQUEST ) } } plus override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == PERMISSIONS_REQUEST) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED){ // Permission ok. Do work. } } } plus fun buildAlertMessageNoGps(context: Context) { val builder = AlertDialog.Builder(context); builder.setMessage("Your GPS is disabled. Do you want to enable it?") .setCancelable(false) .setPositiveButton("Yes") { _, _ -> context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) } .setNegativeButton("No") { dialog, _ -> dialog.cancel(); } val alert = builder.create(); alert.show(); } usage checkOrAskLocationPermission() { // Permission ok. Do work. }
This code work for me. I also handled case "Never Ask Me" In AndroidManifest.xml <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> In build.gradle (Module: app) dependencies { .... implementation "com.google.android.gms:play-services-location:16.0.0" } This is CurrentLocationManager.kt import android.Manifest import android.app.Activity import android.content.Context import android.content.IntentSender import android.content.pm.PackageManager import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.os.Bundle import android.os.CountDownTimer import android.support.v4.app.ActivityCompat import android.support.v4.content.ContextCompat import android.util.Log import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.CommonStatusCodes import com.google.android.gms.common.api.ResolvableApiException import com.google.android.gms.location.LocationRequest import com.google.android.gms.location.LocationServices import com.google.android.gms.location.LocationSettingsRequest import com.google.android.gms.location.LocationSettingsStatusCodes import java.lang.ref.WeakReference object CurrentLocationManager : LocationListener { const val REQUEST_CODE_ACCESS_LOCATION = 123 fun checkLocationPermission(activity: Activity) { if (ContextCompat.checkSelfPermission( activity, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_CODE_ACCESS_LOCATION ) } else { Thread(Runnable { // Moves the current Thread into the background android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND) // requestLocationUpdates(activity) }).start() } } /** * be used in HomeActivity. */ const val REQUEST_CHECK_SETTINGS = 55 /** * The number of millis in the future from the call to start(). * until the countdown is done and onFinish() is called. * * * It is also the interval along the way to receive onTick(long) callbacks. */ private const val TWENTY_SECS: Long = 20000 /** * Timer to get location from history when requestLocationUpdates don't return result. */ private var mCountDownTimer: CountDownTimer? = null /** * WeakReference of current activity. */ private var mWeakReferenceActivity: WeakReference<Activity>? = null /** * user's location. */ var currentLocation: Location? = null #Synchronized fun requestLocationUpdates(activity: Activity) { if (mWeakReferenceActivity == null) { mWeakReferenceActivity = WeakReference(activity) } else { mWeakReferenceActivity?.clear() mWeakReferenceActivity = WeakReference(activity) } //create location request: https://developer.android.com/training/location/change-location-settings.html#prompt val mLocationRequest = LocationRequest() // Which your app prefers to receive location updates. Note that the location updates may be // faster than this rate, or slower than this rate, or there may be no updates at all // (if the device has no connectivity) mLocationRequest.interval = 20000 //This method sets the fastest rate in milliseconds at which your app can handle location updates. // You need to set this rate because other apps also affect the rate at which updates are sent mLocationRequest.fastestInterval = 10000 mLocationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY //Get Current Location Settings val builder = LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest) //Next check whether the current location settings are satisfied val client = LocationServices.getSettingsClient(activity) val task = client.checkLocationSettings(builder.build()) //Prompt the User to Change Location Settings task.addOnSuccessListener(activity) { Log.d("CurrentLocationManager", "OnSuccessListener") // All location settings are satisfied. The client can initialize location requests here. // If it's failed, the result after user updated setting is sent to onActivityResult of HomeActivity. val activity1 = mWeakReferenceActivity?.get() if (activity1 != null) { startRequestLocationUpdate(activity1.applicationContext) } } task.addOnFailureListener(activity) { e -> Log.d("CurrentLocationManager", "addOnFailureListener") val statusCode = (e as ApiException).statusCode when (statusCode) { CommonStatusCodes.RESOLUTION_REQUIRED -> // Location settings are not satisfied, but this can be fixed // by showing the user a dialog. try { val activity1 = mWeakReferenceActivity?.get() if (activity1 != null) { // Show the dialog by calling startResolutionForResult(), // and check the result in onActivityResult(). val resolvable = e as ResolvableApiException resolvable.startResolutionForResult( activity1, REQUEST_CHECK_SETTINGS ) } } catch (sendEx: IntentSender.SendIntentException) { // Ignore the error. sendEx.printStackTrace() } LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { // Location settings are not satisfied. However, we have no way // to fix the settings so we won't show the dialog. } } } } fun startRequestLocationUpdate(appContext: Context) { val mLocationManager = appContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager if (ActivityCompat.checkSelfPermission( appContext.applicationContext, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { //Utilities.showProgressDialog(mWeakReferenceActivity.get()); if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { mLocationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 10000, 0f, this ) } else { mLocationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 10000, 0f, this ) } } /*Timer to call getLastKnownLocation() when requestLocationUpdates don 't return result*/ countDownUpdateLocation() } override fun onLocationChanged(location: Location?) { if (location != null) { stopRequestLocationUpdates() currentLocation = location } } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) { } override fun onProviderEnabled(provider: String) { } override fun onProviderDisabled(provider: String) { } /** * Init CountDownTimer to to get location from history when requestLocationUpdates don't return result. */ #Synchronized private fun countDownUpdateLocation() { mCountDownTimer?.cancel() mCountDownTimer = object : CountDownTimer(TWENTY_SECS, TWENTY_SECS) { override fun onTick(millisUntilFinished: Long) {} override fun onFinish() { if (mWeakReferenceActivity != null) { val activity = mWeakReferenceActivity?.get() if (activity != null && ActivityCompat.checkSelfPermission( activity, Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED ) { val location = (activity.applicationContext .getSystemService(Context.LOCATION_SERVICE) as LocationManager) .getLastKnownLocation(LocationManager.PASSIVE_PROVIDER) stopRequestLocationUpdates() onLocationChanged(location) } else { stopRequestLocationUpdates() } } else { mCountDownTimer?.cancel() mCountDownTimer = null } } }.start() } /** * The method must be called in onDestroy() of activity to * removeUpdateLocation and cancel CountDownTimer. */ fun stopRequestLocationUpdates() { val activity = mWeakReferenceActivity?.get() if (activity != null) { /*if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {*/ (activity.applicationContext .getSystemService(Context.LOCATION_SERVICE) as LocationManager).removeUpdates(this) /*}*/ } mCountDownTimer?.cancel() mCountDownTimer = null } } In MainActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... CurrentLocationManager.checkLocationPermission(this#LoginActivity) } override fun onDestroy() { CurrentLocationManager.stopRequestLocationUpdates() super.onDestroy() } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == CurrentLocationManager.REQUEST_CODE_ACCESS_LOCATION) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { //denied val builder = AlertDialog.Builder(this) builder.setMessage("We need permission to use your location for the purpose of finding friends near you.") .setTitle("Device Location Required") .setIcon(com.eswapp.R.drawable.ic_info) .setPositiveButton("OK") { _, _ -> if (ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.ACCESS_FINE_LOCATION ) ) { //only deny CurrentLocationManager.checkLocationPermission(this#LoginActivity) } else { //never ask again val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val uri = Uri.fromParts("package", packageName, null) intent.data = uri startActivityForResult(intent, CurrentLocationManager.REQUEST_CHECK_SETTINGS) } } .setNegativeButton("Ask Me Later") { _, _ -> } // Create the AlertDialog object and return it val dialog = builder.create() dialog.show() } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { CurrentLocationManager.requestLocationUpdates(this) } } } //Forward Login result to the CallBackManager in OnActivityResult() override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { //case 1. After you allow the app access device location, Another dialog will be displayed to request you to turn on device location //case 2. Or You chosen Never Ask Again, you open device Setting and enable location permission CurrentLocationManager.REQUEST_CHECK_SETTINGS -> when (resultCode) { RESULT_OK -> { Log.d("REQUEST_CHECK_SETTINGS", "RESULT_OK") //case 1. You choose OK CurrentLocationManager.startRequestLocationUpdate(applicationContext) } RESULT_CANCELED -> { Log.d("REQUEST_CHECK_SETTINGS", "RESULT_CANCELED") //case 1. You choose NO THANKS //CurrentLocationManager.requestLocationUpdates(this) //case 2. In device Setting screen: user can enable or not enable location permission, // so when user back to this activity, we should re-call checkLocationPermission() CurrentLocationManager.checkLocationPermission(this#LoginActivity) } else -> { //do nothing } } else -> { super.onActivityResult(requestCode, resultCode, data) } } }
After having it defined in your manifest file, a friendlier alternative to the native solution would be using Aaper: https://github.com/LikeTheSalad/aaper like so: #EnsurePermissions(permissions = [Manifest.permission.ACCESS_FINE_LOCATION]) private fun scanForLocation() { // Your code that needs the location permission granted. } Disclaimer, I'm the creator of Aaper.
Looking for a simpler code? Try this! if (ContextCompat.checkSelfPermission(LoginActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(LoginActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CALL); } Also, don't forget to ask for permissions obviously
Remove Run Time Permission for current location in Marshmallow
I am trying to create an app. App asking every time location Access in Marsh Mallow, always when we open the app. Please suggested the best Process for solve my problem. using following code- #Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; //for marshmallow final int LOCATION_PERMISSION_REQUEST_CODE = 100; ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } mMap.setMyLocationEnabled(true); buildGoogleApiClient(); mGoogleApiClient.connect(); } thanks.
Try writting in if else, if permission is not given ask for it or else do what you want to do. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(checkSelfPermission(Manifest.permission.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); } } else { // do your stuff } and also override onRequestPermissionsResult and apply your code afer you have granted permissions.
Please reflect your code yourself. Think about the order of requesting and checking the permission. You should check the permission before you're asking for it. This makes sure to prevent asking if the permission was already granted... Have a look at the example provided by Google and consider adapting this example for your needs: // Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } } Additionally you should overwrite the callback method onRequestPermissionsResult to handle the user's grantResults. // Callback with the request from calling requestPermissions(...) #Override public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) { // Make sure it's our original READ_CONTACTS request if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) { if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "Read Contacts permission granted", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Read Contacts permission denied", Toast.LENGTH_SHORT).show(); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } Edit: This is thecode which you should change ActivityCompat.requestPermissions(this, new String[] {android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } For further reading have a look at the article Understanding App Permissions