android GrantPermissionsActivity 详解
16lz
2021-01-23
存在的意义:
在Android 6.0之后(SDK >22)对于Runtime Permission严格控制,在第三方应用打开Runtime permission
的时候系统需要提醒用户,一般的情况下,Runtime permission 默认的权限是denied 的,应用需要获取应用就必要申请,在request 的时候会弹出一个跟用户交互的提示框,而这些就是GrantPermissionActivity 存在的意义。
下面来看下GrantPermissionsActivity 注册的信息:
先来看此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 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 详解。更多相关文章
- Android简明开发教程六:用户界面设计
- 2011.06.07(2)——— android 调试android源码包下的package应用的
- 【30篇突击 android】源码统计 十八
- Android消息处理机制——AsyncTask 源码解析
- 【实习周记】Android getevent.c源码分析
- 超级清爽android计算器界面源码