public class

GrantPermissionRule

extends java.lang.Object

 java.lang.Object

↳androidx.test.rule.GrantPermissionRule

Gradle dependencies

compile group: 'androidx.test', name: 'rules', version: '1.6.1'

  • groupId: androidx.test
  • artifactId: rules
  • version: 1.6.1

Artifact androidx.test:rules:1.6.1 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.test:rules com.android.support.test:rules

Androidx class mapping:

androidx.test.rule.GrantPermissionRule android.support.test.rule.GrantPermissionRule

Overview

The GrantPermissionRule Rule allows granting of runtime permissions on Android M (API 23) and above. Use this Rule when a test requires a runtime permission to do its work.

When applied to a test class this Rule attempts to grant all requested runtime permissions. The requested permissions will then be granted on the device and will take immediate effect. Permissions can only be requested on Android M (API 23) or above and will be ignored on all other API levels. 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.

Note, this Rule is usually used to grant runtime permissions to avoid the permission dialog from showing up and blocking the App's Ui. This is especially helpful for Ui-Testing to avoid losing control over the app under test.

The requested permissions will be granted for all test methods in the test class. Use GrantPermissionRule.grant(String...) static factory method to request a variable number of permissions.

Usage:

 @Rule
 public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule
     .grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
 

Note: As per the documentation this rule will automatically grant when is requested.

See Request App Permissions for more details on runtime permissions.

For tests running on Android SDKs >= API 28, use
android.app.UiAutomation instead.

Summary

Methods
public final Statementapply(Statement base, Description description)

public static GrantPermissionRulegrant(java.lang.String permissions[])

Static factory method that grants the requested permissions.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static GrantPermissionRule grant(java.lang.String permissions[])

Static factory method that grants the requested permissions.

Permissions will be granted before any methods annotated with @Before but before any test method execution.

Parameters:

permissions: a variable list of Android permissions

Returns:

GrantPermissionRule

See also:

public final Statement apply(Statement base, Description description)

Source

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Lice`nse is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.test.rule;

import static androidx.test.internal.util.Checks.checkNotNull;

import android.Manifest.permission;
import android.os.Build.VERSION;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.test.internal.platform.ServiceLoaderWrapper;
import androidx.test.internal.platform.content.PermissionGranter;
import androidx.test.runner.permission.PermissionRequester;
import androidx.test.runner.permission.UiAutomationPermissionGranter;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

/**
 * The {@code GrantPermissionRule} Rule allows granting of runtime permissions on Android M (API 23)
 * and above. Use this {@code Rule} when a test requires a runtime permission to do its work.
 *
 * <p>When applied to a test class this Rule attempts to grant all requested runtime permissions.
 * The requested permissions will then be granted on the device and will take immediate effect.
 * Permissions can only be requested on Android M (API 23) or above and will be ignored on all other
 * API levels. 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.
 *
 * <p>Note, this Rule is usually used to grant runtime permissions to avoid the permission dialog
 * from showing up and blocking the App's Ui. This is especially helpful for Ui-Testing to avoid
 * losing control over the app under test.
 *
 * <p>The requested permissions will be granted for all test methods in the test class. Use {@link
 * #grant(String...)} static factory method to request a variable number of permissions.
 *
 * <p>Usage:
 *
 * <pre>
 * &#064;Rule
 * public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule
 *     .grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
 * </pre>
 *
 * <p>
 *
 * <p>Note: As per <a
 * href=https://developer.android.com/reference/android/Manifest.permission.html#READ_EXTERNAL_STORAGE>
 * the documentation</a> this rule will automatically grant {@link
 * android.Manifest.permission#READ_EXTERNAL_STORAGE} when {@link
 * android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is requested.
 *
 * <p>See <a href="https://developer.android.com/training/permissions/requesting">Request App
 * Permissions</a> for more details on runtime permissions.
 *
 * <p>For tests running on Android SDKs >= API 28, use <br>
 * {@link android.app.UiAutomation#grantRuntimePermission(String, String)} instead.
 */
public class GrantPermissionRule implements TestRule {

  private PermissionGranter permissionGranter;

  private GrantPermissionRule() {
    PermissionGranter granter =
        ServiceLoaderWrapper.loadSingleServiceOrNull(PermissionGranter.class);
    if (granter == null) {
      if (VERSION.SDK_INT >= 28) {
        granter = new UiAutomationPermissionGranter();
      } else {
        // use the shell permission requester
        granter = new PermissionRequester();
      }
    }

    setPermissionGranter(granter);
  }

  @VisibleForTesting
  GrantPermissionRule(@NonNull PermissionGranter permissionGranter) {
    setPermissionGranter(permissionGranter);
  }

  /**
   * Static factory method that grants the requested permissions.
   *
   * <p>Permissions will be granted before any methods annotated with {@code &#64;Before} but before
   * any test method execution.
   *
   * @param permissions a variable list of Android permissions
   * @return {@link GrantPermissionRule}
   * @see android.Manifest.permission
   */
  public static GrantPermissionRule grant(String... permissions) {
    GrantPermissionRule grantPermissionRule = new GrantPermissionRule();
    grantPermissionRule.grantPermissions(permissions);
    return grantPermissionRule;
  }

  private void grantPermissions(String... permissions) {
    Set<String> permissionSet = satisfyPermissionDependencies(permissions);
    permissionGranter.addPermissions(permissionSet.toArray(new String[permissionSet.size()]));
  }

  private Set<String> satisfyPermissionDependencies(String... permissions) {
    Set<String> permissionList = new LinkedHashSet<>(Arrays.asList(permissions));
    // Explicitly grant READ_EXTERNAL_STORAGE permission when WRITE_EXTERNAL_STORAGE was requested.
    if (permissionList.contains(permission.WRITE_EXTERNAL_STORAGE)) {
      permissionList.add(permission.READ_EXTERNAL_STORAGE);
    }
    return permissionList;
  }

  @Override
  public final Statement apply(final Statement base, Description description) {
    return new RequestPermissionStatement(base);
  }

  private void setPermissionGranter(PermissionGranter permissionGranter) {
    this.permissionGranter = checkNotNull(permissionGranter, "permissionRequester cannot be null!");
  }

  private class RequestPermissionStatement extends Statement {

    private final Statement base;

    public RequestPermissionStatement(Statement base) {
      this.base = base;
    }

    @Override
    public void evaluate() throws Throwable {
      permissionGranter.requestPermissions();
      base.evaluate();
    }
  }
}