android GrantPermissionsActivity 详解

存在的意义:

在Android 6.0之后(SDK >22)对于Runtime Permission严格控制,在第三方应用打开Runtime permission

的时候系统需要提醒用户,一般的情况下,Runtime permission 默认的权限是denied 的,应用需要获取应用就必要申请,在request 的时候会弹出一个跟用户交互的提示框,而这些就是GrantPermissionActivity 存在的意义。

下面来看下GrantPermissionsActivity 注册的信息:

        <activity android:name=".permission.ui.GrantPermissionsActivity"
                android:configChanges="orientation|keyboardHidden|screenSize"
                android:excludeFromRecents="true"
                android:theme="@style/GrantPermissions"
                android:visibleToInstantApps="true">
            <intent-filter android:priority="1">
                <action android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
先来看此Activity 注册的地方,在action 为android.content.pm.action.REQUEST_PERMISSIONS的时候触发。
再来看Activity.java 中的 requestPermissions:
 public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (requestCode < 0) { //requestCode 必须为正数
            throw new IllegalArgumentException("requestCode should be >= 0");
        }
        if (mHasCurrentPermissionsRequest) {
            Log.w(TAG, "Can reqeust only one set of permissions at a time");
            // Dispatch the callback with empty arrays which means a cancellation.
            onRequestPermissionsResult(requestCode, new String[0], new int[0]);
            return;
        }
        Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
        startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
        mHasCurrentPermissionsRequest = true;
    }
其中buildRequestPermissionsIntent 用来创建所需的intent:
    public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
        if (ArrayUtils.isEmpty(permissions)) {
           throw new IllegalArgumentException("permission cannot be null or empty");
        }
        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
        intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
        intent.setPackage(getPermissionControllerPackageName());
        return intent;
    }
首先传的action 就是GrantPermissionsActivity 所需要的action,这个intent 还将需要request 的permissions 带入,最关键的是指定了intent 所指向的package 为PackageInstaller。
 
到此,我们知道GrantPermissionsActivity 存在是为了处理requestPermissions。
 

分析源码:

详细的源码可以看:packages/apps/PackageInstaller/src/com/android/packageinstaller/permission/ui/GrantPermissionsActivity.java
主要偏向于UI 逻辑的控制,在这里主要总计几个重要部分:

1、mRequestedPermissions

这个是通过intent 的extra 传过来的,extra 的name 是PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES
        mRequestedPermissions = getIntent().getStringArrayExtra(
                PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);

2、GrantPermissionsViewHandlerImpl

这个是用来更新activity UI的重要类
    mViewHandler = new com.android.packageinstaller.permission.ui.handheld
            .GrantPermissionsViewHandlerImpl(this, getCallingPackage())
            .setResultListener(this);

3、setContentView(mViewHandler.createView());

acitivity 将GrantPermissionsViewHandlerImpl 中的createView 出来的View 显示出来。

4、mAppPermissions

            mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false,
                new Runnable() {
                    @Override
                    public void run() {
                        setResultAndFinish();
                    }
                });
这个AppPermissions 其实就是单个应用所拥有的所有的group permission 的统计,详细看
private final ArrayList<AppPermissionGroup> mGroups = new ArrayList<>();

5、showNextPermissionGroupGrantRequest

读取request 的group 相关信息,通过mViewHandler.updateUi 来更新UI。
	mViewHandler.updateUi(groupState.mGroup.getName(), groupCount, currentIndex,
			Icon.createWithResource(resources, icon), message,
			groupState.mGroup.isUserSet());

6、onClick

    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.permission_allow_button:
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName, true, false);
                }
                break;
            case R.id.permission_deny_button:
                mAllowButton.setEnabled(true);
                if (mResultListener != null) {
                    view.performAccessibilityAction(
                            AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
                    mResultListener.onPermissionGrantResult(mGroupName, false,
                            AppPermissionGroup.isStrictOpEnable() ? false : mShowDonNotAsk
                                    && mDoNotAskCheckbox.isChecked());
                }
                break;
            case R.id.permission_more_info_button:
                Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS);
                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppPackageName);
                intent.putExtra(ManagePermissionsActivity.EXTRA_ALL_PERMISSIONS, true);
                mActivity.startActivity(intent);
                break;
            case R.id.do_not_ask_checkbox:
                mAllowButton.setEnabled(!mDoNotAskCheckbox.isChecked());
                break;
        }
    }
提示框的click 事件是在GrantPermissionsViewHandlerImpl 这里处理的,最后会通过callback 调回到GrantPermissionsActivity 中。

7、onPermissionGrantResult

    public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) {
        GroupState groupState = mRequestGrantPermissionGroups.get(name);
        if (groupState.mGroup != null) {
            if (granted) {
                groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
                        groupState.affectedPermissions);
                groupState.mState = GroupState.STATE_ALLOWED;
            } else {
                if (!AppPermissionGroup.isStrictOpEnable()) {
                    groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
                            groupState.affectedPermissions);
                }
                groupState.mState = GroupState.STATE_DENIED;

                int numRequestedPermissions = mRequestedPermissions.length;
                for (int i = 0; i < numRequestedPermissions; i++) {
                    String permission = mRequestedPermissions[i];

                    if (groupState.mGroup.hasPermission(permission)) {
                        EventLogger.logPermissionDenied(this, permission,
                                mAppPermissions.getPackageInfo().packageName);
                    }
                }
            }
            updateGrantResults(groupState.mGroup);
        }
        if (!showNextPermissionGroupGrantRequest()) {
            setResultAndFinish();
        }
    }
这里的callback 是从GrantPermissionsViewHandlerImpl 回来,确定执行grant 还是revoke。

 

总结:

其实核心思想就是想通过request 的时候跟用户进行交互,弹出一个提示框。CTA也是这样要求的,存在一个疑问就是,如果第三方应用直接调用check permission 之后grant permission,而不通过request 怎么办,那这样可能就没有交互了。详细可以看下 android grantRuntimePermission 详解
 
 
 

 
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值