I want to avoid ask others permission if the user not grant one.
For example: I ask for read/write external storage and camera, if the user deny the first, the library ask for camera permission, camera permission is redundant in this case.
RxPermissions.getInstance(getActivity()).request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
.subscribe(granted -> {
if (granted) {
dispatchCamera();
} else {
showError();
}
});
I think I could use requestEach, but I dont know how stop to emit items if one permission is not granted and also I cant obtain the final result, if the user grant all permissions.
I suppose your problem was solved, but I gonna place answer, for somebody else, who get into same trouble.
All you need is takeUntil or takeWhile operator with requestEach(depends what stream behaviour you want). TakeUntil unsubscribe you from stream, and bring you only events with granted permissions and one of permission denied inclusive.If you want get only permission granted events without any of them == denied, pls use takeWhile opertator.
Just maybe you would have to experement with this code a while, cause I didnt use this library yet, and maybe something would behave not exactly as you want.
So code might be like this:
RxPermissions
.getInstance(getActivity())
.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA)
.takeWhile(permission -> permission.granted)
//or use take untill if you want to get permission.granted == false event
//.takeUntil(permission -> !permission.granted)
.subscribe(granted -> {
if (granted) {
dispatchCamera();
} else {
showError();
}
});
Related
I am very new to Android programming and I am having trouble requesting storage permission. The idea is to have the phone generate a small label that will print from a mobile printer via Bluetooth, but as proof of concept I was going to have the phone just save a PDF or something for now.
I added this line to the AndroidManifest.xml:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:remove="android:maxSDKVersion" />
and from the MainActivity.kt:
class MainActivity : AppCompatActivity() {
private val REQUEST_STORAGE = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED)
{
println("Permissions Denied")
requestStoragePermission()
println("Passed Command")
} else {
println("PERMISSIONS GRANTED")
}
private fun requestStoragePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
permission.WRITE_EXTERNAL_STORAGE
)
) {
requestPermissions(this, arrayOf(permission.WRITE_EXTERNAL_STORAGE), REQUEST_STORAGE)
} else {
// Eh, prompt anyway
requestPermissions(this, arrayOf(permission.WRITE_EXTERNAL_STORAGE), REQUEST_STORAGE)
}
}
}
No matter what iteration of the requestPermissions command I try, the dialog box never shows and attempting to save any file results in a failure. I know this question has been asked a lot, but none of the solutions that work for other people are working here and I'm not sure why.
I have tried:
\\this is latest iteration
requestPermissions(this, arrayOf(permission.WRITE_EXTERNAL_STORAGE), REQUEST_STORAGE)
\\this was first iteration
ActivityCompact.requestPermissions(
this#MainActivity,
arrayOf(permission.WRITE_EXTERNAL_SOTRAGE),
REQUEST_STORAGE
)
\\this one also caused an error so I abandoned the idea of moving this out of the main class
ActivityCompact.requestPermissions(
MainActivity(),
arrayOf(permission.WRITE_EXTERNAL_SOTRAGE),
REQUEST_STORAGE
)
I need the user to be able to give storage access, at least while it's still in development to convince my boss to buy a mobile printer I can use to print the actual label.
I have started default google sample project related to request runtime permissions topic. By default it uses camera permission. When I had changed Camera permission to WRITE_EXTERNAL_STORAGE permission it stops showing permission dialog too. It means nothing is wrong with your code, the issue has some different cause.
Likely it is related to changes in behaviour related to new Android API.
I haven't found root cause yet, but this links shows changes in behaviour on Android 9, 10, 11:
Different use cases
No need in permission since API 19
Variety of changes among different APIs
UPDATE
Code above doesn't show dialog for MANAGE_EXTERNAL_STORAGE permission, but you have asked for WRITE_EXTERNAL_STORAGE permission. Default google sample is able to show this permission dialog on Android API 30. Here is relevant code:
if (shouldShowRequestPermissionRationaleCompat(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Provide an additional rationale to the user if the permission was not granted
// and the user would benefit from additional context for the use of the permission.
// Display a SnackBar with a button to request the missing permission.
layout.showSnackbar(R.string.camera_access_required,
Snackbar.LENGTH_INDEFINITE, R.string.ok) {
requestPermissionsCompat(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
PERMISSION_REQUEST_CAMERA)
}
} else {
layout.showSnackbar(R.string.camera_permission_not_available, Snackbar.LENGTH_SHORT)
// Request the permission. The result will be received in onRequestPermissionResult().
requestPermissionsCompat(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_REQUEST_CAMERA)
}
fun AppCompatActivity.requestPermissionsCompat(permissionsArray: Array<String>,
requestCode: Int) {
ActivityCompat.requestPermissions(this, permissionsArray, requestCode)
}
From the doc, shouldShowRequestPermissionRationale indicates whether you should show permission rationale UI.
I found:
if change one permission to "Notify" and before first showing the permission-request-dialog, shouldShowRequestPermissionRationale return false
if deny the permission with the "Never ask again" checkbox selected, shouldShowRequestPermissionRationale return false
Then I met a problem, how to distinguish these two cases? I mean, in the following code snippet from Android developer:
if (ContextCompat.checkSelfPermission(
CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
PackageManager.PERMISSION_GRANTED) {
// You can use the API that requires the permission.
performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
// In an educational UI, explain to the user why your app requires this
// permission for a specific feature to behave as expected. In this UI,
// include a "cancel" or "no thanks" button that allows the user to
// continue using your app without granting the permission.
showInContextUI(...);
} else {
// You can directly ask for the permission.
requestPermissions(CONTEXT,
new String[] { Manifest.permission.REQUESTED_PERMISSION },
REQUEST_CODE);
}
In the case 2, though denied the permission with "Never ask again", the code still invokes requestPermissions?
I'm currently writing some tests for an app. If the app does not have storage permission, a fragment pops up. I know how to grant permission with "grant permission rule" but is there a method to revoke permission?
No, that is not possible. Quote from https://developer.android.com/reference/android/support/test/rule/GrantPermissionRule:
Once a permission is granted it will apply for all tests running in the current Instrumentation. There is no way of revoking a permission after it was granted. Attempting to do so will crash the Instrumentation process.
What I can suggest is to wrap permission methods into some service and mock the value checking if the permission is granted
Yes, during testing its possible...Feuby gave a somewhat correct answer to the same question in this SO 2017 question
Android revoke permission at start of each test
Repeating his code
public static boolean checkCameraPermission(MainActivity thisActivity) {
return ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
public static void checkAndAskCameraPermission(final MainActivity thisActivity) {
if (!checkCameraPermission(thisActivity)) {
//No right is granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.CAMERA)) {
//Open a dialog explaining why you are asking permission then when when positive button is triggered, call this line
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.CAMERA},
CHECK_FOR_CAMERA_PERMISSION);
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.CAMERA},
CHECK_FOR_CAMERA_PERMISSION);
}
}
}
Currently I am programming an android app which reads out the phone number of the user. Because the app is developed for SDK 23+ (target sdk 27) I have to request the read sms permission. If the user denies the permission the first time a dialog should appear where the use of the phone number is explained. Then the user can choose to request the permission once more or to type the phone number manually. If the user tiks "never ask again" a dialog should appear where the user is instructed to allow the permission via the settings.
To check if the user has ticked never ask again, I use the method shouldShowRequestPermissionRationale. But the method always returns false, even if I never ticked never ask again.
Here is the relevant code:
public class SettingsSettingsFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
public void readNumber() {
if (person.getPhoneNumber() == null || person.getPhoneNumber().equalsIgnoreCase("")) {
if (checkSelfPermission(getActivity(), READ_SMS) != PackageManager.PERMISSION_GRANTED)
requestPermission();
else {
//read phoneNumber
}
}
//request permission send sms
private void requestPermission() {
requestPermissions(new String[]{Manifest.permission.READ_SMS}, PERMISSION_REQUEST_SEND_SMS);
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_SEND_SMS)
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
// user rejected the permission
boolean showRationale = shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS);
if (!showRationale) {
// user also CHECKED "never ask again" - show dialog
//show dialog: please allow in settings
} else if (counter < 2) {
// explain the permission, and give the user the possibility to ask once more
counter++;
}
}
Why is shouldShowRequestPermissionRationale always returning false?
The code is from here: Android M - check runtime permission - how to determine if the user checked "Never ask again"?
Thanks for help in advance.
According to android developers documentation of shouldShowRequestPermissionRationale():
method returns true if the app has requested this permission previously and the user denied the request.
If the user turned down the permission request in the past and chose the Don't ask again option in the permission request system dialog, this method returns false
If you haven't requested permission before it will return false because there is no need to pop the rational alert dialog.
This answer was very helpful for me to understand the issue.
Your requestPermission() is for READ_SMS, butshouldShowRequestPermissionRationale() is about SEND_SMS.
shouldShowRequestPermissionRationale() keeps returning false until user is asked for the "relevant" permission. Once requested, it returns true until user denies the same permission with "Never Ask Again" checked.
So, in your case, SEND_SMS is never requested. Therefore shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS) will keep returning false as expected. I made the same mistake before.
When we ask permission from the user on his phone, is there a way we can inform the OS not to ask this permission again? No matter what the user's response is.
If the program does not "desperately" require the permission, you can use SharedPreferences and store a variable called firstTime withe boolean value of true.
Then check in the onCreate method for that variable. if it is true, ask the permission then set the value to false and save it. Then when the user will rerun the application, it won't be the "FirstTime" so he won't be prompted with the permission.
SharedPreferences pref = this.getSharedPreferences("PACKAGE.NAME",MODE_PRIVATE);
Boolean firstTime = pref.getBoolean("firstTime",true);
if(firstTime){
//Ask for permissions here
pref.edit().putBoolean("firstTime",false).apply();
}
No, sorry. You would need to keep track of whether you asked the user for permissions, then use that information to determine whether or not to ask in the future.
When you ask the permission in any way like in the following, in the dialog that would be open to ask for permission there is a check box that by checking it, OS would not ask you for that permission any more:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_WRITE_EXTERNAL_STORAGE);
}
}