amp
amp

Reputation: 12352

GrantPermissionRule Failed to grant permissions

I am writing a test class and I am trying to grant the permissions using the rule GrantPermissionRule:

@Rule
public GrantPermissionRule permissionsRule = GrantPermissionRule.grant(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE);

But I get the following error at the beginning of the test execution:

junit.framework.AssertionFailedError: Failed to grant permissions, see logcat for details
    at junit.framework.Assert.fail(Assert.java:50)
    at android.support.test.runner.permission.PermissionRequester.requestPermissions(PermissionRequester.java:110)
    at android.support.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:128)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
    at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1886)

And this is the logcat output (Errors only):

12-23 13:03:21.196 13242-13242/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@[email protected]@app_chimera@m@[email protected]@classes.dex: Permission denied
12-23 13:03:21.721 13306-13306/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@[email protected]@app_chimera@m@[email protected]@classes.dex: Permission denied
12-23 13:03:22.361 13328-13328/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@[email protected]@app_chimera@m@[email protected]@classes.dex: Permission denied
12-23 13:03:26.303 13436-13467/my.app.package E/GrantPermissionCallable: Permission: android.permission.READ_EXTERNAL_STORAGE cannot be granted!

But this seems to happen only in my Redmi 4 with Android 6.0.1. But in a Samsung Galaxy Tab S with 6.0.1 it works, as well in some emulators...

What am I missing?

Upvotes: 21

Views: 14577

Answers (8)

SerjantArbuz
SerjantArbuz

Reputation: 1234

I faced same problem:

  1. Run on emulator with API>32 -> Got exception about WRITE_EXTERNAL_STORAGE
  2. If run on API<33 -> Got exception about POST_NOTIFICATIONS

For first issue Deni answer helped, but the second one can't be resolved the same way.


So I created a new TestRule class based on original GrantPermissionRule:

/**
 * Custom realization of [GrantPermissionRule] with ability to skip grant check.
 *
 * [isActualPermission] - pass here your api check. If FALSE - permission check will be skipped.
 */
@SuppressLint("RestrictedApi")
@ExperimentalTestApi
class GrantPermissionApiRule(
    private val isActualPermission: Boolean,
    private val permissionGranter : PermissionGranter,
    vararg permissions: String
) : TestRule {

    init {
        val permissionSet = satisfyPermissionDependencies(*permissions)
        permissionGranter.addPermissions(*permissionSet.toTypedArray())
    }

    @VisibleForTesting
    private fun satisfyPermissionDependencies(vararg permissions: String): Set<String> {
        val permissionList: MutableSet<String> = LinkedHashSet(listOf(*permissions))
        /**
         * Explicitly grant READ_EXTERNAL_STORAGE permission when WRITE_EXTERNAL_STORAGE was
         * requested.
         */
        if (permissionList.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE)
        }
        return permissionList
    }

    override fun apply(base: Statement, description: Description): Statement {
        return RequestPermissionStatement(base, isActualPermission, permissionGranter)
    }

    private class RequestPermissionStatement(
        private val base: Statement,
        private val isActualPermission: Boolean,
        private val permissionGranter: PermissionGranter
    ) : Statement() {

        @Throws(Throwable::class)
        override fun evaluate() {
            if (isActualPermission) {
                permissionGranter.requestPermissions()
            }
            base.evaluate()
        }
    }

    companion object {
        fun grant(
            isActualPermission: Boolean,
            vararg permissions: String
        ): GrantPermissionApiRule {
            val granter = ServiceLoaderWrapper.loadSingleService(PermissionGranter::class.java) {
                PermissionRequester()
            }
            return GrantPermissionApiRule(isActualPermission, granter, *permissions)
        }
    }
}

If function permissionGranter.requestPermissions() not called - you will not receive exception on wrong API.


All you need to do with this realization is check current API version and pass isActualPermission inside this TestRule.

Like this:

/**
 * If current device api >= TIRAMISU (33) - permission rule will be skipped.
 */
@get:Rule
val writeExternalGrantRule: GrantPermissionApiRule = GrantPermissionApiRule.grant(
    Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU, 
    Manifest.permission.WRITE_EXTERNAL_STORAGE
)

Upvotes: 1

Deni Erdyneev
Deni Erdyneev

Reputation: 1819

In my case I don't declare WRITE_EXTERNAL_STORAGE in manifest and it was provided from some library, but in the new version of that library they set maxSdkVersion

So I just add that permission to my manifest and ignore maxSdkVersion

<uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:remove="android:maxSdkVersion"
        tools:ignore="ScopedStorage" />

Upvotes: 1

Akhha8
Akhha8

Reputation: 490

Following code fixed my issue, my test now are passing in all supported versions of my application.


Kotlin, the example provided also needs camera, you can remove it if you don't need it.
// Android 13 requires more specific permission to read media
// https://stackoverflow.com/questions/53903976
private val requiredMediaPermissions = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

    Manifest.permission.READ_MEDIA_IMAGES
} else {

    Manifest.permission.READ_EXTERNAL_STORAGE
}

Upvotes: 0

Fah
Fah

Reputation: 306

I faced this error when I tried to grant the POST_NOTIFICATIONS permission on a device with Android lower than 13. So check if the devices API level is high or low enough for the permissions you grant.

Upvotes: 4

hicham raf
hicham raf

Reputation: 11

in my case, the READ_EXTERNAL_STORAGE permission is no longer granted since API level 32. changed to an emulator/device that has an API level of 31 or lower fixed the issue

Upvotes: 1

Achraf Amil
Achraf Amil

Reputation: 1375

For what it's worth: For me I just forgot specifying the permission in the app's manifest.

Upvotes: 1

Prajwal Waingankar
Prajwal Waingankar

Reputation: 2710

The above-answered option wasn't available in my OPPO device.

But there is an option called "Disable Permissions Monitoring" which does the same functionality.

To fix this issue, Turn ON the option of "Disbale Permission Functionality" under the Developer Options

Upvotes: 18

amp
amp

Reputation: 12352

Found the solution. I had to grant permission in the developer options menu:

usb_debugging_security_settings

Upvotes: 17

Related Questions