I'm using the Android Beacon Library. Since Marshmallow, I am seeing the following error, as expected and documented.
Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
I have my ranging code in a Fragment, and the RuntimeException is thrown when the Fragment is on screen, as expected as I'm not prompting for permission. If I hit the home button, Pause is called, and I'm unbinding beaconManager, and the exception is no longer thrown, again, as expected. Coming back to Activity from previous app list, the RuntimeException is thrown again each scan.
Why is the exception thrown when in the foreground even though I have added the permission to the AndroidManifest?
According to the documentation HERE, you only need to prompt the user for location permission if you are performing a scan in the background?
you'll get the following error in LogCat when you try to do a bluetooth scan in the background, and no beacons will be detected
Does this mean ONLY a background scan, or am I misinterpreting the documentation, and you must prompt regardless? I want to avoid the extra (off-putting perhaps to nervous users) prompt for permission inside the app if avoidable!!
My Manifest contains -
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
My snipped code from the Fragment is -
public class NearMeNowFragment extends Fragment implements BeaconConsumer {
//Beacon manager stuff
private BeaconManager beaconManager;
<SNIP>
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
beaconManager = BeaconManager.getInstanceForApplication(getActivity());
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.near_me_now, container, false);
//Set up beacon stuff if Bluetooth available
if (verifyBluetooth(false)) {
beaconManager.bind(this);
}
<SNIP>
return rootView;
}
/***************************
Beacon config methods
****************************
*/
@Override
public void onBeaconServiceConnect() {
//update all scan periods
beaconManager.setForegroundScanPeriod(1100l);
beaconManager.setForegroundBetweenScanPeriod(8900l);
beaconManager.setAndroidLScanningDisabled(true);
try {
beaconManager.updateScanPeriods();
} catch (RemoteException e) {
e.printStackTrace();
}
beaconManager.setRangeNotifier(new RangeNotifier() {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
<SNIP>
//handling beacons here
...
} else {
Log.i(TAG, "ZERO BEACONS IN SCAN");
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region(TAG, null, null, null));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public Context getApplicationContext() {
return getActivity().getApplicationContext();
}
@Override
public void unbindService(ServiceConnection serviceConnection) {
getActivity().unbindService(serviceConnection);
}
@Override
public boolean bindService(Intent intent, ServiceConnection serviceConnection, int mode) {
return getActivity().bindService(intent, serviceConnection, mode);
}
@Override
public void onPause() {
super.onPause();
if(beaconManager.isBound(this)){
beaconManager.unbind(this);
}
}
@Override
public void onResume() {
super.onResume();
beaconManager.bind(this);
}
@Override
public void onDestroy() {
super.onDestroy();
if(beaconManager.isBound(this)){
beaconManager.unbind(this);
}
}
}
My actual Logcat error is
W/Binder﹕ Caught a RuntimeException from the binder stub implementation. java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
To clarify the requirement is different depending on whether you set targetSdkVersion 23
in your build.gradle file.
If you target SDK 23 (Marshmallow) or higher:
If you target SDK 22 or lower: