refusedListAfterRequest = new LinkedList<>();
412 | for (Permission requestResult : permissions) {
413 | if (!requestResult.isGranted()) {
414 | refusedListAfterRequest.add(requestResult);
415 | }
416 | }
417 | if (refusedListAfterRequest.size() == 0) {
418 | PermissionDebug.d(TAG, "all permission are request ok");
419 | listener.onAllPermissionOk(permissionsToRequest);
420 | } else {
421 | PermissionDebug.d(TAG, "some permission are refused size=" + refusedListAfterRequest.size());
422 | listener.onPermissionDenied(PermissionTools.convert(refusedListAfterRequest));
423 | }
424 | }
425 | });
426 | }
427 |
428 | private void requestSpecialPermission(final Special specialPermission, final SpecialPermissionListener listener) {
429 | checkStatusBeforeDoSomething(new CheckStatusCallBack() {
430 | @Override
431 | public void onStatusOk(Activity activity) {
432 | new PermissionRequester(activity)
433 | .withPermission(specialPermission)
434 | .request(listener);
435 | }
436 | });
437 |
438 | }
439 |
440 | }
441 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/adapter/SimplePermissionAdapter.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.adapter;
2 |
3 | import com.qw.soul.permission.bean.Permission;
4 | import com.qw.soul.permission.callbcak.CheckRequestPermissionListener;
5 |
6 |
7 | /**
8 | * @author cd5160866
9 | */
10 | public abstract class SimplePermissionAdapter implements CheckRequestPermissionListener {
11 |
12 | @Override
13 | public void onPermissionOk(Permission permission) {
14 |
15 | }
16 |
17 | @Override
18 | public void onPermissionDenied(Permission permission) {
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/adapter/SimplePermissionsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.adapter;
2 |
3 | import com.qw.soul.permission.bean.Permission;
4 | import com.qw.soul.permission.callbcak.CheckRequestPermissionsListener;
5 |
6 |
7 | /**
8 | * @author cd5160866
9 | */
10 | public abstract class SimplePermissionsAdapter implements CheckRequestPermissionsListener {
11 | @Override
12 | public void onAllPermissionOk(Permission[] allPermissions) {
13 |
14 | }
15 |
16 | @Override
17 | public void onPermissionDenied(Permission[] refusedPermissions) {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/adapter/SimpleSpecialPermissionAdapter.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.adapter;
2 |
3 | import com.qw.soul.permission.bean.Special;
4 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public abstract class SimpleSpecialPermissionAdapter implements SpecialPermissionListener {
10 |
11 | @Override
12 | public void onDenied(Special permission) {
13 |
14 | }
15 |
16 | @Override
17 | public void onGranted(Special permission) {
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/bean/Permission.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.bean;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import androidx.annotation.NonNull;
7 | import com.qw.soul.R;
8 | import com.qw.soul.permission.SoulPermission;
9 | import com.qw.soul.permission.debug.PermissionDebug;
10 |
11 | /**
12 | * @author cd5160866
13 | */
14 | public class Permission {
15 |
16 | private static final String TAG = Permission.class.getSimpleName();
17 |
18 | private static final int FLAG_IS_GRANTED = 1;
19 |
20 | private static final int FLAG_SHOULD_RATIONALE = 1 << 1;
21 |
22 | private int mFlags = 0;
23 | /**
24 | * 权限名称
25 | */
26 | public String permissionName;
27 |
28 | /**
29 | * 根据名称构建一个默认权限对象,默认失败
30 | *
31 | * @param permissionName 权限名称
32 | */
33 | public static Permission getDefault(@NonNull String permissionName) {
34 | return new Permission(permissionName, PackageManager.PERMISSION_DENIED, false);
35 | }
36 |
37 | /**
38 | * 根据名称构建一个默认成功的权限对象
39 | *
40 | * @param permissionName 权限名称
41 | */
42 | public static Permission getDefaultSuccess(@NonNull String permissionName) {
43 | return new Permission(permissionName, PackageManager.PERMISSION_GRANTED, false);
44 | }
45 |
46 | public Permission(String permissionName, int isGranted, boolean shouldRationale) {
47 | this.permissionName = permissionName;
48 | if (isGranted == PackageManager.PERMISSION_GRANTED) {
49 | mFlags |= FLAG_IS_GRANTED;
50 | }
51 | if (shouldRationale) {
52 | mFlags |= FLAG_SHOULD_RATIONALE;
53 | }
54 | }
55 |
56 | /**
57 | * @return 是否已经授予
58 | */
59 | public boolean isGranted() {
60 | return (mFlags & FLAG_IS_GRANTED) != 0;
61 | }
62 |
63 | /**
64 | * @return 是否需要给用户一个解释
65 | */
66 | public boolean shouldRationale() {
67 | return (mFlags & FLAG_SHOULD_RATIONALE) != 0;
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return permissionName + " isGranted: " + isGranted() + " shouldRationale " + shouldRationale();
73 | }
74 |
75 |
76 | public String getPermissionLabel() {
77 | Context context = SoulPermission.getInstance().getContext();
78 | if (null == context) {
79 | PermissionDebug.e(TAG, "soul permission do not init");
80 | return "";
81 | }
82 | PackageManager manager = context.getPackageManager();
83 | try {
84 | return manager.getPermissionInfo(permissionName, 0).loadLabel(manager).toString();
85 | } catch (PackageManager.NameNotFoundException e) {
86 | return "";
87 | }
88 | }
89 |
90 | /**
91 | * 获取权限名称描述
92 | * use getPermissionLabel instead
93 | *
94 | * @return desc of permission
95 | * @see #getPermissionLabel
96 | */
97 | @Deprecated
98 | public String getPermissionNameDesc() {
99 | Context context = SoulPermission.getInstance().getContext();
100 | if (null == context) {
101 | PermissionDebug.e(TAG, "soul permission do not init");
102 | return "";
103 | }
104 | String desc;
105 | switch (permissionName) {
106 | case Manifest.permission_group.CAMERA:
107 | case Manifest.permission.CAMERA:
108 | desc = context.getResources().getString(R.string.permission_camera);
109 | break;
110 | case Manifest.permission_group.CONTACTS:
111 | case Manifest.permission.READ_CONTACTS:
112 | case Manifest.permission.WRITE_CONTACTS:
113 | case Manifest.permission.GET_ACCOUNTS:
114 | desc = context.getResources().getString(R.string.permission_contact);
115 | break;
116 | case Manifest.permission_group.PHONE:
117 | case Manifest.permission.CALL_PHONE:
118 | case Manifest.permission.READ_CALL_LOG:
119 | case Manifest.permission.WRITE_CALL_LOG:
120 | case Manifest.permission.ADD_VOICEMAIL:
121 | case Manifest.permission.USE_SIP:
122 | case Manifest.permission.PROCESS_OUTGOING_CALLS:
123 | desc = context.getResources().getString(R.string.permission_call);
124 | break;
125 | case Manifest.permission_group.STORAGE:
126 | case Manifest.permission.WRITE_EXTERNAL_STORAGE:
127 | case Manifest.permission.READ_EXTERNAL_STORAGE:
128 | desc = context.getResources().getString(R.string.permission_storage);
129 | break;
130 | case Manifest.permission_group.LOCATION:
131 | case Manifest.permission.ACCESS_FINE_LOCATION:
132 | case Manifest.permission.ACCESS_COARSE_LOCATION:
133 | desc = context.getResources().getString(R.string.permission_location);
134 | break;
135 | case Manifest.permission.READ_PHONE_STATE:
136 | desc = context.getResources().getString(R.string.permission_phone_status);
137 | break;
138 | case Manifest.permission_group.CALENDAR:
139 | case Manifest.permission.READ_CALENDAR:
140 | case Manifest.permission.WRITE_CALENDAR:
141 | desc = context.getResources().getString(R.string.permission_calender);
142 | break;
143 | case Manifest.permission_group.MICROPHONE:
144 | case Manifest.permission.RECORD_AUDIO:
145 | desc = context.getResources().getString(R.string.permission_microphone);
146 | break;
147 | case Manifest.permission_group.SENSORS:
148 | case Manifest.permission.BODY_SENSORS:
149 | desc = context.getResources().getString(R.string.permission_sensor);
150 | break;
151 | case Manifest.permission_group.SMS:
152 | case Manifest.permission.SEND_SMS:
153 | case Manifest.permission.RECEIVE_SMS:
154 | case Manifest.permission.READ_SMS:
155 | case Manifest.permission.RECEIVE_WAP_PUSH:
156 | case Manifest.permission.RECEIVE_MMS:
157 | desc = context.getResources().getString(R.string.permission_sms);
158 | break;
159 | default:
160 | desc = context.getResources().getString(R.string.permission_undefined);
161 | break;
162 | }
163 | return desc;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/bean/Permissions.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.bean;
2 |
3 | /**
4 | * 这个类只为了参数清晰..
5 | *
6 | * @author cd5160866
7 | */
8 | public class Permissions {
9 |
10 | private Permission[] permissions;
11 |
12 | public static Permissions build(String... permissions) {
13 | return new Permissions(permissions);
14 | }
15 |
16 | public static Permissions build(Permission... permissions) {
17 | return new Permissions(permissions);
18 | }
19 |
20 | private Permissions() {
21 | }
22 |
23 | private Permissions(String[] permissions) {
24 | this.permissions = new Permission[permissions.length];
25 | for (int i = 0; i < permissions.length; i++) {
26 | this.permissions[i] = Permission.getDefault(permissions[i]);
27 | }
28 | }
29 |
30 | private Permissions(Permission[] permissions) {
31 | this.permissions = permissions;
32 | }
33 |
34 | public Permission[] getPermissions() {
35 | return permissions;
36 | }
37 |
38 | public String[] getPermissionsString() {
39 | String[] result = new String[permissions.length];
40 | for (int i = 0; i < permissions.length; i++) {
41 | result[i] = permissions[i].permissionName;
42 | }
43 | return result;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/bean/Special.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.bean;
2 |
3 | /**
4 | * @author cd5160866
5 | */
6 | public enum Special {
7 | /**
8 | * 通知权限
9 | */
10 | NOTIFICATION,
11 |
12 | /**
13 | * 系统弹框
14 | */
15 | SYSTEM_ALERT,
16 |
17 | /**
18 | * 允许安装未知权限
19 | */
20 | UNKNOWN_APP_SOURCES,
21 |
22 | /**
23 | * 修改系统设置
24 | */
25 | WRITE_SETTINGS
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/CheckRequestPermissionListener.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 |
4 | import com.qw.soul.permission.bean.Permission;
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public interface CheckRequestPermissionListener {
10 |
11 | /**
12 | * 权限ok,可做后续的事情
13 | *
14 | * @param permission 权限实体类
15 | */
16 | void onPermissionOk(Permission permission);
17 |
18 | /**
19 | * 权限不ok,被拒绝或者未授予
20 | *
21 | * @param permission 权限实体类
22 | */
23 | void onPermissionDenied(Permission permission);
24 | }
25 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/CheckRequestPermissionsListener.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 |
4 | import com.qw.soul.permission.bean.Permission;
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public interface CheckRequestPermissionsListener {
10 |
11 | /**
12 | * 所有权限ok,可做后续的事情
13 | *
14 | * @param allPermissions 权限实体类
15 | */
16 | void onAllPermissionOk(Permission[] allPermissions);
17 |
18 | /**
19 | * 不ok的权限,被拒绝或者未授予
20 | *
21 | * @param refusedPermissions 权限实体类
22 | */
23 | void onPermissionDenied(Permission[] refusedPermissions);
24 | }
25 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/CheckStatusCallBack.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 | import android.app.Activity;
4 |
5 | /**
6 | * @author cd5160866
7 | */
8 | public interface CheckStatusCallBack {
9 |
10 | /**
11 | * 状态OK
12 | *
13 | * @param activity 状态可用的回调
14 | */
15 | void onStatusOk(Activity activity);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/GoAppDetailCallBack.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 | import android.content.Intent;
4 |
5 | public interface GoAppDetailCallBack {
6 |
7 | /**
8 | * 从App详情页回来
9 | *
10 | * @param data from onActivityResult
11 | */
12 | void onBackFromAppDetail(Intent data);
13 | }
14 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/RequestPermissionListener.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 |
4 | import com.qw.soul.permission.bean.Permission;
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public interface RequestPermissionListener {
10 |
11 | /**
12 | * 得到权限检查结果
13 | *
14 | * @param permissions 封装权限的数组
15 | */
16 | void onPermissionResult(Permission[] permissions);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/callbcak/SpecialPermissionListener.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.callbcak;
2 |
3 |
4 | import com.qw.soul.permission.bean.Special;
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public interface SpecialPermissionListener {
10 |
11 | /**
12 | * 权限ok,可做后续的事情
13 | *
14 | * @param permission 权限实体类
15 | * {@link com.qw.soul.permission.bean.Special }
16 | */
17 | void onGranted(Special permission);
18 |
19 | /**
20 | * 权限不ok,被拒绝或者未授予
21 | *
22 | * @param permission 权限实体类
23 | */
24 | void onDenied(Special permission);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/checker/AppOpsChecker.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.checker;
2 |
3 | import android.Manifest;
4 | import android.app.AppOpsManager;
5 | import android.content.Context;
6 | import android.os.Binder;
7 | import android.os.Build;
8 | import com.qw.soul.permission.debug.PermissionDebug;
9 | import com.qw.soul.permission.request.PermissionConfig;
10 |
11 | import java.lang.reflect.Method;
12 |
13 | import static android.os.Build.VERSION_CODES.KITKAT;
14 |
15 | /**
16 | * @author cd5160866
17 | */
18 | class AppOpsChecker implements PermissionChecker {
19 |
20 | private static final String TAG = AppOpsChecker.class.getSimpleName();
21 |
22 | private Context context;
23 |
24 | private String permission;
25 |
26 | AppOpsChecker(Context context) {
27 | this(context, null);
28 | }
29 |
30 | AppOpsChecker(Context context, String permission) {
31 | this.context = context;
32 | this.permission = permission;
33 | }
34 |
35 | /**
36 | * 老的通過反射方式檢查權限狀態
37 | * 结果可能不准确,如果返回false一定未授予
38 | * 按需在里面添加
39 | *
40 | * 如果没匹配上或者异常都默认权限授予
41 | *
42 | * @return 检查结果
43 | */
44 |
45 | @Override
46 | public boolean check() {
47 | if (null == permission) {
48 | return true;
49 | }
50 | if (PermissionConfig.skipOldRom) {
51 | return true;
52 | }
53 | switch (permission) {
54 | case Manifest.permission.READ_CONTACTS:
55 | return checkOp(4);
56 | case Manifest.permission.WRITE_CONTACTS:
57 | return checkOp(5);
58 | case Manifest.permission.CALL_PHONE:
59 | return checkOp(13);
60 | case Manifest.permission.READ_PHONE_STATE:
61 | return checkOp(51);
62 | case Manifest.permission.CAMERA:
63 | return checkOp(26);
64 | case Manifest.permission.READ_EXTERNAL_STORAGE:
65 | return checkOp(59);
66 | case Manifest.permission.WRITE_EXTERNAL_STORAGE:
67 | return checkOp(60);
68 | case Manifest.permission.ACCESS_FINE_LOCATION:
69 | return checkOp(1);
70 | case Manifest.permission.ACCESS_COARSE_LOCATION:
71 | return checkOp(0);
72 | case Manifest.permission.RECORD_AUDIO:
73 | return checkOp(27);
74 | case Manifest.permission.BODY_SENSORS:
75 | return checkOp(56);
76 | case Manifest.permission.READ_CALENDAR:
77 | return checkOp(8);
78 | case Manifest.permission.WRITE_CALENDAR:
79 | return checkOp(9);
80 | case Manifest.permission.SEND_SMS:
81 | return checkOp(20);
82 | case Manifest.permission.READ_SMS:
83 | return checkOp(14);
84 | case Manifest.permission.RECEIVE_SMS:
85 | return checkOp(16);
86 | default:
87 | break;
88 | }
89 | return true;
90 | }
91 |
92 | /**
93 | * check by reflect
94 | */
95 | boolean checkOp(int op) {
96 | if (Build.VERSION.SDK_INT < KITKAT) {
97 | PermissionDebug.d(TAG, "4.4 below");
98 | return true;
99 | }
100 | try {
101 | AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
102 | Method method = AppOpsManager.class.getDeclaredMethod("checkOp", int.class, int.class, String.class);
103 | return 0 == (int) method.invoke(manager, op, Binder.getCallingUid(), context.getPackageName());
104 | } catch (Exception e) {
105 | PermissionDebug.w(TAG, e.toString());
106 | e.printStackTrace();
107 | }
108 | return true;
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/checker/CheckerFactory.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.checker;
2 |
3 | import android.content.Context;
4 | import com.qw.soul.permission.PermissionTools;
5 | import com.qw.soul.permission.bean.Special;
6 |
7 | /**
8 | * @author cd5160866
9 | */
10 | public class CheckerFactory {
11 |
12 | public static PermissionChecker create(Context context, Special permission) {
13 | return new SpecialChecker(context, permission);
14 | }
15 |
16 | public static PermissionChecker create(Context context, String permission) {
17 | if (PermissionTools.isOldPermissionSystem(context)) {
18 | return new AppOpsChecker(context, permission);
19 | } else {
20 | return new RunTimePermissionChecker(context, permission);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/checker/PermissionChecker.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.checker;
2 |
3 | /**
4 | * @author cd5160866
5 | */
6 | public interface PermissionChecker {
7 |
8 | /**
9 | * 检查权限
10 | *
11 | * @return 检查结果
12 | */
13 | boolean check();
14 | }
15 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/checker/RunTimePermissionChecker.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.checker;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import androidx.core.content.ContextCompat;
7 |
8 | import static android.os.Build.VERSION_CODES.M;
9 |
10 | /**
11 | * @author cd5160866
12 | */
13 | class RunTimePermissionChecker implements PermissionChecker {
14 |
15 | private String permission;
16 |
17 | private Context context;
18 |
19 | RunTimePermissionChecker(Context context, String permission) {
20 | this.permission = permission;
21 | this.context = context;
22 | }
23 |
24 | @TargetApi(M)
25 | @Override
26 | public boolean check() {
27 | int checkResult = ContextCompat.checkSelfPermission(context, permission);
28 | return checkResult == PackageManager.PERMISSION_GRANTED;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/checker/SpecialChecker.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.checker;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.provider.Settings;
6 | import androidx.core.app.NotificationManagerCompat;
7 | import com.qw.soul.permission.bean.Special;
8 | import com.qw.soul.permission.debug.PermissionDebug;
9 |
10 | import static android.os.Build.VERSION_CODES.M;
11 | import static android.os.Build.VERSION_CODES.O;
12 |
13 | /**
14 | * @author cd5160866
15 | */
16 | public class SpecialChecker implements PermissionChecker {
17 |
18 | private static final String TAG = SpecialChecker.class.getSimpleName();
19 |
20 | private Context context;
21 |
22 | private Special permission;
23 |
24 | public SpecialChecker(Context context, Special permission) {
25 | this.context = context;
26 | this.permission = permission;
27 | }
28 |
29 | @Override
30 | public boolean check() {
31 | try {
32 | switch (permission) {
33 | case NOTIFICATION:
34 | return checkNotification();
35 | case SYSTEM_ALERT:
36 | return checkSystemAlert();
37 | case UNKNOWN_APP_SOURCES:
38 | return checkUnknownSource();
39 | case WRITE_SETTINGS:
40 | return checkWriteSystemSettings();
41 | default:
42 | return true;
43 | }
44 | } catch (Exception e) {
45 | PermissionDebug.w(TAG, e.toString());
46 | }
47 | return true;
48 | }
49 |
50 | private boolean checkNotification() {
51 | return NotificationManagerCompat.from(context).areNotificationsEnabled();
52 | }
53 |
54 | private boolean checkSystemAlert() {
55 | if (Build.VERSION.SDK_INT >= M) {
56 | return Settings.canDrawOverlays(context);
57 | }
58 | return new AppOpsChecker(context).checkOp(24);
59 | }
60 |
61 | private boolean checkUnknownSource() {
62 | if (Build.VERSION.SDK_INT >= O) {
63 | return context.getPackageManager().canRequestPackageInstalls();
64 | }
65 | return true;
66 | }
67 |
68 | private boolean checkWriteSystemSettings() {
69 | if (Build.VERSION.SDK_INT >= M) {
70 | return Settings.System.canWrite(context);
71 | }
72 | return true;
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/debug/PermissionDebug.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.debug;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * @author cd5160866
7 | */
8 | public class PermissionDebug {
9 |
10 | private static boolean isDebug = false;
11 |
12 | public static void setDebug(boolean isDebug) {
13 | PermissionDebug.isDebug = isDebug;
14 | }
15 |
16 | public static boolean isDebug() {
17 | return isDebug;
18 | }
19 |
20 | public static void d(String tag, String msg) {
21 | if (isDebug) {
22 | Log.d(tag, msg);
23 | }
24 | }
25 |
26 | public static void w(String tag, String msg) {
27 | if (isDebug) {
28 | Log.w(tag, msg);
29 | }
30 | }
31 |
32 | public static void e(String tag, String msg) {
33 | if (isDebug) {
34 | Log.e(tag, msg);
35 | }
36 | }
37 |
38 | public static void v(String tag, String msg) {
39 | if (isDebug) {
40 | Log.v(tag, msg);
41 | }
42 | }
43 |
44 | public static void i(String tag, String msg) {
45 | if (isDebug) {
46 | Log.i(tag, msg);
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/exception/ContainerStatusException.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.exception;
2 |
3 | /**
4 | * @author cd5160866
5 | */
6 | public class ContainerStatusException extends IllegalStateException {
7 |
8 | public ContainerStatusException() {
9 | super(" activity did not existence, check your app status before use soulPermission");
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/exception/InitException.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.exception;
2 |
3 | import java.lang.IllegalStateException;
4 |
5 |
6 | /**
7 | * @author cd5160866
8 | */
9 | public class InitException extends IllegalStateException {
10 |
11 | public InitException() {
12 | super("auto init failed ,you need invoke SoulPermission.init() in your application");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/IPermissionActions.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request;
2 |
3 | import android.annotation.TargetApi;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.Nullable;
7 | import com.qw.soul.permission.bean.Special;
8 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack;
9 | import com.qw.soul.permission.callbcak.RequestPermissionListener;
10 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
11 |
12 | import static android.os.Build.VERSION_CODES.M;
13 |
14 | /**
15 | * @author cd5160866
16 | */
17 | public interface IPermissionActions {
18 |
19 | /**
20 | * 请求权限
21 | *
22 | * @param permissions 权限
23 | * @param listener 回调
24 | */
25 | @TargetApi(M)
26 | void requestPermissions(String[] permissions, RequestPermissionListener listener);
27 |
28 |
29 | /**
30 | * 请求特殊权限
31 | *
32 | * @param permission 特殊权限
33 | * @param listener 回调
34 | */
35 | void requestSpecialPermission(Special permission, SpecialPermissionListener listener);
36 |
37 | /**
38 | * 去应用详情页
39 | *
40 | * @param callBack 回调
41 | */
42 | void goAppDetail(@Nullable GoAppDetailCallBack callBack);
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/PermissionConfig.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request;
2 |
3 | /**
4 | * @author cd5160866
5 | */
6 | public class PermissionConfig {
7 |
8 | /**
9 | * 是否跳过老的rom的权限检查 ,即老的rom默认直接返回ture 而不是appOpps反射检查后的结果
10 | */
11 | public static boolean skipOldRom = false;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/PermissionFragmentFactory.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request;
2 |
3 | import android.app.Activity;
4 | import android.app.Fragment;
5 | import android.os.Build;
6 | import androidx.fragment.app.FragmentActivity;
7 | import androidx.fragment.app.FragmentManager;
8 |
9 | import com.qw.soul.permission.debug.PermissionDebug;
10 | import com.qw.soul.permission.request.fragment.PermissionFragment;
11 | import com.qw.soul.permission.request.fragment.PermissionSupportFragment;
12 |
13 | import java.lang.reflect.Field;
14 | import java.util.List;
15 |
16 |
17 | /**
18 | * @author cd5160866
19 | */
20 | class PermissionFragmentFactory {
21 |
22 | private static final String TAG = PermissionFragmentFactory.class.getSimpleName();
23 |
24 | private static final String FRAGMENT_TAG = "permission_fragment_tag";
25 |
26 | static IPermissionActions create(Activity activity) {
27 | IPermissionActions action;
28 | if (activity instanceof FragmentActivity) {
29 | FragmentManager supportFragmentManager = getSupportFragmentManager((FragmentActivity) activity);
30 | PermissionSupportFragment permissionSupportFragment = (PermissionSupportFragment) supportFragmentManager.findFragmentByTag(FRAGMENT_TAG);
31 | if (null == permissionSupportFragment) {
32 | permissionSupportFragment = new PermissionSupportFragment();
33 | supportFragmentManager.beginTransaction()
34 | .add(permissionSupportFragment, FRAGMENT_TAG)
35 | .commitNowAllowingStateLoss();
36 | }
37 | action = permissionSupportFragment;
38 | } else {
39 | android.app.FragmentManager fragmentManager = getFragmentManager(activity);
40 | PermissionFragment permissionFragment = (PermissionFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
41 | if (null == permissionFragment) {
42 | permissionFragment = new PermissionFragment();
43 | fragmentManager.beginTransaction()
44 | .add(permissionFragment, FRAGMENT_TAG)
45 | .commitAllowingStateLoss();
46 | //make it commit like commitNow
47 | fragmentManager.executePendingTransactions();
48 | }
49 | action = permissionFragment;
50 | }
51 | return action;
52 | }
53 |
54 | private static FragmentManager getSupportFragmentManager(FragmentActivity activity) {
55 | FragmentManager fragmentManager = activity.getSupportFragmentManager();
56 | //some specific rom will provide a null List
57 | boolean childAvailable = null != fragmentManager.getFragments();
58 | if (childAvailable && fragmentManager.getFragments().size() > 0
59 | && null != fragmentManager.getFragments().get(0)) {
60 | return fragmentManager.getFragments().get(0).getChildFragmentManager();
61 | }
62 | return fragmentManager;
63 | }
64 |
65 | private static android.app.FragmentManager getFragmentManager(Activity activity) {
66 | android.app.FragmentManager fragmentManager = activity.getFragmentManager();
67 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
68 | if (null != fragmentManager.getFragments()
69 | && fragmentManager.getFragments().size() > 0
70 | && null != fragmentManager.getFragments().get(0)) {
71 | return fragmentManager.getFragments().get(0).getChildFragmentManager();
72 | }
73 | } else {
74 | try {
75 | Field fragmentsField = Class.forName("android.app.FragmentManagerImpl").getDeclaredField("mAdded");
76 | fragmentsField.setAccessible(true);
77 | List fragmentList = (List) fragmentsField.get(fragmentManager);
78 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
79 | && null != fragmentList
80 | && fragmentList.size() > 0
81 | && null != fragmentList.get(0)) {
82 | PermissionDebug.d(TAG, "reflect get child fragmentManager success");
83 | return fragmentList.get(0).getChildFragmentManager();
84 | }
85 | } catch (Exception e) {
86 | PermissionDebug.w(TAG, "try to get childFragmentManager failed " + e.toString());
87 | e.printStackTrace();
88 | }
89 | }
90 | return fragmentManager;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/PermissionRequester.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import androidx.annotation.Nullable;
6 | import com.qw.soul.permission.bean.Permission;
7 | import com.qw.soul.permission.bean.Special;
8 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack;
9 | import com.qw.soul.permission.callbcak.RequestPermissionListener;
10 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
11 | import com.qw.soul.permission.request.fragment.FragmentProxy;
12 |
13 | import static android.os.Build.VERSION_CODES.M;
14 |
15 | /**
16 | * 运行时权限请求者
17 | *
18 | * @author cd5160866
19 | */
20 | public class PermissionRequester {
21 |
22 | private FragmentProxy permissionFragment;
23 |
24 | private String[] permissions;
25 |
26 | private Special permissionSpecial;
27 |
28 | public PermissionRequester(Activity activity) {
29 | this.permissionFragment = new FragmentProxy(PermissionFragmentFactory.create(activity));
30 | }
31 |
32 | /**
33 | * 权限名称
34 | *
35 | * @param permissionNames 如 Manifest.permission.CAMERA
36 | * {@link android.Manifest.permission }
37 | */
38 | public PermissionRequester withPermission(String... permissionNames) {
39 | this.permissions = permissionNames;
40 | return this;
41 | }
42 |
43 | /**
44 | * 包含权限的实体类
45 | *
46 | * @param permissions 权限实体类
47 | * {@link com.qw.soul.permission.bean.Permission }
48 | */
49 | public PermissionRequester withPermission(Permission... permissions) {
50 | this.permissions = new String[permissions.length];
51 | for (int i = 0, size = permissions.length; i < size; i++) {
52 | this.permissions[i] = permissions[i].permissionName;
53 | }
54 | return this;
55 | }
56 |
57 | /**
58 | * 特殊权限
59 | *
60 | * @param permissionSpecial 特殊权限
61 | * {@link com.qw.soul.permission.bean.Special }
62 | */
63 | public PermissionRequester withPermission(Special permissionSpecial) {
64 | this.permissionSpecial = permissionSpecial;
65 | return this;
66 | }
67 |
68 | /**
69 | * 请求运行时权限
70 | */
71 | @TargetApi(M)
72 | public void request(RequestPermissionListener listener) {
73 | if (permissionFragment == null || permissions == null) {
74 | throw new IllegalArgumentException("fragment or params permission is null");
75 | }
76 | permissionFragment.requestPermissions(permissions, listener);
77 | }
78 |
79 | /**
80 | * 请求特殊权限
81 | */
82 | public void request(SpecialPermissionListener listener) {
83 | if (permissionFragment == null || permissionSpecial == null) {
84 | throw new IllegalArgumentException("fragment or params special permission is null");
85 | }
86 | permissionFragment.requestSpecialPermission(permissionSpecial, listener);
87 | }
88 |
89 | /**
90 | * 去设置页
91 | */
92 | public void goAppDetail(@Nullable GoAppDetailCallBack appDetailCallBack) {
93 | permissionFragment.goAppDetail(appDetailCallBack);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/fragment/FragmentProxy.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request.fragment;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 | import com.qw.soul.permission.bean.Special;
6 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack;
7 | import com.qw.soul.permission.callbcak.RequestPermissionListener;
8 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
9 | import com.qw.soul.permission.debug.PermissionDebug;
10 | import com.qw.soul.permission.request.IPermissionActions;
11 |
12 |
13 | /**
14 | * @author cd5160866
15 | */
16 | public class FragmentProxy implements IPermissionActions {
17 |
18 | private static final String TAG = FragmentProxy.class.getSimpleName();
19 |
20 | private IPermissionActions fragmentImp;
21 |
22 | public FragmentProxy(IPermissionActions fragmentImp) {
23 | this.fragmentImp = fragmentImp;
24 | }
25 |
26 | @Override
27 | public void requestPermissions(@NonNull String[] permissions, RequestPermissionListener listener) {
28 | this.fragmentImp.requestPermissions(permissions, listener);
29 | PermissionDebug.d(TAG, fragmentImp.getClass().getSimpleName() + " request:" + hashCode());
30 | }
31 |
32 | @Override
33 | public void requestSpecialPermission(Special permission, SpecialPermissionListener listener) {
34 | this.fragmentImp.requestSpecialPermission(permission, listener);
35 | PermissionDebug.d(TAG, fragmentImp.getClass().getSimpleName() + " requestSpecial:" + hashCode());
36 | }
37 |
38 | @Override
39 | public void goAppDetail(@Nullable GoAppDetailCallBack callBack) {
40 | this.fragmentImp.goAppDetail(callBack);
41 | PermissionDebug.d(TAG, fragmentImp.getClass().getSimpleName() + " goAppDetail:" + hashCode());
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/fragment/PermissionFragment.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request.fragment;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.app.Fragment;
6 | import android.content.Intent;
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import com.qw.soul.permission.Constants;
10 | import com.qw.soul.permission.PermissionTools;
11 | import com.qw.soul.permission.bean.Permission;
12 | import com.qw.soul.permission.bean.Special;
13 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack;
14 | import com.qw.soul.permission.callbcak.RequestPermissionListener;
15 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
16 | import com.qw.soul.permission.checker.SpecialChecker;
17 | import com.qw.soul.permission.debug.PermissionDebug;
18 | import com.qw.soul.permission.request.IPermissionActions;
19 |
20 | import static android.os.Build.VERSION_CODES.M;
21 |
22 | /**
23 | * @author cd5160866
24 | */
25 | public class PermissionFragment extends Fragment implements IPermissionActions {
26 |
27 | private static final String TAG = PermissionFragment.class.getSimpleName();
28 |
29 | private Special specialToRequest;
30 |
31 | private RequestPermissionListener runtimeListener;
32 |
33 | private SpecialPermissionListener specialListener;
34 |
35 | private GoAppDetailCallBack goAppDetailCallBack;
36 |
37 | @TargetApi(M)
38 | @Override
39 | public void requestPermissions(String[] permissions, RequestPermissionListener listener) {
40 | this.runtimeListener = listener;
41 | requestPermissions(permissions, Constants.REQUEST_CODE_PERMISSION);
42 | }
43 |
44 | @TargetApi(M)
45 | @Override
46 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
47 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
48 | Permission[] permissionResults = new Permission[permissions.length];
49 | //some specific rom will provide a null array
50 | if (null == permissionResults || null == grantResults) {
51 | return;
52 | }
53 | if (requestCode == Constants.REQUEST_CODE_PERMISSION) {
54 | for (int i = 0; i < permissions.length; ++i) {
55 | Permission permission = new Permission(permissions[i], grantResults[i], this.shouldShowRequestPermissionRationale(permissions[i]));
56 | permissionResults[i] = permission;
57 | }
58 | }
59 | if (null != runtimeListener && PermissionTools.isActivityAvailable(getActivity())) {
60 | runtimeListener.onPermissionResult(permissionResults);
61 | }
62 | }
63 |
64 | @Override
65 | public void requestSpecialPermission(Special permission, SpecialPermissionListener listener) {
66 | this.specialListener = listener;
67 | this.specialToRequest = permission;
68 | Intent intent = PermissionTools.getSpecialPermissionIntent(getActivity(), specialToRequest);
69 | if (null == intent) {
70 | PermissionDebug.w(TAG, "create intent failed");
71 | return;
72 | }
73 | try {
74 | startActivityForResult(intent, Constants.REQUEST_CODE_PERMISSION_SPECIAL);
75 | } catch (Exception e) {
76 | e.printStackTrace();
77 | PermissionDebug.e(TAG, e.toString());
78 | }
79 | }
80 |
81 | @Override
82 | public void goAppDetail(@Nullable GoAppDetailCallBack callBack) {
83 | this.goAppDetailCallBack = callBack;
84 | Intent intent = PermissionTools.getAppManageIntent(getActivity());
85 | if (null == intent) {
86 | PermissionDebug.w(TAG, "create intent failed");
87 | return;
88 | }
89 | startActivityForResult(intent, Constants.REQUEST_CODE_APPLICATION_SETTINGS);
90 | }
91 |
92 | @Override
93 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
94 | super.onActivityResult(requestCode, resultCode, data);
95 | Activity activity = getActivity();
96 | if (!PermissionTools.isActivityAvailable(activity)) {
97 | return;
98 | }
99 | if (requestCode == Constants.REQUEST_CODE_PERMISSION_SPECIAL && null != specialToRequest && null != specialListener) {
100 | boolean result = new SpecialChecker(activity, specialToRequest).check();
101 | if (result) {
102 | specialListener.onGranted(specialToRequest);
103 | } else {
104 | specialListener.onDenied(specialToRequest);
105 | }
106 | return;
107 | }
108 | if (requestCode == Constants.REQUEST_CODE_APPLICATION_SETTINGS && null != goAppDetailCallBack) {
109 | goAppDetailCallBack.onBackFromAppDetail(data);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/soulpermission/src/main/java/com/qw/soul/permission/request/fragment/PermissionSupportFragment.java:
--------------------------------------------------------------------------------
1 | package com.qw.soul.permission.request.fragment;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import androidx.fragment.app.Fragment;
10 | import com.qw.soul.permission.Constants;
11 | import com.qw.soul.permission.PermissionTools;
12 | import com.qw.soul.permission.bean.Permission;
13 | import com.qw.soul.permission.bean.Special;
14 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack;
15 | import com.qw.soul.permission.callbcak.RequestPermissionListener;
16 | import com.qw.soul.permission.callbcak.SpecialPermissionListener;
17 | import com.qw.soul.permission.checker.SpecialChecker;
18 | import com.qw.soul.permission.debug.PermissionDebug;
19 | import com.qw.soul.permission.request.IPermissionActions;
20 |
21 | import static android.os.Build.VERSION_CODES.M;
22 |
23 | /**
24 | * @author cd5160866
25 | */
26 | public class PermissionSupportFragment extends Fragment implements IPermissionActions {
27 |
28 | private static final String TAG = PermissionSupportFragment.class.getSimpleName();
29 |
30 | private RequestPermissionListener runtimeListener;
31 |
32 | private SpecialPermissionListener specialListener;
33 |
34 | private Special specialToRequest;
35 |
36 | private GoAppDetailCallBack goAppDetailCallBack;
37 |
38 | @Override
39 | public void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setRetainInstance(true);
42 | }
43 |
44 | @TargetApi(M)
45 | @Override
46 | public void requestPermissions(String[] permissions, RequestPermissionListener listener) {
47 | requestPermissions(permissions, Constants.REQUEST_CODE_PERMISSION);
48 | this.runtimeListener = listener;
49 | }
50 |
51 | @TargetApi(M)
52 | @Override
53 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
54 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
55 | Permission[] permissionResults = new Permission[permissions.length];
56 | //some specific rom will provide a null array
57 | if (null == permissionResults || null == grantResults) {
58 | return;
59 | }
60 | if (requestCode == Constants.REQUEST_CODE_PERMISSION) {
61 | for (int i = 0; i < permissions.length; ++i) {
62 | Permission permission = new Permission(permissions[i], grantResults[i], this.shouldShowRequestPermissionRationale(permissions[i]));
63 | permissionResults[i] = permission;
64 | }
65 | }
66 | if (null != runtimeListener && PermissionTools.isActivityAvailable(getActivity())) {
67 | runtimeListener.onPermissionResult(permissionResults);
68 | }
69 | }
70 |
71 | @Override
72 | public void requestSpecialPermission(Special permission, SpecialPermissionListener listener) {
73 | this.specialListener = listener;
74 | this.specialToRequest = permission;
75 | Intent intent = PermissionTools.getSpecialPermissionIntent(getActivity(), permission);
76 | if (null == intent) {
77 | PermissionDebug.w(TAG, "create intent failed");
78 | return;
79 | }
80 | try {
81 | startActivityForResult(intent, Constants.REQUEST_CODE_PERMISSION_SPECIAL);
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | PermissionDebug.e(TAG, e.toString());
85 | }
86 | }
87 |
88 | @Override
89 | public void goAppDetail(@Nullable GoAppDetailCallBack callBack) {
90 | this.goAppDetailCallBack = callBack;
91 | Intent intent = PermissionTools.getAppManageIntent(getActivity());
92 | if (null == intent) {
93 | PermissionDebug.w(TAG, "create intent failed");
94 | return;
95 | }
96 | startActivityForResult(intent, Constants.REQUEST_CODE_APPLICATION_SETTINGS);
97 | }
98 |
99 | @Override
100 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
101 | super.onActivityResult(requestCode, resultCode, data);
102 | Activity activity = getActivity();
103 | if (!PermissionTools.isActivityAvailable(activity)) {
104 | return;
105 | }
106 | if (requestCode == Constants.REQUEST_CODE_PERMISSION_SPECIAL && null != specialToRequest && null != specialListener) {
107 | boolean result = new SpecialChecker(activity, specialToRequest).check();
108 | if (result) {
109 | specialListener.onGranted(specialToRequest);
110 | } else {
111 | specialListener.onDenied(specialToRequest);
112 | }
113 | return;
114 | }
115 | if (requestCode == Constants.REQUEST_CODE_APPLICATION_SETTINGS && null != goAppDetailCallBack) {
116 | goAppDetailCallBack.onBackFromAppDetail(data);
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/soulpermission/src/main/res/values-en/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Camera permission
3 | Location permission
4 | Dial permission
5 | Contact permission
6 | Storage permission
7 | Read phone status permission
8 | Calender permission
9 | SMS permission
10 | Sensor permission
11 | Microphone permission
12 | Unkonwn permission
13 | Try to auto jump settings center failed, please try by yourself
14 |
15 |
--------------------------------------------------------------------------------
/soulpermission/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 相机权限
3 | 定位权限
4 | 电话权限
5 | 通讯录权限
6 | 存储权限
7 | 获取手机状态权限
8 | 日历权限
9 | SMS权限
10 | 传感器权限
11 | 麦克风权限
12 | 未知权限
13 | 跳转失败,请自行前往设置中心设置
14 |
15 |
--------------------------------------------------------------------------------