Location target permission 23 - android

I'm using altbeacon library to monitor and range beacons. I've read your requesting permission page and just want to know, if I target location permission for API 23+ (), will scan works on devices with API < 23? I don't have real device, so can't test it. Or is there any way to not request location permission with device with API below 23? Thanks for your answers

Restating the core question:
If you build an app that has a minSdkVersion < 23 but the targetSdkVersion >= 23, what happens when you try to scan for bluetooth beacons?
Short answer: it works.
Longer answer:
The user permissions request won't happen. with a minSdkVersion < 23, The compiler will stop you from including a line of code like requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
 because it won't run on earlier Android versions. If you wrap it in an if statement like if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) it won't get executed. If you add annotations like #SuppressLint("NewApi") the app will crash when trying to execute the code.
The beacon scanning will just work, both in the foreground and the background, regardless of the fact that the user permissions have not been granted. Earlier Android versions can't request the permission from the user, so the app just behaves as if they have been granted.

On Android 23 and on, you need to check if the app has been granted a "dangerous" permission and if not ask the user.
The Android support library has helper functions for this.
See Requesting Permissions at Run Time.
The main functions are checkSelfPermission and requestPermissions.
In order not to have problems with older versions of Android you can use the following to check if you are on a device running Marshmallow or not:
public static boolean isMNC() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
This will return true if you are on a device running Marshmallow or newer, false otherwise. So, if this returns true, check for the permission, otherwise don't.
You should probably also use the annotation #SuppressLint("NewApi") on the function where you call the checkSelfPermission and requestPermissions.

Related

Testing for Application level permission on Marshmallow when target API is less than Marshmallow

I have an application that has a targetSDKversion of 21 (can't move up above 21 yet).
It uses Location services but I've been able to test to make sure the system level location permission is enabled but on a device with 6.0 installed, you can turn off the application level location permissions. I haven't been able to determine if this level of permissions has been enabled or not.
I'm currently calling the following:
locationMode = Settings.Secure.getInt(activity.getContentResolver(),
Settings.Secure.LOCATION_MODE);
returnVal = (locationMode != Settings.Secure.LOCATION_MODE_OFF);
Which returns a true value since the locationMode is 3 (that it's been enabled) even though the location at application level has been disabled.
A lot of the references I've been finding on line all use API calls that are not available in API 21 (which we just can't go to yet.)
Can anyone give me something that I can check on newer devices to see if the application level permissions are enabled or not but still be able to do this test with a targetSDKVersion of 21. I will be testing that the Build.VERSION is >= 23 before doing this test. Or is this even possible?
You can use this to see if an application level permission is on or off. It checks based on API level as well so it is safe to use on all devices.
boolean hasApplicationLevelLocationPermission(Context context) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}

BroadcastReceiver for Bluetooth device discovery works on one device but not on another

