Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to request Location Permission at runtime

Tags:

java

android

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);       }  } 
like image 629
bojan Avatar asked Oct 19 '16 22:10

bojan


People also ask

How do I request runtime permission?

Requesting Android Runtime Permissions For this the following method needs to be called on every permission. checkSelfPermission(String perm); It returns an integer value of PERMISSION_GRANTED or PERMISSION_DENIED.

Which permission are required to get a location in Android?

Android offers two location permissions: ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION .


2 Answers

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:

enter image description here

enter image description here

On Android 12 (API 31) it will do the same, but the interface is different:

enter image description here

enter image description here

enter image description here

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);     } } 
like image 65
Daniel Nugent Avatar answered Oct 04 '22 09:10

Daniel Nugent


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.

like image 27
Yashas Avatar answered Oct 04 '22 08:10

Yashas