104

I'm trying to get the GPS coordinates to display when I click a button in my activity layout. The following is the method that gets called when I click the button:

public void getLocation(View view) {
    TextView tv = (TextView) findViewById(R.id.gps_coord_view);
    LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
    Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
    tv.setText("Latitude: " + loc.getLatitude() + "\nLongitude: " + loc.getLongitude());
}

I'm getting an error that says

Call requires permission which may be rejected by user. Code should explicitly check to see if permission is available.

I have already granted these permissions in my AndroidManifest. The error is taken care of and the app compiles when I add the following before calling lm.getLastKnownLocation:

if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
        && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    return;
}

However, the app crashes when I press the button that calls getLocation when it's clicked. What is going on? Is there better/simpler way to grab the GPS coordinates of the device?

2
  • Probably you could attach an exception log.
    – Milan
    Commented Sep 10, 2015 at 4:30
  • 1
    Use ContextCompat.checkSelfPermission(context,permission) and make sure you have mentioned appropriate permissions in manifest Commented Sep 12, 2015 at 4:03

6 Answers 6

159

With Android API level (23), we are required to check for permissions. https://developer.android.com/training/permissions/requesting.html

I had your same problem, but the following worked for me and I am able to retrieve Location data successfully:

(1) Ensure you have your permissions listed in the Manifest:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

(2) Ensure you request permissions from the user:

if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {

            ActivityCompat.requestPermissions( this, new String[] {  android.Manifest.permission.ACCESS_COARSE_LOCATION  },
                                                LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION );
        }

(3) Ensure you use ContextCompat as this has compatibility with older API levels.

(4) In your location service, or class that initializes your LocationManager and gets the last known location, we need to check the permissions:

if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

(5) This approach only worked for me after I included @TargetApi(23) at the top of my initLocationService method.

(6) I also added this to my gradle build:

compile 'com.android.support:support-v4:23.0.1'

Here is my LocationService for reference:

public class LocationService implements LocationListener  {

    //The minimum distance to change updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters

    //The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 0;//1000 * 60 * 1; // 1 minute

    private final static boolean forceNetwork = false;

    private static LocationService instance = null;

    private LocationManager locationManager;
    public Location location;
    public double longitude;
    public double latitude; 


    /**
     * Singleton implementation
     * @return
     */
    public static LocationService getLocationManager(Context context)     {
        if (instance == null) {
            instance = new LocationService(context);
        }
        return instance;
    }

    /**
     * Local constructor
     */
    private LocationService( Context context )     {

        initLocationService(context); 
        LogService.log("LocationService created");
    }



    /**
     * Sets up location service after permissions is granted
     */
    @TargetApi(23)
    private void initLocationService(Context context) {


        if ( Build.VERSION.SDK_INT >= 23 &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED &&
             ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return  ;
        }

        try   {
            this.longitude = 0.0;
            this.latitude = 0.0;
            this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

            // Get GPS and network status
            this.isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            this.isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (forceNetwork) isGPSEnabled = false;

            if (!isNetworkEnabled && !isGPSEnabled)    {
                // cannot get location
                this.locationServiceAvailable = false;
            }
            //else
            {
                this.locationServiceAvailable = true;

                if (isNetworkEnabled) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    if (locationManager != null)   {
                        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        updateCoordinates();
                    }
                }//end if

                if (isGPSEnabled)  {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null)  {
                        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        updateCoordinates();
                    }
                }
            }
        } catch (Exception ex)  {
            LogService.log( "Error creating location service: " + ex.getMessage() );

        }
    }       


    @Override
    public void onLocationChanged(Location location)     {
        // do stuff here with location object 
    }
}

I tested with an Android Lollipop device so far only. Hope this works for you.

