Pressing allows after requesting permission for ACCESS_COARSE_LOCATION doesn't turn on location - nougat

2.2k views Asked by At

Lastly I ran into problem that, I can't scan for beacons because of lack of ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION.

I tried to fix it by using code found here, but it actually help me partially.

When this view appears enter image description here I click allow. After that I doesn't get this java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results error anymore, but I can't still see my beacons and when I open settings view the location is turned off like on picture bellow.

enter image description here

When I turn on location by finger everything works ok, so I can see my beacons and app works as it should. And here is the question is these some kind of bug or I missed something to turn on location from code behind after access to device location is turned on?

For developing I use Nexus 5x with android 7.1.1.

EDITED: Code is copied from tutorial linked above, the fragment with button which starts beacon scanner:

 public void onBleClicked(View view)
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

                final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("This app needs location access");
                builder.setMessage("Please grant location access so this app can detect beacons.");
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {

                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
                            }
                    }
                });
                builder.show();
            }
    BleManager bleManager = new BleManager(this);
    bleManager.tryToTurnOnBle();
}

Fragment of manifest where permissions are declared:

<!-- app only for phones -->
<uses-feature android:name="android.hardware.telephony"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

The bluetooth permissions are apparently in library.

What I found right now is fact that there is similar question to mine here. But this solution with redirecting user to location option screen is not seems to be clean one for me.

2

There are 2 answers

1
Madhan On BEST ANSWER

Location can be determined by two ways:

1.Using NETWORK_PROVIDER

2.Using GPS_PROVIDER

NETWORK_PROVIDER: It determines the location of the users using cell towers,wifi access points. It is commonly used for determining location inside the rooms or buildings. Here the GPS coordinates are not able to be obtained.

You can specify either

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

or

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

in order to get location using the NETWORK_PROVIDER.

GPS_PROVIDER: It determines the location of the users using satellites. For this, the GPS coordinates are obtained and used for positioning. The GPS receiver in the smartphone receives the signals from satellites. These signals are processed and precise locations are determined.It works better in outdoors – direct sky/satellite views and communication occurs.

You need specify the permission

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

in order to use location from GPS_PROVIDER.

Fine locations: It gives better and accurate locations. So, that I recommend you to use this to get your beacon locations. It gives permission for using both GPS_PROVIDER and NETWORK_PROVIDER or GPS_PROVIDER only for determining the position.

Coarse locations: It provides less accurate locations.It gives permission for using NETWORK_PROVIDER only for determining the position.

Now, come to the implementation. - Declare the above said two permissions in the AnroidManifest.xml file: - In the java part, do the following: Request the permission if it not granted yet:

private void requestPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
} 

When the above method is called, a dialog asking permission will appear. On selecting Allow or Deny, the below callback gets triggered.

In the onRequestPermissionsResult

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case PERMISSION_REQUEST_CODE_LOCATION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
                    boolean isGpsProviderEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                    boolean isNetworkProviderEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                    //Location permission is given. Check if the providers are available and start location updates.
                    if (isGpsProviderEnabled && isNetworkProviderEnabled) {
                        startLocationUpdates();
                    } else {
                        Log.d(TAG, "GPS and Network providers are disabled");
                    }
                } else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    boolean should = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
                    if (should) {
                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
                    } else {
                        promptSettings();
                    }
                }
        }
    }

In the promptSettings() method, let the user to enable location from the Settings screen.

private void promptSettings() {
AlertDialog.Builder builder;

        builder = new AlertDialog.Builder(MainActivity.this);
        builder.setTitle(getResources().getString(R.string.unable_to_find_location));
        builder.setMessage(getResources().getString(R.string.message_denied_location_permission));
        builder.setCancelable(false);
        builder.setPositiveButton(getResources().getString(R.string.go_to_settings), (dialog, which) -> {
            dialog.dismiss();
            builder = null;
            if (!checkPermission(MainActivity.this)) {
                goToSettings();
            }
        });
        builder.show();
    }

In the check permissions method:

public boolean checkPermission(Context context) {
    int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
    return result == PackageManager.PERMISSION_GRANTED;
}

The goToSettings() allows the user to go to Settings screen:

private void goToSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivityForResult(intent, 1);
    }

Note: You need to give the below permissions in the manifest to scan the beacons. I hope you are doing that, if not please do it.

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
0
davidgyoung On

As of Android Marshmallow (6.0), Location must be turned on in settings for apps to scan for Bluetooth LE devices including beacons. This requirement is in addition to the requirement that apps get dynamic permissions. You can see code below to query for location services being turned on and to prompt the user to turn it on if needed.

private void verifyLocationServices()  {
        final LocationManager manager = (LocationManager) getSystemService(this.LOCATION_SERVICE);

        if (!manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("This app requires that location services be enabled.  Please enable location in settings.")
                    .setCancelable(false)
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(final DialogInterface dialog, final int id) {
                            startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                        }
                    });
            final AlertDialog alert = builder.create();
            alert.show();
        }
}