Multi-Image picker Library Permission issue - android

Using expo version 37..0.12
While trying to load multi-images there is a permission error reading the images
Following is the error
Permissions.askAsync(Permissions.CAMERA,Permissions.CAMERA_ROLL, Permissions.READ_EXTERNAL_STORAGE);
Error: [Unhandled promise rejection: Error: Failed to get permissions]
This happens in Android while using multi-image picker library: "expo-image-picker-multiple": "1.4.0"

I assume you already used this permission in your manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />.
If yes its probably because you don't have runtime permissions in your project like this
val requestPermissionLauncher =
registerForActivityResult(RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
}
Ref: Android Docs for Runtime Permission

Related

How to request permissions on Android

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)
}

Qt on android how to get positioning with android.permission.ACCESS_COARSE_LOCATION

I'm using Qt (6.4.1) for android. I used to ask "ACCESS_FINE_LOCATION" permission to get GPS position using code like:
auto permissionGPS = QtAndroidPrivate::requestPermission("android.permission.ACCESS_FINE_LOCATION").result();
if(permissionGPS == QtAndroidPrivate::Authorized){
source = QGeoPositionInfoSource::createDefaultSource(0);
if (source) {
auto last = source->lastKnownPosition(false);
if(last.isValid()){
receivePosition(last);
}else{
connect(source, &QGeoPositionInfoSource::positionUpdated, this, &Locator::receivePosition);
source->startUpdates();
}
}
}else{
emit GPSRefusal(false);
}
Unfortunately if the user perfers to allow "ACCESS_COARSE_LOCATION", this code doesn't work anymore.
If I replace requested permission with "ACCESS_COARSE_LOCATION" (which is reasonable for my app), I get the following error:
W qt.positioning.android: : Position data not available due to missing permission 4
Does any one know how to get ACCESS_COARSE_LOCATION positioning working with Qt ?
For an Android 13 device you first have to request COARSE location permission.
And only after you obtained permission request gps FINE permission.
Two steps.

Android 12 not showing correct permissions request screen

My app requires precise user location because it requires the user to be at specific locations to perform tasks. I have followed the documentation for the proper way to request both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION together.
class LocationChooserFragment : BottomSheetDialogFragment() {
// only relevant parts shown
/**
* A utility class that holds all the code for requesting location updates,
* so that we can re-use it in multiple fragments.
*/
private var locationTracker: LocationTracker? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// all the other initialization for viewbinding
tryToGetLocationUpdates()
}
private fun tryToGetLocationUpdates() {
val request = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true && permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true) {
requestLocationUpdates()
}
}
when {
ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED -> {
Timber.i("Already have required permissions")
requestLocationUpdates()
}
shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) ||
shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION) -> {
Timber.i("Showing permission rationale dialog")
// A wrapper to show a dialog that explains what we need permissions for
alertDialog(
title = getString(R.string.permissions),
msg = getString(R.string.why_we_need_location),
onClick = { yes ->
if (yes) {
request.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
))
}
}
)
}
else -> {
Timber.i("Prompting for location permissions")
request.launch(arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
))
}
}
}
private fun requestLocationUpdates() {
if (locationProvider == null) {
locationProvider = LocationProvider(requireContext())
}
locationProvider?.requestLocationUpdates()
}
}
The problem I have is that my users are not getting prompted to allow precise location.
I expect to see the prompt in Figure 3 from the documentation:
Figure 3. System permissions dialog that appears when your app requests both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION in a single runtime request.
Instead, I see the prompt in Figure 2 from the documentation:
Figure 2. System permissions dialog that appears when your app requests ACCESS_COARSE_LOCATION only.
Additionally, I expect that when I already have COARSE permission and I request FINE and COARSE permission again, I should see the "Upgrade to Precise permission" dialog, but I don't see any prompt at all.
I have tested this on Pixel 3a (physical device and emulator) as well as received reports from other users on various Pixel and Samsung Galaxy devices that are running Android 12.
The problem was not present when we used compileSdk 30 and targetSdkVersion 30 in build.gradle, but we need to be able to support new features and new versions of Android (and to be able to upgrade to dependencies that only support building with newer SDK versions.
Why is the permission dialog not showing properly?
Comparing my AndroidManifest.xml to the generated file in the built app (using the "Analyze APK" feature in Android Studio), I discovered that the generated APK file had the following entry:
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
Clearly, the maxSdkVersion is preventing the OS from giving me the permission I need.
Using grep on the app\build directory, I found app\build\intermediates\manifest_merge_blame_file\appnameDebug\manifest-merger-blame-appname-debug-report.txt, which included these lines:
17 <uses-permission
17-->C:\path\to\my\appname\app\src\main\AndroidManifest.xml:12:2-76
18 android:name="android.permission.ACCESS_FINE_LOCATION"
18-->C:\path\to\my\appname\app\src\main\AndroidManifest.xml:12:19-73
19 android:maxSdkVersion="30" />
19-->[com.github.50ButtonsEach:flic2lib-android:1.3.1] C:\Users\moshe\.gradle\caches\transforms-3\dced3886509296f1029e8245af379a07\transformed\jetified-flic2lib-android-1.3.1\AndroidManifest.xml:17:9-35
It turns out the developers of this library originally used ACCESS_FINE_LOCATION for connecting to nearby Bluetooth devices, and since Android 12 has separate permissions for that, they don't need it anymore so they added a max SDK version.
I added the tools:remove="android:maxSdkVersion" property to the ACCESS_FINE_LOCATION <uses-permission /> element, and now my permissions work properly.

Android Studio Constantly Shows Error While Creating An Instance of ActivityResultCallback

I started learning about how I can request app permissions from the Google Documentation. This is basically the code that I'm trying to execute.
// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
registerForActivityResult(RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
}
Unfortunately, whenever I'm trying to write the registerForActivityResult(...) part, Android Studio keeps highlighting it as an error.
There's another step that I need to perform along with this. It tells me to add this dependency. Even after doing that, Android Studio still shows me that it shows an error. Can anyone tell me why this happens?
You're missing the following
// Kotlin
implementation 'androidx.activity:activity-ktx:1.2.0-beta01'
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'

Android Marshmallow: How to allow Runtime Permissions programatically?

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.

Categories

Resources