11
  • 2
    I like your solution, but you should check if locationManager is null before using it, not later.
    – Fer
    Commented Oct 19, 2015 at 11:10
  • 9
    LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION this line not work version 23
    – user3402040
    Commented Nov 8, 2015 at 20:52
  • 4
    the LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION is not working to me as well.
    – Kairi San
    Commented Feb 3, 2016 at 7:23
  • 1
    @delive, LocationService.MY_PERMISSION_ACCESS_COURSE_LOCATION -> you have to defined this int code in your own activity (which implemented ActivityCompat.OnRequestPermissionsResultCallback) class, for details please check this link.
    – chubao
    Commented Mar 1, 2016 at 2:36
  • 11
    COARSE not COURSE
    – Chris Cox
    Commented Feb 19, 2017 at 16:46
49

SIMPLE SOLUTION

I wanted to support apps pre api 23 and instead of using checkSelfPermission I used a try / catch

try {
   location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException e) {
   dialogGPS(this.getContext()); // lets the user know there is a problem with the gps
}
0
40

The last part of the error message you quoted states: ...with ("checkPermission") or explicitly handle a potential "SecurityException"

A much quicker/simpler way of checking if you have permissions is to surround your code with try { ... } catch (SecurityException e) { [insert error handling code here] }. If you have permissions, the 'try' part will execute, if you don't, the 'catch' part will.

1
  • 1
    Useful if you don't have an Activity or Context object you can check permissions for. Commented Dec 29, 2015 at 9:01
9

Use my custome class to check or request permisson

public class Permissons {

        //Request Permisson
        public static void Request_STORAGE(Activity act,int code)
        {

            ActivityCompat.requestPermissions(act, new
                    String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},code);
        }
        public static void Request_CAMERA(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.CAMERA},code);
        }
        public static void Request_FINE_LOCATION(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.ACCESS_FINE_LOCATION},code);
        }
        public static void Request_READ_SMS(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_SMS},code);
        }
        public static void Request_READ_CONTACTS(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_CONTACTS},code);
        }
        public static void Request_READ_CALENDAR(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.READ_CALENDAR},code);
        }
        public static void Request_RECORD_AUDIO(Activity act,int code)
        {
            ActivityCompat.requestPermissions(act, new
                    String[]{Manifest.permission.RECORD_AUDIO},code);
        }

        //Check Permisson
        public static boolean Check_STORAGE(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act,android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_CAMERA(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.CAMERA);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_FINE_LOCATION(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.ACCESS_FINE_LOCATION);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_SMS(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_SMS);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_CONTACTS(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CONTACTS);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_READ_CALENDAR(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.READ_CALENDAR);
            return result == PackageManager.PERMISSION_GRANTED;
        }
        public static boolean Check_RECORD_AUDIO(Activity act)
        {
            int result = ContextCompat.checkSelfPermission(act, Manifest.permission.RECORD_AUDIO);
            return result == PackageManager.PERMISSION_GRANTED;
        }
    }

Example

if(!Permissons.Check_STORAGE(MainActivity.this))
{
   //if not permisson granted so request permisson with request code
   Permissons.Request_STORAGE(MainActivity.this,22);
}
2
  • thanks, but i want to ask, what's the function of "int code"? Commented May 1, 2019 at 15:08
  • this code use to permisson result granted or decline on Activity result Commented May 1, 2019 at 18:09
4

if you are working on dynamic permissions and any permission like ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION giving error "cannot resolve method PERMISSION_NAME" in this case write you code with permission name and then rebuild your project this will regenerate the manifest(Manifest.permission) file.

2

If you simply want to check for permissions (rather than request for permissions), I wrote a simple extension like so:

fun BaseActivity.checkPermission(permissionName: String): Boolean {
        return if (Build.VERSION.SDK_INT >= 23) {
            val granted =
                ContextCompat.checkSelfPermission(this, permissionName)
            granted == PackageManager.PERMISSION_GRANTED
        } else {
            val granted =
                PermissionChecker.checkSelfPermission(this, permissionName)
            granted == PermissionChecker.PERMISSION_GRANTED
        }
    }

Now, if I want to check for a permission I can simply pass in a permission like so:

checkPermission(Manifest.permission.READ_CONTACTS)

Not the answer you're looking for? Browse other questions tagged or ask your own question.