Code:
I use the following code taken from here with a target API level 23 (and minimum API level 18).
private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action))
{
bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
deviceNameTextView.setText(bluetoothDevice.getName());
}
}
};
On a button pressed event I call:
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery(); // was initialized successsfully
My AndroidManifest.xml contains:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Devices:
Samsung Galaxy S III (API level 18)
Sony Xperia Z3 (API level 23)
Facts:
both devices are running the exact same code
device 1 can discover device 2 (and any other Bluetooth device)
device 2 cannot discover device 1 (or any other Bluetooth device)
both devices are discoverable
tested discoverability with the standard system dialog for pairing for both devices successfully
both devices were unpaired at all times (I don't want to pair)
No exceptions are thrown.
What is wrong?
Update 1:
Since API level 23 permissions may have to be requested at run time. Yvette pointed me to that, thank you! Unfortunately it didn't solve my problem.
What speaks against her theory is the following:
mBluetoothAdapter.startDiscovery() returns true, which means success (see here).
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity , Manifest.permission.BLUETOOTH_ADMIN);
if(permissionCheck == PackageManager.PERMISSION_GRANTED)
Log.i("info", "Permission granted!");
else
Log.i("info", "Permission not granted!");
Running this code with BLUETOOTH_ADMIN and BLUETOOTH returns both times:
Permission granted!
When doing some research, I found the following article from the official documentation regarding changes in Android 6.0 (API level 23).
To access the hardware identifiers of nearby external devices via
Bluetooth and Wi-Fi scans, your app must now have the
ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions:
- WifiManager.getScanResults()
- BluetoothDevice.ACTION_FOUND
- BluetoothLeScanner.startScan()
So, I was missing the permissions ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION all along. But just adding them in the AndroidManifest.xml file is not enough. You have to request those privileges at run time like Yvette suggested.
You can find here how you can do that or just use this piece of code I wrote to get the permissions needed for Bluetooth discovery.
final int CODE = 5; // app defined constant used for onRequestPermissionsResult
String[] permissionsToRequest =
{
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.BLUETOOTH,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
};
boolean allPermissionsGranted = true;
for(String permission : permissionsToRequest)
{
allPermissionsGranted = allPermissionsGranted && (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
}
if(!allPermissionsGranted)
{
ActivityCompat.requestPermissions(this, permissionsToRequest, CODE);
}
mBluetoothAdapter.startDiscovery();
This code is assuming that the user grants the permissions (for simplicity). If you want your app to behave differently when the permissions are not granted see "Handle the permissions request response" in this article.
Sounds like you're not managing runtime permissions for sdk 23 and higher. The phone with the sdk of 23 will either silently ignore any requests that require runtime permissions or crash.
Also see in the docs System Permissions.
If your app lists normal permissions in its manifest (that is, permissions that don't pose much risk to the user's privacy or the device's operation), the system automatically grants those permissions. If your app lists dangerous permissions in its manifest (that is, permissions that could potentially affect the user's privacy or the device's normal operation), the system asks the user to explicitly grant those permissions. The way Android makes the requests depends on the system version, and the system version targeted by your app:
If the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the app requests permissions from the user at run-time. The user can revoke the permissions at any time, so the app needs to check whether it has the permissions every time it runs. For more information about requesting permissions in your app, see the Working with System Permissions training guide.
If the device is running Android 5.1 (API level 22) or lower, or the app's targetSdkVersion is 22 or lower, the system asks the user to grant the permissions when the user installs the app. If you add a new permission to an updated version of the app, the system asks the user to grant that permission when the user updates the app. Once the user installs the app, the only way they can revoke the permission is by uninstalling the app.
Often times a permission failure will result in a SecurityException being thrown back to the application. However, this is not guaranteed to occur everywhere. For example, the sendBroadcast(Intent) method checks permissions as data is being delivered to each receiver, after the method call has returned, so you will not receive an exception if there are permission failures. In almost all cases, however, a permission failure will be printed to the system log.
The permissions provided by the Android system can be found at Manifest.permission. Any application may also define and enforce its own permissions, so this is not a comprehensive list of all possible permissions.
A particular permission may be enforced at a number of places during
your program's operation:
At the time of a call into the system, to prevent an application from
executing certain functions.
When starting an activity, to prevent
applications from launching activities of other applications.
Both
sending and receiving broadcasts, to control who can receive your
broadcast or who can send a broadcast to you.
When accessing and
operating on a content provider.
Binding to or starting a service.
As for the app crashing:
Everything every Android Developer must know about new Android's Runtime Permission
Next question in your head right now. So will my application crash?
Such a kindness sent from god delivered through the Android team. When we call a function that requires a permission user revoked on application with targetSdkVersion less than 23, no any Exception will be thrown. Instead it will just simply do nothing. For the function that return value, it will return either null or 0 depends on the case.
But don't be too happy. Although application would not be crashed from calling a function. It may still can crash from what that application does next with those returned value.
Some more details in these answers Require dangerous permissions during installation When asking for runtime permission for location

detect if permissions revoked or not

I'm using a rooted M device and trying to access the permissions setting for other apps.
I would like to know which permissions are granted or revoked by user for each app
can this be available?
can checkSelfPermission() work for that?
Also, if I'm downloading an app which is not developed for M version can the detection operation work or not because I found that any app whit target version lower than 23 will always return PERMISSION_GRANTED
checkSelfPermission returning PERMISSION_GRANTED for revoked permission with targetSdkVersion <= 22

Android's ContextCompat.checkSelfPermission() returns incorrect value

I am trying to check for permissions being granted/revoked by user in Android Marshmallow. Unfortunately ContextCompat.checkSelfPermission() (which is a warpper around Context.checkCallingOrSelfPermission) seems to always return PackageManager.PERMISSION_GRANTED (0) if you have included that specific permission in your manifest regardless of the current state of the permission (e.g. if the user has revoked the permission). I also tried someContext.checkCallingOrSelfPermission(), but the result is the same.
Has anyone experienced this? I am using Android Marshmallow on nVidia Shield console (using nVidia's Beta program).
As it turns out, The targetSdkVersion in the manifest must be 23, mine was 22. If your target SDK is 23 (Android 6), all of the permissions (in your manifest) are disabled by default, whereas if your target SDK is 22 (Android 5.1) and your app is running on Android 6, all of the permissions are enabled by default when the user installs the app, and even if the user revokes the permissions later on, the mentioned API returns incorrect value (which is a bug in my opinion).

Marshmallow Fingerprint Scanner Hardware Presence

I am looking to get started with the Marshmallow Fingerprint Authentication API. I understand that to ask for permission, I must use the following method:
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.USE_FINGERPRINT);
And I must check if the device is running API level 23 or higher. But before I ask for permission, I would like to check if the device actually has a fingerprint scanner to begin with. I found the following two methods to do this check:
FingerprintManager manager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
manager.isHardwareDetected();
manager.hasEnrolledFingerprints();
But both methods require USE_FINGERPRINT permission to be called at all. Why would I want to ask for permission to use a fingerprint scanner that I do not even know exists? Are there any other methods to find out if a scanner exists? Or is the only way to ask for permission first?
I just found the class FingerprintManagerCompat, which does exactly what you would expect:
A class that coordinates access to the fingerprint hardware.
On platforms before M, this class behaves as there would be no fingerprint hardware available.
The same methods from FingerprintManager in this class do not require USE_FINGERPRINT permission, enabling you to call them before you ask for USE_FINGERPRINT permission.
FingerprintManagerCompat manager = FingerprintManagerCompat.from(mContext);
manager.isHardwareDetected();
manager.hasEnrolledFingerprints();
These methods will also yield the expected false results on pre-Marshmallow devices.
Try hasSystemFeature(PackageManager.FEATURE_FINGERPRINT) on a PackageManager instance (you can get one from calling getPackageManager() on any handy Context).
FingerprintManager class supports Android devices running on API 23 or higher and throws an exception on devices running lower Android versions.
FingerprintManagerCompat class give backward compatibility of isHardwareDetected method in lower Android Version but it always returns false for API 23 or higher
I picked best of both and created this method to check for FingerPrint Sensor hardware support in all Android version.
private boolean isSensorAvialable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return ActivityCompat.checkSelfPermission(AppContext, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED &&
AppContext.getSystemService(FingerprintManager.class).isHardwareDetected();
} else {
return FingerprintManagerCompat.from(AppContext).isHardwareDetected();
}
}
#CommonsWare mentioned something important, hasSystemFeature. To be on the safe side, if your using Java, make sure you call hasSystemFeature or check for null FingerprintManager return value when calling getSystermService even on devices running API 23 or higher. For Kotlin, use an optional variable and do a smart cast when calling getSystemService to avoid unpredictable crashes in the wild for devices without the Fingerprint hardware but running API 23 or greater.

Categories

Resources