How can be handle permission issue in Sdk 22 .If user manually deny the permission.Their is way of handling permission in Marshmallow,but how can be it done in below M?.
Before Android Marshmallow users accept permissions just by installing your app (They can see the request permission list before installing).
So you don't need to handle denied permission for users running a version below Android Marshmallow.
for below Marshmallow version just give permission in manifest file.
Actually Android minimum sdk version 21-22 i.e. 5.0 doesn't need to check permission but when we have to Test the our app on different phones for eg. on minimum sdk version 23 i.e. on Marshmallow. You need to check permission externally in your App.
For Handling the permissions in App
Write below code in Your Starting_Activity
private void requestingPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_NETWORK_STATE)){
//Exaplian here why you need this permission
}
//Ask for the permission
ActivityCompat.requestPermissions(this,new String[]{
Manifest.permission.ACCESS_NETWORK_STATE, },STORAGE_PERMISSION_CODE);}
Now Add another
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//checking the request code of Permission request
if (requestCode == STORAGE_PERMISSION_CODE){
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){//Toast.makeText(getApplicationContext(),"Permission Granted",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(),"Permission Denied",Toast.LENGTH_SHORT).show();
}
}
}
Dont forget call below method in your activity onCreate() Method
requestingPermission();
Related
I've created a sample Wear OS app, which should discover BLE devices, but my code requires Bluetooth permission. When I put these lines in manifest:
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
corresponding permission is not displayed in settings/apps/permissions and every permission request does nothing. By the way, my BLE-devices (a speaker and a esp-32) is not shown in settings/Bluetooth also.
How can I grant Bluetooth permissions for my app or how can I connect BLE device to my watch?
upd:
I tried these:
if (checkSelfPermission(Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf<String>(Manifest.permission.BLUETOOTH), 1001)
}
if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf<String>(Manifest.permission.BLUETOOTH_CONNECT), 1001)
}
if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf<String>(Manifest.permission.BLUETOOTH_SCAN), 1001)
}
if (checkSelfPermission(Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf<String>(Manifest.permission.BLUETOOTH_ADMIN), 1001)
}
But dialogs windows still are not displayed
According documentation, you need particular permissions in based of the target Android API version.
If your app targets Android 11 (API level 30) or lower, declare the following permissions in your app's manifest file:
BLUETOOTH is necessary to perform any Bluetooth classic or BLE communication, such as requesting a connection, accepting a connection, and transferring data.
ACCESS_FINE_LOCATION is necessary because, on Android 11 and lower, a Bluetooth scan could potentially be used to gather information about the location of the user.
If your app targets Android 9 (API level 28) or lower, you can declare the ACCESS_COARSE_LOCATION permission instead of the ACCESS_FINE_LOCATION permission.
In order to perform a scan to discover BLE devices the app must require explicitaly to the user the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission also to be declared in the AndroidManifest.xml.
In my project (WearOS API version 28) I used this code in the onCreate function of MainActivity class
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(this,new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
1);
}
And I overrided the onRequestPermissionsResult function
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
switch (requestCode) {
case 1:
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Logger.d("MainActivity","Permission approved");
} else {
Logger.d("MainActivity","Error getting permission");
}
return;
}
}
This works for me, I hope would help you
there are some permissions like camera, bluetooth which need to be asked first and then manually provided. use this in the activity that loads first in your app.
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf<String>(Manifest.permission.CAMERA), 1001);
} //ask camera permissions
make sure to do required changes.
According to "developer.android.com"
If the app targets Android 8.0 (API level 26), the system grants only
READ_EXTERNAL_STORAGE at that time; however, if the app later requests
WRITE_EXTERNAL_STORAGE, the system immediately grants that privilege
without prompting the user.
Now, I have the READ_EXTERNAL_STORAGE and I'm requesting the DownloadManager to download a file in the Public Download folder
downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, mAttachmentItem.getFilename());
Unfortunately, I got
E/UncaughtException: java.lang.IllegalStateException: Unable to create directory: /storage/emulated/0/data/user/0/com.abc.cba/files
at android.app.DownloadManager$Request.setDestinationInExternalPublicDir(DownloadManager.java:699)
I have declared both of permissions in the Manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Read permission is already Granted and in Runtime I'm requesting Write permission, the system doesn't prompt any message or dialog, it's always Denied(Not Granted) in "onRequestPermissionsResult"
public static boolean isPermissionsToAccessStorageAreGranted(Context context, Activity activity) {
ArrayList<String> permissions = new ArrayList<>();
if (!PermissionUtil.checkPermissions(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissions.isEmpty()) {
String[] permissionsList = permissions.toArray(new String[permissions.size()]);
PermissionUtil.requestPermissions(activity, permissionsList,
PermissionUtil.REQUESTCODE_ACCESS_STORAGE);
return false;
} else {
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==REQUESTCODE_ACCESS_STORAGE && grantResults[0]== PackageManager.PERMISSION_GRANTED){
/* downloadFile(); */
}
}
I'm trying to grant those two permissions via ADB, it shows me an error:
adb shell pm grant com.abc.cba
android.permission.WRITE_EXTERNAL_STORAGE
Operation not allowed: java.lang.SecurityException: Package com.abc.cbs
has not requested permission android.permission.WRITE_EXTERNAL_STORAGE
adb shell pm grant com.abc.cba
android.permission.READ_EXTERNAL_STORAGE
Operation not allowed: java.lang.SecurityException: Can't change
android.permission.READ_EXTERNAL_STORAGE. It is required by the
application
Actually, It was an external problem. One of App Libs I'm using request the WRITE_EXTERNAL_PERMISSION with android:maxSdkVersion. So when merging with my Manifest it will remove the permission for the whole application.
The Solution is to add:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>
You are correct in adding the permissions to the manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
For versions of Lollipop and higher, you need to also request the permissions at runtime. To solve this problem, I created a new method requestAppPermission that I call when the main activity is created. This method runs only for Lollipop and higher, and returns early otherwise:
private void requestAppPermissions() {
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
if (hasReadPermissions() && hasWritePermissions()) {
return;
}
ActivityCompat.requestPermissions(this,
new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, REQUEST_WRITE_STORAGE_REQUEST_CODE); // your request code
}
private boolean hasReadPermissions() {
return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
}
private boolean hasWritePermissions() {
return (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
}
I call this method in the activity's onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other things
requestAppPermissions();
}
On first load, this will prompt the user to accept permissions.
Then, before you run any code that needs to read and write to storage, you can check these permissions, either by storing the values or running those checks again using methods hasReadPermissions() and hasWritePermissions() defined above.
UPDATE: See this answer for a better solution
EDIT: This is not a solution, just a quick workaround.
If you get permission denied error even when the permissions are granted and you already implemented permission checks,
make sure you're not targetting api level 29:
Change targetSdkVersion and compilesdkversion from 29 to 28 or any other lower level.
For Oreo,
you need to explicitly do a READ_EXTERNAL_STORAGE request (by code) even if you have already requested and is granted the WRITE_EXTERNAL_STORAGE permission, and vis versa.
prior to this, READ_EXTERNAL_STORAGE is automatically granted when WRITE_EXTERNAL_STORAGE is granted.
so what you need to do, is to
1) ask for WRITE permission in your codes.
2) when user grants the WRITE permission, ask again for READ permission - this will be automatically granted (you will get an exception if you do not ask for a READ explicitly)
The changes for Oreo doesn't make much sense to me (no idea why do we need to ask for a permission that is automatically granted), but that is what it is.
https://developer.android.com/about/versions/oreo/android-8.0-changes.html#rmp
You have to grant permissions at runtime on Marshmallow or higher.
Sample snippet :
private static final int REQUEST_WRITE_STORAGE = 112;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean hasPermission = (ContextCompat.checkSelfPermission(getBaseContext(),
Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
if (!hasPermission) {
ActivityCompat.requestPermissions(SplashScreen.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE, Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS, Manifest.permission.INTERNET
},
REQUEST_WRITE_STORAGE);
}else{ startMainActivity(); }
}
Hope it helps.
Use this
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
instead of
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE/>"
Some of your third party libraries are override maxSdkVersion like com.vungle:publisher-sdk-android, to finding them just check the Merged Manifest below of your manifest screen. see this
For SDK 29 and Later
If you are still having issue to accessing external storage, consider using android:requestLegacyExternalStorage="true" in your <application> tag of your manifest.
Just a notice: on Android P I had to show a terminate dialog box to user asking to restart the app because even after all written above app couldn't read external storage, only after restart. Seriously, those guys in google makes Android better each time. 6, 8, and now so much troubles with 9, one more such stupid update and I will go to iOS :)
I have an app that I published, and it has something like this:
requestStoragePermission();
and the function:
private void requestStoragePermission(){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},STORAGE_PERMISSION_CODE);
}
#Override //user response
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if(requestCode == STORAGE_PERMISSION_CODE){
//If permission is granted
if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//Displaying a toast
String string = getString(R.string.permissionOk);
Toast.makeText(this,string,Toast.LENGTH_LONG).show();
}
else{
//Displaying another toast if permission is not granted
String string = getString(R.string.permissionError);
Toast.makeText(this,string,Toast.LENGTH_LONG).show();
}
}
}
It works ok on android 6... but how will it be interpretation on android 4, for example, which does not need permissions? is it a bad practise?
On API levels where it is not required for the user to grant a dangerous permission, requesting that permission does not pop up a dialog for the user and the permission is automatically granted. This still adheres with Google's security policy because for those API levels the user has to grant the permissions during the installation process instead.
Some will tell you to check the API level in your code and only request the permission if it is below 23. This is just an extra layer on top of what the code already does internally and thus increases the complexity of your code. You don't have to do that.
There is no way to request persmission in android 4.
You simply have to add the permissions in android-manifest file and everything will be taken care of.
However, make sure your request permission code is not executed in these versions. For that use something like:
if(Build.VERSION.SDK_INT<23){
//DoNOtRequestPersmissions
}
In my projects, to request permissions, I usually have a function that I call arePermissionsGranted(). In that function, if the API level is lower than 23, it automatically says 'the permissions are granted', since you do not need to request them. If API level is 23 or higher, it checks if the permissions have been granted and if not, requests them.
I'm developing an app that require some system permissions, however these are no longer granted automatically at installation time on Android Marshmallow.
I would like to request these permissions at runtime and run some kind of automation to grant them without needing a user to tap the 'allow' button when the System permissions Dialog appears.
How can I achieve this? Is there any way to do so in Marshmallow and later versions?
For Marshmallow or later permissions are not granted at install time and must be requested when required at runtime (if not granted previously.)
To do this, you need to run ActivityCompat.requestPermissions() to pop up the systems permissions dialog in your Activity, at the time when the user is undertaking an action that requires additional system permissions.
An example of this for the WRITE_EXTERNAL_STORAGE permission would be:
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
WRITE_EXTERNAL_STORAGE_REQUEST_CODE
);
Note: WRITE_EXTERNAL_STORAGE_REQUEST_CODE is an arbitrary integer constant you should define elsewhere.
The permissions you request should also be declared in your AndroidManifest.xml. In this example the declaration would be:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
In order to handle the system permissions dialog response you will also need to implement onRequestPermissionsResult() in your Activity. For this example the code would be similar to
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
if (grantResults.length == 0 || grantResults[0] == PackageManager.PERMISSION_DENIED) {
return; //permission not granted, could also optionally log an error
}
if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
//Do whatever you needed the write permissions for
}
}
If you are automating your app through Espresso, UIAutomator and/or some other UI testing framework you will need to anticipate and click the system dialog during your test, which can be accomplished with the following test code:
private void allowPermissionsIfNeeded() {
if (Build.VERSION.SDK_INT >= 23) {
UiObject allowPermissions = mDevice.findObject(new UiSelector().text("Allow"));
if (allowPermissions.exists()) {
try {
allowPermissions.click();
} catch (UiObjectNotFoundException e) {
Timber.e(e, "There is no permissions dialog to interact with ");
}
}
}
}
A more comprehensive explanation of testing System UI Permissions is available here.
I found out that an simpler way to automate the permission acceptance without using UIAutomator or espresso in a CI scenario is to simply, pre-installing the apk via adb using:
adb install -g {my_apk_file}
The -g flag automatically grants all manifest permissions to the app. Afterwards if you launch your espresso test suite, the ui won't ask you again to grant them.
I just started off with android M and I am unable to access the external storage. I get the following error
Caused by: java.lang.SecurityException: Permission Denial: reading
com.android.providers.media.MediaProvider uri
content://media/external/images/media from pid=15355, uid=10053 requires
android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
I am adding user-permission in manifest like
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
and my build file is with following settings :
compileSdkVersion 23
buildToolsVersion "22.0.1"
minSdkVersion 16
targetSdkVersion 23
How to read and write from external storage in android M?
Reading from the documentation. I have to ask user for permission at runtime. Code example :
Add permission to android manifest like we used to do earlier :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Check if the user has already granted the permission. If yes, skip asking for permission and continue with your work flow else ask user for permission :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.System.canWrite(this)) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE}, 2909);
} else {
// continue with your code
}
} else {
// continue with your code
}
Now to check if the user granted the permission or denied it #Override OnRequestPermissionResult to get a callback :
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 2909: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("Permission", "Granted");
} else {
Log.e("Permission", "Denied");
}
return;
}
}
}
I was not able to READ external storage only by asking WRITE
permission, so i had to request for
Manifest.permission.READ_EXTERNAL_STORAGE as well.
Also if you want to target versions below api 23, check the Build
VERSION at runtime with IF statement and ask for permissions only if
VERSION is equal or above Android M.
In case you are looking for a way to handle in any android version (you are compiling for M, but some devices can be using other versions) there is a compatibility version.
if (ContextCompat.checkSelfPermission(CreatePlayerActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(CreatePlayerActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Show an expanation 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.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(CreatePlayerActivity.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
In regards to the selected answer:
Settings.System.canWrite(this) and WRITE_EXTERNAL_STORAGE are two very different things! Should be:
boolean needsRead = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED;
boolean needsWrite = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED;
if (needsRead || needsWrite)
requestStoragePermission()
I was struggling with WRITE_EXTERNAL_STORAGE permission: after I requested it, the dialog didn't show up and immediately returned DENIED.
The problem was in one of the included libraries. It contained the same permission declaration in its AndroidManifest.xml, but with maxSdkVersion="22". The declaration in application's manifest file was overridden by the library.
To override permission from the library I used the following:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:node="remove"
tools:selector="com.example.lib" />
I hope this might be helpful.
I used this utility on github. It works with with both API 22 and 23. Adding runtime permissions is not hard but having to seperate your code and move the methods around to capture callbacks is a little pain. This library provides a chained api to do all you need to do for supporting runtime permissions.
https://github.com/kayvannj/PermissionUtil