showNextPermissionGroupGrantRequest负责在将app需要申请的权限分组后,将每个授权分组以一个对话框的形式向用户申请。如图所示:

授权界面总共由五个按钮,由具体情况决定显示那一部分:“允许”,“总是允许”,“仅在使用此应用允许”,“拒绝”,“拒绝,不要再询问”。
显示界面的规则如下:
1.如果当前的GroupState里面有一个权限拥有对应的后台权限(无论app是否声明这个对应的后台权限),则会用“仅在使用此应用允许”按钮取代“允许”按钮;进一步说,如果当前的GroupState带有一个后台AppPermissionGroup或者带有一个拥有后台AppPermissionGroup的前台AppPermissionGroup(参考“前后台权限的AppPermissionGroup”一节),且后台AppPermissionGroup的权限还没被授权,则显示“总是允许”按钮。如果应用申请了ACCESS_COARSE_LOCATION前台权限,但是没有申请ACCESS_BACKGROUND_LOCATION后台权限,这样是不会有“总是允许”按钮的,因为前台AppPermissionGroup没有拥有一个后台AppPermissionGroup。换句话说,“允许”按钮适用于没有前后台区分的运行时权限,“仅在使用此应用允许”是仅仅授予了前台权限,“总是允许”是同时授予了前后台权限。
2.如果当前的GroupState的权限曾被拒绝了,第二次显示对话框时,则会显示“允许”(非前后台区分台权限被拒绝)/“仅在使用此应用允许”(前台权限被拒绝),“拒绝”,“拒绝,不要再询问”三个按钮。
packages/apps/PermissionController/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
private boolean showNextPermissionGroupGrantRequest() {
int numGroupStates = mRequestGrantPermissionGroups.size();
int numGrantRequests = 0;
for (int i = 0; i < numGroupStates; i++) {
if (shouldShowRequestForGroupState(mRequestGrantPermissionGroups.valueAt(i))) {
numGrantRequests++;
int currentIndex = 0;
for (GroupState groupState : mRequestGrantPermissionGroups.values()) {
if (!shouldShowRequestForGroupState(groupState)) {
continue;
if (groupState.mState == GroupState.STATE_UNKNOWN) {
GroupState foregroundGroupState;
GroupState backgroundGroupState;
if (groupState.mGroup.isBackgroundGroup()) {
backgroundGroupState = groupState;
foregroundGroupState = getForegroundGroupState(groupState.mGroup.getName());
} else {
foregroundGroupState = groupState;
backgroundGroupState = getBackgroundGroupState(groupState.mGroup.getName());
CharSequence appLabel = mAppPermissions.getAppLabel();
Icon icon;
try {
icon = Icon.createWithResource(groupState.mGroup.getIconPkg(),
groupState.mGroup.getIconResId());
} catch (Resources.NotFoundException e) {
Log.e(LOG_TAG, "Cannot load icon for group" + groupState.mGroup.getName(), e);
icon = null;
// If no background permissions are granted yet, we need to ask for background
// permissions
boolean needBackgroundPermission = false;
boolean isBackgroundPermissionUserSet = false;
if (backgroundGroupState != null) {
if (!backgroundGroupState.mGroup.areRuntimePermissionsGranted()) {
needBackgroundPermission = true;
isBackgroundPermissionUserSet = backgroundGroupState.mGroup.isUserSet();
// If no foreground permissions are granted yet, we need to ask for foreground
// permissions
boolean needForegroundPermission = false;
boolean isForegroundPermissionUserSet = false;
if (foregroundGroupState != null) {
if (!foregroundGroupState.mGroup.areRuntimePermissionsGranted()) {
needForegroundPermission = true;
isForegroundPermissionUserSet = foregroundGroupState.mGroup.isUserSet();
// The button doesn't show when its label is null
mButtonLabels = new CharSequence[NUM_BUTTONS];
mButtonLabels[LABEL_ALLOW_BUTTON] = getString(R.string.grant_dialog_button_allow);
mButtonLabels[LABEL_ALLOW_ALWAYS_BUTTON] = null;
mButtonLabels[LABEL_ALLOW_FOREGROUND_BUTTON] = null;
mButtonLabels[LABEL_DENY_BUTTON] = getString(R.string.grant_dialog_button_deny);
if (isForegroundPermissionUserSet || isBackgroundPermissionUserSet) {
mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] =
getString(R.string.grant_dialog_button_deny_and_dont_ask_again);
} else {
mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] = null;
int messageId;
int detailMessageId = 0;
if (needForegroundPermission) {
messageId = groupState.mGroup.getRequest();
if (groupState.mGroup.hasPermissionWithBackgroundMode()) {
mButtonLabels[LABEL_ALLOW_BUTTON] = null;
mButtonLabels[LABEL_ALLOW_FOREGROUND_BUTTON] =
getString(R.string.grant_dialog_button_allow_foreground);
if (needBackgroundPermission) {
mButtonLabels[LABEL_ALLOW_ALWAYS_BUTTON] =
getString(R.string.grant_dialog_button_allow_always);
if (isForegroundPermissionUserSet || isBackgroundPermissionUserSet) {
mButtonLabels[LABEL_DENY_BUTTON] = null;
} else {
detailMessageId = groupState.mGroup.getRequestDetail();
} else {
if (needBackgroundPermission) {
messageId = groupState.mGroup.getBackgroundRequest();
detailMessageId = groupState.mGroup.getBackgroundRequestDetail();
mButtonLabels[LABEL_ALLOW_BUTTON] =
getString(R.string.grant_dialog_button_allow_background);
mButtonLabels[LABEL_DENY_BUTTON] =
getString(R.string.grant_dialog_button_deny_background);
mButtonLabels[LABEL_DENY_AND_DONT_ASK_AGAIN_BUTTON] =
getString(R.string
.grant_dialog_button_deny_background_and_dont_ask_again);
} else {
// Not reached as the permissions should be auto-granted
return false;
CharSequence message = getRequestMessage(appLabel, groupState.mGroup, this,
messageId);
Spanned detailMessage = null;
if (detailMessageId != 0) {
try {
detailMessage = Html.fromHtml(
getPackageManager().getResourcesForApplication(
groupState.mGroup.getDeclaringPackage()).getString(
detailMessageId), 0);
} catch (NameNotFoundException ignored) {
// Set the permission message as the title so it can be announced.
setTitle(message);
mViewHandler.updateUi(groupState.mGroup.getName(), numGrantRequests, currentIndex,
icon, message, detailMessage, mButtonLabels);
return true;
if (groupState.mState != GroupState.STATE_SKIPPED) {
currentIndex++;
return false;
private void openApp(String packageName) {
PackageManager pm = getPackageManager();
PackageInfo pi = null;
try {
pi = pm.getPackageInfo(packageName, 0);
} catch (NameNotFound
申请前提,manifest一定要有,没有是不会通过的。
动态申请代码:
public final void requestPermissions(@NonNull String[] permissions, int requestCode)
启动一个供用户选择的授权界面:
final Intent intent = getPackageManager().buildRequestPermissionsIntent(permis
private String[] requestPermissions = new String[]{
Manifest.permission.INTERNET,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.RECORD_AUDIO
* 申请权限
private void re...
这句话,没有的话再顶部加上;
2、添加依赖
implementation "org.permissionsdispatcher:permissionsdispatcher:4.5.0"
kapt "org.permissionsdispatch
纯纯纯小白学习记录
在之前的Android版本中,开发者只需要在AndroidMainfest.xml中声明即可,
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tinno.actioncalldemo">
<uses-permission android:name="android.permission.CALL_PHONE"/>
.....
以打电话为例子
首先在AndroidManifest.xml文件中声明如下权限:
<uses-permission android:name="android.permission.CALL_PHONE" />
然后运行时申请权限
public class RuntimePermissionTest extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState)