Full Code of getActivity/XXPermissions for AI

master 1384135be5a8 cached
157 files
942.7 KB
234.1k tokens
1092 symbols
1 requests
Download .txt
Showing preview only (1,004K chars total). Download the full file or copy to clipboard to get everything.
Repository: getActivity/XXPermissions
Branch: master
Commit: 1384135be5a8
Files: 157
Total size: 942.7 KB

Directory structure:
gitextract_kzfq42ja/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── config.yml
│   │   ├── issue_en_template_bug.yml
│   │   ├── issue_en_template_question.yml
│   │   ├── issue_en_template_suggest.yml
│   │   ├── issue_zh_template_bug.yml
│   │   ├── issue_zh_template_question.yml
│   │   └── issue_zh_template_suggest.yml
│   └── workflows/
│       └── android.yml
├── .gitignore
├── Details-en.md
├── Details-zh.md
├── HelpDoc-en.md
├── HelpDoc-zh.md
├── LICENSE
├── README-en.md
├── README.md
├── app/
│   ├── AppSignature.jks
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── hjq/
│           │           └── permissions/
│           │               └── demo/
│           │                   ├── AppApplication.java
│           │                   ├── HealthDataPrivacyPolicyActivity.java
│           │                   ├── MainActivity.java
│           │                   ├── WindowLifecycleManager.java
│           │                   ├── example/
│           │                   │   ├── ExampleAccessibilityService.java
│           │                   │   ├── ExampleDeviceAdminReceiver.java
│           │                   │   ├── ExampleNotificationListenerService.java
│           │                   │   └── ExampleVpnService.java
│           │                   └── permission/
│           │                       ├── PermissionConverter.java
│           │                       ├── PermissionDescription.java
│           │                       └── PermissionInterceptor.java
│           └── res/
│               ├── drawable/
│               │   └── permission_description_popup_bg.xml
│               ├── layout/
│               │   ├── activity_main.xml
│               │   ├── health_data_privacy_policy_activity.xml
│               │   └── permission_description_popup.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── strings_demo.xml
│               │   ├── strings_permission.xml
│               │   └── styles.xml
│               ├── values-v21/
│               │   └── styles.xml
│               ├── values-zh/
│               │   ├── strings_demo.xml
│               │   └── strings_permission.xml
│               └── xml/
│                   ├── accessibility_service_config.xml
│                   ├── device_admin_config.xml
│                   └── locales_config.xml
├── build.gradle
├── common.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── library/
│   ├── build.gradle
│   ├── proguard-permissions.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── com/
│                   └── hjq/
│                       └── permissions/
│                           ├── DefaultPermissionDescription.java
│                           ├── DefaultPermissionInterceptor.java
│                           ├── OnPermissionCallback.java
│                           ├── OnPermissionDescription.java
│                           ├── OnPermissionInterceptor.java
│                           ├── XXPermissions.java
│                           ├── core/
│                           │   ├── OnPermissionFragmentCallback.java
│                           │   ├── PermissionChannelImpl.java
│                           │   ├── PermissionChannelImplByRequestPermissions.java
│                           │   ├── PermissionChannelImplByStartActivity.java
│                           │   └── PermissionRequestMainLogic.java
│                           ├── fragment/
│                           │   ├── IFragmentCallback.java
│                           │   ├── IFragmentMethod.java
│                           │   ├── IFragmentMethodExtension.java
│                           │   ├── IFragmentMethodNative.java
│                           │   ├── factory/
│                           │   │   ├── PermissionFragmentFactory.java
│                           │   │   ├── PermissionFragmentFactoryByAndroid.java
│                           │   │   └── PermissionFragmentFactoryByAndroidX.java
│                           │   └── impl/
│                           │       ├── android/
│                           │       │   ├── PermissionAndroidFragment.java
│                           │       │   ├── PermissionAndroidFragmentByRequestPermissions.java
│                           │       │   └── PermissionAndroidFragmentByStartActivity.java
│                           │       └── androidx/
│                           │           ├── PermissionAndroidXFragment.java
│                           │           ├── PermissionAndroidXFragmentByRequestPermissions.java
│                           │           └── PermissionAndroidXFragmentByStartActivity.java
│                           ├── manager/
│                           │   ├── ActivityOrientationManager.java
│                           │   ├── AlreadyRequestPermissionsManager.java
│                           │   └── PermissionRequestCodeManager.java
│                           ├── manifest/
│                           │   ├── AndroidManifestInfo.java
│                           │   ├── AndroidManifestParser.java
│                           │   └── node/
│                           │       ├── ActivityManifestInfo.java
│                           │       ├── ApplicationManifestInfo.java
│                           │       ├── BroadcastReceiverManifestInfo.java
│                           │       ├── IntentFilterManifestInfo.java
│                           │       ├── MetaDataManifestInfo.java
│                           │       ├── PermissionManifestInfo.java
│                           │       ├── ServiceManifestInfo.java
│                           │       └── UsesSdkManifestInfo.java
│                           ├── permission/
│                           │   ├── PermissionChannel.java
│                           │   ├── PermissionGroups.java
│                           │   ├── PermissionLists.java
│                           │   ├── PermissionNames.java
│                           │   ├── PermissionPageType.java
│                           │   ├── base/
│                           │   │   ├── BasePermission.java
│                           │   │   └── IPermission.java
│                           │   ├── common/
│                           │   │   ├── DangerousPermission.java
│                           │   │   └── SpecialPermission.java
│                           │   ├── dangerous/
│                           │   │   ├── AccessBackgroundLocationPermission.java
│                           │   │   ├── AccessMediaLocationPermission.java
│                           │   │   ├── BluetoothAdvertisePermission.java
│                           │   │   ├── BluetoothConnectPermission.java
│                           │   │   ├── BluetoothScanPermission.java
│                           │   │   ├── BodySensorsBackgroundPermission.java
│                           │   │   ├── BodySensorsPermission.java
│                           │   │   ├── GetInstalledAppsPermission.java
│                           │   │   ├── HealthDataBasePermission.java
│                           │   │   ├── NearbyWifiDevicesPermission.java
│                           │   │   ├── PostNotificationsPermission.java
│                           │   │   ├── ReadExternalStoragePermission.java
│                           │   │   ├── ReadHealthDataHistoryPermission.java
│                           │   │   ├── ReadHealthDataInBackgroundPermission.java
│                           │   │   ├── ReadHealthRatePermission.java
│                           │   │   ├── ReadMediaAudioPermission.java
│                           │   │   ├── ReadMediaImagesPermission.java
│                           │   │   ├── ReadMediaVideoPermission.java
│                           │   │   ├── ReadMediaVisualUserSelectedPermission.java
│                           │   │   ├── ReadPhoneNumbersPermission.java
│                           │   │   ├── StandardDangerousPermission.java
│                           │   │   ├── StandardFitnessAndWellnessDataPermission.java
│                           │   │   ├── StandardHealthRecordsPermission.java
│                           │   │   └── WriteExternalStoragePermission.java
│                           │   └── special/
│                           │       ├── AccessNotificationPolicyPermission.java
│                           │       ├── BindAccessibilityServicePermission.java
│                           │       ├── BindDeviceAdminPermission.java
│                           │       ├── BindNotificationListenerServicePermission.java
│                           │       ├── BindVpnServicePermission.java
│                           │       ├── ManageExternalStoragePermission.java
│                           │       ├── ManageMediaPermission.java
│                           │       ├── NotificationServicePermission.java
│                           │       ├── PackageUsageStatsPermission.java
│                           │       ├── PictureInPicturePermission.java
│                           │       ├── RequestIgnoreBatteryOptimizationsPermission.java
│                           │       ├── RequestInstallPackagesPermission.java
│                           │       ├── ScheduleExactAlarmPermission.java
│                           │       ├── SystemAlertWindowPermission.java
│                           │       ├── UseFullScreenIntentPermission.java
│                           │       └── WriteSettingsPermission.java
│                           ├── start/
│                           │   ├── IStartActivityDelegate.java
│                           │   ├── StartActivityAgent.java
│                           │   ├── StartActivityDelegateByActivity.java
│                           │   ├── StartActivityDelegateByContext.java
│                           │   ├── StartActivityDelegateByFragmentAndroid.java
│                           │   └── StartActivityDelegateByFragmentAndroidX.java
│                           └── tools/
│                               ├── PermissionApi.java
│                               ├── PermissionChecker.java
│                               ├── PermissionSettingPage.java
│                               ├── PermissionTaskHandler.java
│                               ├── PermissionUtils.java
│                               └── PermissionVersion.java
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false

================================================
FILE: .github/ISSUE_TEMPLATE/issue_en_template_bug.yml
================================================
name: Submit Bug
description: Please let me know the issues with the framework, and I will assist you in resolving them!
title: "[Bug]:"
labels: ["bug"]

body:
  - type: markdown
    attributes:
      value: |
        ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide)
  - type: input
    id: input_id_1
    attributes:
      label: Framework Version [Required]
      description: Please enter the version of the framework you are using.
    validations:
      required: true
  - type: textarea
    id: input_id_2
    attributes:
      label: Issue Description [Required]
      description: Please describe the issue you are facing.
    validations:
      required: true
  - type: textarea
    id: input_id_3
    attributes:
      label: Steps to Reproduce [Required]
      description: Please provide steps to reproduce the issue.
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: Is the Issue Reproducible? [Required]
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: input
    id: input_id_5
    attributes:
      label: Project targetSdkVersion [Required]
    validations:
      required: true
  - type: input
    id: input_id_6
    attributes:
      label: Device Information [Required]
      description: Please provide the brand and model of the device where the issue occurred.
    validations:
      required: true
  - type: input
    id: input_id_7
    attributes:
      label: Android Version [Required]
      description: Please provide the Android version where the issue occurred.
    validations:
      required: true
  - type: dropdown
    id: input_id_8
    attributes:
      label: Issue Source Channel [Required]
      multiple: true
      options:
        - Encountered by myself
        - Identified in Bugly
        - User feedback
        - Other channels
  - type: input
    id: input_id_9
    attributes:
      label: Is it specific to certain device models? [Required]
      description: Specify whether the issue is specific to certain devices (e.g., specific brand or Android version).
    validations:
      required: true
  - type: dropdown
    id: input_id_10
    attributes:
      label: Does the latest version of the framework have this issue? [Required]
      description: If you are using an older version, it is recommended to upgrade and check if the issue still persists.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_11
    attributes:
      label: Is the issue mentioned in the framework documentation? [Required]
      description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_12
    attributes:
      label: Did you consult the framework documentation but couldn't find a solution? [Required]
      description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes."
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_13
    attributes:
      label: Has a similar issue been reported in the issue list? [Required]
      description: You can search the issue list for keywords related to your problem and refer to the solutions provided by others.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_14
    attributes:
      label: Have you searched the issue list but couldn't find a solution? [Required]
      description: If you have searched the issue list and couldn't find a solution, you can select "Yes."
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_15
    attributes:
      label: Can the issue be reproduced with a demo project? [Required]
      description: Check if the issue can be reproduced in a minimal demo project to isolate potential issues in your own code.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: textarea
    id: input_id_16
    attributes:
      label: Provide Error Stack Trace
      description: If there is an error, please provide the stack trace. Note, Do not include obfuscated code in the stack trace.
      render: text
    validations:
      required: false
  - type: textarea
    id: input_id_17
    attributes:
      label: Provide Screenshots or Videos
      description: Provide screenshots or videos if necessary. This field is optional.
    validations:
      required: false
  - type: textarea
    id: input_id_18
    attributes:
      label: Provide a Solution
      description: If you have already found a solution, this field is optional.
    validations:
      required: false

================================================
FILE: .github/ISSUE_TEMPLATE/issue_en_template_question.yml
================================================
name: Ask a Question
description: Ask your questions, and I will provide you with answers.
title: "[Question]:"
labels: ["question"]

body:
  - type: markdown
    attributes:
      value: |
        ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide)
  - type: textarea
    id: input_id_1
    attributes:
      label: Question Description [Required]
      description: Please describe your question (Note, If it is a framework bug, please do not raise it here, as it will not be accepted).
    validations:
      required: true
  - type: dropdown
    id: input_id_2
    attributes:
      label: Is the issue mentioned in the framework documentation? [Required]
      description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_3
    attributes:
      label: Did you consult the framework documentation but couldn't find a solution? [Required]
      description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes."
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: Has a similar issue been reported in the issue list? [Required]
      description: You can search the issue list for keywords related to your problem and refer to the solutions provided by others.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_5
    attributes:
      label: Have you searched the issue list but couldn't find a solution? [Required]
      description: If you have searched the issue list and couldn't find a solution, you can select "Yes."
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true

================================================
FILE: .github/ISSUE_TEMPLATE/issue_en_template_suggest.yml
================================================
name: Submit Suggestion
description: Please let me know the shortcomings of the framework, so that I can improve it!
title: "[Suggestion]:"
labels: ["help wanted"]

body:
  - type: markdown
    attributes:
      value: |
        ## [Warning: Please make sure to fill in the issue template accurately. If an issue is found to be filled incorrectly, it will be closed without further notice.](https://github.com/getActivity/IssueTemplateGuide)
  - type: textarea
    id: input_id_1
    attributes:
      label: What are the shortcomings you have noticed in the framework? [Required]
      description: You can describe any aspects of the framework that you are not satisfied with.
    validations:
      required: true
  - type: dropdown
    id: input_id_2
    attributes:
      label: Has a similar suggestion been made in the issue list? [Required]
      description: If a similar suggestion has already been made, I will not address it again.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_3
    attributes:
      label: Is the suggestion mentioned in the framework documentation? [Required]
      description: The documentation provides answers to frequently asked questions. Please check if the information you are looking for is already provided.
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: Did you consult the framework documentation but couldn't find a solution? [Required]
      description: If you have consulted the documentation but still couldn't find a solution, you can select "Yes."
      multiple: false
      options:
        - "Not Selected"
        - "Yes"
        - "No"
    validations:
      required: true
  - type: textarea
    id: input_id_5
    attributes:
      label: How do you suggest improving it? [Optional]
      description: You can provide your ideas or approaches for the author's reference.
    validations:
      required: false

================================================
FILE: .github/ISSUE_TEMPLATE/issue_zh_template_bug.yml
================================================
name: 提交 Bug
description: 请告诉我框架存在的问题,我会协助你解决此问题!
title: "[Bug]:"
labels: ["bug"]

body:
  - type: markdown
    attributes:
      value: |
        ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide)
  - type: input
    id: input_id_1
    attributes:
      label: 框架版本【必填】
      description: 请输入你使用的框架版本
    validations:
      required: true
  - type: textarea
    id: input_id_2
    attributes:
      label: 问题描述【必填】
      description: 请输入你对这个问题的描述
    validations:
      required: true
  - type: textarea
    id: input_id_3
    attributes:
      label: 复现步骤【必填】
      description: 请输入问题的复现步骤
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: 是否必现【必填】
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: input
    id: input_id_5
    attributes:
      label: 项目 targetSdkVersion【必填】
    validations:
      required: true
  - type: input
    id: input_id_6
    attributes:
      label: 出现问题的手机信息【必填】
      description: 请填写出现问题的品牌和机型
    validations:
      required: true
  - type: input
    id: input_id_7
    attributes:
      label: 出现问题的安卓版本【必填】
      description: 请填写出现问题的 Android 版本
    validations:
      required: true
  - type: dropdown
    id: input_id_8
    attributes:
      label: 问题信息的来源渠道【必填】
      multiple: true
      options:
        - 自己遇到的
        - Bugly 看到的
        - 用户反馈
        - 其他渠道
  - type: input
    id: input_id_9
    attributes:
      label: 是部分机型还是所有机型都会出现【必答】
      description: 部分/全部(例如:某为,某 Android 版本会出现)
    validations:
      required: true
  - type: dropdown
    id: input_id_10
    attributes:
      label: 框架最新的版本是否存在这个问题【必答】
      description: 如果用的是旧版本的话,建议升级看问题是否还存在
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_11
    attributes:
      label: 框架文档是否提及了该问题【必答】
      description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_12
    attributes:
      label: 是否已经查阅框架文档但还未能解决的【必答】
      description: 如果查阅了文档但还是没有解决的话,可以选择是
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_13
    attributes:
      label: issue 列表中是否有人曾提过类似的问题【必答】
      description: 可以在 issue 列表在搜索问题关键字,参考一下别人的解决方案
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_14
    attributes:
      label: 是否已经搜索过了 issue 列表但还未能解决的【必答】
      description: 如果搜索过了 issue 列表但是问题没有解决的话,可以选择是
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_15
    attributes:
      label: 是否可以通过 Demo 来复现该问题【必答】
      description: 排查一下是不是自己的项目代码写得有问题导致的
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: textarea
    id: input_id_16
    attributes:
      label: 提供报错堆栈
      description: 如果有报错的话必填,注意不要拿被混淆过的代码堆栈上来
      render: text
    validations:
      required: false
  - type: textarea
    id: input_id_17
    attributes:
      label: 提供截图或视频
      description: 根据需要提供,此项不强制
    validations:
      required: false
  - type: textarea
    id: input_id_18
    attributes:
      label: 提供解决方案
      description: 如果已经解决了的话,此项不强制
    validations:
      required: false

================================================
FILE: .github/ISSUE_TEMPLATE/issue_zh_template_question.yml
================================================
name: 提出疑问
description: 提出你的困惑,我会给你解答
title: "[疑惑]:"
labels: ["question"]

body:
  - type: markdown
    attributes:
      value: |
        ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide)
  - type: textarea
    id: input_id_1
    attributes:
      label: 问题描述【必填】
      description: 请描述一下你的问题(注意:如果确定是框架 bug 请不要在这里提,否则一概不受理)
    validations:
      required: true
  - type: dropdown
    id: input_id_2
    attributes:
      label: 框架文档是否提及了该问题【必答】
      description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_3
    attributes:
      label: 是否已经查阅框架文档但还未能解决的【必答】
      description: 如果查阅了文档但还是没有解决的话,可以选择是
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: issue 列表中是否有人曾提过类似的问题【必答】
      description: 可以在 issue 列表在搜索问题关键字,参考一下别人的解决方案
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_5
    attributes:
      label: 是否已经搜索过了 issue 列表但还未能解决的【必答】
      description: 如果搜索过了 issue 列表但是问题没有解决的话,可以选择是
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true

================================================
FILE: .github/ISSUE_TEMPLATE/issue_zh_template_suggest.yml
================================================
name: 提交建议
description: 请告诉我框架的不足之处,让我做得更好!
title: "[建议]:"
labels: ["help wanted"]

body:
  - type: markdown
    attributes:
      value: |
        ## [【警告:请务必按照 issue 模板填写,不要抱有侥幸心理,一旦发现 issue 没有按照模板认真填写,一律直接关闭】](https://github.com/getActivity/IssueTemplateGuide)
  - type: textarea
    id: input_id_1
    attributes:
      label: 你觉得框架有什么不足之处?【必答】
      description: 你可以描述框架有什么令你不满意的地方
    validations:
      required: true
  - type: dropdown
    id: input_id_2
    attributes:
      label: issue 是否有人曾提过类似的建议?【必答】
      description: 一旦出现重复提问我将不会再次解答
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_3
    attributes:
      label: 框架文档是否提及了该问题【必答】
      description: 文档会提供最常见的问题解答,可以先看看是否有自己想要的
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: dropdown
    id: input_id_4
    attributes:
      label: 是否已经查阅框架文档但还未能解决的【必答】
      description: 如果查阅了文档但还是没有解决的话,可以选择是
      multiple: false
      options:
        - "未选择"
        - "是"
        - "否"
    validations:
      required: true
  - type: textarea
    id: input_id_5
    attributes:
      label: 你觉得该怎么去完善会比较好?【非必答】
      description: 你可以提供一下自己的想法或者做法供作者参考
    validations:
      required: false

================================================
FILE: .github/workflows/android.yml
================================================
name: Android CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8


================================================
FILE: .gitignore
================================================
.gradle
.idea
.cxx
.externalNativeBuild
build
captures

._*
*.iml
.DS_Store
local.properties

================================================
FILE: Details-en.md
================================================
#### Table of Contents

* [Intent Extreme Jump Fallback Mechanism](#intent-extreme-jump-fallback-mechanism)

* [Compatibility with Permission Request API Crash Issues](#compatibility-with-permission-request-api-crash-issues)

* [Avoiding System Permission Callback Null Pointer Issues](#avoiding-system-permission-callback-null-pointer-issues)

* [Automatic Permission Split Requests](#automatic-permission-split-requests)

* [Framework Completely Separates UI Layer](#framework-completely-separates-ui-layer)

* [Core Logic and Specific Permissions Completely Decoupled](#core-logic-and-specific-permissions-completely-decoupled)

* [Automatic Background Permission Adaptation](#automatic-background-permission-adaptation)

* [Support for Cross-Platform Environment Calls](#support-for-cross-platform-environment-calls)

* [Callback Lifecycle Synchronized with Host](#callback-lifecycle-synchronized-with-host)

* [Support for Custom Permission Requests](#support-for-custom-permission-requests)

* [New Version Permissions Support Backward Compatibility](#new-version-permissions-support-backward-compatibility)

* [Screen Rotation Scenario Adaptation](#screen-rotation-scenario-adaptation)

* [Background Permission Request Scenario Adaptation](#background-permission-request-scenario-adaptation)

* [Fix Android 12 Memory Leak Issue](#fix-android-12-memory-leak-issue)

* [Support for Code Error Detection](#support-for-code-error-detection)

#### Intent Extreme Jump Fallback Mechanism

* Before introducing this feature, let me ask you a question: please analyze if there's any problem with this code?

```java
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData("package:" + getPackageName());
startActivityForResult(intent, 1024);
```

* You might say: It's simple, this is just code to jump to the application details page, what could be wrong with it? Are you trying to trick me?

* This code seems to have no problems and runs fine, but it's actually a huge pitfall. Some manufacturers have directly removed the `ACTION_APPLICATION_DETAILS_SETTINGS` intent. Yes, you heard right - completely removed it. When this code runs on these devices, the application will crash. I'm not joking:

```text
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.settings.APPLICATION_DETAILS_SETTINGS dat=Package Name:com.xxx.xxx }
```

* If you still don't believe me, look here [Github Search `No Activity found to handle Intent  act=android.settings.APPLICATION_DETAILS_SETTINGS`](https://github.com/search?q=No+Activity+found+to+handle+Intent++act%3Dandroid.settings.APPLICATION_DETAILS_SETTINGS&type=issues):

* It's not just the `ACTION_APPLICATION_DETAILS_SETTINGS` intent; other intents have the same issue. If you don't believe me, check here [Github Search `No Activity found to handle Intent  act=android`](https://github.com/search?q=No+Activity+found+to+handle+Intent++act%3Dandroid&type=issues).

```
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.settings.MANAGE_UNKNOWN_APP_SOURCES (has data) }
```

* After reading this, you might want to complain, but the problem exists, and irrational complaints never solve problems. Only rational analysis and serious thinking are the way out. The issue is that the `Intent` can't be found. The simplest and most effective solution is to check if the `Intent` exists before jumping. If it exists, then jump; if not, don't jump. But if you think that's all there is to it, you're being too simplistic. Things are rarely as simple as they seem. Non-existent `Intent` jumps will fail, but have you considered that even existing `Intent` jumps don't guarantee success? If you don't believe me, look here [Github Search `Permission Denial: starting Intent`](https://github.com/search?q=Permission+Denial%3A+starting+Intent&type=issues). Now you understand why I called it a pitfall?

```text
java.lang.SecurityException: 
Permission Denial: starting Intent { act=android.settings.MANAGE_UNKNOWN_APP_SOURCES (has data) cmp=xxxx/xxx }
```

* I'm not saying this to make you solve the problem, but to make you aware that it exists. Of course, the framework has already handled this issue. All the problems you can think of, the framework has already thought of and handled for you. Just one line of code, call the `XXPermissions.startPermissionActivity` method. If you're curious about how the framework implements this but too lazy to look at the source code, I've got you covered. The principle is actually very simple: when the framework gets the permission settings page, it puts all possible `Intent`s in a List collection, filters out non-existent `Intent`s, and then tries each `Intent` one by one. If one fails, it jumps to the next one, until it succeeds or there are no more `Intent`s left.

#### Compatibility with Permission Request API Crash Issues

* Before introducing this feature, let me ask you a question: please analyze if there's any problem with this code?

```java
activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, 1024);
```

* You might say: This is just a simple code using the system API to request permissions. What could be wrong with it? As long as you don't call it on devices below Android 6.0, it should be fine.

* Theoretically, that's correct, but theory is just theory. In reality, calling this on Android 6.0 and above devices can also cause crashes. Yes, you didn't misread - Android 6.0 and above can crash. It sounds magical that such an important system API could crash. If you don't believe me, check here [XXPermissions/issues/153](https://github.com/getActivity/XXPermissions/issues/153), [XXPermissions/issues/126](https://github.com/getActivity/XXPermissions/issues/126), [XXPermissions/issues/327](https://github.com/getActivity/XXPermissions/issues/327), [XXPermissions/issues/339](https://github.com/getActivity/XXPermissions/issues/339), or if that's not enough, look here [Github Search `act=android.content.pm.action.REQUEST_PERMISSIONS`](https://github.com/search?q=act%3Dandroid.content.pm.action.REQUEST_PERMISSIONS&type=issues). Doesn't that instantly change your understanding?

```text
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.android.packageinstaller (has extras) }
```

* This situation can occur for several reasons:

    1. Manufacturer developers changed the package name of the `com.android.packageinstaller` system application but didn't test it properly before release (low probability)

    2. Manufacturer developers deleted the `com.android.packageinstaller` system application but didn't test it properly before release (low probability)

    3. Manufacturer developers modified Android system source code affecting the permission module but didn't test it properly before release (low probability)

    4. Manufacturers actively cut the permission request function, for example on TV devices, indirectly causing apps requesting dangerous permissions to crash when requesting permissions (low probability)

    5. Users have Root privileges and accidentally deleted the `com.android.packageinstaller` system application when streamlining system apps (higher probability)

* After analyzing the source code of `Activity.requestPermissions`, it essentially still calls `startActivityForResult`, but the `Activity` can't be found. The best solution I can think of is to use `try catch` to prevent it from crashing. You might wonder if simply using `try catch` is enough? Won't it cause other problems? Won't it cause `onRequestPermissionsResult` not to be called, leading to the permission request process getting stuck? Although this problem can't be tested, theoretically it shouldn't happen. I experimented by using an incorrect `Intent` with `startActivityForResult` and `try catch`, and found that `onActivityResult` was still normally called by the system. This proves that using `try catch` with `startActivityForResult` doesn't affect the `onActivityResult` callback. I also analyzed the source code for `Activity` callbacks and found that both `onRequestPermissionsResult` and `onActivityResult` are called by the `dispatchActivityResult` method. In that extreme case, since `onActivityResult` can be called, it proves that `dispatchActivityResult` must have been normally called by the system, and similarly, `onRequestPermissionsResult` must also be normally called by `dispatchActivityResult`, forming a complete logical loop.

* Additional test conclusion: I debugged the `Activity.requestPermissions` method and secretly modified the permission request `Intent`'s `Action` to an incorrect one, and the permission callback still worked normally.

* If this extreme situation does occur, all dangerous permission requests will necessarily go through the failure callback, but what the framework can do is: try to prevent the application from crashing and ensure it completes the entire permission request process.

#### Avoiding System Permission Callback Null Pointer Issues

* Before introducing this feature, let me ask you a question: please analyze if there's any problem with this code?

```java
public final class XxxActivity extends AppCompatActivity  {

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (permissions.length == 0 || grantResults.length == 0) {
            return;
        }
        if (permissions[0].equals(Manifest.permission.CAMERA) && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            System.out.println("Camera permission granted successfully");
        } else {
            System.out.println("Failed to get camera permission");
        }
    }
}
```

* You might say: This is normal handling of permission request results in the permission callback. I write it like this all the time. It looks fine to me. Are you just finding fault?

* What if I told you that the `permissions` or `grantResults` array parameters returned by the system could be null? Would you believe it? I know you probably don't, because you see that both `permissions` and `grantResults` parameters have `@NonNull` annotations (and if you look at the Activity source code, you'll also see `@NonNull` annotations), which means the system should never return null. At this point, you probably think I'm deceiving you.

* I know you don't believe me, so I've prepared evidence. Please look here [XXPermissions/issues/191](https://github.com/getActivity/XXPermissions/issues/191), [XXPermissions/issues/106](https://github.com/getActivity/XXPermissions/issues/106), [XXPermissions/issues/236](https://github.com/getActivity/XXPermissions/issues/236), or if that's not enough, look here [Github Search `NullPointerException onRequestPermissionsResult`](https://github.com/search?q=NullPointerException+onRequestPermissionsResult&type=issues);

* After reading this, what are you thinking? What is the system trying to do? Marking parameters as non-null but returning null - isn't that deceiving us? The problem exists, and irrational complaints never solve problems. Only rational analysis and serious thinking are the way out.

* Currently, the device brands reporting this issue include vivo, Xiaomi, and Lenovo, indicating that this problem is likely another pit dug by `Google` engineers. There are two approaches to solving this problem:

    1. Still use the `permissions` and `grantResults` parameters to determine the permission status: Before using them, first check the array objects for null, then continue using them.

    2. No longer use the `permissions` and `grantResults` parameters to determine the permission status: Switch to using `checkSelfPermission` to determine the permission status.

* Although both can solve the problem, there are slight differences. The framework ultimately adopts the second approach. There's a Chinese saying: "Once unfaithful, never trusted again." Since it can do such unprincipled things, we must guard against other tricks it might have, such as:

    1. The returned array objects are not null, but there are no elements in the arrays. If not checked in advance, calling them could trigger an `ArrayIndexOutOfBoundsException`.

    2. The returned array objects are not null, there are elements in the arrays, but the lengths of the `permissions` and `grantResults` arrays are different. If not checked in advance, calling them could trigger an `ArrayIndexOutOfBoundsException`.

    3. The returned array objects are not null, there are elements in the arrays, the lengths of the two arrays are normal, but the returned `grantResults` don't match reality. The user clearly granted the permission, but the array stores `-1` (`PackageManager.PERMISSION_DENIED`).

* At this point, you might suddenly realize that solving this null pointer problem isn't as simple as just adding a null check? There's so much more to it. I want to tell everyone that no matter what the problem is, I will take it seriously, because what I pursue is never just solving the problem, but finding the optimal solution among all possible solutions.

#### Automatic Permission Split Requests

* In some scenarios, you need to request multiple permissions at once, such as microphone permission and calendar permission. In this case, product managers may want to split the permissions into two separate requests to display separate explanation dialogs for each permission. This design makes feature development more complex. Without splitting the requests, you would only need to add logic to show and close the dialog before and after the permission request. Now with split requests, you can't write it that way. You have to write it separately, which means writing various nested callbacks. Just thinking about doing this makes your head spin, almost making you want to throw up last night's midnight snack.

* I understand everyone's pain and frustration, so I added a processing mechanism to the framework that automatically categorizes the permissions you pass in. For example, microphone permission is grouped into one category, calendar permission into another, and then they are split into two separate permission requests. When combined with the permission explanation interface opened by the framework, which tells you what permission is being requested, you can display the specific permission explanation dialog based on the permission. With this, the feature is completed easily and elegantly. While the iOS team is still struggling with implementation, you've already completed it and left work early. No delays, no pain, just the satisfaction of implementing the feature.

#### Framework Completely Separates UI Layer

* Some permission frameworks implement a set of permission explanation dialog UI and logic internally, requiring specific interfaces to be implemented for modification. I believe this design is unreasonable because displaying a permission explanation dialog is not a mandatory operation. Without it, calling the permission request API will still pop up the authorization box. Additionally, when it comes to UI, the UI designed within the framework inevitably cannot satisfy everyone's needs (it's a thankless task) because everyone receives different design drafts. So the best solution is for the framework not to write UI and logic internally, but to design relevant interfaces for this aspect and then hand it over to the outer layer for implementation. Of course, the framework's Demo module will also implement a case for the outer layer to reference (or directly copy the code). This not only solves the problem of inconsistent UI requirements but also reduces the size of the framework - killing two birds with one stone.

#### Core Logic and Specific Permissions Completely Decoupled

* The frameworks you see on the market that can support both dangerous permissions and special permissions have very high code coupling. This leads to a problem: for example, if you only use it to request dangerous permissions, when packaging, it will include special permissions code logic in the APK. It's like wanting to eat fried chicken, but the clerk tells you that you can only get fried chicken if you order a ten-person set meal. You think to yourself that even if you stuff yourself, you can't finish a ten-person set meal. Isn't this design clearly a trap? Although an app with more code won't "die from overeating" like a person, we shouldn't waste resources recklessly. A little waste here, a little waste there, and after development, you look at the APK size and it's 250 MB, and you have to consider size optimization. The key is that you can't optimize it because this part of the code is hardcoded in the framework, and the framework is remotely dependent. You'd have to switch to local dependencies to make changes, which means there might be bugs that increase a lot of self-testing workload. Importantly, the benefits of making changes are low, but the risks are extremely high, and you could easily end up on the layoff list while making changes.

* For this problem, the framework has a brilliant design solution: encapsulate the implementation of different permissions into objects. You pass whatever permission object you request, and objects that aren't referenced will be removed during code obfuscation. This way, when packaging the official version, there won't be redundant code, and it won't occupy extra APK size. It truly achieves "pay for what you use." You no longer have to consider whether to buy a ten-person set meal just to eat a piece of fried chicken. No need to hesitate or waver. With XXPermissions, you can buy separately, buy what you want to eat, buy as much as you want to eat, suitable for all ages, honest and fair.

* Of course, for some frameworks that don't support any special permissions or handle specific dangerous permissions separately, but simply use the system's API - using `context.requestPermissions` to request permissions and `context.checkSelfPermission` to check permissions - does this count as completely decoupled? Actually, it does, because they indeed don't directly depend on specific permissions in the core logic. But such frameworks don't meet the needs of real-world development because in a commercialized app, it's impossible to only request dangerous permissions. Need notification permission? Need installation package permission? Need floating window permission? As long as these frameworks support any special permission, this problem will exist. Of course, if they don't support it, then there's no problem. But the key is whether it's possible to both support these permissions and decouple the code? This is the key to the problem, which really tests the understanding of the framework and code design. As of now, only XXPermissions has truly achieved both support and decoupling.

#### Automatic Background Permission Adaptation

* Android 10 added [background location permission](https://developer.android.google.cn/about/versions/11/privacy/location?hl=zh-cn#background-location) and Android 13 added [background sensor permission](https://developer.android.google.cn/about/versions/13/behavior-changes-13?hl=zh-cn#body-sensors-background-permission). Don't think these background permissions are no different from ordinary dangerous permissions; the differences are very significant, and if you don't understand them clearly, it's easy to encounter bugs.

    1. Foreground and background permissions cannot be requested together. You must request foreground permissions first, then background permissions. Requesting background permissions without foreground permissions will definitely be rejected by the system, which is beyond doubt.

    2. After Android 11, there must be a certain time interval between foreground and background permission requests. That is, after splitting the two permission requests, you must ensure that there is a certain time interval between them, otherwise the request will fail. Testing shows it cannot be less than 150 milliseconds.

    3. The background location permission corresponds to two foreground location permissions: precise location permission (`ACCESS_FINE_LOCATION`) and approximate location permission (`ACCESS_COARSE_LOCATION`). In versions `Android 10 ~ Android 11`, the background location permission is anchored to the precise location permission. Only when this permission is granted can you request the background location permission. In Android 12 and later versions, the background location permission can be anchored to either the precise location permission or the approximate location permission. When either of these permissions is granted, you can request the background location permission.

* However, the framework has already handled these issues for you, and you don't need to handle them manually. The specific handling solutions are as follows:

    1. Automatically identify background permissions and their corresponding foreground permissions, then automatically split them into two permission requests: first request foreground permissions, then request background permissions.

    2. When requesting background permissions, add a time delay first, which is the 150 milliseconds mentioned earlier, then request the background permissions, thus avoiding this issue.

    3. When judging background location permissions, different Android versions are handled differently for foreground location permissions. In versions `Android 10 ~ Android 11`, precise location permission is used; in `Android 12` and later versions, either precise location permission or approximate location permission is used, ensuring the same expected effect across different Android versions.

#### Support for Cross-Platform Environment Calls

* As we all know, [FlutterActivity](https://github.com/flutter/flutter/blob/03ef1ba910cac387f7b2af8ab09ca955d3974663/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java), [ComposeActivity](https://github.com/androidx/androidx/blob/8d08d42d60f7cc7ec0034d0b7ff6fd953516d96a/emoji2/emoji2-emojipicker/samples/src/main/java/androidx/emoji2/emojipicker/samples/ComposeActivity.kt), [UnityPlayerActivity](https://github.com/FabianTerhorst/PokemonGo/blob/d511b045f1492e0bae71778ef528f3d768d218cd/java/com/unity3d/player/UnityPlayerActivity.java), [Cocos2dxActivity](https://github.com/irontec/Ikasesteka/blob/master/Ikasesteka/cocos2d/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxActivity.java) are all subclasses of Activity, but they are not subclasses of [FragmentActivity](https://github.com/androidx/androidx/blob/8d08d42d60f7cc7ec0034d0b7ff6fd953516d96a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java). Their inheritance relationships are as follows:

    1. `FlutterActivity extends Activity`

    2. `ComposeActivity extends ComponentActivity extends Activity`

    3. `UnityPlayerActivity extends Activity`

    4. `Cocos2dxActivity extends Activity`

    5. `FragmentActivity extends ComponentActivity extends Activity`

* This creates a problem: some permission request frameworks use a transparent `Fragment` to get permission request callbacks. If the permission request framework uses `androidx.fragment.app.Fragment`, then it must require the outer layer to pass in an `androidx.fragment.app.FragmentActivity` object. If the `Activity` you're using is not a subclass of `androidx.fragment.app.FragmentActivity`, what should you do? Simple, you might say, just modify the current `Activity` to directly inherit from `androidx.fragment.app.FragmentActivity`, right? But what if your current `Activity` must inherit from `FlutterActivity`, `ComposeActivity`, `UnityPlayerActivity`, or `Cocos2dxActivity`? What should you do then? Modify their source code? Or modify the permission framework's source code? Whichever solution you choose, the cost of adaptation will be very high and difficult to maintain in the future. This is neither realistic nor scientific. Do you suddenly feel like heaven has blocked your path? Is writing permission request API code by hand the only way to implement permission requests?

* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The specific implementation principle is: the framework will determine if the `Activity` object you pass in is a subclass of `androidx.fragment.app.FragmentActivity`. If it is, it will use `androidx.fragment.app.Fragment` for permission requests; if not, it will use `android.app.Fragment` for permission requests. This way, no matter which type of `Activity` you use, the framework can automatically adapt.

#### Callback Lifecycle Synchronized with Host

* Most permission request frameworks on the market use a single type of `Fragment` to handle permission request callbacks, but this leads to a problem. Suppose a framework uses `androidx.fragment.app.Fragment` to handle permission request callbacks, but you initiated the permission request in `android.app.Fragment`, or vice versa, you used `androidx.fragment.app.Fragment` but the framework used `android.app.Fragment`. You can't pass your own `Fragment` as the host to the permission request framework; you can only pass the `Activity` object to the framework through `fragment.getActivity()`. This makes the `Activity` the host object, leading to a lifecycle asynchronization problem: your own `Fragment` may have been destroyed, but the framework will still callback the permission request result listener, causing `Memory leak` at best and triggering `Exception` at worst.

* The reason for this problem is that the `Fragment` used by the third-party framework and your `Fragment` are not actually the same type. Although they have the same class name, they are in different packages. Plus, as just mentioned, you can only pass the `Activity` object to the framework through `fragment.getActivity()`, so your own `Fragment` cannot form an effective lifecycle binding with the framework's `Fragment`. What you actually want is to bind to your own `Fragment`'s lifecycle, but the framework ultimately binds to the `Activity`'s lifecycle, which can easily trigger a crash. You can see the specific manifestation in this issue: [XXPermissions/issues/365](https://github.com/getActivity/XXPermissions/issues/365).

* Actually, the framework has already thought of this problem and has solved it for you without requiring any handling on your part. The approach to solving this problem is: the framework will automatically select the best type of `Fragment` based on the type of object you pass in. If the host you pass in is an `androidx.fragment.app.FragmentActivity` or `androidx.fragment.app.Fragment` object, the framework will internally create an `androidx.fragment.app.Fragment` to receive permission request callbacks. If the host you pass in is a regular `Activity` or `android.app.Fragment`, the framework will internally create an `android.app.Fragment` to receive permission request callbacks. This way, no matter what host object you pass in, the framework will bind to its lifecycle, ensuring that when the permission request result is called back to the outermost layer, the host object is still in a normal state.

* At this point, you might jump in and say, I can implement this without the framework. I can manually check the `Fragment`'s state in the permission callback method. Isn't it just a matter of two or three lines of code? Why does the framework make it so complicated? Your idea seems reasonable but doesn't stand up to scrutiny. If your project requests permissions in a dozen places, you would need to consider this issue in every callback method. Additionally, when requesting new permissions in the future, you would also need to consider this issue. Can you ensure that you won't miss anything when making changes? And what if this requirement was developed by your colleague, but only you know about this issue, and they are unaware? Do you know what might happen in that case? I believe you understand better than I do. The solution you provided, although it can temporarily solve the problem, treats the symptoms but not the root cause. The fundamental issue is that the approach to solving the problem is flawed, following a patch-the-hole mentality rather than thinking about blocking the leak at the source. Or perhaps you already knew how to completely cure it but chose the easiest way to handle it, which undoubtedly plants a time bomb in the project.

#### Support for Custom Permission Requests

* As the name suggests, developers can not only request permissions already supported by the framework but also request permissions they define themselves. This feature is very powerful and can meet the needs of the following scenarios:

    1. You can define and request permissions not supported by the framework, such as boot auto-start permission, desktop shortcut permission, read clipboard permission, write clipboard permission, operate external storage `Android/data` permission, specific manufacturer permissions, and even [Bluetooth switch, WIFI switch, location switch](https://github.com/getActivity/XXPermissions/issues/170), etc. Let your imagination run wild here. Now you only need to inherit the `DangerousPermission` or `SpecialPermission` class provided by the framework to implement custom permissions. In previous versions, this could only be achieved by modifying the framework's source code, which was very cumbersome. You not only had to study the framework's source code but also had to do strict self-testing after modification. Now you don't need to do that anymore; the framework provides this extension interface, and implementing one interface can achieve it.

    2. Developers no longer need to rely on the permission framework author to adapt new permissions. When Google releases a new Android version with new permissions, and the framework hasn't had time to adapt, but you urgently need to request this new permission, you can use this feature to adapt the new permission first.

#### New Version Permissions Support Backward Compatibility

* With the continuous update of the Android version, dangerous permissions and special permissions are also increasing, so there will be a version compatibility problem at this time. Higher version Android devices support applying for lower version permissions, but lower version Android devices do not support If you apply for a higher version of the permission, then there will be a compatibility problem at this time.

* After verification, other permission frameworks chose the simplest and rude way, which is not to do compatibility, but to the caller of the outer layer for compatibility. The caller needs to judge the Android version in the outer layer first, and upload it on the higher version. Enter new permissions to the framework, and pass the old permissions to the framework on the lower version. This method seems simple and rude, but the development experience is poor. At the same time, it also hides a pit. The outer callers know that the new permissions correspond to Which is the old permission of ? I think not everyone knows it, and once the cognition is wrong, it will inevitably lead to wrong results.

* I think the best way is to leave it to the framework. **XXPermissions** does exactly that. When the outer caller applies for a higher version of the permission, then the lower version of the device will automatically add the lower version of the permission. To apply, to give the simplest example, the new `MANAGE_EXTERNAL_STORAGE` permission that appeared in Android 11, if it is applied for this permission on Android 10 and below devices, the framework will automatically add `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` to apply, in Android On Android 10 and below devices, we can directly use `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` as `MANAGE_EXTERNAL_STORAGE`, because what `MANAGE_EXTERNAL_STORAGE` can do, on Android 10 and below devices, we need to use `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` Only then can it be done.

* So when you use **XXPermissions**, you can directly apply for new permissions. You don’t need to care about the compatibility of old and new permissions. The framework will automatically handle it for you. Unlike other frameworks, What I want to do more is to let everyone handle the permission request with a single code, and let the framework handle everything that the framework can do.

#### Screen Rotation Scenario Adaptation

* When the system permission request dialog pops up and the Activity is rotated, it will cause the permission request callback to fail because screen rotation causes the Fragment in the framework to be destroyed and recreated, leading to the callback object being directly recycled and ultimately causing the callback to be abnormal. There are several solutions: one is to add the `android:configChanges="orientation"` attribute in the manifest file so that screen rotation won't cause the Activity and Fragment to be destroyed and recreated; another is to directly fix the display direction of the Activity in the manifest file. But both of these solutions require the framework user to handle them, which is obviously not flexible enough. The problem should be solved by those who created it, and framework problems should be solved by the framework. **RxPermissions**' solution is to set `fragment.setRetainInstance(true)` on the PermissionFragment object, so even if the screen rotates, the Activity object will be destroyed and recreated, but the Fragment won't be destroyed and recreated, still reusing the previous object. But there's a problem: if the Activity overrides the `onSaveInstanceState` method, it will directly cause this approach to fail. This approach obviously only treats the symptoms but not the root cause. **XXPermissions**' approach is more direct: when the **PermissionFragment** is bound to the Activity, it **fixes the screen orientation** of the current Activity, and after the permission request is completed, it **restores the screen orientation**.

* In all permission request frameworks, as long as they use Activity/Fragment to request permissions, this problem will occur because as soon as the user rotates the screen, it will cause the permission callback to not callback normally. Currently, XXPermissions is one of the few frameworks that solves this problem, while PermissionX directly borrowed XXPermissions' solution. For details, see [XXPermissions/issues/49](https://github.com/getActivity/XXPermissions/issues/49) and [PermissionX/issues/51](https://github.com/guolindev/PermissionX/issues/51).

#### Background Permission Request Scenario Adaptation

* When we apply for permissions after doing time-consuming operations (such as obtaining the privacy agreement on the splash screen page and then applying for permissions), the activity will be returned to the desktop (retired to the background) during the network request process, and then the permission request will be in the background state At this time, the permission application may be abnormal, which means that the authorization dialog box will not be displayed, and if it is not handled properly, it will cause a crash, such as [ RxPermissions/issues/249](https://github.com/tbruyelle/RxPermissions/issues/249). The reason is that the PermissionFragment in the framework will do a detection when `commit`/ `commitNow` arrives at the Activity. If the state of the Activity is invisible, an exception will be thrown, and **RxPermissions** It is the use of `commitNow` that will cause the crash, and the use of `commitAllowingStateLoss`/ `commitNowAllowingStateLoss` can avoid Enable this detection, although this can avoid crashes, but there will be another problem. The `requestPermissions` API provided by the system will not pop up the authorization dialog when the Activity is not visible. **XXPermissions** was resolved by moving the `requestPermissions` timing from `onCreate` to `onResume`, because `Activity` It is bundled with the life cycle method of `Fragment`. If `Activity` is invisible, then even if `Fragment` is created, only The `onCreate` method will be called instead of its `onResume` method. Finally, when the Activity returns from the background to the foreground, not only will the `onResume` method of `Activity` be triggered, but also the `onResume` method of `PermissionFragment` will be triggered. Applying for permissions in this method can ensure that the timing of the final `requestPermissions` call is when `Activity` is in a visible state.

#### Fix Android 12 Memory Leak Issue

* Recently someone asked me about a memory leak[ XXPermissions/issues/133 ](https://github.com/getActivity/XXPermissions/issues/133). After practice, I confirmed that this problem really exists, but by looking at the code stack, I found that this problem is caused by the code of the system, which caused this problem The following conditions are required:

    1. Use on Android 12 devices

    2. Called `Activity.shouldShowRequestPermissionRationale`

    3. After that, the activity.finish method is actively called in the code

* The process of troubleshooting: After tracing the code, it is found that the code call stack is like this

    * Activity.shouldShowRequestPermissionRationale

    * PackageManager.shouldShowRequestPermissionRationale (implementation object is ApplicationPackageManager)

    * PermissionManager.shouldShowRequestPermissionRationale

    * new PermissionManager(Context context)

    * new PermissionUsageHelper(Context context)

    * AppOpsManager.startWatchingStarted

* The culprit is that `PermissionUsageHelper` holds the `Context` object as a field, and calls `AppOpsManager.startWatchingStarted` in the constructor to start monitoring, so that PermissionUsageHelper The object will be added to the `AppOpsManager#mStartedWatchers` collection, so that when the Activity actively calls finish, it does not use `stopWatchingStarted` to remove the listener, resulting in  object has been held in the `AppOpsManager#mStartedWatchers` collection, which indirectly causes the Activity object to be unable to be recycled by the system.

* The solution to this problem is also very simple and rude, which is to replace the `Context` parameter passed in from the outer layer from the `Activity` object to the `Application` object That's right, some people may say, `Activity` only has the `shouldShowRequestPermissionRationale` method, but what should I do if there is no such method in Application? After looking at the implementation of this method, in fact, that method will eventually call the `PackageManager.shouldShowRequestPermissionRationale` method (**Hidden API, but not blacklisted**), so as long as you can get `PackageManager` object, and finally use reflection to execute this method, so that memory leaks can be avoided.

* Fortunately, Google did not include `PackageManager.shouldShowRequestPermissionRationale` in the reflection blacklist, otherwise there is no way to clean up this mess this time, or it can only be implemented by modifying the system source code, but this way I can only wait for Google to fix it in the subsequent Android version, but fortunately, after the `Android 12 L` version, this problem has been fixed, [ The specific submission record can be viewed here](https://cs.android.com/android/_/android/platform/frameworks/base/+/0d47a03bfa8f4ca54b883ff3c664cd4ea4a624d9:core/java/android/permission/PermissionUsageHelper.java;dlc=cec069482f80019c12f3c06c817d33fc5ad6151f), but for `Android 12` This is still a historical issue.

* It is worth noting that XXPermissions is the first and only framework of its kind to fix this problem. In addition, I also provided a solution to Google's [AndroidX](https://github.com/androidx/androidx/pull/435) project for free. At present, Merge Request has been merged into the main branch. I believe that through this move, the memory leak problem of nearly 1 billion Android 12 devices around the world will be solved.

#### Support for Code Error Detection

* In the daily maintenance of the framework, many people have reported to me that there are bugs in the framework, but after investigation and positioning, it is found that 95% of the problems come from some irregular operations of the caller, which not only caused great harm to me At the same time, it also greatly wasted the time and energy of many friends, so I added a lot of review elements to the framework, in **debug mode**, **debug mode**, **debug mode**, once some operations do not conform to the specification, the framework will directly throw an exception to the caller, and correctly guide the caller to correct the error in the exception information, for example:

    * If the caller applies for permissions without passing in any permissions, the framework will throw an exception.

    * The incoming Context instance is not an Activity object, the framework will throw an exception, or the state of the incoming Activity is abnormal (already **Finishing** or **Destroyed**), in this case Generally, it is caused by applying for permissions asynchronously, and the framework will also throw an exception. Please apply for permissions at the right time. If the timing of the application cannot be estimated, please make a good judgment on the activity status in the outer layer before applying for permissions.

    * If the current project is not adapted to partition storage, apply for `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` permissions

        * When the project's `targetSdkVersion >= 29`, you need to register the `android:requestLegacyExternalStorage="true"` attribute in the manifest file, otherwise the framework will throw an exception. If you don't add it, it will cause a problem, obviously it has been obtained Storage permissions, but the files on the external storage cannot be read and written normally on the Android 10 device.

        * When the project's `targetSdkVersion >= 30`, you cannot apply for `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` permissions, but should apply for `MANAGE_EXTERNAL_STORAGE` permissions

        * If the current project is already adapted to partitioned storage, you only need to register a meta-data attribute in the manifest file: `<meta-data android:name="ScopedStorage" android:value="true"/>`

    * If the requested permissions do not match the **targetSdkVersion** in the project, the framework will throw an exception because **targetSdkVersion** represents which Android version the project is adapted to, and the system will Automatically do backward compatibility, assuming that the application permission only appeared on Android 11, but **targetSdkVersion** is still at 29, then the application on some models will have authorization exceptions, and also That is, the user has clearly authorized, but the system always returns false.

    * If the dynamically applied permission is not registered in `AndroidManifest.xml`, the framework will throw an exception, because if you don’t do this, you can apply for permission, but there will be no authorization pop-up window, and it will be directly rejected by the system, and the system will not give any pop-up windows and prompts, and this problem is **Must-have** on every phone model.

    * If the dynamic application permission is registered in `AndroidManifest.xml`, but an inappropriate `android:maxSdkVersion` attribute value is set, the framework will throw an exception, for example: `<uses-permission android:name="xxxx" android:maxSdkVersion="29"/>`, such a setting will lead to the application of permissions on Android 11 ( `Build.VERSION.SDK_INT >= 30`) and above devices, the system will think that this permission is not registered in the manifest file, and directly reject it This permission application will not give any pop-up windows and prompts. This problem is also inevitable.

    * If you apply for the three permissions `MANAGE_EXTERNAL_STORAGE`, `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` at the same time, the framework will throw an exception, telling you not to apply at the same time These three permissions are because on Android 11 and above devices, if `MANAGE_EXTERNAL_STORAGE` permission is applied, `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` The necessity of permission, this is because applying for `MANAGE_EXTERNAL_STORAGE` permission is equivalent to possessing a more powerful ability than `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE`, If you insist on doing that, it will be counterproductive. Assuming that the framework allows it, there will be two authorization methods at the same time, one is pop-up authorization, and the other is page-jump authorization. The user needs to authorize twice, but in fact there are `MANAGE_EXTERNAL_STORAGE` permission is sufficient for use, at this time you may have a question in mind, you do not apply for `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` permission, Android There is no `MANAGE_EXTERNAL_STORAGE` permission below 11, isn't there a problem? Regarding this issue, you can rest assured that the framework will make judgments. If you apply for the `MANAGE_EXTERNAL_STORAGE` permission, the framework below Android 11 will automatically add `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` to apply, so it will not be unusable due to lack of permissions under lower versions.

    * If you don't need the above detections, you can turn them off by calling the `unchecked` method, but it should be noted that I don't recommend you to turn off this detection, because in **release mode** When it is closed, you don't need to close it manually, and it only triggers these detections under **debug mode**.

* The reason for these problems is that we are not familiar with these mechanisms, and if the framework does not impose restrictions, then various strange problems will arise. As the author of the framework, not only you are suffering, but also as the framework author. Injuried. Because these problems are not caused by the framework, but by some irregular operations of the caller. I think the best way to solve this problem is to do a unified inspection by the framework, because I am the author of the framework, and I have **Strong professional ability and sufficient experience** knowledge about permission application, and know what to do and what not to do. It should be done, In this way, these irregular operations can be intercepted one by one.

* When there is a problem with the permission application, do you hope that someone will come to remind you and tell you what is wrong? How to correct it? However, these XXPermissions have done it. Among all the permission request frameworks, I am the first person to do this. I think **make a frame** is not only to do a good job of function, but also to make complex The scene is handled well, and more importantly, **people oriented**, because the framework itself serves people, and what we need to do is not only to solve everyone's needs, but also to help everyone avoid detours in the process.

================================================
FILE: Details-zh.md
================================================
#### 目录

* [Intent 跳转极限兜底机制](#intent-跳转极限兜底机制)

* [兼容请求权限 API 崩溃问题](#兼容请求权限-api-崩溃问题)

* [规避系统权限回调空指针问题](#规避系统权限回调空指针问题)

* [应用商店权限合规处理](#应用商店权限合规处理)

* [自动拆分权限进行请求](#自动拆分权限进行请求)

* [框架内部完全剥离 UI 层](#框架内部完全剥离-ui-层)

* [核心逻辑和具体权限完全解耦](#核心逻辑和具体权限完全解耦)

* [自动适配后台权限](#自动适配后台权限)

* [支持在跨平台环境中调用](#支持在跨平台环境中调用)

* [回调生命周期与宿主保持同步](#回调生命周期与宿主保持同步)

* [支持自定义权限申请](#支持自定义权限申请)

* [支持读取应用列表权限](#支持读取应用列表权限)

* [新版本权限支持向下兼容](#新版本权限支持向下兼容)

* [屏幕旋转场景适配](#屏幕旋转场景适配)

* [后台申请权限场景适配](#后台申请权限场景适配)

* [修复 Android 12 内存泄漏问题](修复-android-12-内存泄漏问题)

* [第三方厂商兼容性优化](#第三方厂商兼容性优化)

* [支持检测代码错误](#支持检测代码错误)

#### Intent 跳转极限兜底机制

* 在介绍这个功能之前,我先问大家一个问题,请你分析一下这段代码是否有什么问题?

```java
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData("package:" + getPackageName());
startActivityForResult(intent, 1024);
```

* 你可能会说:很简单啊,这不就是一个跳转到应用详情页的代码,还能有什么问题?你莫不是要找我的茬?

* 这段代码看似没有问题,运行起来也没有问题,但实际上是一个天坑,你没有看到或者遇到并不代表不存在,有些厂商直接阉割了 `ACTION_APPLICATION_DETAILS_SETTINGS` 这个意图,是的你没有听错,就是直接阉割,这段代码在这些设备上面运行,应用就会闪崩,没有跟你开玩笑,

```text
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.settings.APPLICATION_DETAILS_SETTINGS dat=Package Name:com.xxx.xxx }
```

* 你如果还是不信,请看这里 [Github Search `No Activity found to handle Intent  act=android.settings.APPLICATION_DETAILS_SETTINGS`](https://github.com/search?q=No+Activity+found+to+handle+Intent++act%3Dandroid.settings.APPLICATION_DETAILS_SETTINGS&type=issues):

* 其实不止是 `ACTION_APPLICATION_DETAILS_SETTINGS` 这个意图,其他的意图也会,一个都跑不了,你如果不信可以看这里 [Github Search `No Activity found to handle Intent  act=android`](https://github.com/search?q=No+Activity+found+to+handle+Intent++act%3Dandroid&type=issues)。

```
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.settings.MANAGE_UNKNOWN_APP_SOURCES (has data) }
```

* 看完你是不是想吐槽一下?但问题已经存在,非理性的抱怨永远解决不了问题,只有理性的分析和认真的思考才是唯一的出路。这个问题无非是 `Intent` 找不到了,最简单有效的方法,就是在跳转前对 `Intent` 进行判断,如果存在这个 `Intent` 再跳转,如果不存在就不跳转,你如果要是真的那么想问题就太片面了,事情往往没有你想得那么简单,不存在的 `Intent` 跳转会失败,那你有没有想过,存在的 `Intent` 也不代表一定能跳转成功,你如果不信可以看这里 [Github Search `Permission Denial: starting Intent`](https://github.com/search?q=Permission+Denial%3A+starting+Intent&type=issues),现在知道为什么叫天坑了吧?

```text
java.lang.SecurityException: 
Permission Denial: starting Intent { act=android.settings.MANAGE_UNKNOWN_APP_SOURCES (has data) cmp=xxxx/xxx }
```

* 说这些并不是想让大家解决,而是让大家意识到有这个问题,当然框架内部已经处理好这个问题,你能想到的所有问题,框架已经提前想到了,并且已经帮你处理好了,只需要一句代码,调用 `XXPermissions.startPermissionActivity` 方法即可。假设你很好奇框架是怎么实现的,又懒得看源码实现,这点我也帮你想到了,在这里我介绍框架是怎么实现的,原理其实很简单,框架获取这个权限设置页的时候,把能想到的 `Intent` 写到 List 集合中,再筛选掉不存在的 `Intent`,然后挨个 `Intent` 进行跳转,如果失败就跳转到下一个,直到跳转成功或者没有下一个 `Intent` 了为止。

#### 兼容请求权限 API 崩溃问题

* 在介绍这个功能之前,我先问大家一个问题,请你分析一下这段代码是否有什么问题?

```java
activity.requestPermissions(new String[]{Manifest.permission.CAMERA}, 1024);
```

* 你可能会说:这不就是一段再简单不过用系统 API 申请权限的代码吗?还能有什么问题,你只要不在 Android 6.0 以下的设备调用就肯定没有问题。

* 理论上是这样的,但是理论终究是理论,实际情况是在 Android 6.0 及以上的设备调用也有可能出现崩溃,对的你没有看错,Android 6.0 以上调用会出现崩溃,听着也太魔幻了,那么重要的系统 API 居然也会崩溃?如果不信可以看这里 [XXPermissions/issues/153](https://github.com/getActivity/XXPermissions/issues/153)、[XXPermissions/issues/126](https://github.com/getActivity/XXPermissions/issues/126)、[XXPermissions/issues/327](https://github.com/getActivity/XXPermissions/issues/327)、[XXPermissions/issues/339](https://github.com/getActivity/XXPermissions/issues/339),如果还不够看的话可以看这里 [Github Search `act=android.content.pm.action.REQUEST_PERMISSIONS`](https://github.com/search?q=act%3Dandroid.content.pm.action.REQUEST_PERMISSIONS&type=issues),看完是不是瞬间颠覆了你的认知?

```text
android.content.ActivityNotFoundException: 
No Activity found to handle Intent { act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.android.packageinstaller (has extras) }
```

* 出现这种情况有以下几种可能:

    1. 厂商开发工程师修改了 `com.android.packageinstaller` 系统应用的包名,但是没有自测好就上线了(概率较小)

    2. 厂商开发工程师删除了 `com.android.packageinstaller` 这个系统应用,但是没有自测好就上线了(概率较小)

    3. 厂商开发工程师在修改 Android 系统源码的时候,改动的代码影响到权限模块,但是没有自测好就上线了(概率较小)

    4. 厂商主动阉割掉了权限申请功能,例如在电视 TV 设备上面,间接导致请求危险权限的 App 一请求权限就闪退(概率较小)

    5. 用户有 Root 权限,在精简系统 App 的时候不小心删掉了 `com.android.packageinstaller` 这个系统应用(概率较大)

* 经过分析 `Activity.requestPermissions` 的源码,它本质上还是调用 `startActivityForResult`,只不过 `Activity` 找不到了而已,目前能想到最好的解决方式,就是用 `try catch` 避免它出现崩溃,看到这里你可能会有一个疑问,就简单粗暴 `try catch`?你确定不会引发其他问题?会不会导致 `onRequestPermissionsResult` 没有回调?从而导致权限请求流程卡住的情况?虽然这个问题没有办法测试,但理论上是不会的,因为我用了错误的 `Intent` 进行 `startActivityForResult` 并进行 `try catch` 做实验,结果 `onActivityResult` 还是有被系统正常回调,证明对 `startActivityForResult` 进行 `try catch` 并不会影响 `onActivityResult` 的回调,我还分析了 `Activity` 回调方面的源码实现,发现无论是 `onRequestPermissionsResult` 还是 `onActivityResult`,回调它们的都是 `dispatchActivityResult` 方法,在那种极端情况下,既然 `onActivityResult` 能被回调,那么就证明 `dispatchActivityResult` 肯定有被系统正常调用的,同理 `onRequestPermissionsResult` 也肯定会被 `dispatchActivityResult` 正常调用,从而形成一个完整的逻辑闭环。

* 补充后续测试结论:我在 debug 了 `Activity.requestPermissions` 方法,偷偷修改权限请求 `Intent` 的 `Action` 成错误的,结果权限回调能正常回调。

* 如果真的出现这种极端情况,所有危险权限的申请必然会走失败的回调,但是框架能做的是:尽量让应用不要崩溃,并且能走完整个权限申请的流程。

#### 规避系统权限回调空指针问题

* 在介绍这个功能之前,我先问大家一个问题,请你分析一下这段代码是否有什么问题?

```java
public final class XxxActivity extends AppCompatActivity  {

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (permissions.length == 0 || grantResults.length == 0) {
            return;
        }
        if (permissions[0].equals(Manifest.permission.CAMERA) && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            System.out.println("获取相机权限成功");
        } else {
            System.out.println("获取相机权限失败");
        }
    }
}
```

* 你可能会说:这不是正常在权限回调中处理权限请求结果,我平时就是那么写的,怎么看都没有什么毛病啊,你是不是没事找茬?

* 如果我告诉你一件事,系统返回的参数 `permissions` 或 `grantResults` 数组对象有可能会为空,你会不会相信呢?我知道你肯定不信,因为你看到了 `permissions` 和 `grantResults` 参数上面都有 `@NonNull` 注解(点进去 Activity 源码里面看到的也是  `@NonNull` 注解),就代表系统返回的一定不为空,到这里你肯定认为我在欺骗你。

* 我知道你不信,所以证据给你备好了,请看这里 [XXPermissions/issues/191](https://github.com/getActivity/XXPermissions/issues/191)、[XXPermissions/issues/106](https://github.com/getActivity/XXPermissions/issues/106)、[XXPermissions/issues/236](https://github.com/getActivity/XXPermissions/issues/236),如果还不够看的话可以看这里 [Github Search `NullPointerException onRequestPermissionsResult`](https://github.com/search?q=NullPointerException+onRequestPermissionsResult&type=issues);

* 看完是不是不知道你是何种想法?系统这是要闹哪样?把参数标记成不为空结果却给我返回空的,这难道不是在欺骗我的感情?问题已经存在,非理性的抱怨永远解决不了问题,只有理性的分析和认真的思考才是唯一的出路。

* 目前反馈这个问题的机型品牌有 vivo、小米、联想;就说明这个问题大概率又是 `Google` 工程师挖的坑,解决这个问题的思路有两种:

    1. 仍然要用 `permissions` 和 `grantResults` 参数来判断权限的状态:使用之前需要先对数组对象进行防空判断,然后继续使用。

    2. 不再使用  `permissions` 和 `grantResults`  参数来判断权限的状态:改用 `checkSelfPermission` 的方式来判断权限状态。

* 虽然两种都可以解决问题,但是两种略有区别,框架最终采用的是第二种,中国有一句老话叫:一次不忠终身不用,既然它能干这种毫无底线的事情,就不得不防它还有其他小动作,例如以下场景:

    1. 返回的数组对象不为空,但是数组里面没有元素,如果事先不进行判断,一调用就可能会触发角标越界异常 `ArrayIndexOutOfBoundsException`

    2. 返回的数组对象不为空,数组里面也有元素,但是 `permissions` 和 `grantResults` 两个数组的长度不一样,如果事先不进行判断,一调用就可能会触发角标越界异常 `ArrayIndexOutOfBoundsException`

    3. 返回的数组对象不为空,数组里面也有元素,两个数组的长度也是正常的,但是返回的 `grantResults` 与实际不匹配,用户明明授予了权限,但是这个数组存的却是 `-1`(`PackageManager.PERMISSION_DENIED`)

* 到这里你是不是瞬间觉得解决这个空指针的问题好像不是只是加一下防空判断那么简单?原来里面的学问那么多。在此我想跟大家说,无论是什么问题,我都会认真对待,因为我追求的从来不是能解决问题就好,而是在所有能想到的解决方案中找出最优解。

#### 应用商店权限合规处理

* 现在国内的应用商店,在申请权限的时候,需要同步告知权限申请的目的,否则会被拒绝上架或更新,框架已经帮你考虑到这点了,目前已经开放相应的接口,你可以实现接口来这一需求,具体效果如下图所示:

* 虽然这个功能自己不需要框架提供接口也能实现,只需要在权限申请前显示弹窗,权限申请完成取消弹窗就行,但是这样会使你写的代码不优雅,因为这部分的代码是直接写死在 `Activity/Fragment` 类中的,不仅会增加 `Activity/Fragment` 类的复杂度,并且每个用到权限申请的 `Activity/Fragment` 类都要写一份这样的代码,后续会变得难以维护,正是考虑到这个问题,框架才开放了这个接口,还在 Demo 工程实现了一份完整的案例供你参考,你不仅可以轻而易举实现这个功能,过程无需操心实现的细节和是否有 Bug,因为你能想到的,我都帮你想到了,你没有想到的,我也帮你想到了。

#### 自动拆分权限进行请求

* 在一些需求场景下,需要同时申请多种权限,例如麦克风权限和日历权限,这个时候产品经理想要拆分成两次权限进行申请,以便能够分开显示两个权限的说明弹窗,这样的设计会导致功能开发比较复杂,如果不拆分申请的情况下只需要在请求权限前后加一下显示和关闭弹窗的逻辑就行了,现在要分成两次权限申请后就不能这样写了,只能分开写,分开写就意味着要写各种嵌套和回调,一想到要这样做就一个头两个大,差点就把昨晚吃的宵夜给呕出来。

* 大家的苦,大家的痛,不用多说,我都懂,所以我在框架加了一套处理机制,会自动将你传入的权限进行归类分组,例如麦克风权限归为一组,日历权限归为一组,然后会拆分成两次权限申请,这个时候在搭配上框架开放的权限说明接口,这个接口会告诉你申请什么权限,你再根据权限来展示具体的权限说明弹窗就行了,至此这个功能轻松又优雅地完成了,iOS 端还吭哧吭哧实现,你已经完成并提前下班了,没有延迟,没有痛苦,有的只是实现功能的爽感。

#### 框架内部完全剥离 UI 层

* 某些权限框架内部会实现一套权限说明弹窗的 UI 和逻辑,需要实现特定的接口才能修改,但是我认为这样的设计是不合理的,因为展示权限说明弹窗并不是一个必须的操作,没有它调用权限申请 API 照样会弹出授权框,另外涉及到 UI,框架内部设计的 UI 注定无法满足所有人的需求(吃力不讨好),因为每个人拿到的设计图都是不一样的,所以最好的方案是,框架自己不要在内部写 UI 和逻辑,而是设计好这方面相关的接口,然后全权交由外层实现,当然框架 Demo 模块也会实现一份案例供外层借鉴(供外层直接抄代码),这样不仅能解决 UI 需求不一致的问题,还能减少框架的体积,一箭双雕。

#### 核心逻辑和具体权限完全解耦

* 你在市面上能看到的能同时支持申请危险权限和特殊权限的框架,它们的代码耦合度非常高,这样会导致一个问题,例如你只拿它申请了危险权限,但是最终打包的时候,会连同特殊权限的代码逻辑一起给打包到 apk 中的,这就好比你现在想吃炸鸡,但店员告诉你只有点十个人的套餐才有炸鸡,你心想自己一个人就算撑死也没有办法吃完这十个人的套餐,这种设计不是明摆着坑人吗?虽然 app 多一些代码不会跟人一样被撑死,但是也不要肆意挥霍,这里浪费一点,那里浪费一点,开发完后一看 apk 体积 250 mb,还得考虑体积优化,关键是你还没有办法优化,因为这部分代码是写死在框架中,框架又是通过远程依赖,你就得换成本地依赖去改,改了就意味着可能有 bug 要增加很多自测的工作量,重要的是改了收益不高,但是风险极高,很容易改着改着将自己送上裁员名单。

* 针对这个问题,框架有一个堪称鬼才的设计方案,就是将不同权限的实现封装成对象,你申请什么权限就传什么对象,这样没有引用的对象就会在开启代码混淆的时候一并移除,这样打正式包的时候就不会有冗余的代码,更不会占用多余的 apk 的体积,真正做到了用多少算多少,再也不用为了想吃一块炸鸡而考虑要不要买个十个套餐,无需纠结,无需徘徊,在 XXPermissions 这里可以做到分开买,想吃什么买什么,想吃多少买多少,老少兼宜,童叟无欺。

* 当然对于某些框架,它既不支持任何特殊权限,也没有针对某个危险权限做单独的处理,只是简单套用系统的 API,请求权限就直接用 `context.requestPermissions`,判断权限就直接用 `context.checkSelfPermission`,这种算不算完全解耦呢?其实是算的,因为人家确实没有在核心逻辑中直接依赖具体某个权限,但是这种框架不符合现实开发的需求,因为在一个商业化的 app 中不可能只请求危险权限,通知权限要吧?安装包权限要吧?悬浮窗权限要吧?只要这些框架支持任何一个特殊权限,就会存在这个问题,当然不支持当然就没有这个问题,关键是能不能做到既能支持,又能对代码进行解耦呢?这才是问题的关键,非常考验对框架的理解和代码的设计,截止目前只有 XXPermissions 真正做到了既要又要。

#### 自动适配后台权限

* Android 10 上面新增了[后台定位权限](https://developer.android.google.cn/about/versions/11/privacy/location?hl=zh-cn#background-location) 和 Android 13 上面新增了[后台传感器权限](https://developer.android.google.cn/about/versions/13/behavior-changes-13?hl=zh-cn#body-sensors-background-permission),你可千万别认为这两个后台权限跟普通的危险权限没有区别,这里面的区别非常大,要是没有搞清楚容易出 Bug。

    1. 前台权限和后台权限不能放在一起申请,必须先申请前台权限,才能申请后台权限,如果在没有前台权限的前提下申请后台权限是肯定会被系统拒绝的,这是毋庸置疑的。

    2. 在 Android 11 之后,前台权限和后台权限申请必须保证一定的时间间隔,也就是拆分两次权限申请之后,还要保证这两次权限申请有一定的时间间隔,否则也会申请失败,经过测试不能低于 150 毫秒。

    3. 后台定位权限对应的前台定位权限有两个,精确定位权限(`ACCESS_FINE_LOCATION`)和模糊定位权限(`ACCESS_COARSE_LOCATION`),在 `Android 10 ~ Android 11` 的版本,后台定位权限锚定的前台权限就是精确定位权限,只有这个权限同意的时候,才能申请后台定位权限,而到了 Android 12 及之后的版本,后台定位权限锚定的前台权限既可以是精确定位权限,也可以是模糊定位权限,这两个权限任一同意的时候,就可以申请后台定位权限。

* 然而上面这些问题,框架已经帮你处理了,你无需自己再手动处理,具体处理方案如下:

    1. 自动识别后台权限和与之对应的前台权限,然后自动拆分成两次权限申请,先申请前台权限,再申请后台权限。

    2. 在申请后台权限的时候,先加一段时间的延迟,也就是前面说的 150 毫秒,再进行申请后台权限,由此规避这个问题。

    3. 在判断后台定位权限的时候,会针对不同的 Android 版本做前台定位权限判断,在 `Android 10 ~ Android 11` 的版本就用精确定位权限,`Android 12` 及之后的版本就用精确定位权限或者模糊定位权限,确保不同 Android 版本能达到同样的预期效果。

#### 支持在跨平台环境中调用

* 众所周知 [FlutterActivity](https://github.com/flutter/flutter/blob/03ef1ba910cac387f7b2af8ab09ca955d3974663/engine/src/flutter/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java)、[ComposeActivity](https://github.com/androidx/androidx/blob/8d08d42d60f7cc7ec0034d0b7ff6fd953516d96a/emoji2/emoji2-emojipicker/samples/src/main/java/androidx/emoji2/emojipicker/samples/ComposeActivity.kt)、[UnityPlayerActivity](https://github.com/FabianTerhorst/PokemonGo/blob/d511b045f1492e0bae71778ef528f3d768d218cd/java/com/unity3d/player/UnityPlayerActivity.java)、[Cocos2dxActivity](https://github.com/irontec/Ikasesteka/blob/master/Ikasesteka/cocos2d/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxActivity.java) 这些都是 Activity 的子类,但是它们都不是 [FragmentActivity](https://github.com/androidx/androidx/blob/8d08d42d60f7cc7ec0034d0b7ff6fd953516d96a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java) 的子类,它们的继承关系是这样的:

    1. `FlutterActivity extends Activity`

    2. `ComposeActivity extends ComponentActivity extends Activity`

    3. `UnityPlayerActivity extends Activity`

    4. `Cocos2dxActivity extends Activity`

    5. `FragmentActivity extends ComponentActivity extends Activity`

* 这样就会出现一个问题,有些权限请求框架是用一个透明的 `Fragment` 获得权限申请的回调,如果这个权限请求框架用的是 `androidx.fragment.app.Fragment`,那么就必须要求外层传入 `androidx.fragment.app.FragmentActivity` 对象,假设这个时候你用的 `Activity` 并不是 `androidx.fragment.app.FragmentActivity` 的子类,请问你该怎么办?那简单,我就修改当前 `Activity` 直接继承 `androidx.fragment.app.FragmentActivity` 不就行了?那如果你目前的 `Activity` 是一定要继承 `FlutterActivity`、`ComposeActivity`、`UnityPlayerActivity`、`Cocos2dxActivity` 呢?请问你又该怎么改?难不成去改它们的源码?还是去改权限框架的源码?无论选哪种解决方案,改造的成本都会很大,后续也不好维护,这既不现实,也不科学。是不是突然感觉上天把路给你堵死了?难不成只能手写权限申请 API 的代码才能实现权限请求了?

* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,具体的实现原理是:框架会判断你传入的 `Activity` 对象是不是 `androidx.fragment.app.FragmentActivity` 的子类,如果是的话,则会用 `androidx.fragment.app.Fragment` 进行权限申请,如果不是的话,则会用 `android.app.Fragment` 进行权限申请,这样无论你用哪种 `Activity`,框架都能自动进行适配。

#### 回调生命周期与宿主保持同步

* 目前市面上大多数权限请求框架都会用单种 `Fragment` 处理权限请求回调,但是这样会导致一个问题,假设某个框架用的是 `androidx.fragment.app.Fragment` 处理权限请求回调,但是你却是在 `android.app.Fragment` 发起的权限请求,又或者反过来,你用 `androidx.fragment.app.Fragment` 框架用 `android.app.Fragment`,你无法把你自己的 `Fragment` 当做宿主,然后传给权限请求框架,只能通过 `fragment.getActivity()` 将 `Activity` 对象传给框架,这样 `Activity` 就成了宿主对象,这样都会导致一个生命周期不同步的问题,就是你自己的 `Fragment` 已经销毁的情况,但是框架仍会回调权限请求结果的监听器,轻则导致 `Memory leak`,重则会触发 `Exception`。

* 导致这个问题的原因是,第三方框架用的 `Fragment` 和你的 `Fragment` 实际上不是一个类型的,虽然它们的类名一样,但是它们所在的包名不一样,加上刚刚说的你只能通过 `fragment.getActivity()` 将 `Activity` 对象传给框架,这样你自己的 `Fragment` 无法和框架的 `Fragment` 之间无法形成一种有效的生命周期绑定,实际你想要的是绑定你自己 `Fragment` 的生命周期,但框架最终绑定的是 `Activity` 生命周期,这样很可能会触发 Crash,具体表现你可以看一下这个 issue:[XXPermissions/issues/365](https://github.com/getActivity/XXPermissions/issues/365)。

* 其实这个问题框架已经想到了,并且已经帮你解决了,无需你做任何处理,解决这个问题的思路是:框架会根据你传入的对象类型,自动选择最佳类型的 `Fragment`,假设你传入的宿主是 `androidx.fragment.app.FragmentActivity` 或者 `androidx.fragment.app.Fragment` 对象,框架内部则会创建 `androidx.fragment.app.Fragment` 来接收权限请求回调,假设你传入的宿主是普通的 `Activity` 或者 `android.app.Fragment`,框架内部则会创建 `android.app.Fragment` 来接收权限请求回调,这样无论你传入的是什么宿主对象,框架都会和它的生命周期做绑定,确保在回调权限请求结果给到最外层的时候,宿主对象仍处于正常的状态。

* 这个时候你可能会跳出来说,这个不用框架我也能实现,我自己在权限回调的方法中,自己手动判断一下 `Fragment` 的状态不就行了?不就是两三句代码的事情?框架为什么搞得那么麻烦?你的想法看似有道理,但实则经不起推敲,假设你的项目有十几处地方申请了权限,那么你需要在每个回调方法都考虑这个问题,另外后续申请新的权限,你也要考虑这个问题,你能确保自己改的时候不会出现漏网之鱼?还有假设这个需求是你的同事开发的,但是只有你知道这个事情,他并不知情的情况下,你知道这种情况下可能会发生什么吗?我相信你比我更懂。你提供的解决问题方法,虽然可以暂时解决问题,但是治标不治本,究其根本是解决的思路有问题,遵循的是有洞补洞的思维,而没有想从源头堵住漏洞。又或者你原本就知道怎么彻底根治,只不过选择了最轻松的方式来处理,但这无疑是给项目埋了一颗定时炸弹。

#### 支持自定义权限申请

* 顾名思义,开发者除了可以申请框架中已支持的权限,还支持申请开发者自己定义的权限,这个功能非常强大,此功能可以满足以下场景的需求:

    1. 可以定义一些框架不支持的权限并进行申请,例如开机自启权限、桌面快捷方式权限、读取剪贴板权限、写入剪贴板权限、操作外部存储 `Android/data` 权限,特定厂商的一些权限等等适配,甚至是[蓝牙开关、WIFI 开关、定位开关](https://github.com/getActivity/XXPermissions/issues/170)等等,此处请尽情发挥你的想象力,现在只需要继承框架提供的 `DangerousPermission` 或 `SpecialPermission` 类即可实现自定义权限,要知道这个功能放在之前的版本只能通过修改框架的源码才能实现,过程十分麻烦,你不仅要研究框架的源码,又要在修改后做严格的自测,而现在不需要这样做了,框架对外提供了这个扩展接口,实现一个接口即可实现。

    2. 开发者不需要再依赖权限框架作者来适配新的权限,当 Google 发布了新的 Android 版本,并且增加了新的权限,而框架来不及适配,而你又急需申请这个新的权限,那么这个时候可以使用这个功能,率先对新权限进行适配。

#### 支持读取应用列表权限

* 这个权限非常特殊,它不属于 Android 原生的权限,而是由[工信部](http://www.taf.org.cn/StdDetail.aspx?uid=3A7D6656-43B8-4C46-8871-E379A3EA1D48&stdType=TAF)牵头,联合各大中国手机厂商搞的一个权限,目前支持手机厂商有:

|     品牌    |                版本要求           | 是否默认授予 |
| :--------: | :------------------------------: | :--------: |
|     华为   |       HarmonyOS 3.0.0 及以上版本     |      否     |
|     荣耀   |       MagicOS 6.0 及以上版本         |      否     |
|     小米   |  MIUI 13 或 HyperOS 1.0.0 及以上版本  |  MIUI 默认授予 </br> HyperOS 默认没有授予   |
|     红米   |              和小米雷同               |   和小米雷同  |
|     OPPO  |       (ColorOS 12 及以上版本 && Android 11+) 或者 </br> (ColorOS 11.1 及以上版本 && Android 12+)        |      否     |
|     VIVO  |       OriginOS 4 && Android 14      |      否      |
|     一加   |           和 OPPO 雷同               |  和 OPPO 雷同 |
|     真我   |       RealmeUI 3.0 及以上版本         |      否     |

* 目前不支持的手机厂商有:

|   品牌    |   测试的手机机型    |             测试的版本                | 是否有申请该权限的入口 |
| :------: | :---------------: | :---------------------------------: | :-----------------: |
|    魅族   |     魅族 18x      |     Flyme 9.2.3.1A && Android 11    |          是         |
|    锤子   |   坚果手机 Pro 2S  | SmartisanOS 7.2.0.2 && Android 8.1  |          否         |
|    奇虎   |  360 手机 N7 Lite |      360UI 3.0 && Android 8.1       |          否         |
|   小辣椒   |     小辣椒S6      |    小辣椒 Os 3.0 && Android 7.1.1    |          否         |

* 还有一些厂商没有列出来,并不是作者没有做测试,而是他们的系统本身就是直接用 Android 的,Android 原生目前不支持申请该权限

* 另外框架还做了一些特殊处理:

    * 在小米手机的 MIUI,但是这套机制只支持 MIUI 13 及以上的版本,然而框架内部做了一些兼容手段,目前已经适配了所有 MIUI 版本读取应用列表权限的申请。

    * 三星手机从 OneUI 5.1.1 开始支持读取应用列表权限,但是这套机制完全不支持,然而框架内部做了一些兼容手段,目前已经适配了所有 OneUI 版本读取应用列表权限的申请。

    * 魅族手机从 Flyme 8.x(不知道具体是哪个版本)开始支持读取应用列表权限,但是这套机制完全不支持,然而框架内部做了一些兼容手段,目前已经适配了 Flyme 9.x 及之后的版本读取应用列表权限的申请。

#### 新版本权限支持向下兼容

* 随着 Android 版本的不断更新,危险权限和特殊权限也在增加,那么这个时候会有一个版本兼容问题,高版本的安卓设备是支持申请低版本的权限,但是低版本的安卓设备是不支持申请高版本的权限,那么这个时候会出现一个兼容性的问题。

* 经过核查,其他权限框架选择了一种最简单粗暴的方式,就是不去做兼容,而是交给外层的调用者做兼容,需要调用者在外层先判断安卓版本,在高版本上面传入新权限给框架,而在低版本上面传入旧权限给框架,这种方式看似简单粗暴,但是开发体验差,同时也暗藏了一个坑,外层的调用者他们知道这个新权限对应着的旧权限是哪个吗?我觉得不是每个人都知道,而一旦认知出现错误,必然会导致结果出现错误。

* 我觉得最好的做法是交给框架来做,**XXPermissions** 正是那么做的,外层调用者申请高版本权限的时候,那么在低版本设备上面,会自动添加低版本的权限进行申请,举个最简单的例子,Android 11 出现的 `MANAGE_EXTERNAL_STORAGE` 新权限,如果是在 Android 10 及以下的设备申请这个权限时,框架会自动添加 `READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 进行申请,在 Android 10 及以下的设备上面,我们可以直接把 `READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 当做 `MANAGE_EXTERNAL_STORAGE` 来用,因为 `MANAGE_EXTERNAL_STORAGE` 能干的事情,在 Android 10 及以下的设备上面,要用 `READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 才能做得了。

* 所以大家在使用 **XXPermissions** 的时候,直接拿新的权限去申请就可以了,完全不需要关心新旧权限的兼容问题,框架会自动帮你做处理的,与其他框架不同的是,我更想做的是让大家一句代码搞定权限请求,框架能做到的,统统交给框架做处理。

#### 屏幕旋转场景适配

* 当系统权限申请对话框弹出后对 Activity 进行屏幕旋转,会导致权限申请回调失效,因为屏幕旋转会导致框架中的 Fragment 销毁重建,这样会导致里面的回调对象直接被回收,最终导致回调不正常。解决方案有几种,一是在清单文件中添加  `android:configChanges="orientation"` 属性,这样屏幕旋转时不会导致 Activity 和 Fragment 销毁重建,二是直接在清单文件中固定 Activity 显示的方向,但是以上两种方案都要使用框架的人处理,这样显然是不够灵活的,解铃还须系铃人,框架的问题应当由框架来解决,而 **RxPermissions** 的解决方式是给 PermissionFragment 对象设置 `fragment.setRetainInstance(true)`,这样就算屏幕旋转了,Activity 对象会销毁重建,而 Fragment 也不会跟着销毁重建,还是复用着之前那个对象,但是存在一个问题,如果 Activity 重写了 `onSaveInstanceState` 方法会直接导致这种方式失效,这样做显然只是治标不治本,而 **XXPermissions** 的方式会更直接点,在 **PermissionFragment** 绑定到 Activity 上面时,把当前 Activity 的**屏幕方向固定住**,在权限申请结束后再把**屏幕方向还原回去**。

* 在所有的权限请求框架中,只要使用了 Activity/Fragment 申请权限都会出现这个问题,因为只要用户一转动屏幕,就会导致权限回调无法正常回调,目前 XXPermissions 为数不多解决这个问题的框架,而 PermissionX 则是直接借鉴了 XXPermissions 的解决方案,详情请见 [XXPermissions/issues/49](https://github.com/getActivity/XXPermissions/issues/49) 、[PermissionX/issues/51](https://github.com/guolindev/PermissionX/issues/51)。

#### 后台申请权限场景适配

* 当我们做耗时操作之后申请权限(例如在闪屏页获取隐私协议再申请权限),在网络请求的过程中将 Activity 返回桌面去(退到后台),然后会导致权限请求是在后台状态中进行,在这个时机上就可能会导致权限申请不正常,表现为不会显示授权对话框,处理不当的还会导致崩溃,例如 [RxPermissions/issues/249](https://github.com/tbruyelle/RxPermissions/issues/249)。原因在于框架中的 PermissionFragment 在 `commit` / `commitNow` 到 Activity 的时候会做一个检测,如果 Activity 的状态是不可见时则会抛出异常,而 **RxPermissions** 正是使用了 `commitNow` 才会导致崩溃 ,使用 `commitAllowingStateLoss` / `commitNowAllowingStateLoss` 则可以避开这个检测,虽然这样可以避免崩溃,但是会出现另外一个问题,系统提供的 `requestPermissions` API 在 Activity 不可见时调用也不会弹出授权对话框,**XXPermissions** 的解决方式是将 `requestPermissions` 时机从 `onCreate` 转移到了 `onResume`,这是因为 `Activity` 和 `Fragment` 的生命周期方法是捆绑在一起的,如果 `Activity` 是不可见的,那么就算创建了 `Fragment` 也只会调用 `onCreate` 方法,而不会去调用它的 `onResume` 方法,最后当 Activity 从后台返回到前台时,不仅会触发 `Activity` 的 `onResume` 方法,也会触发 `PermissionFragment` 的 `onResume` 方法,在这个方法申请权限就可以保证最终 `requestPermissions` 调用的时机是在 `Activity` 处于可见状态的情况下。

#### 修复 Android 12 内存泄漏问题

* 最近有人跟我提了一个内存泄漏的问题 [XXPermissions/issues/133](https://github.com/getActivity/XXPermissions/issues/133) ,我经过实践后确认这个问题真实存在,但是通过查看代码堆栈,发现这个问题是系统的代码引起的,引发这个问题需要以下几个条件:

    1. 在 Android 12 的设备上使用

    2. 调用了 `Activity.shouldShowRequestPermissionRationale`

    3. 在这之后又主动在代码调用了 activity.finish 方法

* 排查的过程:经过对代码的追踪,发现代码调用栈是这样的

    * Activity.shouldShowRequestPermissionRationale

    * PackageManager.shouldShowRequestPermissionRationale(实现对象为 ApplicationPackageManager)

    * PermissionManager.shouldShowRequestPermissionRationale

    * new PermissionManager(Context context)

    * new PermissionUsageHelper(Context context)

    * AppOpsManager.startWatchingStarted

* 罪魁祸首其实是 `PermissionUsageHelper` 将 `Context` 对象作为字段持有着,并在构造函数中调用 `AppOpsManager.startWatchingStarted` 开启监听,这样 PermissionUsageHelper 对象就会被添加进 `AppOpsManager#mStartedWatchers` 集合中,这样导致在 Activity 主动调用 finish 的时候,并没有使用 `stopWatchingStarted` 来移除监听,导致 `Activity` 对象一直被 `AppOpsManager#mStartedWatchers` 集合中持有着,所以间接导致了 Activity 对象无法被系统回收。

* 针对这个问题处理也很简单粗暴,就是将在外层传入的 `Context` 参数从 `Activity` 对象给替换成 `Application` 对象即可,有人可能会说了,`Activity` 里面才有 `shouldShowRequestPermissionRationale` 方法,而 Application 里面没有这个方法怎么办?看了一下这个方法的实现,其实那个方法最终会调用 `PackageManager.shouldShowRequestPermissionRationale` 方法(**隐藏 API,但是并不在黑名单中**)里面去,所以只要能获取到 `PackageManager` 对象即可,最后再使用反射去执行这个方法,这样就能避免出现内存泄漏。

* 幸好 Google 没有将 `PackageManager.shouldShowRequestPermissionRationale` 列入到反射黑名单中,否则这次想给 Google 擦屁股都没有办法了,要不然只能用修改系统源码实现的方式,但这种方式只能等谷歌在后续的 Android 版本上面修复了,不过庆幸的是,在 `Android 12 L` 的版本之后,这个问题被修复了,[具体的提交记录可以点击此处查看](https://cs.android.com/android/_/android/platform/frameworks/base/+/0d47a03bfa8f4ca54b883ff3c664cd4ea4a624d9:core/java/android/permission/PermissionUsageHelper.java;dlc=cec069482f80019c12f3c06c817d33fc5ad6151f),但是对于 `Android 12` 而言,这仍是一个历史遗留问题。

* 值得注意的是:XXPermissions 是目前同类框架第一款也是唯一一款修复这个问题的框架,另外针对这个问题,我还给谷歌的 [AndroidX](https://github.com/androidx/androidx/pull/435) 项目无偿提供了解决方案,目前 Merge Request 已被合入主分支,我相信通过这一举措,将解决全球近 10 亿台 Android 12 设备出现的内存泄露问题。

#### 第三方厂商兼容性优化

* 虽然我填的很多坑都是 Google 工程师给挖的,但是这里面也有国内厂商工程师的一份,他们的骚操作对比 Google 有过之而不及,真是应征了那句话,世界是一个草台班子,这里就不多说了,说多了全是泪,直接进入主题:

    1. `GET_INSTALLED_APPS` 这个权限是工信部联合各大手机厂商推出的,框架除了按照这套标准进行适配,还做了额外的适配:

        * 三星的 OneUI 5.1.1 开始支持这个权限,但不是按照工信部出台的这套标准来做的,如果只是按照工信部的标准来适配,根本无法申请这个权限,但是框架内部针对 OneUI 进行了兼容,目前所有的 OneUI 版本都支持申请该权限。

        * 小米的 MIUI 13 开始按照工信部的要求进行适配,如果是之前的机型则可能无法申请该权限,但是框架内部针对低版本的 MIUI 进行了兼容,目前所有的 MIUI 版本都支持申请该权限。

        * 魅族 Flyme 8.x 有这个读取应用列表权限的入口,但是经过测试发现,Flyme 并没有按照工信部出台的这套标准来做的,也就是在这种情况是无法申请到这个权限的,然而框架内部做了一些兼容手段,目前已经适配了 Flyme 9.x 及之后的版本读取应用列表权限的申请。

    2. 悬浮窗权限兼容 Android 6.0 及以下机型:众所周知 `SYSTEM_ALERT_WINDOW` 是 Android 6.0 才开始新增的特殊权限,在此之前的版本是不支持的,但是有一些国内厂商已经提前做了这个权限,这就会导致一个兼容问题,有部分 Android 6.0 以下的用户是无法申请悬浮窗权限,针对这个问题,框架目前进行了兼容,目前所有的机型都支持申请该权限。

    3.  `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` 权限针对小米机型的优化:请求忽略电池优化选项权限在用户授权后,发现在小米机型用代码判断权限状态还是 false,然后再次点击申请权限,却发现权限已经授予,经过排查后发现,在授权后不能立即判断这个权限的状态,否则是不准确的,需要延迟一段时间判断才是准确的,经过无数次实验,确定需要延迟 1000 毫秒才没问题,众所周知 1000 毫秒等于 1 秒,这个延迟也太大了,我都怀疑他们到底有没有自测就把代码发出来了,不过有一个好消息,后续发现澎湃 2.0 修复了这个 Bug,至于为什么会修复这个问题,我对比了一下澎湃 1.0 和澎湃 2.0,结果发现请求忽略电池优化选项权限的设置页 UI 有很大的改动,我想如果他们这辈子没有进行大改版,这个 Bug 将会永远存在。

    4. `ACCESS_NOTIFICATION_POLICY` 针对华为或者荣耀机型兼容性处理:勿扰权限在华为或者荣耀机型上面无法跳转到当前应用的勿扰权限设置页,只能跳转到所有应用的勿扰权限列表页,再找到对应开启,到这里肯定有人站出来说了,这就是送分题,你在跳转之前,先判断 `Intent` 是否存在再跳不就解决了?你的想法很好,但是行不通,我用代码判断这个 `Intent` 是存在的,也能成功跳转,但是立马给你返回失败,具体情况你可以看一下 [XXPermissions/issues/190](https://github.com/getActivity/XXPermissions/issues/190),目前框架的解决方案是,如果当前厂商系统是 `HarmonyOS`、`MagicOS`、`EMUI` 中的任一一个,就不跳转到当前应用的勿扰权限设置页去授权,而是跳转到所有应用的勿扰权限列表页去授权,虽然这样麻烦一点,用户体验也会变差,但却是目前能想到的最好的解决方案。

* 针对以上问题,都在框架内部进行了处理,虽然无需你做任何处理,但是你仍需知道有这样一件事,所以哪里有什么岁月静好,只不过有前人替你把坑踩了个遍。虽然厂商们总是填坑少挖坑多,但是也有某些厂商在某个细节做得很不错,具体如下:

    1. 小米有一个细节做得很好,就是支持当前应用跳转到具体的权限设置页,这是由于[小米自己开放](https://dev.mi.com/docs/appsmarket/technical_docs/adaptation_FAQ/#10) 了 `miui.intent.action.APP_PERM_EDITOR` 这个隐式意图才能实现,目前框架已经进行了适配,这样用户在小米机型上面手动授权的时候,就不需要先跳转到应用详情页上面,再点一下才能进去权限设置页了。

    1. 魅族有一个细节做得很好,就是支持当前应用跳转到具体的权限设置页,这是由于魅族自己开放了 `com.meizu.safe.security.SHOW_APPSEC` 这个隐式意图才能实现,目前框架已经进行了适配,这样用户在魅族机型上面手动授权的时候,就不需要先跳转到应用详情页上面,再点一下才能进去权限设置页了。

    2. OPPO 有一个细节做得很好,不仅可以直接跳转到具体的权限设置页 ,还能支持高亮要授权的权限选项,具体接入文档可以看这里 [OPPO 应用权限受阻跳转优化适配](https://open.oppomobile.com/new/developmentDoc/info?id=12983),目前框架已经进行了适配,这样用户在 OPPO 机型上面手动授权的时候,会自动滚动并高亮要设置的权限项,用户体验会大大提升,在此希望其他国内的厂商们跟进。

#### 支持检测代码错误

* 在框架的日常维护中,有很多人跟我反馈过框架有 Bug,但是经过排查和定位发现,这其中有 95% 的问题来自于调用者一些不规范操作导致的,这不仅对我造成很大的困扰,同时也极大浪费了很多小伙伴的时间和精力,于是我在框架中加入了很多审查元素,在 **debug 模式**、**debug 模式**、**debug 模式** 下,一旦有某些操作不符合规范,那么框架会直接抛出异常给调用者,并在异常信息中正确指引调用者纠正错误,例如:

    * 如果调用者没有传入任何权限就申请权限的话,框架会抛出异常。

    * 传入的 Context 实例不是 Activity 对象,框架会抛出异常,又或者传入的 Activity 的状态异常(已经 **Finishing** 或者 **Destroyed**),这种情况一般是在异步申请权限导致的,框架也会抛出异常,请在合适的时机申请权限,如果申请的时机无法预估,请在外层做好  Activity 状态判断再进行权限申请。

    * 如果当前项目在没有适配分区存储的情况下,申请 `READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 权限

        * 当项目的 `targetSdkVersion >= 29` 时,需要在清单文件中注册 `android:requestLegacyExternalStorage="true"` 属性,否则框架会抛出异常,如果不加会导致一个问题,明明已经获取到存储权限,但是无法在 Android 10 的设备上面正常读写外部存储上的文件。

        * 当项目的 `targetSdkVersion >= 30` 时,则不能申请 `READ_EXTERNAL_STORAGE` 和 `WRITE_EXTERNAL_STORAGE` 权限,而是应该申请 `MANAGE_EXTERNAL_STORAGE` 权限

        * 如果当前项目已经适配了分区存储,那么只需要在清单文件中注册一个 meta-data 属性即可: `<meta-data android:name="ScopedStorage" android:value="true" />`

    * 如果申请的权限和项目中的 **targetSdkVersion** 对不上,框架会抛出异常,是因为 **targetSdkVersion** 代表着项目适配到哪个 Android 版本,系统会自动做向下兼容,假设申请的权限是 Android 11 才出现的,但是 **targetSdkVersion** 还停留在 29,那么在某些机型上的申请,会出现授权异常的情况,也就是用户明明授权了,但是系统返回的始终是 false。

    * 如果动态申请的权限没有在 `AndroidManifest.xml` 中进行注册,框架会抛出异常,因为如果不这么做,是可以进行申请权限,但是不会出现授权弹窗,直接被系统拒绝,并且系统不会给出任何弹窗和提示,并且这个问题在每个机型上面都是**必现的**。

    * 如果动态申请的权限有在 `AndroidManifest.xml` 中进行注册,但是设定了不恰当的 `android:maxSdkVersion` 属性值,框架会抛出异常,举个例子:`<uses-permission android:name="xxxx" android:maxSdkVersion="29" />`,这样的设定会导致在 Android 11 (`Build.VERSION.SDK_INT >= 30`)及以上的设备申请权限,系统会认为这个权限没有在清单文件中注册,直接拒绝本次的权限申请,并且也是不会给出任何弹窗和提示,这个问题也是必现的。

    * 如果你同时申请了 `MANAGE_EXTERNAL_STORAGE`、`READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 这三个权限,框架会抛出异常,告诉你不要同时申请这三个权限,这是因为在 Android 11 及以上设备上面,申请了 `MANAGE_EXTERNAL_STORAGE` 权限,则没有申请 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 权限的必要,这是因为申请了 `MANAGE_EXTERNAL_STORAGE` 权限,就等于拥有了比 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 更加强大的能力,如果硬要那么做反而适得其反,假设框架允许的情况下,会同时出现两种授权方式,一种是弹窗授权,另一种是跳页面授权,用户要进行两次授权,但是实际上面有了 `MANAGE_EXTERNAL_STORAGE` 权限就满足使用了,这个时候大家可能心中有一个疑问了,你不申请 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 权限,Android 11 以下又没有 `MANAGE_EXTERNAL_STORAGE` 这个权限,那不是会有问题?关于这个问题大家可以放心,框架会做判断,如果你申请了 `MANAGE_EXTERNAL_STORAGE` 权限,在 Android 11 以下框架会自动添加 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 来申请,所以在低版本下也不会因为没有权限导致的无法使用。

    * 如果你不需要上面这些检测,可通过调用 `unchecked` 方法来关闭,但是需要注意的是,我并不建议你去关闭这个检测,因为在 **release 模式** 时它是关闭状态,不需要你手动关闭,而它只在 **debug 模式** 下才会触发这些检测。

* 出现这些问题的原因是,我们对这些机制不太熟悉,而如果框架不加以限制,那么引发各种奇奇怪怪的问题出现,作为框架的作者,表示不仅你们很痛苦,作为框架作者表示也很受伤。因为这些问题不是框架导致的,而是调用者的某些操作不规范导致的。我觉得这个问题最好的解决方式是,由框架做统一的检查,因为我是框架的作者,对权限申请这块知识点有**较强的专业能力和足够的经验**,知道什么该做,什么不该做,这样就可以对这些骚操作进行一一拦截。

* 当权限申请出现问题时,你希不希望能有个人过来提醒你,告诉你哪里错了?该怎么去纠正?然而这些 XXPermissions 都做到了,在所有的权限请求框架中,我算是第一个做这件事的人,我认为**做好一个框架**不仅仅是要把功能做好,把复杂的场景处理好,更重要的是要**以人为本**,因为框架本身就是为人服务的,要做的不仅仅是解决大家的需求,还要帮助大家在这个过程中少走弯路。

================================================
FILE: HelpDoc-en.md
================================================
#### Catalog

* [Android 11 location permission adaptation](#android-11-location-permission-adaptation)

* [Android 11 storage permission adaptation](#android-11-storage-permission-adaptation)

* [When do I need to adapt to the characteristics of partitioned storage](#when-do-i-need-to-adapt-to-the-characteristics-of-partitioned-storage)

* [Why does the app restart after Android 11 grants the install permission](#why-does-the-app-restart-after-android-11-grants-the-install-permission)

* [Why is the storage permission granted but the permission setting page still shows unauthorized](#why-is-the-storage-permission-granted-but-the-permission-setting-page-still-shows-unauthorized)

* [What should I do if the dialog box pops up before and after the permission application](#what-should-i-do-if-the-dialog-box-pops-up-before-and-after-the-permission-application)

* [How to know in the callback which permissions are permanently denied](#how-to-know-in-the-callback-which-permissions-are-permanently-denied)

* [Why does the new version of the framework remove the function of automatically applying for AndroidManifest permissions](#why-does-the-new-version-of-the-framework-remove-the-function-of-automatically-applying-for-androidmanifest-permissions)

* [Why does the new version of the framework remove the function of constantly applying for permissions](#why-does-the-new-version-of-the-framework-remove-the-function-of-constantly-applying-for-permissions)

* [Why not use ActivityResultContract to request permission](#why-not-use-activityresultcontract-to-request-permission)

* [How to deal with the problem that the permission request is successful but the blank pass is returned](#how-to-deal-with-the-problem-that-the-permission-request-is-successful-but-the-blank-pass-is-returned)

* [Why cannot I access the files in the Android/data directory after authorization](#why-cannot-i-access-the-files-in-the-androiddata-directory-after-authorization)

* [Is there any problem with skipping the installation permission application and installing the apk directly](#Is-there-any-problem-with-skipping-the-installation-permission-application-and-installing-the-apk-directly)

#### Android 11 Location Permission Adaptation

* On Android 10, positioning permissions are divided into foreground permissions (precise and fuzzy) and background permissions, while on Android 11, you need to apply for these two permissions separately. If you apply for these two permissions ** Ruthlessly rejected by the system ** at the same time, even the permission application dialog box will not pop up, and the system will reject it immediately. It directly leads to the failure of location permission application.

* If you are using the latest version of **XXPermissions**, you ** Congratulations ** can directly pass the foreground and background positioning permissions to the framework. The framework has automatically applied for these two permissions separately for you. The whole adaptation process ** Zero cost **.

* However, it should be noted that the application process is divided into two steps. The first step is to apply for the foreground location permission, and the second step is to apply for the background location permission. The user must first agree to the foreground location permission before entering the application for the background location permission. There are two ways to approve the foreground location permission: check `Allow only while using the app` or `Ask every time`. In the background location permission application, the user must check `Allow all the time`. Only in this way can the background location permission application be approved.

* And if your application only needs to use the location function in the foreground, but does not need to use the location function in the background, please do not apply for `Permission.ACCESS_BACKGROUND_LOCATION` permission.

![](picture/en/help_doc_android_11_location_adapter_1.jpg) ![](picture/en/help_doc_android_11_location_adapter_2.jpg)

#### Android 11 storage permission adaptation

* If your project needs to adapt to Android 11 storage permissions, you need to upgrade targetSdkVersion first.

```groovy
android 
    defaultConfig {
        targetSdkVersion 30
    }
}
```

* Add Android 11storage permissions to register in the manifest file.

```xml
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
```

* It should be noted that the old version of the storage permissions also need to be registered in the manifest file, because the framework will automatically switch to the old version of the application mode when applying for storage permissions in an environment lower than Android 11.

```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```

* You also need to add this attribute to the manifest file, otherwise you won't be able to read and write files on external storage on Android 10 devices.

```xml
<application
    android:requestLegacyExternalStorage="true">
```
    
* Finally, call the following code directly.

```java
XXPermissions.with(MainActivity.this)
        // The scoped storage that has been adapted to Android 11 needs to be called like this
        //.permission(PermissionLists.getReadExternalStoragePermission())
        //.permission(PermissionLists.getWriteExternalStoragePermission())
        // Not yet adapted to Android 11 scoped storage needs to be called like this
        .permission(PermissionLists.getManageExternalStoragePermission())
        .request(new OnPermissionCallback() {
            ......
        });
```

![](picture/en/demo_request_manage_storage_permission.jpg)

#### When do I need to adapt to the characteristics of partitioned storage

* If your app needs to be available on Google Play, you need to check it out in detail: [ Google App Store policy (need to climb over the wall) ](https://support.google.com/googleplay/android-developer/answer/9956427). [ Google Play notifications ](https://developer.android.google.cn/training/data-storage/manage-all-files#all-files-access-google-play)

* The origin of scoped storage: Google has received many complaints from users before, saying that many applications create directories and files under the SD card, which makes it very troublesome for users to manage mobile phone files (there are so many foreign netizens with obsessive-compulsive disorder, ha ha), so in the Android 10 version update. Google requires all developers to store media files in their own internal directory or in the internal directory of the SD card, but Google has adopted a relaxed policy on one version, adding `android:requestLegacyExternalStorage="true"` the adaptation of this feature to the manifest file, but on Android 11, you have two options:

    1. Adapting scoped storage: This is a method recommended by Google, but it will increase the workload, because it is very troublesome to adapt scoped storage, which is my personal feeling. However, for some specific applications, such as file managers, backup and recovery applications, anti-virus applications, document management applications, on-device file search, disk and file encryption, device-to-device data migration and so on, they must use external storage, which requires the second way to achieve.

    2. Apply for external storage permissions: This is a way that Google does not recommend. It only needs `MANAGE_EXTERNAL_STORAGE` permissions, and there is basically no pressure to adapt. However, there will be a problem, that is, when it is put on the Google App Market, it must be reviewed and approved by Google Play.

* To sum up, I think both are good and bad, but I can share my views with you.

    1. If your app needs to be on the Google Apps Marketplace, you need to adapt to partitioned storage as soon as possible, because Google is really doing it this time.

    2. If your application is only available in the china application market, and there is no subsequent need to be available in the Google application market, then you can also directly apply for `MANAGE_EXTERNAL_STORAGE` permission to read and write external storage.

#### Why does the app restart after Android 11 grants the install permission

* [Android 11 feature adjustment, installation of external source application requires restarting App](https://cloud.tencent.com/developer/news/637591)

* First of all, this problem is a new feature of Android 11, not caused by the framework. Of course, there is no way to avoid this problem, because the application is killed by the system, and the level of the application is certainly not as high as that of the system. At present, there is no solution for this in the industry. If you have a good solution, you are welcome to provide it to me.

* In addition, after practice, this problem will no longer appear on Android 12, proving that the problem has been fixed by Google.

#### Why is the storage permission granted but the permission setting page still shows unauthorized

* First of all, I need to correct a wrong idea. `READ_EXTERNAL_STORAGE` `WRITE_EXTERNAL_STORAGE` These two permissions and `MANAGE_EXTERNAL_STORAGE` permissions are two different things. Although they are both called storage permissions, they belong to two completely different permissions. If you apply for `MANAGE_EXTERNAL_STORAGE` permission and grant permission, However, you do not see that the permission has been granted on the permission setting page. Please note that this situation is normal, because what you see on the permission setting page is the storage grant status `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` permission status, not `MANAGE_EXTERNAL_STORAGE` the permission status, but at this time, the storage permission has been obtained. You don't have to worry about the permission status displayed on the permission setting page. You can read and write files directly. There will be no permission problem.

* One more question, why only appear on devices above Android 11? First of all `MANAGE_EXTERNAL_STORAGE`, only Android 11 has permission. Android 10 and previous versions do not have this permission. If you apply for `MANAGE_EXTERNAL_STORAGE` permission on a lower version device, the framework will help you do downward compatibility. Will automatically help you replace `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` permissions to apply, this time you see the permission settings page of the storage permission status must be normal, which is why you only see this problem in Android 11 and above devices.

#### What should I do if the dialog box pops up before and after the permission application

* There are interfaces provided within the framework that can fulfill this requirement, It is enough to implement the interface provided [OnPermissionDescription](library/src/main/java/com/hjq/permissions/OnPermissionDescription.java) and [OnPermissionInterceptor](library/src/main/java/com/hjq/permissions/OnPermissionInterceptor.java) in the framework. For specific implementation, please refer to the [PermissionDescription](app/src/main/java/com/hjq/permissions/demo/PermissionDescription.java) and [PermissionInterceptor](app/src/main/java/com/hjq/permissions/demo/PermissionInterceptor.java) class provided in Demo. It is recommended to download the source code and read it, and then introduce the code into the project

* The way to use is also very simple. There are two specific settings, one for local settings and the other for global settings.

```java
XXPermissions.with(this)
        .permission(PermissionLists.getXxx())
        // Set permission request description (local settings)
        .description(new PermissionDescription())
        // Set permission request interceptor (local settings)
        .interceptor(new PermissionInterceptor())
        .request(new OnPermissionCallback() {
            ......
        });
```

```java
public class XxxApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        
        // Set permission request description (global setting)
        XXPermissions.setPermissionDescription(PermissionDescription.class);
        // Set permission request interceptor (global setting)
        XXPermissions.setPermissionInterceptor(PermissionInterceptor.class);
    }
}
```

#### How to know in the callback which permissions are permanently denied

* Requirement scenario: Suppose you apply for calendar permission and recording permission at the same time, but both are rejected by the user. However, one of the two groups of permissions is permanently rejected. How to determine whether a certain group of permissions is permanently rejected? Here is a code example:

```java
XXPermissions.with(this)
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getReadCalendarPermission())
    .permission(PermissionLists.getWriteCalendarPermission())
    .request(new OnPermissionCallback() {

        @Override
        public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
            boolean allGranted = deniedList.isEmpty();
            if (!allGranted) {
                IPermission recordAudioPermission = PermissionLists.getRecordAudioPermission();
                if (deniedList.contains(recordAudioPermission) &&
                    XXPermissions.isDoNotAskAgainPermission(activity, recordAudioPermission)) {
                    toast("The recording permission request was denied, and the user checked Do not ask");
                }
                return;
            }
            toast("Acquired recording and calendar permissions successfully");
        }
    });
```

#### Why does the new version of the framework remove the function of automatically applying for AndroidManifest permissions

> [ [Issue] It is recommended to restore the two practical functions of jumping to the permission setting page and obtaining all permissions of AndroidManifest](https://github.com/getActivity/XXPermissions/issues/54)

* The function of obtaining the list permission and applying. Although this is very convenient, there are some hidden dangers. Because the list file in apk is ultimately merged by the list files of multiple modules, it will become uncontrollable. This will make it impossible for us to predict the permissions applied for, and it will also mix some unnecessary permissions. Therefore, after careful consideration, this function will be removed.

#### Why does the new version of the framework remove the function of constantly applying for permissions

> [ [Issue] Optimization issue with keep requesting get after permission denied](https://github.com/getActivity/XXPermissions/issues/39)

* Assuming that the user refuses the permission, if the framework applies again, the possibility that the user will grant it is relatively small. At the same time, some app stores have disabled this behavior. After careful consideration, the API related to this function will be removed.

* If you still want to use this way to apply for permission, in fact, there is no way, you can refer to the following ways to achieve.

```java
public class PermissionActivity extends AppCompatActivity implements OnPermissionCallback {

    @Override
    public void onClick(View view) {
        requestCameraPermission();
    }

    private void requestCameraPermission() {
        XXPermissions.with(this)
                .permission(PermissionLists.getCameraPermission())
                .request(this);
    }

    @Override
    public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
        boolean allGranted = deniedList.isEmpty();
        if (!allGranted) {
            boolean doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList);
            if (doNotAskAgain) {
                toast("Authorization is permanently denied, please manually grant permission to take camera");
                // If it is permanently denied, jump to the application permission system settings page
                XXPermissions.startPermissionActivity(activity, deniedList);
            } else {
                requestCameraPermission();
            }
            return;
        }
        toast("Successfully obtained permission to take camera");
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode != XXPermissions.REQUEST_CODE) {
            return;
        }
        toast("Detected that you just returned from the permission settings interface");
    }
}
```

#### Why not use ActivityResultContract to request permission

> [ [Issue] Whether the permission application for onActivityResult callback has been considered and switched to ActivityResultContract](https://github.com/getActivity/XXPermissions/issues/103)

* Activity ResultContract is a new API added in Activity `1.2.0-alpha02` and Fragment `1.3.0-alpha02`, which has a certain threshold for use, and the project must be based on Android X. And the version of Android X must be `1.3.0-alpha01` above. If it is replaced `ActivityResultContract`, some developers will not be able to use **XXPermissions**, which is a serious problem. But in fact, changing to Activity ResultContract does not bring any benefits. For example, I have solved the problems of Fragment screen rotation and background application before, so what is the significance of changing? Some people may say that the official onActivityResult has been marked as obsolete. Don't worry. The reason why it is marked as obsolete is just for Google to promote new technology. But it can be clearly said that the official will not delete this API. More accurately, it will not dare. Why? You can see how Activity ResultContract is implemented? It is also implemented by rewriting the `onRequestPermissionsResult` method callback of the Activity `onActivityResult`. You can see the implementation of these two methods in the `androidx.activity.ComponentActivity` class, which will not be repeated here.

#### How to deal with the problem that the permission request is successful but the blank pass is returned

* There is no solution to this problem. The permission request framework can only help you apply for permission. As for what you do when you apply for permission, the framework cannot know or intervene. The return of the blank pass is the manufacturer's own behavior. The purpose is to protect the user's privacy, because it cannot be used without permission in some applications. The return of the blank pass is to avoid this situation. You want to ask me what to do? I can only say that the arm can't resist the thigh, so don't make some unnecessary resistance.

#### Why cannot I access the files in the Android/data directory after authorization

* First of all, no matter what kind of storage permission you apply for, you cannot directly read the android/data directory on Android 11. This is a new feature on Android 11, and you need to make additional adaptation. You can refer to this open source project for the specific adaptation process.

#### Is there any problem with skipping the installation permission application and installing the apk directly

* If you are careful, you may find that you can install apk without installation permissions. So why should I apply for `REQUEST_INSTALL_PACKAGES` permissions? Isn't that unnecessary?

* Here I want to say, is not what you imagine, next let us experiment, here selected `Google piexl 3XL (Android 12)` and `Xiaomi phone 12 (Android 12)` respectively do a test

```java
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
} else {
    uri = Uri.fromFile(file);
}

intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.startActivity(intent);
```

![](picture/en/help_doc_install_package_android_1.jpg) ![](picture/en/help_doc_install_package_android_2.jpg)

![](picture/en/help_doc_install_package_miui_1.jpg) ![](picture/en/help_doc_install_package_miui_2.jpg)

* See here, I believe you have noticed some differences, also jump to install apk page, on the Android native system, will show the `Cancel` and `Settings` option, click `Cancel` option will cancel the installation, only click `Settings` option, will let you grant the installation package permissions, On top of MIUI, the `Allow` and `Restrict` options are displayed, as well as a `Don't show again` option. If the user checks `Don't show again` and clicks the `Restrict` option, The next time the application goes to the install apk page, it will be directly rejected by the system, and only a toast prompt will be displayed. The conclusion of the problem is: You can directly jump to the page of installing apk, but it is not recommended to do so, because on some mobile phones, the system may directly reject the request to install apk, so the standard writing should be, first judge whether there is no installation permission, if not, apply for, if there is, then jump to the page of installing apk, Of course, if you apply for installation permissions using this framework, you don't need to determine whether there are permissions or not to apply directly. Whether there is authorization or not, it will inform you through the callback, and you can then handle it from the callback.

================================================
FILE: HelpDoc-zh.md
================================================
#### 目录

* [Android 11 定位权限适配](#android-11-定位权限适配)

* [Android 11 存储权限适配](#android-11-存储权限适配)

* [什么情况下需要适配分区存储特性](#什么情况下需要适配分区存储特性)

* [Android 11 授予了安装权限之后为什么应用重启了](#android-11-授予了安装权限之后为什么应用重启了)

* [为什么授予了存储权限但是权限设置页还是显示未授权](#为什么授予了存储权限但是权限设置页还是显示未授权)

* [我想在申请前和申请后统一弹对话框该怎么处理](#我想在申请前和申请后统一弹对话框该怎么处理)

* [如何在回调中知道哪些权限被永久拒绝了](#如何在回调中知道哪些权限被永久拒绝了)

* [为什么不兼容 Android 6.0 以下的危险权限申请](#为什么不兼容-android-60-以下的危险权限申请)

* [新版框架为什么移除了自动申请清单权限的功能](#新版框架为什么移除了自动申请清单权限的功能)

* [新版框架为什么移除了不断申请权限的功能](#新版框架为什么移除了不断申请权限的功能)

* [新版框架为什么移除了国产手机权限设置页功能](#新版框架为什么移除了国产手机权限设置页功能)

* [为什么不用 ActivityResultContract 来申请权限](#为什么不用-activityresultcontract-来申请权限)

* [怎么处理权限请求成功但是返回空白通行证的问题](#怎么处理权限请求成功但是返回空白通行证的问题)

* [为什么授权了还是无法访问 Android/data 目录下的文件](#为什么授权了还是无法访问-android-data-目录下的文件)

* [跳过安装权限申请然后直接安装 apk 会有什么问题吗](#跳过安装权限申请然后直接安装-apk-会有什么问题吗)

* [如何应对国内某些应用商店在明确拒绝权限后 48 小时内不允许再次申请的问题](#如何应对国内某些应用商店在明确拒绝权限后-48-小时内不允许再次申请的问题)

#### Android 11 定位权限适配

* 在 Android 10 上面,定位权限被划分为前台权限(精确和模糊)和后台权限,而到了 Android 11 上面,需要分别申请这两种权限,如果同时申请这两种权限会**惨遭系统无情拒绝**,连权限申请对话框都不会弹,立马被系统拒绝,直接导致定位权限申请失败。

* 如果你使用的是 **XXPermissions** 最新版本,那么**恭喜你**,直接将前台定位权限和后台定位权限全部传给框架即可,框架已经自动帮你把这两种权限分开申请了,整个适配过程**零成本**。

* 但是需要注意的是:申请过程分为两个步骤,第一步是申请前台定位权限,第二步是申请后台定位权限,用户必须要先同意前台定位权限才能进入后台定位权限的申请。同意前台定位权限的方式有两种:勾选 `仅在使用该应用时允许` 或 `仅限这一次`,而到了后台定位权限申请中,用户必须要勾选 `始终允许`,只有这样后台定位权限才能申请通过。

* 还有如果你的应用只需要在前台使用定位功能, 而不需要在后台中使用定位功能,那么请不要连带申请 `Permission.ACCESS_BACKGROUND_LOCATION` 权限。

![](picture/zh/help_doc_android_11_location_adapter_1.jpg) ![](picture/zh/help_doc_android_11_location_adapter_2.jpg)

#### Android 11 存储权限适配

* 如果你的项目需要适配 Android 11 存储权限,那么需要先将 targetSdkVersion 进行升级

```groovy
android 
    defaultConfig {
        targetSdkVersion 30
    }
}
```

* 再添加 Android 11 存储权限注册到清单文件中

```xml
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
```

* 需要注意的是,旧版的存储权限也需要在清单文件中注册,因为在低于 Android 11 的环境下申请存储权限,框架会自动切换到旧版的申请方式

```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
```

* 还需要在清单文件中加上这个属性,否则在 Android 10 的设备上将无法正常读写外部存储上的文件

```xml
<application
    android:requestLegacyExternalStorage="true">
```
    
* 最后直接调用下面这句代码

```java
XXPermissions.with(MainActivity.this)
        // 适配 Android 11 分区存储这样写
        //.permission(PermissionLists.getReadExternalStoragePermission())
        //.permission(PermissionLists.getWriteExternalStoragePermission())
        // 不适配 Android 11 分区存储这样写
        .permission(PermissionLists.getManageExternalStoragePermission())
        .request(new OnPermissionCallback() {
            ......
        });
```

![](picture/zh/demo_request_manage_storage_permission.jpg)

#### 什么情况下需要适配分区存储特性

* 如果你的应用需要上架 GooglePlay,那么需要详细查看:[谷歌应用商店政策(需要翻墙)](https://support.google.com/googleplay/android-developer/answer/9956427)、[Google Play 通知](https://developer.android.google.cn/training/data-storage/manage-all-files#all-files-access-google-play)

* 分区存储的由来:谷歌之前收到了很多用户投诉,说很多应用都在 SD 卡下创建目录和文件,导致用户管理手机文件非常麻烦(强迫症的外国网友真多,哈哈),所以在 Android 10 版本更新中,谷歌要求所有开发者将媒体文件存放在自己内部目录或者 SD 卡内部目录中,不过谷歌在一版本上采取了宽松政策,在清单文件中加入 `android:requestLegacyExternalStorage="true"` 即可跳过这一特性的适配,不过在 Android 11 上面,你有两种选择:

    1. 适配分区存储:这个是谷歌推荐的一种方式,但是会增加工作量,因为分区存储适配起来十分麻烦,我个人感觉是这样的。不过对于一些特定应用,例如文件管理器、备份和恢复应用、防病毒应用、文档管理应用、设备上的文件搜索、磁盘和文件加密、设备到设备数据迁移等这类应用它们就一定需要用到外部存储,这个时候就需要用第二种方式来实现了。

    2. 申请外部存储权限:这个是谷歌不推荐的一种方式,只需要 `MANAGE_EXTERNAL_STORAGE` 权限即可,适配起来基本无压力,但是会存在一个问题,就是上架谷歌应用市场的时候,要经过 Google Play 审核和批准。

* 这两种总结下来,我觉得各有好坏,不过我可以跟大家谈谈我的看法

    1. 如果你的应用需要上架谷歌应用市场,需要尽快适配分区存储,因为谷歌这次来真的了

    2. 如果你的应用只上架国内的应用市场,并且后续也没有上架谷歌应用市场的需要,那么你也可以直接申请 `MANAGE_EXTERNAL_STORAGE` 权限来读写外部存储

#### Android 11 授予了安装权限之后为什么应用重启了

* [Android 11 特性调整,安装外部来源应用需要重启 App](https://cloud.tencent.com/developer/news/637591)

* 先说结论,这个问题是 Android 11 的新特性,并非框架的问题导致的,当然这个问题是没有办法规避的,因为应用是被系统杀死的,应用的等级肯定不如系统的高,目前行业对这块也没有解决方案,如果你有好的解决方案,欢迎你提供给我。

* 另外经过实践,这个问题在 Android 12 上面已经不会再出现,证明问题已经被谷歌修复了。

#### 为什么授予了存储权限但是权限设置页还是显示未授权

* 首先我需要先纠正大家一个错误的想法,`READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 这两个权限和 `MANAGE_EXTERNAL_STORAGE` 权限是两码事,虽然都叫存储权限,但是属于两种完全不同的权限,你如果申请的是 `MANAGE_EXTERNAL_STORAGE` 权限,并且授予了权限,但是在权限设置页并没有看到已授予,请注意这种情况是正常的,因为你在权限设置页看到的是存储授予状态是 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 权限状态的,而不是 `MANAGE_EXTERNAL_STORAGE` 权限状态的,但是这个时候已经获取到存储权限了,你大可不必管权限设置页显示的权限状态,直接读写文件即可,不会有权限问题的。

* 还有一个问题,为什么只在 Android 11 以上的设备出现?首先 `MANAGE_EXTERNAL_STORAGE` 权限是 Android 11 才有权限,Android 10 及之前的版本是没有这个权限的,你如果在低版本设备上申请了 `MANAGE_EXTERNAL_STORAGE` 权限,那么框架会帮你做向下兼容,会自动帮你替换成 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 权限去申请,这个时候你看到权限设置页的存储权限状态肯定是正常的,这就是为什么你只在 Android 11 以上的设备才会看到这个问题。

#### 我想在申请前和申请后统一弹对话框该怎么处理

* 框架内部有提供接口可以实现这一需求,通过实现框架中提供的 [OnPermissionDescription](library/src/main/java/com/hjq/permissions/OnPermissionDescription.java) 和 [OnPermissionInterceptor](library/src/main/java/com/hjq/permissions/OnPermissionInterceptor.java) 接口即可,具体实现可参考 Demo 中提供的 [PermissionDescription](app/src/main/java/com/hjq/permissions/demo/PermissionDescription.java)  和 [PermissionInterceptor](app/src/main/java/com/hjq/permissions/demo/PermissionInterceptor.java) 类,建议下载源码后进行阅读,再将代码引入到项目中

* 使用方式也很简单,具体有两种设置方式,一种针对局部设置,另外一种是全局设置

```java
XXPermissions.with(this)
        .permission(PermissionLists.getXxx())
        // 设置权限说明(局部设置)
        .description(new PermissionDescription())
        // 设置权限请求拦截器(局部设置)
        .interceptor(new PermissionInterceptor())
        .request(new OnPermissionCallback() {
            ......
        });
```

```java
public class XxxApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        
        // 设置权限说明(全局设置)
        XXPermissions.setPermissionDescription(PermissionDescription.class);
        // 设置权限请求拦截器(全局设置)
        XXPermissions.setPermissionInterceptor(PermissionInterceptor.class);
    }
}
```

#### 如何在回调中知道哪些权限被永久拒绝了

* 需求场景:假设同时申请日历权限和录音权限,结果都被用户拒绝了,但是这两组权限中有一组权限被永久拒绝了,如何判断某一组权限有没有被永久拒绝?这里给出代码示例:

```java
XXPermissions.with(this)
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getReadCalendarPermission())
    .permission(PermissionLists.getWriteCalendarPermission())
    .request(new OnPermissionCallback() {

        @Override
        public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
            boolean allGranted = deniedList.isEmpty();
            if (!allGranted) {
                IPermission recordAudioPermission = PermissionLists.getRecordAudioPermission();
                if (deniedList.contains(recordAudioPermission) &&
                    XXPermissions.isDoNotAskAgainPermission(activity, recordAudioPermission)) {
                    toast("录音权限请求被拒绝了,并且用户勾选了不再询问");
                }
                return;
            }
            toast("获取录音和日历权限成功");
        }
    });
```

#### 为什么不兼容 Android 6.0 以下的危险权限申请

* 因为 Android 6.0 以下的危险权限管理是手机厂商做的,那个时候谷歌还没有统一危险权限管理的方案,所以就算我们的应用没有适配也不会有任何问题,因为手机厂商对这块有自己的处理,但是有一点是肯定的,就算用户拒绝了授权,也不会导致应用崩溃,只会返回空白的通行证。

* 如果 **XXPermissions** 做这块的适配也可以做到,通过反射系统服务 AppOpsManager 类中的字段即可,但是并不能保证权限判断的准确性,可能会存在一定的误差,其次是适配的成本太高,因为国内手机厂商太多,对这块的改动参差不齐。

* 考虑到 Android 6.0 以下的设备占比很低,后续也会越来越少,会逐步退出历史的舞台,所以我的决定是不对这块做适配。

#### 新版框架为什么移除了自动申请清单权限的功能

> [【issue】建议恢复跳转权限设置页和获取AndroidManifest的所有权限两个实用功能](https://github.com/getActivity/XXPermissions/issues/54)

* 获取清单权限并申请的功能,这个虽然非常方便,但是存在一些隐患,因为 apk 中的清单文件最终是由多个 module 的清单文件合并而成,会变得不可控,这样会使我们无法预估申请的权限,并且还会掺杂一些不需要的权限,所以经过慎重考虑移除该功能。

#### 新版框架为什么移除了不断申请权限的功能

> [【issue】关于拒绝权限后一直请求获取的优化问题](https://github.com/getActivity/XXPermissions/issues/39)

* 假设用户拒绝了权限,如果框架再次申请,那么用户会授予的可能性也是比较小,同时某些应用商店已经禁用了这种行为,经过慎重考虑,对这个功能相关的 API 进行移除。

* 如果你还想用这种方式来申请权限,其实并不是没有办法,可以参考以下方式来实现

```java
public class PermissionActivity extends AppCompatActivity implements OnPermissionCallback {

    @Override
    public void onClick(View view) {
        requestCameraPermission();
    }

    private void requestCameraPermission() {
        XXPermissions.with(this)
                .permission(PermissionLists.getCameraPermission())
                .request(this);
    }

    @Override
    public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
        boolean allGranted = deniedList.isEmpty();
        if (!allGranted) {
            boolean doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList);
            if (doNotAskAgain) {
                toast("被永久拒绝授权,请手动授予拍照权限"");
                // 如果是被永久拒绝就跳转到应用权限系统设置页面
                XXPermissions.startPermissionActivity(activity, deniedList);
            } else {
                requestCameraPermission();
            }
            return;
        }
        toast("获取拍照权限成功");
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode != XXPermissions.REQUEST_CODE) {
            return;
        }
        toast("检测到你刚刚从权限设置界面返回回来");
    }
}
```

#### 新版框架为什么移除了国产手机权限设置页功能

> [【issue】权限拒绝并不再提示的问题](https://github.com/getActivity/XXPermissions/issues/99)

> [【issue】正常申请存储权限时,永久拒绝,然后再应用设置页开启权限询问,系统权限申请弹窗未显示](https://github.com/getActivity/XXPermissions/issues/100)

* **XXPermissions** 9.0 及之前是有存在这一功能的,但是我在后续的版本上面将这个功能移除了,原因是有很多人跟我反馈这个功能其实存在很大的缺陷,例如在一些华为新机型上面可能跳转的页面不是应用的权限设置页,而是所有应用的权限管理列表界面。

* 首先这个问题要从 **XXPermissions** 跳转到国产手机设置页的原理讲起,从谷歌提供的原生 API 我们最多只能跳转到应用详情页,并不能直接跳转到权限设置页,而需要用户在应用详情页再次点击才能进入权限设置页。如果从用户体验的角度上看待这个问题,肯定是直接跳转到权限设置页是最好的,但是这种方式是不受谷歌支持的,当然也有方法实现,网上都有一个通用的答案,就是直接捕获某个品牌手机的权限设置页 `Activity` 包名然后进行跳转。这种想法的起点是好的,但是存在许多问题,并不能保证每个品牌的所有机型都能适配到位,手机产商更改这个 `Activity` 的包名的次数和频率比较高,在最近发布的一些新的华为机型上面几乎已经全部失效,也就是 `startActivity` 的时候会报 `ActivityNotFoundException` 或 `SecurityException` 异常,当然这些异常是可以被捕捉到的,但是仅仅只能捕获到崩溃,一些非崩溃的行为我们并不能从中得知和处理,例如我刚刚讲过的华为的问题,这些问题并不能导致崩溃,但是会导致功能出现异常。

* 另外值得一提的是 [Android 11 对软件包可见性进行了限制](https://developer.android.google.cn/about/versions/11/privacy/package-visibility),所以这种跳包名的方式在未来将会完全不可行。

* 最终决定:这个功能的出发点是好的,但是我们没办法做好它,经过慎重考虑,决定将这个功能在 [9.2](https://github.com/getActivity/XXPermissions/releases/tag/9.2) 及之后的版本进行移除。

#### 为什么不用 ActivityResultContract 来申请权限

> [【issue】是否有考虑 onActivityResult 回调的权限申请切换成 ActivityResultContract](https://github.com/getActivity/XXPermissions/issues/103)

* ActivityResultContract 是 Activity `1.2.0-alpha02` 和 Fragment `1.3.0-alpha02` 中新追加的新 API,有一定的使用门槛,必须要求项目是基于 AndroidX,并且 AndroidX 的版本还要是 `1.3.0-alpha01` 以上才可以,如果替换成 `ActivityResultContract` 来实现,那么就会导致一部分开发者用不了 **XXPermissions**,这是一个比较严重的问题,但实际上换成 ActivityResultContract 来实现本身没有带来任何的效益,例如我之前解决过的 Fragment 屏幕旋转及后台申请的问题,所以更换的意义又在哪里呢?有人可能会说官方已经将 onActivityResult 标记成过时,大家不必担心,之所以标记成过时只不过是谷歌为了推广新技术,但是可以明确说,官方是一定不会删掉这个 API 的,更准确来说是一定不敢,至于为什么?大家可以去看看 ActivityResultContract 是怎么实现的?它也是通过重写 Activity 的 `onActivityResult`、`onRequestPermissionsResult` 方法回调实现的,具体大家可以去看 `androidx.activity.ComponentActivity` 类中这两个方法的实现就会明白了,这里不再赘述。

#### 怎么处理权限请求成功但是返回空白通行证的问题

* 此问题无解,权限请求框架只能帮你申请权限,至于你申请权限做什么操作,框架无法知道,也无法干预,还有返回空白通行证是厂商自己的行为,目的就是为了保护用户的隐私,因为在某些应用上面不给权限就不能用,返回空白通行证是为了规避这种情况的发生。你要问我怎么办?我只能说胳膊拗不过大腿,别做一些无谓的抵抗。

#### 为什么授权了还是无法访问 Android/data 目录下的文件

* 首先无论你申请了哪种存储权限,在 Android 11 上面就是无法直接读取 Android/data 目录的,这个是 Android 11 上的新特性,需要你进行额外适配,具体适配流程可以参考这个开源项目 [https://github.com/getActivity/AndroidVersionAdapter](https://github.com/getActivity/AndroidVersionAdapter)

#### 跳过安装权限申请然后直接安装 apk 会有什么问题吗

* 有细心的同学可能发现了,不需要安装权限也可以直接调起安装 apk,那我为什么还要申请 `REQUEST_INSTALL_PACKAGES` 权限?这不是脱裤子放屁,多此一举吗?

* 在这里我想说的是,并不是你想象的那样,接下来让我们试验一下,这里选用了 `Google piexl 3XL(Android 12)` 和 `小米手机 12(Android 12)` 分别做一下测试

```java
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
} else {
    uri = Uri.fromFile(file);
}

intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
context.startActivity(intent);
```

![](picture/zh/help_doc_install_package_android_1.jpg) ![](picture/zh/help_doc_install_package_android_2.jpg)

![](picture/zh/help_doc_install_package_miui_1.jpg) ![](picture/zh/help_doc_install_package_miui_2.jpg)

* 看到这里,我相信大家已经发现了一些差异,同样是跳转到安装 apk 页面,在 Android 原生系统上面,会显示 `取消` 和 `设置` 的选项,点击 `取消` 的选项会取消安装,只有点击 `设置` 的选项,才会让你授予安装包权限,授予了才能进行安装,而在 MIUI 上面,会显示 `允许` 和 `禁止` 的选项,另外还有一个 `记住我的选择` 的选项,如果用户勾选了这个 `记住我的选择` 并且点击了 `禁止` 的选项,那么应用下次跳转到安装 apk 页面会被系统直接拒绝,并且只会显示一个 toast 提示,问题结论是:可以直接跳转到安装 apk 页面,但是不建议那么做,因为在有些手机上面,系统可能会直接拒绝这个安装 apk 的请求,针对这个问题,所以标准的写法应该是,先判断有没有安装权限,没有的话就申请,有的话再去跳转到安装 apk 的页面,当然你如果用的是本框架申请的安装权限,可以不需要判断有没有权限直接申请,有授权和没有授权都会通过回调告诉你,你再从回调中做处理。

#### 如何应对国内某些应用商店在明确拒绝权限后 48 小时内不允许再次申请的问题

* 首先这种属于业务逻辑的问题,框架本身是不会做这种事情的,但并非不能实现,这得益于框架良好的设计,框架内部提供了一个叫 OnPermissionInterceptor 的拦截器类,当前有权限申请的时候,会走 requestPermissions 方法的回调,你可以重写这个方法的逻辑,先去判断要申请的权限是否在 48 小时内已经申请过了一次了,如果没有的话,就走权限申请的流程,如果有的话,那么就直接回调权限申请失败的方法。

```java
public final class PermissionInterceptor implements OnPermissionInterceptor {

    private static final String SP_NAME_PERMISSION_REQUEST_TIME_RECORD = "permission_request_time_record";

    @Override
    public void onRequestPermissionStart(@NonNull Activity activity,
                                         @NonNull List<IPermission> requestList,
                                         @NonNull PermissionFragmentFactory<?, ?> fragmentFactory,
                                         @NonNull OnPermissionDescription permissionDescription,
                                         @Nullable OnPermissionCallback callback) {
        SharedPreferences sharedPreferences = activity.getSharedPreferences(SP_NAME_PERMISSION_REQUEST_TIME_RECORD, Context.MODE_PRIVATE);
        String permissionKey = String.valueOf(requestList);
        long lastRequestPermissionTime = sharedPreferences.getLong(permissionKey, 0);
        if (System.currentTimeMillis() - lastRequestPermissionTime <= 1000 * 60 * 60 * 24 * 2) {
            List<IPermission> deniedList = XXPermissions.getDeniedPermissions(activity, requestList);
            List<IPermission> grantedList = new ArrayList<>(requestList);
            grantedList.removeAll(deniedList);
            onRequestPermissionEnd(activity, true, requestList, grantedList, deniedList, callback);
            return;
        }
        sharedPreferences.edit().putLong(permissionKey, System.currentTimeMillis()).apply();
        // 如果之前没有申请过权限,或者距离上次申请已经超过了 48 个小时,则进行申请权限
        dispatchPermissionRequest(activity, requestList, fragmentFactory, permissionDescription, callback);
    }
}
```

================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, June 2018
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2018 Huang JinQun

   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 License 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.


================================================
FILE: README-en.md
================================================
# [中文文档](README.md)

# Permission request framework

![](logo.png)

* project address: [Github](https://github.com/getActivity/XXPermissions)

* [Click here to download demo apk directly](https://github.com/getActivity/XXPermissions/releases/download/28.0/XXPermissions.apk)

![](picture/en/demo_request_permission_activity.jpg) ![](picture/en/demo_request_single_permission.jpg) ![](picture/en/demo_request_group_permission.jpg)

![](picture/en/demo_request_system_alert_window_permission.jpg) ![](picture/en/demo_request_notification_service_permission.jpg) ![](picture/en/demo_request_notification_service_channel_permission.jpg) 

![](picture/en/demo_request_full_screen_notifications_permission.jpg) ![](picture/en/demo_request_write_settings_permission.jpg) ![](picture/en/demo_request_manage_storage_permission.jpg) 

![](picture/en/demo_request_usage_stats_permission.jpg) ![](picture/en/demo_request_schedule_exact_alarm_permission.jpg) ![](picture/en/demo_request_bind_notification_listener_permission.jpg) 

![](picture/en/demo_request_access_notification_policy_permission.jpg) ![](picture/en/demo_request_ignore_battery_optimizations_permission.jpg) ![](picture/en/demo_request_bind_vpn_service_permission.jpg) 

![](picture/en/demo_request_accessibility_service_permission.jpg) ![](picture/en/demo_request_device_admin_permission.jpg) ![](picture/en/demo_request_picture_in_picture_permission.jpg)

![](picture/en/demo_request_health_data_permission_1.jpg) ![](picture/en/demo_request_health_data_permission_2.jpg)

#### Integration steps

* If your project Gradle configuration is in `7.0` below, needs to be in `build.gradle` file added

```groovy
allprojects {
    repositories {
        // JitPack remote repository:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
```

* If your Gradle configuration is `7.0` or above, needs to be in `settings.gradle` file added

```groovy
dependencyResolutionManagement {
    repositories {
        // JitPack remote repository:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
```

* After configuring the remote warehouse, under the project app module `build.gradle` Add remote dependencies to the file

```groovy
android {
    // Support JDK 1.8
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // Device compatibility framework:https://github.com/getActivity/DeviceCompat
    implementation 'com.github.getActivity:DeviceCompat:2.3'
    // Permission request framework:https://github.com/getActivity/XXPermissions
    implementation 'com.github.getActivity:XXPermissions:28.0'
}
```

#### Support library compatible

* Option 1: Use remote dependencies of the old version framework

```groovy
dependencies {
    // Device compatibility framework:https://github.com/getActivity/DeviceCompat
    implementation 'com.github.getActivity:DeviceCompat:2.3'
    // Permission request framework:https://github.com/getActivity/XXPermissions
    implementation 'com.github.getActivity:XXPermissions:26.8'
}
```

* Option 2: If your project is still in the Support phase and it's not convenient to migrate to **AndroidX** yet, but you want to use the latest version of the framework, you can use the [JetifierStandalone](https://developer.android.com/tools/jetifier#install) tool provided by **Google** to convert the **aar** packages from the released Release versions into **Support-compatible aar** packages using reverse mode.

* You can choose either of the above two options, but it's still not recommended. These are only stopgap measures, not long-term solutions. Subsequent versions of the framework will no longer support **Support** projects. The best approach is to migrate your project to **AndroidX**.

#### scoped storage

* If the project has been adapted to the Android 10 scoped storage feature, please go to`AndroidManifest.xml`join in

```xml
<manifest>

    <application>

        <!-- Inform XXPermissions that the current project has adapted to the scoped storage feature -->
        <meta-data
            android:name="ScopedStorage"
            android:value="true" />

    </application>

</manifest>
```

* If the current project does not adapt to this feature, then this step can be ignored

* It should be noted that this option is used by the framework to determine whether the current project is adapted to scoped storage. It should be noted that if your project has been adapted to the scoped storage feature, you can use`READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE`To apply for permission, if your project has not yet adapted to the partition feature, even if you apply`READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE`The permissions will also cause the files on the external storage to be unable to be read normally. If your project is not suitable for scoped storage, please use`MANAGE_EXTERNAL_STORAGE`To apply for permission, so that the files on the external storage can be read normally. If you want to know more about the features of Android 10 partition storage, you can[Click here to view and learn](https://github.com/getActivity/AndroidVersionAdapter#android-100).

#### Frame obfuscation rules

The framework has automatically added the framework's obfuscation rules for you internally. When you add the framework's dependent remote libraries, the framework's obfuscation rules will also be carried into your project. You don't need to add them manually yourself. Specific obfuscation rule content [Click here to view](library/proguard-permissions.pro)

#### One code to get permission request has never been easier

* Java code example

```java
XXPermissions.with(this)
    // Request multiple permission
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getCameraPermission())
    // Setting does not trigger error detection mechanism (local setting)
    //.unchecked()
    .request(new OnPermissionCallback() {

        @Override
        public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
            boolean allGranted = deniedList.isEmpty();
            if (!allGranted) {
                // Determine whether the permissions that failed requests have been checked by the user to no longer ask
                boolean doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList);
                // The logic for failing to handle permission requests here
                ......
                return;
            }
            // The logic for handling permission requests here is successful
            ......
        }
    });
```

* Kotlin code example

```kotlin

XXPermissions.with(this)
    // Request multiple permission
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getCameraPermission())
    // Setting does not trigger error detection mechanism (local setting)
    //.unchecked()
    .request(object : OnPermissionCallback {

        override fun onResult(grantedList: MutableList<IPermission>, deniedList: MutableList<IPermission>) {
            val allGranted = deniedList.isEmpty()
            if (!allGranted) {
                // Determine whether the permissions that failed requests have been checked by the user to no longer ask
                val doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList)
                // The logic for failing to handle permission requests here
                // ......
                return
            }
            // The logic for handling permission requests here is successful
            // ......
        }
    })
```

#### Introduction to other APIs of the framework

```java
// Check if a single permission is granted
XXPermissions.isGrantedPermission(@NonNull Context context, @NonNull IPermission permission);
XXPermissions.isGrantedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.isGrantedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// Get the granted permissions from a permission list
XXPermissions.getGrantedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.getGrantedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// Get the denied permissions from a permission list
XXPermissions.getDeniedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.getDeniedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// Determine whether the two permissions are equal
XXPermissions.equalsPermission(@NonNull IPermission permission, @NonNull IPermission permission2);
XXPermissions.equalsPermission(@NonNull IPermission permission, @NonNull String permissionName);
XXPermissions.equalsPermission(@NonNull String permissionName1, @NonNull String permissionName2);

// Determine whether a certain permission is included in the permission list
XXPermissions.containsPermission(@NonNull List<IPermission> permissions, @NonNull IPermission permission);
XXPermissions.containsPermission(@NonNull List<IPermission> permissions, @NonNull String permissionName);

// Check if a permission is a health permission
XXPermissions.isHealthPermission(@NonNull IPermission permission);

// Check if a permission has been denied with the "Never ask again" option selected 
// (Must be called within the permission request callback to be effective)
XXPermissions.isDoNotAskAgainPermission(@NonNull Activity activity, @NonNull IPermission permission);
XXPermissions.isDoNotAskAgainPermissions(@NonNull Activity activity, @NonNull IPermission[] permissions);
XXPermissions.isDoNotAskAgainPermissions(@NonNull Activity activity, @NonNull List<IPermission> permissions);

// Navigate to the permission settings page (Context version)
XXPermissions.startPermissionActivity(@NonNull Context context);
XXPermissions.startPermissionActivity(@NonNull Context context, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Context context, @NonNull List<IPermission> permissions);

// Navigate to the permission settings page (Activity version)
XXPermissions.startPermissionActivity(@NonNull Activity activity);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// Navigate to the permission settings page (Android Fragment version)
XXPermissions.startPermissionActivity(@NonNull Fragment fragment);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// Navigate to the permission settings page (AndroidX Fragment version)
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// Set the permission description provider (Global setting)
XXPermissions.setPermissionDescription(Class<? extends OnPermissionDescription> clazz);

// Set the permission request interceptor (Global setting)
XXPermissions.setPermissionInterceptor(Class<? extends OnPermissionInterceptor> clazz);

// Set whether to enable error detection mode (Global setting)
XXPermissions.setCheckMode(boolean checkMode);
```

#### Comparison between similar permission request frameworks

|                       Adaptation details                     | [XXPermissions](https://github.com/getActivity/XXPermissions)  | [AndPermission](https://github.com/yanzhenjie/AndPermission) | [PermissionX](https://github.com/guolindev/PermissionX) |  [AndroidUtilCode-PermissionUtils](https://github.com/Blankj/AndroidUtilCode)   | [PermissionsDispatcher](https://github.com/permissions-dispatcher/PermissionsDispatcher) | [RxPermissions](https://github.com/tbruyelle/RxPermissions) |  [EasyPermissions](https://github.com/googlesamples/easypermissions) |  [Dexter](https://github.com/Karumi/Dexter) |
|:------------------------------------------------------------:| :------------: | :------------: | :------------: | :------------: | :------------: | :------------: | :------------: | :------------: |
|                     Corresponding version                    |  28.0 |  2.0.3  |  1.8.1    |  1.31.0    |   4.9.2  |  0.12   |  3.0.0   |  6.2.3   |
|                        Number of issues                      |  [![](https://img.shields.io/github/issues/getActivity/XXPermissions.svg)](https://github.com/getActivity/XXPermissions/issues)  |  [![](https://img.shields.io/github/issues/yanzhenjie/AndPermission.svg)](https://github.com/yanzhenjie/AndPermission/issues)  |  [![](https://img.shields.io/github/issues/guolindev/PermissionX.svg)](https://github.com/guolindev/PermissionX/issues)  |  [![](https://img.shields.io/github/issues/Blankj/AndroidUtilCode.svg)](https://github.com/Blankj/AndroidUtilCode/issues)  |  [![](https://img.shields.io/github/issues/permissions-dispatcher/PermissionsDispatcher.svg)](https://github.com/permissions-dispatcher/PermissionsDispatcher/issues)  |  [![](https://img.shields.io/github/issues/tbruyelle/RxPermissions.svg)](https://github.com/tbruyelle/RxPermissions/issues)  |  [![](https://img.shields.io/github/issues/googlesamples/easypermissions.svg)](https://github.com/googlesamples/easypermissions/issues)  |  [![](https://img.shields.io/github/issues/Karumi/Dexter.svg)](https://github.com/Karumi/Dexter/issues)  |
|                  Framework Maintenance Status                |**In maintenance**|  stop maintenance | stop maintenance |  stop maintenance | stop maintenance | stop maintenance | stop maintenance | stop maintenance |
|                     `SCHEDULE_EXACT_ALARM`                   |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                   `MANAGE_EXTERNAL_STORAGE`                  |  ✅  |  ❌  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                   `REQUEST_INSTALL_PACKAGES`                 |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                      `PICTURE_IN_PICTURE`                    |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                     `SYSTEM_ALERT_WINDOW`                    |  ✅  |  ✅  |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |
|                        `WRITE_SETTINGS`                      |  ✅  |  ✅  |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |
|                     `NOTIFICATION_SERVICE`                   |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                `NOTIFICATION_SERVICE`(Channel)               |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|              `BIND_NOTIFICATION_LISTENER_SERVICE`            |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                  `ACCESS_NOTIFICATION_POLICY`                |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|             `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`           |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                     `PACKAGE_USAGE_STATS`                    |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                    `USE_FULL_SCREEN_INTENT`                  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                       `BIND_VPN_SERVICE`                     |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                  `BIND_ACCESSIBILITY_SERVICE`                |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                      `BIND_DEVICE_ADMIN`                     |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                        `MANAGE_MEDIA`                        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|             Intent Extreme Jump Fallback Mechanism           |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|     Compatibility with Permission Request API Crash Issues   |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|    Avoiding System Permission Callback Null Pointer Issues   |  ✅  |   ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|              Automatic Permission Split Requests             |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|            Framework Completely Separates UI Layer           |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|    Core Logic and Specific Permissions Completely Decoupled  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ✅  |  ✅  |  ✅  |
|           Automatic Background Permission Adaptation         |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|          Support for Cross-Platform Environment Calls        |  ✅  |  ✅  |  ❌  |  ✅  |  ❌  |  ❌  |  ✅  |  ✅  |
|           Callback Lifecycle Synchronized with Host          |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|             Support for Custom Permission Requests           |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|     New Version Permissions Support Backward Compatibility   |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|              Screen Rotation Scenario Adaptation             |  ✅  |  ❌  |  ✅  |  ❌ |  ❌  |  ❌   |  ❌  |  ❌  |
|       Background Permission Request Scenario Adaptation      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                Fix Android 12 Memory Leak Issue              |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|                Support for Code Error Detection              |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |

#### [For specific implementation details, please click here to view](Details-en.md)

#### [For other frequently asked questions, please click here](HelpDoc-en.md)

#### Framework highlights

* Take the lead: the first permission request framework adapted to Android 16

* Concise and easy to use: using the method of chain call, only one line of code is needed to use

* Comprehensive support: the first and only permission request framework that adapts to all Android versions

* Overcoming technical difficulties: the first framework to solve system memory leaks in Android 12 for permission applications

* Adapt to extreme situations: No matter how extreme and harsh the environment is to apply for permissions, the framework is still strong

* Downward Compatibility: New permissions can be applied normally in the old system, and the framework will automatically adapt without the caller's adaptation

* Automatic error detection: If an error occurs, the framework will actively throw an exception to the caller (only judged under Debug, and kill the bug in the cradle)

#### Author's other open source projects

* Android middle office: [AndroidProject](https://github.com/getActivity/AndroidProject)![](https://img.shields.io/github/stars/getActivity/AndroidProject.svg)![](https://img.shields.io/github/forks/getActivity/AndroidProject.svg)

* Android middle office kt version: [AndroidProject-Kotlin](https://github.com/getActivity/AndroidProject-Kotlin)![](https://img.shields.io/github/stars/getActivity/AndroidProject-Kotlin.svg)![](https://img.shields.io/github/forks/getActivity/AndroidProject-Kotlin.svg)

* Toast framework: [Toaster](https://github.com/getActivity/Toaster)![](https://img.shields.io/github/stars/getActivity/Toaster.svg)![](https://img.shields.io/github/forks/getActivity/Toaster.svg)

* Network framework: [EasyHttp](https://github.com/getActivity/EasyHttp)![](https://img.shields.io/github/stars/getActivity/EasyHttp.svg)![](https://img.shields.io/github/forks/getActivity/EasyHttp.svg)

* Title bar framework: [TitleBar](https://github.com/getActivity/TitleBar)![](https://img.shields.io/github/stars/getActivity/TitleBar.svg)![](https://img.shields.io/github/forks/getActivity/TitleBar.svg)

* Floating window framework: [EasyWindow](https://github.com/getActivity/EasyWindow)![](https://img.shields.io/github/stars/getActivity/EasyWindow.svg)![](https://img.shields.io/github/forks/getActivity/EasyWindow.svg)

* Device compatibility framework:[DeviceCompat](https://github.com/getActivity/DeviceCompat) ![](https://img.shields.io/github/stars/getActivity/DeviceCompat.svg) ![](https://img.shields.io/github/forks/getActivity/DeviceCompat.svg)

* Shape view framework: [ShapeView](https://github.com/getActivity/ShapeView)![](https://img.shields.io/github/stars/getActivity/ShapeView.svg)![](https://img.shields.io/github/forks/getActivity/ShapeView.svg)

* Shape drawable framework: [ShapeDrawable](https://github.com/getActivity/ShapeDrawable)![](https://img.shields.io/github/stars/getActivity/ShapeDrawable.svg)![](https://img.shields.io/github/forks/getActivity/ShapeDrawable.svg)

* Language switching framework: [Multi Languages](https://github.com/getActivity/MultiLanguages)![](https://img.shields.io/github/stars/getActivity/MultiLanguages.svg)![](https://img.shields.io/github/forks/getActivity/MultiLanguages.svg)

* Gson parsing fault tolerance: [GsonFactory](https://github.com/getActivity/GsonFactory)![](https://img.shields.io/github/stars/getActivity/GsonFactory.svg)![](https://img.shields.io/github/forks/getActivity/GsonFactory.svg)

* Logcat viewing framework: [Logcat](https://github.com/getActivity/Logcat)![](https://img.shields.io/github/stars/getActivity/Logcat.svg)![](https://img.shields.io/github/forks/getActivity/Logcat.svg)

* Nested scrolling layout framework:[NestedScrollLayout](https://github.com/getActivity/NestedScrollLayout) ![](https://img.shields.io/github/stars/getActivity/NestedScrollLayout.svg) ![](https://img.shields.io/github/forks/getActivity/NestedScrollLayout.svg)

* Android version guide: [AndroidVersionAdapter](https://github.com/getActivity/AndroidVersionAdapter)![](https://img.shields.io/github/stars/getActivity/AndroidVersionAdapter.svg)![](https://img.shields.io/github/forks/getActivity/AndroidVersionAdapter.svg)

* Android code standard: [AndroidCodeStandard](https://github.com/getActivity/AndroidCodeStandard)![](https://img.shields.io/github/stars/getActivity/AndroidCodeStandard.svg)![](https://img.shields.io/github/forks/getActivity/AndroidCodeStandard.svg)

* Android resource summary:[AndroidIndex](https://github.com/getActivity/AndroidIndex) ![](https://img.shields.io/github/stars/getActivity/AndroidIndex.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidIndex.svg)

* Android open source leaderboard: [AndroidGithubBoss](https://github.com/getActivity/AndroidGithubBoss)![](https://img.shields.io/github/stars/getActivity/AndroidGithubBoss.svg)![](https://img.shields.io/github/forks/getActivity/AndroidGithubBoss.svg)

* Studio boutique plugins: [StudioPlugins](https://github.com/getActivity/StudioPlugins)![](https://img.shields.io/github/stars/getActivity/StudioPlugins.svg)![](https://img.shields.io/github/forks/getActivity/StudioPlugins.svg)

* Emoji collection: [EmojiPackage](https://github.com/getActivity/EmojiPackage)![](https://img.shields.io/github/stars/getActivity/EmojiPackage.svg)![](https://img.shields.io/github/forks/getActivity/EmojiPackage.svg)

* China provinces json: [ProvinceJson](https://github.com/getActivity/ProvinceJson)![](https://img.shields.io/github/stars/getActivity/ProvinceJson.svg)![](https://img.shields.io/github/forks/getActivity/ProvinceJson.svg)

* Markdown documentation:[MarkdownDoc](https://github.com/getActivity/MarkdownDoc) ![](https://img.shields.io/github/stars/getActivity/MarkdownDoc.svg) ![](https://img.shields.io/github/forks/getActivity/MarkdownDoc.svg)

## License

```text
Copyright 2018 Huang JinQun

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 License 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.
```

================================================
FILE: README.md
================================================
# [English Doc](README-en.md)

# 权限请求框架

![](logo.png)

* 项目地址:[Github](https://github.com/getActivity/XXPermissions)

* 博文地址:[月下载 40 万次的框架是怎么练成的?](https://juejin.cn/post/7547408384585629711)

* 可以扫码下载 Demo 进行演示或者测试,如果扫码下载不了的,[点击此处可直接下载](https://github.com/getActivity/XXPermissions/releases/download/28.0/XXPermissions.apk)

![](picture/zh/download_demo_apk_qr_code.png)

![](picture/zh/demo_request_permission_activity.jpg) ![](picture/zh/demo_request_single_permission.jpg) ![](picture/zh/demo_request_group_permission.jpg)

![](picture/zh/demo_request_system_alert_window_permission.jpg) ![](picture/zh/demo_request_notification_service_permission.jpg) ![](picture/zh/demo_request_notification_service_channel_permission.jpg) 

![](picture/zh/demo_request_full_screen_notifications_permission.jpg) ![](picture/zh/demo_request_write_settings_permission.jpg) ![](picture/zh/demo_request_manage_storage_permission.jpg) 

![](picture/zh/demo_request_usage_stats_permission.jpg) ![](picture/zh/demo_request_schedule_exact_alarm_permission.jpg) ![](picture/zh/demo_request_bind_notification_listener_permission.jpg) 

![](picture/zh/demo_request_access_notification_policy_permission.jpg) ![](picture/zh/demo_request_ignore_battery_optimizations_permission.jpg) ![](picture/zh/demo_request_bind_vpn_service_permission.jpg) 

![](picture/zh/demo_request_picture_in_picture_permission.jpg) ![](picture/zh/demo_request_accessibility_service_permission.jpg) ![](picture/zh/demo_request_device_admin_permission.jpg) 

![](picture/zh/demo_request_get_installed_apps_permission.jpg) ![](picture/zh/demo_request_health_data_permission_1.jpg) ![](picture/zh/demo_request_health_data_permission_2.jpg)

#### 集成步骤

* 如果你的项目 Gradle 配置是在 `7.0` 以下,需要在 `build.gradle` 文件中加入

```groovy
allprojects {
    repositories {
        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
```

* 如果你的 Gradle 配置是 `7.0` 及以上,则需要在 `settings.gradle` 文件中加入

```groovy
dependencyResolutionManagement {
    repositories {
        // JitPack 远程仓库:https://jitpack.io
        maven { url 'https://jitpack.io' }
    }
}
```

* 配置完远程仓库后,在项目 app 模块下的 `build.gradle` 文件中加入远程依赖

```groovy
android {
    // 支持 JDK 1.8 及以上
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // 设备兼容框架:https://github.com/getActivity/DeviceCompat
    implementation 'com.github.getActivity:DeviceCompat:2.3'
    // 权限请求框架:https://github.com/getActivity/XXPermissions
    implementation 'com.github.getActivity:XXPermissions:28.0'
}
```

#### Support 库兼容

* 方案一:沿用旧版本框架的远程依赖

```
dependencies {
    // 设备兼容框架:https://github.com/getActivity/DeviceCompat
    implementation 'com.github.getActivity:DeviceCompat:2.3'
    // 权限请求框架:https://github.com/getActivity/XXPermissions
    implementation 'com.github.getActivity:XXPermissions:26.8'
}
```

* 方案二:如果你的项目仍处于 Support 阶段,目前不方便转到 **AndroidX** 中来,但又想用最新版本的框架,可以使用 **Google** 提供的 [JetifierStandalone](https://developer.android.google.cn/tools/jetifier?hl=zh-cn#install) 工具将已发布版本 [Release](https://github.com/getActivity/XXPermissions/releases) 中的 **aar** 包通过反向模式转成 **Support** 版本的 **aar** 包来使用。

* 上述两种方案任选其一即可,但是仍旧不推荐你那样做,因为这些只是权宜之计,并非长久之计,框架后续的版本已不再支持 **Support** 项目,最好的方案是将项目迁移到 **AndroidX**。

* 将项目从 **Support** 迁移 **AndroidX** 相关的教程:[AndroidX 踩坑指南](https://juejin.cn/post/7053773917495754782)

#### 分区存储

* 如果项目已经适配了 Android 10 分区存储特性,请在 `AndroidManifest.xml` 中加入

```xml
<manifest>

    <application>

        <!-- 告知 XXPermissions 当前项目已经适配了分区存储特性 -->
        <meta-data
            android:name="ScopedStorage"
            android:value="true" />

    </application>

</manifest>
```

* 如果当前项目没有适配这特性,那么这一步骤可以忽略

* 需要注意的是:这个选项是框架用于判断当前项目是否适配了分区存储,需要注意的是,如果你的项目已经适配了分区存储特性,可以使用 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 来申请权限,如果你的项目还没有适配分区特性,就算申请了 `READ_EXTERNAL_STORAGE`、`WRITE_EXTERNAL_STORAGE` 权限也会导致无法正常读取外部存储上面的文件,如果你的项目没有适配分区存储,请使用 `MANAGE_EXTERNAL_STORAGE` 来申请权限,这样才能正常读取外部存储上面的文件,你如果想了解更多关于 Android 10 分区存储的特性,可以[点击此处查看和学习](https://github.com/getActivity/AndroidVersionAdapter#android-100)。

#### 框架混淆规则

* 框架已经在内部自动帮你添加了框架的混淆规则,在你添加框架的依赖远程库的时候,框架的混淆规则也会一同携带到你的项目中,你无需自己手动添加,具体的混淆规则内容 [可点击此处查看](library/proguard-permissions.pro)

#### 一句代码搞定权限请求,从未如此简单

* Java 用法示例

```java
XXPermissions.with(this)
    // 申请多个权限
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getCameraPermission())
    // 设置不触发错误检测机制(局部设置)
    //.unchecked()
    .request(new OnPermissionCallback() {

        @Override
        public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
            boolean allGranted = deniedList.isEmpty();
            if (!allGranted) {
                // 判断请求失败的权限是否被用户勾选了不再询问的选项
                boolean doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList);
                // 在这里处理权限请求失败的逻辑
                ......
                return;
            }
            // 在这里处理权限请求成功的逻辑
            ......
        }
    });
```

* Kotlin 用法示例

```kotlin

XXPermissions.with(this)
    // 申请多个权限
    .permission(PermissionLists.getRecordAudioPermission())
    .permission(PermissionLists.getCameraPermission())
    // 设置不触发错误检测机制(局部设置)
    //.unchecked()
    .request(object : OnPermissionCallback {
        
        override fun onResult(grantedList: MutableList<IPermission>, deniedList: MutableList<IPermission>) {
            val allGranted = deniedList.isEmpty()
            if (!allGranted) {
                // 判断请求失败的权限是否被用户勾选了不再询问的选项
                val doNotAskAgain = XXPermissions.isDoNotAskAgainPermissions(activity, deniedList)
                // 在这里处理权限请求失败的逻辑
                // ......
                return
            }
            // 在这里处理权限请求成功的逻辑
            // ......
        }
    })
```

#### 框架其他 API 介绍

```java
// 判断一个或多个权限是否全部授予了
XXPermissions.isGrantedPermission(@NonNull Context context, @NonNull IPermission permission);
XXPermissions.isGrantedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.isGrantedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// 从权限列表中获取已授予的权限
XXPermissions.getGrantedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.getGrantedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// 从权限列表中获取没有授予的权限
XXPermissions.getDeniedPermissions(@NonNull Context context, @NonNull IPermission[] permissions);
XXPermissions.getDeniedPermissions(@NonNull Context context, @NonNull List<IPermission> permissions);

// 判断两个权限是否相等
XXPermissions.equalsPermission(@NonNull IPermission permission, @NonNull IPermission permission2);
XXPermissions.equalsPermission(@NonNull IPermission permission, @NonNull String permissionName);
XXPermissions.equalsPermission(@NonNull String permissionName1, @NonNull String permissionName2);

// 判断权限列表中是否包含某个权限
XXPermissions.containsPermission(@NonNull List<IPermission> permissions, @NonNull IPermission permission);
XXPermissions.containsPermission(@NonNull List<IPermission> permissions, @NonNull String permissionName);

// 判断某个权限是否为健康权限
XXPermissions.isHealthPermission(@NonNull IPermission permission);

// 判断一个或多个权限是否被勾选了《不再询问》的选项(一定要在权限申请的回调方法中调用才有效果)
XXPermissions.isDoNotAskAgainPermission(@NonNull Activity activity, @NonNull IPermission permission);
XXPermissions.isDoNotAskAgainPermissions(@NonNull Activity activity, @NonNull IPermission[] permissions);
XXPermissions.isDoNotAskAgainPermissions(@NonNull Activity activity, @NonNull List<IPermission> permissions);

// 跳转到权限设置页(Context 版本)
XXPermissions.startPermissionActivity(@NonNull Context context);
XXPermissions.startPermissionActivity(@NonNull Context context, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Context context, @NonNull List<IPermission> permissions);

// 跳转到权限设置页(Activity 版本)
XXPermissions.startPermissionActivity(@NonNull Activity activity);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull Activity activity, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// 跳转到权限设置页(Android Fragment 版本)
XXPermissions.startPermissionActivity(@NonNull Fragment fragment);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull Fragment fragment, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// 跳转到权限设置页(AndroidX Fragment 版本)
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull IPermission... permissions);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions, @IntRange(from = 1, to = 65535) int requestCode);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull IPermission permission, @Nullable OnPermissionCallback callback);
XXPermissions.startPermissionActivity(@NonNull androidx.fragment.app.Fragment xFragment, @NonNull List<IPermission> permissions, @Nullable OnPermissionCallback callback);

// 设置权限描述器(全局设置)
XXPermissions.setPermissionDescription(Class<? extends OnPermissionDescription> clazz);

// 设置权限申请拦截器(全局设置)
XXPermissions.setPermissionInterceptor(Class<? extends OnPermissionInterceptor> clazz);

// 设置是否开启错误检测模式(全局设置)
XXPermissions.setCheckMode(boolean checkMode);
```

#### 同类权限请求框架之间的对比

|         适配细节         | [XXPermissions](https://github.com/getActivity/XXPermissions)  | [AndPermission](https://github.com/yanzhenjie/AndPermission) | [PermissionX](https://github.com/guolindev/PermissionX) |  [AndroidUtilCode-PermissionUtils](https://github.com/Blankj/AndroidUtilCode)   | [PermissionsDispatcher](https://github.com/permissions-dispatcher/PermissionsDispatcher) | [RxPermissions](https://github.com/tbruyelle/RxPermissions) |  [EasyPermissions](https://github.com/googlesamples/easypermissions) |  [Dexter](https://github.com/Karumi/Dexter) |
|:--------------------:| :------------: | :------------: | :------------: | :------------: | :------------: | :------------: | :------------: | :------------: |
|         对应版本         |  28.0 |  2.0.3  |  1.8.1    |  1.31.0    |   4.9.2  |  0.12   |  3.0.0   |  6.2.3   |
|       issues 数       |  [![](https://img.shields.io/github/issues/getActivity/XXPermissions.svg)](https://github.com/getActivity/XXPermissions/issues)  |  [![](https://img.shields.io/github/issues/yanzhenjie/AndPermission.svg)](https://github.com/yanzhenjie/AndPermission/issues)  |  [![](https://img.shields.io/github/issues/guolindev/PermissionX.svg)](https://github.com/guolindev/PermissionX/issues)  |  [![](https://img.shields.io/github/issues/Blankj/AndroidUtilCode.svg)](https://github.com/Blankj/AndroidUtilCode/issues)  |  [![](https://img.shields.io/github/issues/permissions-dispatcher/PermissionsDispatcher.svg)](https://github.com/permissions-dispatcher/PermissionsDispatcher/issues)  |  [![](https://img.shields.io/github/issues/tbruyelle/RxPermissions.svg)](https://github.com/tbruyelle/RxPermissions/issues)  |  [![](https://img.shields.io/github/issues/googlesamples/easypermissions.svg)](https://github.com/googlesamples/easypermissions/issues)  |  [![](https://img.shields.io/github/issues/Karumi/Dexter.svg)](https://github.com/Karumi/Dexter/issues)  |
|        框架维护状态        |**维护中**|  停止维护 | 停止维护 |  停止维护 | 停止维护 | 停止维护 | 停止维护 | 停止维护 |
|       读取应用列表权限       |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        闹钟提醒权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       所有文件管理权限       |  ✅  |  ❌  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        安装包权限         |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        画中画权限         |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        悬浮窗权限         |  ✅  |  ✅  |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |
|        系统设置权限        |  ✅  |  ✅  |  ✅  |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |
|        通知栏权限         |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       通知栏渠道权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       通知栏监听权限        |  ✅  |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|         勿扰权限         |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       忽略电池优化权限       |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|      查看应用使用情况权限      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        全屏通知权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        VPN 权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        无障碍权限         |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       设备管理器权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|        管理媒体权限        |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|   Intent 跳转极限兜底机制    |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|   兼容请求权限 API 崩溃问题    |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|    规避系统权限回调空指针问题     |  ✅  |   ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|      应用商店权限合规处理      |  ✅  |  ❌  |  ❌   |   ✅  |  ❌  |  ❌  |  ❌  |  ❌  |
|      自动拆分权限进行请求      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|    框架内部完全剥离 UI 层     |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|    核心逻辑和具体权限完全解耦     |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ✅  |  ✅  |  ✅  |
|       自动适配后台权限       |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|     支持在跨平台环境中调用      |  ✅  |  ✅  |  ❌  |  ✅  |  ❌  |  ❌  |  ✅  |  ✅  |
|    回调生命周期与宿主保持同步     |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|      支持自定义权限申请       |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|      支持读取应用列表权限      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|     新版本权限支持向下兼容      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       屏幕旋转场景适配       |  ✅  |  ❌  |  ✅  |  ❌ |  ❌  |  ❌   |  ❌  |  ❌  |
|      后台申请权限场景适配      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
| 修复 Android 12 内存泄漏问题 |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|      第三方厂商兼容性优化      |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |
|       支持检测代码错误       |  ✅  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |  ❌  |

#### [具体实现细节请点击这里查看](Details-zh.md)

#### [其他常见疑问请点击此处查看](HelpDoc-zh.md)

#### 框架亮点

* 一马当先:首款适配 Android 16 的权限请求框架

* 简洁易用:采用链式调用的方式,使用只需一句代码

* 支持全面:首款也是唯一一款适配所有 Android 版本的权限请求框架

* 技术难题攻坚:首款解决权限申请在 Android 12 出现系统内存泄漏的框架

* 适配极端情况:无论在多么极端恶劣的环境下申请权限,框架依然坚挺

* 向下兼容属性:新权限在旧系统可以正常申请,框架会做自动适配,无需调用者适配

* 自动检测错误:如果出现错误框架会主动抛出异常给调用者(仅在 Debug 下判断,把 Bug 扼杀在摇篮中)

#### 作者的其他开源项目

* 安卓技术中台:[AndroidProject](https://github.com/getActivity/AndroidProject) ![](https://img.shields.io/github/stars/getActivity/AndroidProject.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject.svg)

* 安卓技术中台 Kt 版:[AndroidProject-Kotlin](https://github.com/getActivity/AndroidProject-Kotlin) ![](https://img.shields.io/github/stars/getActivity/AndroidProject-Kotlin.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidProject-Kotlin.svg)

* 吐司框架:[Toaster](https://github.com/getActivity/Toaster) ![](https://img.shields.io/github/stars/getActivity/Toaster.svg) ![](https://img.shields.io/github/forks/getActivity/Toaster.svg)

* 网络框架:[EasyHttp](https://github.com/getActivity/EasyHttp) ![](https://img.shields.io/github/stars/getActivity/EasyHttp.svg) ![](https://img.shields.io/github/forks/getActivity/EasyHttp.svg)

* 标题栏框架:[TitleBar](https://github.com/getActivity/TitleBar) ![](https://img.shields.io/github/stars/getActivity/TitleBar.svg) ![](https://img.shields.io/github/forks/getActivity/TitleBar.svg)

* 悬浮窗框架:[EasyWindow](https://github.com/getActivity/EasyWindow) ![](https://img.shields.io/github/stars/getActivity/EasyWindow.svg) ![](https://img.shields.io/github/forks/getActivity/EasyWindow.svg)

* 设备兼容框架:[DeviceCompat](https://github.com/getActivity/DeviceCompat) ![](https://img.shields.io/github/stars/getActivity/DeviceCompat.svg) ![](https://img.shields.io/github/forks/getActivity/DeviceCompat.svg)

* ShapeView 框架:[ShapeView](https://github.com/getActivity/ShapeView) ![](https://img.shields.io/github/stars/getActivity/ShapeView.svg) ![](https://img.shields.io/github/forks/getActivity/ShapeView.svg)

* ShapeDrawable 框架:[ShapeDrawable](https://github.com/getActivity/ShapeDrawable) ![](https://img.shields.io/github/stars/getActivity/ShapeDrawable.svg) ![](https://img.shields.io/github/forks/getActivity/ShapeDrawable.svg)

* 语种切换框架:[MultiLanguages](https://github.com/getActivity/MultiLanguages) ![](https://img.shields.io/github/stars/getActivity/MultiLanguages.svg) ![](https://img.shields.io/github/forks/getActivity/MultiLanguages.svg)

* Gson 解析容错:[GsonFactory](https://github.com/getActivity/GsonFactory) ![](https://img.shields.io/github/stars/getActivity/GsonFactory.svg) ![](https://img.shields.io/github/forks/getActivity/GsonFactory.svg)

* 日志查看框架:[Logcat](https://github.com/getActivity/Logcat) ![](https://img.shields.io/github/stars/getActivity/Logcat.svg) ![](https://img.shields.io/github/forks/getActivity/Logcat.svg)

* 嵌套滚动布局框架:[NestedScrollLayout](https://github.com/getActivity/NestedScrollLayout) ![](https://img.shields.io/github/stars/getActivity/NestedScrollLayout.svg) ![](https://img.shields.io/github/forks/getActivity/NestedScrollLayout.svg)

* Android 版本适配:[AndroidVersionAdapter](https://github.com/getActivity/AndroidVersionAdapter) ![](https://img.shields.io/github/stars/getActivity/AndroidVersionAdapter.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidVersionAdapter.svg)

* Android 代码规范:[AndroidCodeStandard](https://github.com/getActivity/AndroidCodeStandard) ![](https://img.shields.io/github/stars/getActivity/AndroidCodeStandard.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidCodeStandard.svg)

* Android 资源大汇总:[AndroidIndex](https://github.com/getActivity/AndroidIndex) ![](https://img.shields.io/github/stars/getActivity/AndroidIndex.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidIndex.svg)

* Android 开源排行榜:[AndroidGithubBoss](https://github.com/getActivity/AndroidGithubBoss) ![](https://img.shields.io/github/stars/getActivity/AndroidGithubBoss.svg) ![](https://img.shields.io/github/forks/getActivity/AndroidGithubBoss.svg)

* Studio 精品插件:[StudioPlugins](https://github.com/getActivity/StudioPlugins) ![](https://img.shields.io/github/stars/getActivity/StudioPlugins.svg) ![](https://img.shields.io/github/forks/getActivity/StudioPlugins.svg)

* 表情包大集合:[EmojiPackage](https://github.com/getActivity/EmojiPackage) ![](https://img.shields.io/github/stars/getActivity/EmojiPackage.svg) ![](https://img.shields.io/github/forks/getActivity/EmojiPackage.svg)

* AI 资源大汇总:[AiIndex](https://github.com/getActivity/AiIndex) ![](https://img.shields.io/github/stars/getActivity/AiIndex.svg) ![](https://img.shields.io/github/forks/getActivity/AiIndex.svg)

* 省市区 Json 数据:[ProvinceJson](https://github.com/getActivity/ProvinceJson) ![](https://img.shields.io/github/stars/getActivity/ProvinceJson.svg) ![](https://img.shields.io/github/forks/getActivity/ProvinceJson.svg)

* Markdown 语法文档:[MarkdownDoc](https://github.com/getActivity/MarkdownDoc) ![](https://img.shields.io/github/stars/getActivity/MarkdownDoc.svg) ![](https://img.shields.io/github/forks/getActivity/MarkdownDoc.svg)

#### 微信公众号:Android轮子哥

![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/official_ccount.png)

#### Android 技术 Q 群:10047167

#### 如果您觉得我的开源库帮你节省了大量的开发时间,请扫描下方的二维码随意打赏,要是能打赏个 10.24 :monkey_face:就太:thumbsup:了。您的支持将鼓励我继续创作:octocat:([点击查看捐赠列表](https://github.com/getActivity/Donate))

![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_ali.png) ![](https://raw.githubusercontent.com/getActivity/Donate/master/picture/pay_wechat.png)

## License

```text
Copyright 2018 Huang JinQun

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 License 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.
```

================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply from : '../common.gradle'

android {

    namespace 'com.hjq.permissions.demo'

    defaultConfig {
        applicationId "com.hjq.permissions.demo"
        // 最低安装版本
        minSdkVersion 18
    }

    // Apk 签名的那些事:https://www.jianshu.com/p/a1f8e5896aa2
    signingConfigs {
        config {
            storeFile file(StoreFile)
            storePassword StorePassword
            keyAlias KeyAlias
            keyPassword KeyPassword
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        }

        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config
        }
    }

    applicationVariants.configureEach { variant ->
        // apk 输出文件名配置
        variant.outputs.configureEach { output ->
            outputFileName = rootProject.getName() + '.apk'
        }
    }
}

dependencies {
    // 依赖 libs 目录下所有的 jar 和 aar 包
    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')

    implementation project(':library')

    // 谷歌兼容库:https://developer.android.google.cn/jetpack/androidx/releases/appcompat?hl=zh-cn
    // noinspection GradleCompatible
    implementation 'androidx.appcompat:appcompat:1.0.0'

    // 设备兼容框架:https://github.com/getActivity/DeviceCompat
    implementation 'com.github.getActivity:DeviceCompat:2.3'

    // 吐司框架:https://github.com/getActivity/Toaster
    implementation 'com.github.getActivity:Toaster:13.8'

    // 标题栏框架:https://github.com/getActivity/TitleBar
    implementation 'com.github.getActivity:TitleBar:10.8'

    // 内存泄漏检测:https://github.com/square/leakcanary
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}

================================================
FILE: app/gradle.properties
================================================
StoreFile = AppSignature.jks
StorePassword = AndroidProject
KeyAlias = AndroidProject
KeyPassword = AndroidProject

================================================
FILE: app/proguard-rules.pro
================================================


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.hjq.permissions.demo">

    <!-- 读取应用列表权限(危险权限,电信终端产业协会联合各大中国手机厂商搞的一个权限) -->
    <uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />

    <!-- 查询所有包信息权限,此权限不需要动态申请 -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />

    <!-- 全屏通知权限(特殊权限,Android 14 新增的权限)-->
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />

    <!-- 闹钟权限(特殊权限,Android 12 新增的权限) -->
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
    <!-- 给 SCHEDULE_EXACT_ALARM 权限加上 android:maxSdkVersion="32" 属性的原因和方法介绍:-->
    <!-- https://developer.android.google.cn/reference/android/Manifest.permission#USE_EXACT_ALARM -->
    <!--<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" android:maxSdkVersion="32" />-->
    <!-- 在清单文件在注册此权限,Android 13 及以上的系统会让闹钟权限(即 SCHEDULE_EXACT_ALARM)默认是授权状态,如果不加则默认是未授权状态 -->
    <!-- 如果你的应用要上架 GooglePlay,那么需要慎重添加此权限,因为不是日历、闹钟、时钟这类应用添加这个权限很难通过 GooglePlay 上架审核 -->
    <!--<uses-permission android:name="android.permission.USE_EXACT_ALARM" />-->

    <!-- 管理媒体权限(特殊权限,Android 12 新增的权限)-->
    <uses-permission android:name="android.permission.MANAGE_MEDIA" tools:ignore="ProtectedPermissions" />

    <!-- 文件管理权限(特殊权限,Android 11 新增的权限)-->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <!-- 安装应用权限(特殊权限,Android 8.0 新增的权限)-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <!-- 悬浮窗权限(特殊权限,Android 6.0 新增的权限,但是有些国产的厂商在 Android 6.0 之前的设备就兼容了) -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

    <!-- 写入系统设置权限(特殊权限,Android 6.0 新增的权限)-->
    <uses-permission android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />

    <!-- 请求忽略电池优化选项权限(特殊权限,Android 6.0 新增的权限)-->
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

    <!-- 勿扰权限,可控制手机响铃模式【静音,震动】(特殊权限,Android 6.0 新增的权限)-->
    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />

    <!-- 查看应用使用情况权限,简称使用统计权限(特殊权限,Android 5.0 新增的权限)-->
    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />

    <!--                                              我是一条华丽的分割线                                              -->

    <!-- 授予对照片和视频的部分访问权限(Android 14.0 新增的权限)-->
    <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />

    <!-- 发送通知权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <!-- WIFI 权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" />

    <!-- 后台传感器权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" />

    <!-- 读取图片权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

    <!-- 读取视频权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!-- 读取音频权限(Android 13.0 新增的权限)-->
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

    <!-- 蓝牙扫描权限(Android 12.0 新增的权限) -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="s" />

    <!-- 蓝牙连接权限(Android 12.0 新增的权限)-->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

    <!-- 蓝牙广播权限(Android 12.0 新增的权限)-->
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

    <!-- 旧版的蓝牙权限,只要静态注册即可 -->
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />

    <!-- 在后台获取位置(Android 10.0 新增的权限)-->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!-- 获取活动步数权限(Android 10.0 新增的权限)-->
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

    <!-- 读取媒体文件的位置位置(Android 10.0 新增的权限)-->
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />

    <!-- 允许呼叫应用继续在另一个应用中启动的呼叫权限(Android 9.0 新增的权限)-->
    <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />

    <!-- 读取手机号码权限(Android 8.0 新增的权限)-->
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />

    <!-- 接听电话权限(Android 8.0 新增的权限,Android 8.0 以下可以采用模拟耳机按键事件来实现接听电话,这种方式不需要权限)-->
    <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />

    <!-- 读取外部存储权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <!-- 写入外部存储权限(注意:这个权限在 targetSdk >= Android 11 并且 Android 11 及以上的设备上面不起作用,请适配分区存储特性代替权限申请)-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

    <!-- 相机权限 -->
    <uses-permission android:name="android.permission.CAMERA" />

    <!-- 麦克风权限 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- 获取精确位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!-- 获取粗略位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!-- 读取联系人权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <!-- 修改联系人权限 -->
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />

    <!-- 访问账户列表权限 -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <!-- 读取日历权限 -->
    <uses-permission android:name="android.permission.READ_CALENDAR" />

    <!-- 修改日历权限 -->
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />

    <!-- 读取电话状态权限 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

    <!-- 拨打电话权限 -->
    <uses-permission android:name="android.permission.CALL_PHONE" />

    <!-- 读取通话记录权限 -->
    <uses-permission android:name="android.permission.READ_CALL_LOG" />

    <!-- 修改通话记录权限 -->
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />

    <!-- 添加语音邮件权限 -->
    <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />

    <!-- 使用 SIP 视频权限 -->
    <uses-permission android:name="android.permission.USE_SIP" />

    <!-- 处理拨出电话 -->
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

    <!-- 使用传感器权限 -->
    <uses-permission android:name="android.permission.BODY_SENSORS" />

    <!-- 发送短信 -->
    <uses-permission android:name="android.permission.SEND_SMS" />

    <!-- 接收短信 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <!-- 读取短信 -->
    <uses-permission android:name="android.permission.READ_SMS" />

    <!-- 接收 WAP 推送消息 -->
    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />

    <!-- 接收彩信 -->
    <uses-permission android:name="android.permission.RECEIVE_MMS" />

    <!--                                              我是一条华丽的分割线                                              -->

    <!-- 在后台读取健康数据权限(任何类型) -->
    <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />

    <!-- 读取以往的健康数据权限(任何类型) -->
    <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />

    <!-- 读取运动消耗的卡路里数据权限 -->
    <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />

    <!-- 写入运动消耗的卡路里数据权限 -->
    <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />

    <!-- 读取活动强度数据权限 -->
    <uses-permission android:name="android.permission.health.READ_ACTIVITY_INTENSITY" />

    <!-- 写入活动强度数据权限 -->
    <uses-permission android:name="android.permission.health.WRITE_ACTIVITY_INTENSITY" />

    <!-- 读取基础体温数据权限 -->
    <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />

    <!-- 写入基础体温数据权限 -->
    <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE" />

    <!-- 读取基础代谢率数据权限 -->
    <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />

    <!-- 写入基础代谢率数据权限 -->
    <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE" />

    <!-- 读取血糖数据权限 -->
    <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />

    <!-- 写入血糖数据权限 -->
    <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" />

    <!-- 读取血压数据权限 --
Download .txt
gitextract_kzfq42ja/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── config.yml
│   │   ├── issue_en_template_bug.yml
│   │   ├── issue_en_template_question.yml
│   │   ├── issue_en_template_suggest.yml
│   │   ├── issue_zh_template_bug.yml
│   │   ├── issue_zh_template_question.yml
│   │   └── issue_zh_template_suggest.yml
│   └── workflows/
│       └── android.yml
├── .gitignore
├── Details-en.md
├── Details-zh.md
├── HelpDoc-en.md
├── HelpDoc-zh.md
├── LICENSE
├── README-en.md
├── README.md
├── app/
│   ├── AppSignature.jks
│   ├── build.gradle
│   ├── gradle.properties
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── hjq/
│           │           └── permissions/
│           │               └── demo/
│           │                   ├── AppApplication.java
│           │                   ├── HealthDataPrivacyPolicyActivity.java
│           │                   ├── MainActivity.java
│           │                   ├── WindowLifecycleManager.java
│           │                   ├── example/
│           │                   │   ├── ExampleAccessibilityService.java
│           │                   │   ├── ExampleDeviceAdminReceiver.java
│           │                   │   ├── ExampleNotificationListenerService.java
│           │                   │   └── ExampleVpnService.java
│           │                   └── permission/
│           │                       ├── PermissionConverter.java
│           │                       ├── PermissionDescription.java
│           │                       └── PermissionInterceptor.java
│           └── res/
│               ├── drawable/
│               │   └── permission_description_popup_bg.xml
│               ├── layout/
│               │   ├── activity_main.xml
│               │   ├── health_data_privacy_policy_activity.xml
│               │   └── permission_description_popup.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── strings_demo.xml
│               │   ├── strings_permission.xml
│               │   └── styles.xml
│               ├── values-v21/
│               │   └── styles.xml
│               ├── values-zh/
│               │   ├── strings_demo.xml
│               │   └── strings_permission.xml
│               └── xml/
│                   ├── accessibility_service_config.xml
│                   ├── device_admin_config.xml
│                   └── locales_config.xml
├── build.gradle
├── common.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── jitpack.yml
├── library/
│   ├── build.gradle
│   ├── proguard-permissions.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           └── java/
│               └── com/
│                   └── hjq/
│                       └── permissions/
│                           ├── DefaultPermissionDescription.java
│                           ├── DefaultPermissionInterceptor.java
│                           ├── OnPermissionCallback.java
│                           ├── OnPermissionDescription.java
│                           ├── OnPermissionInterceptor.java
│                           ├── XXPermissions.java
│                           ├── core/
│                           │   ├── OnPermissionFragmentCallback.java
│                           │   ├── PermissionChannelImpl.java
│                           │   ├── PermissionChannelImplByRequestPermissions.java
│                           │   ├── PermissionChannelImplByStartActivity.java
│                           │   └── PermissionRequestMainLogic.java
│                           ├── fragment/
│                           │   ├── IFragmentCallback.java
│                           │   ├── IFragmentMethod.java
│                           │   ├── IFragmentMethodExtension.java
│                           │   ├── IFragmentMethodNative.java
│                           │   ├── factory/
│                           │   │   ├── PermissionFragmentFactory.java
│                           │   │   ├── PermissionFragmentFactoryByAndroid.java
│                           │   │   └── PermissionFragmentFactoryByAndroidX.java
│                           │   └── impl/
│                           │       ├── android/
│                           │       │   ├── PermissionAndroidFragment.java
│                           │       │   ├── PermissionAndroidFragmentByRequestPermissions.java
│                           │       │   └── PermissionAndroidFragmentByStartActivity.java
│                           │       └── androidx/
│                           │           ├── PermissionAndroidXFragment.java
│                           │           ├── PermissionAndroidXFragmentByRequestPermissions.java
│                           │           └── PermissionAndroidXFragmentByStartActivity.java
│                           ├── manager/
│                           │   ├── ActivityOrientationManager.java
│                           │   ├── AlreadyRequestPermissionsManager.java
│                           │   └── PermissionRequestCodeManager.java
│                           ├── manifest/
│                           │   ├── AndroidManifestInfo.java
│                           │   ├── AndroidManifestParser.java
│                           │   └── node/
│                           │       ├── ActivityManifestInfo.java
│                           │       ├── ApplicationManifestInfo.java
│                           │       ├── BroadcastReceiverManifestInfo.java
│                           │       ├── IntentFilterManifestInfo.java
│                           │       ├── MetaDataManifestInfo.java
│                           │       ├── PermissionManifestInfo.java
│                           │       ├── ServiceManifestInfo.java
│                           │       └── UsesSdkManifestInfo.java
│                           ├── permission/
│                           │   ├── PermissionChannel.java
│                           │   ├── PermissionGroups.java
│                           │   ├── PermissionLists.java
│                           │   ├── PermissionNames.java
│                           │   ├── PermissionPageType.java
│                           │   ├── base/
│                           │   │   ├── BasePermission.java
│                           │   │   └── IPermission.java
│                           │   ├── common/
│                           │   │   ├── DangerousPermission.java
│                           │   │   └── SpecialPermission.java
│                           │   ├── dangerous/
│                           │   │   ├── AccessBackgroundLocationPermission.java
│                           │   │   ├── AccessMediaLocationPermission.java
│                           │   │   ├── BluetoothAdvertisePermission.java
│                           │   │   ├── BluetoothConnectPermission.java
│                           │   │   ├── BluetoothScanPermission.java
│                           │   │   ├── BodySensorsBackgroundPermission.java
│                           │   │   ├── BodySensorsPermission.java
│                           │   │   ├── GetInstalledAppsPermission.java
│                           │   │   ├── HealthDataBasePermission.java
│                           │   │   ├── NearbyWifiDevicesPermission.java
│                           │   │   ├── PostNotificationsPermission.java
│                           │   │   ├── ReadExternalStoragePermission.java
│                           │   │   ├── ReadHealthDataHistoryPermission.java
│                           │   │   ├── ReadHealthDataInBackgroundPermission.java
│                           │   │   ├── ReadHealthRatePermission.java
│                           │   │   ├── ReadMediaAudioPermission.java
│                           │   │   ├── ReadMediaImagesPermission.java
│                           │   │   ├── ReadMediaVideoPermission.java
│                           │   │   ├── ReadMediaVisualUserSelectedPermission.java
│                           │   │   ├── ReadPhoneNumbersPermission.java
│                           │   │   ├── StandardDangerousPermission.java
│                           │   │   ├── StandardFitnessAndWellnessDataPermission.java
│                           │   │   ├── StandardHealthRecordsPermission.java
│                           │   │   └── WriteExternalStoragePermission.java
│                           │   └── special/
│                           │       ├── AccessNotificationPolicyPermission.java
│                           │       ├── BindAccessibilityServicePermission.java
│                           │       ├── BindDeviceAdminPermission.java
│                           │       ├── BindNotificationListenerServicePermission.java
│                           │       ├── BindVpnServicePermission.java
│                           │       ├── ManageExternalStoragePermission.java
│                           │       ├── ManageMediaPermission.java
│                           │       ├── NotificationServicePermission.java
│                           │       ├── PackageUsageStatsPermission.java
│                           │       ├── PictureInPicturePermission.java
│                           │       ├── RequestIgnoreBatteryOptimizationsPermission.java
│                           │       ├── RequestInstallPackagesPermission.java
│                           │       ├── ScheduleExactAlarmPermission.java
│                           │       ├── SystemAlertWindowPermission.java
│                           │       ├── UseFullScreenIntentPermission.java
│                           │       └── WriteSettingsPermission.java
│                           ├── start/
│                           │   ├── IStartActivityDelegate.java
│                           │   ├── StartActivityAgent.java
│                           │   ├── StartActivityDelegateByActivity.java
│                           │   ├── StartActivityDelegateByContext.java
│                           │   ├── StartActivityDelegateByFragmentAndroid.java
│                           │   └── StartActivityDelegateByFragmentAndroidX.java
│                           └── tools/
│                               ├── PermissionApi.java
│                               ├── PermissionChecker.java
│                               ├── PermissionSettingPage.java
│                               ├── PermissionTaskHandler.java
│                               ├── PermissionUtils.java
│                               └── PermissionVersion.java
└── settings.gradle
Download .txt
SYMBOL INDEX (1092 symbols across 109 files)

FILE: app/src/main/java/com/hjq/permissions/demo/AppApplication.java
  class AppApplication (line 14) | public final class AppApplication extends Application {
    method onCreate (line 16) | @Override

FILE: app/src/main/java/com/hjq/permissions/demo/HealthDataPrivacyPolicyActivity.java
  class HealthDataPrivacyPolicyActivity (line 20) | public class HealthDataPrivacyPolicyActivity extends AppCompatActivity {
    method onCreate (line 22) | @Override

FILE: app/src/main/java/com/hjq/permissions/demo/MainActivity.java
  class MainActivity (line 79) | public final class MainActivity extends AppCompatActivity implements Vie...
    method onCreate (line 81) | @Override
    method onClick (line 154) | @Override
    method onActivityResult (line 903) | @Override
    method showGrantedPermissionsToast (line 912) | public void showGrantedPermissionsToast(List<IPermission> grantedList) {
    method toast (line 916) | public void toast(CharSequence text) {
    method toggleNotificationListenerService (line 920) | private void toggleNotificationListenerService() {
    method getAllImagesFromGallery (line 936) | private void getAllImagesFromGallery(boolean acquireLatitudeAndLongitu...
    method latLongToAddressString (line 1005) | private String latLongToAddressString(float latitude, float longitude) {
    method onSensorChanged (line 1030) | @Override
    method onAccuracyChanged (line 1047) | @Override
    method addCountStepListener (line 1056) | private void addCountStepListener() {
    method getAppList (line 1074) | private void getAppList() {

FILE: app/src/main/java/com/hjq/permissions/demo/WindowLifecycleManager.java
  class WindowLifecycleManager (line 18) | public final class WindowLifecycleManager {
    method bindDialogLifecycle (line 23) | public static void bindDialogLifecycle(@NonNull Activity activity, @No...
    method bindPopupWindowLifecycle (line 40) | public static void bindPopupWindowLifecycle(@NonNull Activity activity...
    method registerWindowLifecycleCallbacks (line 57) | private static void registerWindowLifecycleCallbacks(@NonNull Activity...
    method unregisterWindowLifecycleCallbacks (line 68) | private static void unregisterWindowLifecycleCallbacks(@NonNull Activi...
    class WindowLifecycleCallbacks (line 79) | private abstract static class WindowLifecycleCallbacks implements Acti...
      method WindowLifecycleCallbacks (line 84) | private WindowLifecycleCallbacks(@NonNull Activity activity) {
      method onWindowDismiss (line 88) | public abstract void onWindowDismiss();
      method onActivityCreated (line 90) | @Override
      method onActivityStarted (line 95) | @Override
      method onActivityResumed (line 100) | @Override
      method onActivityPaused (line 105) | @Override
      method onActivityStopped (line 110) | @Override
      method onActivitySaveInstanceState (line 115) | @Override
      method onActivityDestroyed (line 120) | @Override

FILE: app/src/main/java/com/hjq/permissions/demo/example/ExampleAccessibilityService.java
  class ExampleAccessibilityService (line 15) | public final class ExampleAccessibilityService extends AccessibilityServ...
    method onServiceConnected (line 20) | @Override
    method onInterrupt (line 30) | @Override
    method onGesture (line 39) | @Override
    method onAccessibilityEvent (line 52) | @Override
    method onKeyEvent (line 128) | @Override
    method log (line 134) | private void log(@NonNull String message) {

FILE: app/src/main/java/com/hjq/permissions/demo/example/ExampleDeviceAdminReceiver.java
  class ExampleDeviceAdminReceiver (line 17) | public final class ExampleDeviceAdminReceiver extends DeviceAdminReceiver {
    method onEnabled (line 19) | @Override
    method onDisabled (line 26) | @Override
    method onDisableRequested (line 33) | @Nullable
    method onPasswordChanged (line 39) | @Override
    method onPasswordFailed (line 46) | @Override
    method onPasswordSucceeded (line 53) | @Override
    method log (line 60) | private void log(@NonNull String message) {

FILE: app/src/main/java/com/hjq/permissions/demo/example/ExampleNotificationListenerService.java
  class ExampleNotificationListenerService (line 17) | public final class ExampleNotificationListenerService extends Notificati...
    method onNotificationPosted (line 22) | @Override
    method onNotificationRemoved (line 49) | @Override

FILE: app/src/main/java/com/hjq/permissions/demo/example/ExampleVpnService.java
  class ExampleVpnService (line 5) | public final class ExampleVpnService extends VpnService {

FILE: app/src/main/java/com/hjq/permissions/demo/permission/PermissionConverter.java
  class PermissionConverter (line 24) | public final class PermissionConverter {
    method getNickNamesByPermissions (line 194) | @NonNull
    method getNickNameListByPermissions (line 217) | @NonNull
    method getNickNameByPermission (line 238) | public static String getNickNameByPermission(@NonNull Context context,...
    method getDescriptionsByPermissions (line 249) | @NonNull
    method getDescriptionListByPermissions (line 268) | @NonNull
    method getDescriptionByPermission (line 287) | @NonNull
    method getPermissionNickNameStringId (line 307) | @Nullable
    method getPermissionDescriptionStringId (line 325) | @Nullable

FILE: app/src/main/java/com/hjq/permissions/demo/permission/PermissionDescription.java
  class PermissionDescription (line 40) | public final class PermissionDescription implements OnPermissionDescript...
    method askWhetherRequestPermission (line 65) | @Override
    method onRequestPermissionStart (line 99) | @Override
    method onRequestPermissionEnd (line 116) | @Override
    method generatePermissionDescription (line 128) | private String generatePermissionDescription(@NonNull Activity activit...
    method showDialog (line 140) | private void showDialog(@NonNull Activity activity, @Nullable String d...
    method dismissDialog (line 178) | private void dismissDialog() {
    method showPopupWindow (line 194) | private void showPopupWindow(@NonNull Activity activity, @NonNull Stri...
    method dismissPopupWindow (line 223) | private void dismissPopupWindow() {
    method isActivityLandscape (line 237) | public static boolean isActivityLandscape(@NonNull Activity activity) {
    method getPhysicalScreenSize (line 244) | @SuppressWarnings("deprecation")

FILE: app/src/main/java/com/hjq/permissions/demo/permission/PermissionInterceptor.java
  class PermissionInterceptor (line 34) | public final class PermissionInterceptor implements OnPermissionIntercep...
    method onRequestPermissionEnd (line 36) | @Override
    method showPermissionSettingDialog (line 61) | private void showPermissionSettingDialog(@NonNull Activity activity,
    method generatePermissionHint (line 127) | @NonNull
    method getBackgroundPermissionOptionLabel (line 258) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/DefaultPermissionDescription.java
  class DefaultPermissionDescription (line 14) | final class DefaultPermissionDescription implements OnPermissionDescript...
    method askWhetherRequestPermission (line 16) | @Override
    method onRequestPermissionStart (line 25) | @Override
    method onRequestPermissionEnd (line 30) | @Override

FILE: library/src/main/java/com/hjq/permissions/DefaultPermissionInterceptor.java
  class DefaultPermissionInterceptor (line 9) | final class DefaultPermissionInterceptor implements OnPermissionIntercep...

FILE: library/src/main/java/com/hjq/permissions/OnPermissionCallback.java
  type OnPermissionCallback (line 13) | public interface OnPermissionCallback {
    method onResult (line 21) | void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IP...

FILE: library/src/main/java/com/hjq/permissions/OnPermissionDescription.java
  type OnPermissionDescription (line 14) | public interface OnPermissionDescription {
    method askWhetherRequestPermission (line 23) | void askWhetherRequestPermission(@NonNull Activity activity,
    method onRequestPermissionStart (line 33) | void onRequestPermissionStart(@NonNull Activity activity, @NonNull Lis...
    method onRequestPermissionEnd (line 40) | void onRequestPermissionEnd(@NonNull Activity activity, @NonNull List<...

FILE: library/src/main/java/com/hjq/permissions/OnPermissionInterceptor.java
  type OnPermissionInterceptor (line 17) | public interface OnPermissionInterceptor {
    method onRequestPermissionStart (line 27) | default void onRequestPermissionStart(@NonNull Activity activity,
    method onRequestPermissionEnd (line 43) | default void onRequestPermissionEnd(@NonNull Activity activity, boolea...
    method dispatchPermissionRequest (line 60) | default void dispatchPermissionRequest(@NonNull Activity activity,

FILE: library/src/main/java/com/hjq/permissions/XXPermissions.java
  class XXPermissions (line 30) | @SuppressWarnings({"unused", "deprecation"})
    method with (line 50) | public static XXPermissions with(@NonNull Context context) {
    method with (line 54) | public static XXPermissions with(@NonNull Fragment fragment) {
    method with (line 58) | public static XXPermissions with(@NonNull androidx.fragment.app.Fragme...
    method setCheckMode (line 65) | public static void setCheckMode(boolean checkMode) {
    method setPermissionInterceptor (line 72) | public static void setPermissionInterceptor(Class<? extends OnPermissi...
    method getPermissionInterceptor (line 79) | @NonNull
    method setPermissionDescription (line 97) | public static void setPermissionDescription(Class<? extends OnPermissi...
    method getPermissionDescription (line 104) | @NonNull
    method XXPermissions (line 144) | private XXPermissions(@NonNull Context context) {
    method XXPermissions (line 148) | private XXPermissions(@NonNull Fragment fragment) {
    method XXPermissions (line 153) | private XXPermissions(@NonNull androidx.fragment.app.Fragment xFragmen...
    method permission (line 161) | public XXPermissions permission(@NonNull IPermission permission) {
    method permissions (line 171) | public XXPermissions permissions(@NonNull List<IPermission> permission...
    method permissions (line 182) | public XXPermissions permissions(@NonNull IPermission[] permissions) {
    method interceptor (line 189) | public XXPermissions interceptor(@Nullable OnPermissionInterceptor per...
    method description (line 197) | public XXPermissions description(@Nullable OnPermissionDescription per...
    method unchecked (line 205) | public XXPermissions unchecked() {
    method request (line 213) | public void request(@Nullable OnPermissionCallback callback) {
    method isCheckMode (line 291) | private boolean isCheckMode(@NonNull Context context) {
    method isGrantedPermission (line 304) | public static boolean isGrantedPermission(@NonNull Context context, @N...
    method isGrantedPermissions (line 308) | public static boolean isGrantedPermissions(@NonNull Context context, @...
    method isGrantedPermissions (line 312) | public static boolean isGrantedPermissions(@NonNull Context context, @...
    method getGrantedPermissions (line 319) | public static List<IPermission> getGrantedPermissions(@NonNull Context...
    method getGrantedPermissions (line 323) | public static List<IPermission> getGrantedPermissions(@NonNull Context...
    method getDeniedPermissions (line 330) | public static List<IPermission> getDeniedPermissions(@NonNull Context ...
    method getDeniedPermissions (line 334) | public static List<IPermission> getDeniedPermissions(@NonNull Context ...
    method equalsPermission (line 341) | public static boolean equalsPermission(@NonNull IPermission permission...
    method equalsPermission (line 345) | public static boolean equalsPermission(@NonNull IPermission permission...
    method equalsPermission (line 349) | public static boolean equalsPermission(@NonNull String permissionName1...
    method containsPermission (line 356) | public static boolean containsPermission(@NonNull List<IPermission> pe...
    method containsPermission (line 360) | public static boolean containsPermission(@NonNull List<IPermission> pe...
    method isHealthPermission (line 367) | public static boolean isHealthPermission(@NonNull IPermission permissi...
    method isDoNotAskAgainPermission (line 378) | public static boolean isDoNotAskAgainPermission(@NonNull Activity acti...
    method isDoNotAskAgainPermissions (line 382) | public static boolean isDoNotAskAgainPermissions(@NonNull Activity act...
    method isDoNotAskAgainPermissions (line 386) | public static boolean isDoNotAskAgainPermissions(@NonNull Activity act...
    method startPermissionActivity (line 392) | public static void startPermissionActivity(@NonNull Context context) {
    method startPermissionActivity (line 396) | public static void startPermissionActivity(@NonNull Context context, @...
    method startPermissionActivity (line 405) | public static void startPermissionActivity(@NonNull Context context, @...
    method startPermissionActivity (line 416) | public static void startPermissionActivity(@NonNull Activity activity) {
    method startPermissionActivity (line 420) | public static void startPermissionActivity(@NonNull Activity activity,
    method startPermissionActivity (line 425) | public static void startPermissionActivity(@NonNull Activity activity,
    method startPermissionActivity (line 430) | public static void startPermissionActivity(@NonNull Activity activity,
    method startPermissionActivity (line 437) | public static void startPermissionActivity(@NonNull Activity activity,
    method startPermissionActivity (line 443) | public static void startPermissionActivity(@NonNull Activity activity,
    method startPermissionActivity (line 464) | public static void startPermissionActivity(@NonNull Fragment fragment) {
    method startPermissionActivity (line 468) | public static void startPermissionActivity(@NonNull Fragment fragment,
    method startPermissionActivity (line 473) | public static void startPermissionActivity(@NonNull Fragment fragment,
    method startPermissionActivity (line 478) | public static void startPermissionActivity(@NonNull Fragment fragment,
    method startPermissionActivity (line 496) | public static void startPermissionActivity(@NonNull Fragment fragment,
    method startPermissionActivity (line 502) | public static void startPermissionActivity(@NonNull Fragment fragment,
    method startPermissionActivity (line 527) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method startPermissionActivity (line 531) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method startPermissionActivity (line 536) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method startPermissionActivity (line 541) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method startPermissionActivity (line 559) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method startPermissionActivity (line 565) | public static void startPermissionActivity(@NonNull androidx.fragment....
    method generatePermissionFragmentFactory (line 591) | @NonNull
    method generatePermissionFragmentFactory (line 596) | @NonNull
    method generatePermissionFragmentFactory (line 602) | @NonNull
    method generatePermissionFragmentFactory (line 608) | private static PermissionFragmentFactory<?, ?> generatePermissionFragm...
    method dispatchPermissionPageCallback (line 628) | private static void dispatchPermissionPageCallback(@NonNull Context co...

FILE: library/src/main/java/com/hjq/permissions/core/OnPermissionFragmentCallback.java
  type OnPermissionFragmentCallback (line 9) | public interface OnPermissionFragmentCallback {
    method onRequestPermissionNow (line 14) | default void onRequestPermissionNow() {
    method onRequestPermissionFinish (line 21) | void onRequestPermissionFinish();
    method onRequestPermissionAnomaly (line 26) | default void onRequestPermissionAnomaly() {

FILE: library/src/main/java/com/hjq/permissions/core/PermissionChannelImpl.java
  class PermissionChannelImpl (line 27) | public abstract class PermissionChannelImpl implements IFragmentCallback {
    method PermissionChannelImpl (line 56) | protected PermissionChannelImpl(@NonNull IFragmentMethod<?, ?> fragmen...
    method setNonSystemRestartMark (line 60) | public void setNonSystemRestartMark(boolean nonSystemRestartMark) {
    method setPermissionFragmentCallback (line 64) | public void setPermissionFragmentCallback(@Nullable OnPermissionFragme...
    method getPermissionFragmentCallback (line 68) | @Nullable
    method getActivity (line 73) | @Nullable
    method commitFragmentDetach (line 78) | private void commitFragmentDetach() {
    method isFragmentUnavailable (line 83) | private boolean isFragmentUnavailable() {
    method requestPermissions (line 90) | @RequiresApi(PermissionVersion.ANDROID_6)
    method getPermissionRequestList (line 161) | @SuppressWarnings("deprecation")
    method getPermissionRequestCode (line 175) | protected int getPermissionRequestCode() {
    method sendTask (line 183) | protected void sendTask(@NonNull Runnable runnable, long delayMillis) {
    method cancelTask (line 187) | protected void cancelTask() {
    method getStartActivityDelegate (line 191) | protected IStartActivityDelegate getStartActivityDelegate() {
    method startPermissionRequest (line 198) | protected abstract void startPermissionRequest(@NonNull Activity activ...
    method onFragmentResume (line 201) | @Override
    method onFragmentDestroy (line 238) | @Override
    method notificationPermissionCallback (line 266) | protected void notificationPermissionCallback() {
    method handlerPermissionCallback (line 278) | protected void handlerPermissionCallback() {

FILE: library/src/main/java/com/hjq/permissions/core/PermissionChannelImplByRequestPermissions.java
  class PermissionChannelImplByRequestPermissions (line 21) | public final class PermissionChannelImplByRequestPermissions extends Per...
    method PermissionChannelImplByRequestPermissions (line 23) | public PermissionChannelImplByRequestPermissions(@NonNull IFragmentMet...
    method startPermissionRequest (line 27) | @Override
    method onFragmentRequestPermissionsResult (line 43) | @Override

FILE: library/src/main/java/com/hjq/permissions/core/PermissionChannelImplByStartActivity.java
  class PermissionChannelImplByStartActivity (line 22) | public final class PermissionChannelImplByStartActivity extends Permissi...
    method PermissionChannelImplByStartActivity (line 27) | public PermissionChannelImplByStartActivity(@NonNull IFragmentMethod<?...
    method startPermissionRequest (line 31) | @Override
    method onFragmentActivityResult (line 42) | @Override

FILE: library/src/main/java/com/hjq/permissions/core/PermissionRequestMainLogic.java
  class PermissionRequestMainLogic (line 28) | public final class PermissionRequestMainLogic {
    method PermissionRequestMainLogic (line 48) | public PermissionRequestMainLogic(@NonNull Activity activity,
    method request (line 65) | public void request() {
    method getUnauthorizedList (line 185) | @NonNull
    method requestPermissionsByFragment (line 311) | private static void requestPermissionsByFragment(@NonNull Activity act...
    method postDelayedHandlerRequestPermissionsResult (line 363) | private void postDelayedHandlerRequestPermissionsResult() {
    method postDelayedUnlockActivityOrientation (line 370) | private void postDelayedUnlockActivityOrientation(@NonNull Activity ac...
    method handlePermissionRequestResult (line 378) | private void handlePermissionRequestResult() {

FILE: library/src/main/java/com/hjq/permissions/fragment/IFragmentCallback.java
  type IFragmentCallback (line 12) | public interface IFragmentCallback {
    method onFragmentResume (line 15) | void onFragmentResume();
    method onFragmentDestroy (line 18) | void onFragmentDestroy();
    method onFragmentRequestPermissionsResult (line 21) | default void onFragmentRequestPermissionsResult(int requestCode, @Null...
    method onFragmentActivityResult (line 26) | default void onFragmentActivityResult(int requestCode, int resultCode,...

FILE: library/src/main/java/com/hjq/permissions/fragment/IFragmentMethod.java
  type IFragmentMethod (line 11) | public interface IFragmentMethod<A extends Activity, M> extends IFragmen...

FILE: library/src/main/java/com/hjq/permissions/fragment/IFragmentMethodExtension.java
  type IFragmentMethodExtension (line 14) | public interface IFragmentMethodExtension<M> {
    method getPermissionChannelImpl (line 19) | @NonNull
    method commitFragmentAttach (line 25) | void commitFragmentAttach(@Nullable M fragmentManager);
    method commitFragmentDetach (line 30) | void commitFragmentDetach();
    method setPermissionFragmentCallback (line 35) | void setPermissionFragmentCallback(@Nullable OnPermissionFragmentCallb...
    method setNonSystemRestartMark (line 40) | void setNonSystemRestartMark(boolean nonSystemRestartMark);

FILE: library/src/main/java/com/hjq/permissions/fragment/IFragmentMethodNative.java
  type IFragmentMethodNative (line 16) | public interface IFragmentMethodNative<A extends Activity> extends IStar...
    method getActivity (line 19) | @Nullable
    method requestPermissions (line 23) | void requestPermissions(@NonNull String[] permissions, @IntRange(from ...
    method getArguments (line 26) | @Nullable
    method setArguments (line 30) | void setArguments(@Nullable Bundle arguments);
    method setRetainInstance (line 33) | void setRetainInstance(boolean retainInstance);
    method isAdded (line 36) | boolean isAdded();
    method isRemoving (line 39) | boolean isRemoving();

FILE: library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactory.java
  class PermissionFragmentFactory (line 21) | public abstract class PermissionFragmentFactory<A extends Activity, M> {
    method PermissionFragmentFactory (line 54) | protected PermissionFragmentFactory(@NonNull A activity, @NonNull M fr...
    method getActivity (line 62) | @NonNull
    method getFragmentManager (line 70) | @NonNull
    method createAndCommitFragment (line 78) | public abstract void createAndCommitFragment(@NonNull List<IPermission...
    method generatePermissionArguments (line 85) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactoryByAndroid.java
  class PermissionFragmentFactoryByAndroid (line 22) | @SuppressWarnings("deprecation")
    method PermissionFragmentFactoryByAndroid (line 25) | public PermissionFragmentFactoryByAndroid(@NonNull Activity activity, ...
    method createAndCommitFragment (line 29) | @Override

FILE: library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactoryByAndroidX.java
  class PermissionFragmentFactoryByAndroidX (line 22) | public final class PermissionFragmentFactoryByAndroidX extends Permissio...
    method PermissionFragmentFactoryByAndroidX (line 24) | public PermissionFragmentFactoryByAndroidX(@NonNull FragmentActivity a...
    method createAndCommitFragment (line 28) | @Override

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragment.java
  class PermissionAndroidFragment (line 18) | @SuppressWarnings("deprecation")
    method setPermissionFragmentCallback (line 21) | @Override
    method setNonSystemRestartMark (line 26) | @Override
    method commitFragmentAttach (line 31) | @Override
    method commitFragmentDetach (line 39) | @Override
    method onResume (line 48) | @Override
    method onDestroy (line 54) | @Override
    method onRequestPermissionsResult (line 60) | @Override
    method onActivityResult (line 66) | @Override

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragmentByRequestPermissions.java
  class PermissionAndroidFragmentByRequestPermissions (line 13) | public final class PermissionAndroidFragmentByRequestPermissions extends...
    method getPermissionChannelImpl (line 18) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragmentByStartActivity.java
  class PermissionAndroidFragmentByStartActivity (line 14) | public final class PermissionAndroidFragmentByStartActivity extends Perm...
    method getPermissionChannelImpl (line 19) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragment.java
  class PermissionAndroidXFragment (line 18) | public abstract class PermissionAndroidXFragment extends Fragment implem...
    method setPermissionFragmentCallback (line 23) | @Override
    method setNonSystemRestartMark (line 31) | @Override
    method commitFragmentAttach (line 39) | @Override
    method commitFragmentDetach (line 50) | @Override
    method onResume (line 59) | @Override
    method onDestroy (line 65) | @Override
    method onRequestPermissionsResult (line 71) | @Override
    method onActivityResult (line 77) | @Override

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragmentByRequestPermissions.java
  class PermissionAndroidXFragmentByRequestPermissions (line 13) | public final class PermissionAndroidXFragmentByRequestPermissions extend...
    method getPermissionChannelImpl (line 18) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragmentByStartActivity.java
  class PermissionAndroidXFragmentByStartActivity (line 14) | public final class PermissionAndroidXFragmentByStartActivity extends Per...
    method getPermissionChannelImpl (line 19) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/manager/ActivityOrientationManager.java
  class ActivityOrientationManager (line 20) | public final class ActivityOrientationManager {
    method ActivityOrientationManager (line 26) | private ActivityOrientationManager() {
    method lockActivityOrientation (line 33) | public static synchronized void lockActivityOrientation(@NonNull Activ...
    method unlockActivityOrientation (line 72) | public static synchronized void unlockActivityOrientation(@NonNull Act...
    method isActivityReverse (line 92) | @SuppressWarnings("deprecation")
    method getIntKeyByActivity (line 124) | private static int getIntKeyByActivity(@NonNull Activity activity) {

FILE: library/src/main/java/com/hjq/permissions/manager/AlreadyRequestPermissionsManager.java
  class AlreadyRequestPermissionsManager (line 15) | public final class AlreadyRequestPermissionsManager {
    method AlreadyRequestPermissionsManager (line 21) | private AlreadyRequestPermissionsManager() {
    method addAlreadyRequestPermissions (line 28) | public static void addAlreadyRequestPermissions(@Nullable List<IPermis...
    method isAlreadyRequestPermissions (line 44) | public static boolean isAlreadyRequestPermissions(@Nullable IPermissio...

FILE: library/src/main/java/com/hjq/permissions/manager/PermissionRequestCodeManager.java
  class PermissionRequestCodeManager (line 15) | public final class PermissionRequestCodeManager {
    method PermissionRequestCodeManager (line 30) | private PermissionRequestCodeManager() {
    method generateRandomRequestCode (line 37) | @IntRange(from = 1, to = 65535)
    method releaseRequestCode (line 68) | public static synchronized void releaseRequestCode(int requestCode) {

FILE: library/src/main/java/com/hjq/permissions/manifest/AndroidManifestInfo.java
  class AndroidManifestInfo (line 20) | public final class AndroidManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/AndroidManifestParser.java
  class AndroidManifestParser (line 31) | public final class AndroidManifestParser {
    method AndroidManifestParser (line 72) | private AndroidManifestParser() {
    method getAndroidManifestInfo (line 79) | @Nullable
    method findApkPathCookie (line 105) | @SuppressWarnings("JavaReflectionMemberAccess")
    method parseAndroidManifest (line 160) | @NonNull
    method parsePackageFromXml (line 223) | @NonNull
    method parseUsesSdkFromXml (line 229) | @NonNull
    method parsePermissionFromXml (line 237) | @NonNull
    method parseApplicationFromXml (line 248) | @NonNull
    method parseActivityFromXml (line 258) | @NonNull
    method parseServerFromXml (line 291) | @NonNull
    method parseBroadcastReceiverFromXml (line 321) | @NonNull
    method parseIntentFilterFromXml (line 351) | @NonNull
    method parseMetaDataFromXml (line 374) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/manifest/node/ActivityManifestInfo.java
  class ActivityManifestInfo (line 13) | public final class ActivityManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/ApplicationManifestInfo.java
  class ApplicationManifestInfo (line 13) | public final class ApplicationManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/BroadcastReceiverManifestInfo.java
  class BroadcastReceiverManifestInfo (line 13) | public final class BroadcastReceiverManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/IntentFilterManifestInfo.java
  class IntentFilterManifestInfo (line 13) | public final class IntentFilterManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/MetaDataManifestInfo.java
  class MetaDataManifestInfo (line 12) | public final class MetaDataManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/PermissionManifestInfo.java
  class PermissionManifestInfo (line 12) | public final class PermissionManifestInfo {
    method neverForLocation (line 40) | public boolean neverForLocation() {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/ServiceManifestInfo.java
  class ServiceManifestInfo (line 13) | public final class ServiceManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/manifest/node/UsesSdkManifestInfo.java
  class UsesSdkManifestInfo (line 9) | public final class UsesSdkManifestInfo {

FILE: library/src/main/java/com/hjq/permissions/permission/PermissionChannel.java
  type PermissionChannel (line 11) | public enum PermissionChannel {

FILE: library/src/main/java/com/hjq/permissions/permission/PermissionGroups.java
  class PermissionGroups (line 9) | public final class PermissionGroups {

FILE: library/src/main/java/com/hjq/permissions/permission/PermissionLists.java
  class PermissionLists (line 62) | public final class PermissionLists {
    method PermissionLists (line 65) | private PermissionLists() {
    method getCachePermission (line 91) | @Nullable
    method putCachePermission (line 101) | private static IPermission putCachePermission(@NonNull IPermission per...
    method getGetInstalledAppsPermission (line 118) | @NonNull
    method getUseFullScreenIntentPermission (line 134) | @NonNull
    method getScheduleExactAlarmPermission (line 151) | @NonNull
    method getManageMediaPermission (line 171) | @NonNull
    method getManageExternalStoragePermission (line 189) | @NonNull
    method getRequestInstallPackagesPermission (line 204) | @NonNull
    method getPictureInPicturePermission (line 218) | @NonNull
    method getSystemAlertWindowPermission (line 233) | @NonNull
    method getWriteSettingsPermission (line 245) | @SuppressWarnings("unused")
    method getRequestIgnoreBatteryOptimizationsPermission (line 258) | @NonNull
    method getAccessNotificationPolicyPermission (line 270) | @NonNull
    method getPackageUsageStatsPermission (line 282) | @NonNull
    method getBindNotificationListenerServicePermission (line 296) | @NonNull
    method getBindVpnServicePermission (line 305) | @NonNull
    method getNotificationServicePermission (line 319) | @NonNull
    method getNotificationServicePermission (line 328) | @NonNull
    method getBindAccessibilityServicePermission (line 342) | @NonNull
    method getBindDeviceAdminPermission (line 353) | @NonNull
    method getBindDeviceAdminPermission (line 361) | @NonNull
    method getReadMediaVisualUserSelectedPermission (line 371) | @NonNull
    method getPostNotificationsPermission (line 385) | @NonNull
    method getNearbyWifiDevicesPermission (line 404) | @NonNull
    method getBodySensorsBackgroundPermission (line 420) | @NonNull
    method getReadMediaImagesPermission (line 435) | @NonNull
    method getReadMediaVideoPermission (line 450) | @NonNull
    method getReadMediaAudioPermission (line 465) | @NonNull
    method getBluetoothScanPermission (line 484) | @NonNull
    method getBluetoothConnectPermission (line 498) | @NonNull
    method getBluetoothAdvertisePermission (line 513) | @NonNull
    method getAccessBackgroundLocationPermission (line 529) | @NonNull
    method getActivityRecognitionPermission (line 544) | @NonNull
    method getAccessMediaLocationPermission (line 568) | @NonNull
    method getAcceptHandoverPermission (line 582) | @NonNull
    method getReadPhoneNumbersPermission (line 600) | @NonNull
    method getAnswerPhoneCallsPermission (line 614) | @NonNull
    method getReadExternalStoragePermission (line 627) | @NonNull
    method getWriteExternalStoragePermission (line 639) | @NonNull
    method getCameraPermission (line 651) | @NonNull
    method getRecordAudioPermission (line 664) | @NonNull
    method getAccessFineLocationPermission (line 677) | @NonNull
    method getAccessCoarseLocationPermission (line 690) | @NonNull
    method getReadContactsPermission (line 703) | @NonNull
    method getWriteContactsPermission (line 716) | @NonNull
    method getGetAccountsPermission (line 729) | @NonNull
    method getReadCalendarPermission (line 742) | @NonNull
    method getWriteCalendarPermission (line 755) | @NonNull
    method getReadPhoneStatePermission (line 779) | @NonNull
    method getCallPhonePermission (line 794) | @NonNull
    method getReadCallLogPermission (line 809) | @NonNull
    method getWriteCallLogPermission (line 826) | @NonNull
    method getAddVoicemailPermission (line 841) | @NonNull
    method getUseSipPermission (line 854) | @NonNull
    method getProcessOutgoingCallsPermission (line 871) | @NonNull
    method getBodySensorsPermission (line 886) | @NonNull
    method getSendSmsPermission (line 900) | @NonNull
    method getReceiveSmsPermission (line 915) | @NonNull
    method getReadSmsPermission (line 930) | @NonNull
    method getReceiveWapPushPermission (line 945) | @NonNull
    method getReceiveMmsPermission (line 960) | @NonNull
    method getReadHealthDataInBackgroundPermission (line 978) | @NonNull
    method getReadHealthDataHistoryPermission (line 994) | @NonNull
    method getReadActiveCaloriesBurnedPermission (line 1007) | @NonNull
    method getWriteActiveCaloriesBurnedPermission (line 1020) | @NonNull
    method getReadActivityIntensityPermission (line 1033) | @NonNull
    method getWriteActivityIntensityPermission (line 1046) | @NonNull
    method getReadBasalBodyTemperaturePermission (line 1059) | @NonNull
    method getWriteBasalBodyTemperaturePermission (line 1072) | @NonNull
    method getReadBasalMetabolicRatePermission (line 1085) | @NonNull
    method getWriteBasalMetabolicRatePermission (line 1098) | @NonNull
    method getReadBloodGlucosePermission (line 1111) | @NonNull
    method getWriteBloodGlucosePermission (line 1124) | @NonNull
    method getReadBloodPressurePermission (line 1137) | @NonNull
    method getWriteBloodPressurePermission (line 1150) | @NonNull
    method getReadBodyFatPermission (line 1163) | @NonNull
    method getWriteBodyFatPermission (line 1176) | @NonNull
    method getReadBodyTemperaturePermission (line 1189) | @NonNull
    method getWriteBodyTemperaturePermission (line 1202) | @NonNull
    method getReadBodyWaterMassPermission (line 1215) | @NonNull
    method getWriteBodyWaterMassPermission (line 1228) | @NonNull
    method getReadBoneMassPermission (line 1241) | @NonNull
    method getWriteBoneMassPermission (line 1254) | @NonNull
    method getReadCervicalMucusPermission (line 1267) | @NonNull
    method getWriteCervicalMucusPermission (line 1280) | @NonNull
    method getReadDistancePermission (line 1293) | @NonNull
    method getWriteDistancePermission (line 1306) | @NonNull
    method getReadElevationGainedPermission (line 1319) | @NonNull
    method getWriteElevationGainedPermission (line 1332) | @NonNull
    method getReadExercisePermission (line 1345) | @NonNull
    method getWriteExercisePermission (line 1358) | @NonNull
    method getReadExerciseRoutesPermission (line 1371) | @NonNull
    method getWriteExerciseRoutePermission (line 1384) | @NonNull
    method getReadFloorsClimbedPermission (line 1397) | @NonNull
    method getWriteFloorsClimbedPermission (line 1410) | @NonNull
    method getReadHeartRatePermission (line 1426) | @NonNull
    method getWriteHeartRatePermission (line 1438) | @NonNull
    method getReadHeartRateVariabilityPermission (line 1451) | @NonNull
    method getWriteHeartRateVariabilityPermission (line 1464) | @NonNull
    method getReadHeightPermission (line 1477) | @NonNull
    method getWriteHeightPermission (line 1490) | @NonNull
    method getReadHydrationPermission (line 1503) | @NonNull
    method getWriteHydrationPermission (line 1516) | @NonNull
    method getReadIntermenstrualBleedingPermission (line 1529) | @NonNull
    method getWriteIntermenstrualBleedingPermission (line 1542) | @NonNull
    method getReadLeanBodyMassPermission (line 1555) | @NonNull
    method getWriteLeanBodyMassPermission (line 1568) | @NonNull
    method getReadMenstruationPermission (line 1581) | @NonNull
    method getWriteMenstruationPermission (line 1594) | @NonNull
    method getReadMindfulnessPermission (line 1607) | @NonNull
    method getWriteMindfulnessPermission (line 1620) | @NonNull
    method getReadNutritionPermission (line 1633) | @NonNull
    method getWriteNutritionPermission (line 1646) | @NonNull
    method getReadOvulationTestPermission (line 1659) | @NonNull
    method getWriteOvulationTestPermission (line 1672) | @NonNull
    method getReadOxygenSaturationPermission (line 1685) | @NonNull
    method getWriteOxygenSaturationPermission (line 1698) | @NonNull
    method getReadPlannedExercisePermission (line 1711) | @NonNull
    method getWritePlannedExercisePermission (line 1724) | @NonNull
    method getReadPowerPermission (line 1737) | @NonNull
    method getWritePowerPermission (line 1750) | @NonNull
    method getReadRespiratoryRatePermission (line 1763) | @NonNull
    method getWriteRespiratoryRatePermission (line 1776) | @NonNull
    method getReadRestingHeartRatePermission (line 1789) | @NonNull
    method getWriteRestingHeartRatePermission (line 1802) | @NonNull
    method getReadSexualActivityPermission (line 1815) | @NonNull
    method getWriteSexualActivityPermission (line 1828) | @NonNull
    method getReadSkinTemperaturePermission (line 1841) | @NonNull
    method getWriteSkinTemperaturePermission (line 1854) | @NonNull
    method getReadSleepPermission (line 1867) | @NonNull
    method getWriteSleepPermission (line 1880) | @NonNull
    method getReadSpeedPermission (line 1893) | @NonNull
    method getWriteSpeedPermission (line 1906) | @NonNull
    method getReadStepsPermission (line 1919) | @NonNull
    method getWriteStepsPermission (line 1932) | @NonNull
    method getReadTotalCaloriesBurnedPermission (line 1945) | @NonNull
    method getWriteTotalCaloriesBurnedPermission (line 1958) | @NonNull
    method getReadVo2MaxPermission (line 1971) | @NonNull
    method getWriteVo2MaxPermission (line 1984) | @NonNull
    method getReadWeightPermission (line 1997) | @NonNull
    method getWriteWeightPermission (line 2010) | @NonNull
    method getReadWheelchairPushesPermission (line 2023) | @NonNull
    method getWriteWheelchairPushesPermission (line 2036) | @NonNull
    method getReadMedicalDataAllergiesIntolerancesPermission (line 2051) | @NonNull
    method getReadMedicalDataConditionsPermission (line 2064) | @NonNull
    method getReadMedicalDataLaboratoryResultsPermission (line 2077) | @NonNull
    method getReadMedicalDataMedicationsPermission (line 2090) | @NonNull
    method getReadMedicalDataPersonalDetailsPermission (line 2103) | @NonNull
    method getReadMedicalDataPractitionerDetailsPermission (line 2116) | @NonNull
    method getReadMedicalDataPregnancyPermission (line 2129) | @NonNull
    method getReadMedicalDataProceduresPermission (line 2142) | @NonNull
    method getReadMedicalDataSocialHistoryPermission (line 2155) | @NonNull
    method getReadMedicalDataVaccinesPermission (line 2168) | @NonNull
    method getReadMedicalDataVisitsPermission (line 2181) | @NonNull
    method getReadMedicalDataVitalSignsPermission (line 2194) | @NonNull
    method getWriteMedicalDataPermission (line 2207) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/permission/PermissionNames.java
  class PermissionNames (line 9) | @SuppressWarnings("unused")
    method PermissionNames (line 779) | private PermissionNames() {

FILE: library/src/main/java/com/hjq/permissions/permission/PermissionPageType.java
  type PermissionPageType (line 9) | public enum PermissionPageType {

FILE: library/src/main/java/com/hjq/permissions/permission/base/BasePermission.java
  class BasePermission (line 29) | public abstract class BasePermission implements IPermission {
    method BasePermission (line 34) | protected BasePermission() {
    method BasePermission (line 38) | protected BasePermission(Parcel in) {
    method describeContents (line 42) | @Override
    method writeToParcel (line 47) | @Override
    method toString (line 52) | @NonNull
    method equals (line 58) | @Override
    method getPackageNameUri (line 74) | @NonNull
    method getApplicationDetailsSettingIntent (line 79) | @NonNull
    method getManageApplicationSettingIntent (line 84) | @NonNull
    method getApplicationSettingIntent (line 89) | @NonNull
    method getAndroidSettingIntent (line 94) | @NonNull
    method checkCompliance (line 99) | @Override
    method checkSelfByTargetSdkVersion (line 118) | protected void checkSelfByTargetSdkVersion(@NonNull Context context) {
    method isRegisterPermissionByManifestFile (line 134) | protected abstract boolean isRegisterPermissionByManifestFile();
    method checkSelfByManifestFile (line 139) | protected void checkSelfByManifestFile(@NonNull Activity activity,
    method checkSelfByRequestPermissions (line 154) | protected void checkSelfByRequestPermissions(@NonNull Activity activit...
    method checkPermissionRegistrationStatus (line 162) | protected static void checkPermissionRegistrationStatus(@Nullable Perm...
    method checkPermissionRegistrationStatus (line 167) | protected static void checkPermissionRegistrationStatus(@Nullable List...
    method checkPermissionRegistrationStatus (line 172) | protected static void checkPermissionRegistrationStatus(@Nullable List...
    method checkPermissionRegistrationStatus (line 182) | protected static void checkPermissionRegistrationStatus(@Nullable Perm...
    method getMinSdkVersion (line 216) | protected static int getMinSdkVersion(@NonNull Context context, @Nulla...
    method findPermissionInfoByList (line 230) | @Nullable
    method checkSelfPermission (line 246) | @RequiresApi(PermissionVersion.ANDROID_6)
    method shouldShowRequestPermissionRationale (line 254) | @RequiresApi(PermissionVersion.ANDROID_6)
    method checkOpPermission (line 282) | @RequiresApi(PermissionVersion.ANDROID_4_4)
    method checkOpPermission (line 298) | @RequiresApi(PermissionVersion.ANDROID_4_4)
    method getOpPermissionMode (line 315) | @RequiresApi(PermissionVersion.ANDROID_4_4)
    method getOpPermissionMode (line 346) | @SuppressWarnings("ConstantConditions")
    method isExistOpPermission (line 381) | @RequiresApi(PermissionVersion.ANDROID_4_4)

FILE: library/src/main/java/com/hjq/permissions/permission/base/IPermission.java
  type IPermission (line 21) | public interface IPermission extends Parcelable {
    method getPermissionName (line 26) | @NonNull
    method getPermissionChannel (line 32) | @NonNull
    method getPermissionPageType (line 38) | @NonNull
    method getPermissionGroup (line 44) | @Nullable
    method getFromAndroidVersion (line 53) | int getFromAndroidVersion(@NonNull Context context);
    method getMinTargetSdkVersion (line 58) | default int getMinTargetSdkVersion(@NonNull Context context) {
    method getOldPermissions (line 65) | @Nullable
    method getForegroundPermissions (line 74) | @Nullable
    method isBackgroundPermission (line 83) | default boolean isBackgroundPermission(@NonNull Context context) {
    method isSupportRequestPermission (line 94) | default boolean isSupportRequestPermission(@NonNull Context context) {
    method isGrantedPermission (line 103) | default boolean isGrantedPermission(@NonNull Context context) {
    method isGrantedPermission (line 112) | boolean isGrantedPermission(@NonNull Context context, boolean skipRequ...
    method isDoNotAskAgainPermission (line 117) | boolean isDoNotAskAgainPermission(@NonNull Activity activity);
    method getPermissionSettingIntents (line 122) | @NonNull
    method getPermissionSettingIntents (line 138) | @NonNull
    method getRequestIntervalTime (line 144) | default int getRequestIntervalTime(@NonNull Context context) {
    method getResultWaitTime (line 151) | default int getResultWaitTime(@NonNull Context context) {
    method checkCompliance (line 158) | default void checkCompliance(@NonNull Activity activity,

FILE: library/src/main/java/com/hjq/permissions/permission/common/DangerousPermission.java
  class DangerousPermission (line 24) | public abstract class DangerousPermission extends BasePermission {
    method DangerousPermission (line 26) | protected DangerousPermission() {
    method DangerousPermission (line 30) | protected DangerousPermission(Parcel in) {
    method getPermissionChannel (line 34) | @NonNull
    method getPermissionPageType (line 40) | @NonNull
    method isGrantedPermission (line 46) | @Override
    method isGrantedPermissionByStandardVersion (line 58) | protected boolean isGrantedPermissionByStandardVersion(@NonNull Contex...
    method isGrantedPermissionByLowVersion (line 68) | protected boolean isGrantedPermissionByLowVersion(@NonNull Context con...
    method isDoNotAskAgainPermission (line 72) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 84) | protected boolean isDoNotAskAgainPermissionByStandardVersion(@NonNull ...
    method isDoNotAskAgainPermissionByLowVersion (line 110) | protected boolean isDoNotAskAgainPermissionByLowVersion(@NonNull Activ...
    method getPermissionSettingIntents (line 114) | @NonNull
    method isRegisterPermissionByManifestFile (line 157) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/common/SpecialPermission.java
  class SpecialPermission (line 19) | public abstract class SpecialPermission extends BasePermission {
    method SpecialPermission (line 21) | protected SpecialPermission() {
    method SpecialPermission (line 25) | protected SpecialPermission(Parcel in) {
    method getPermissionChannel (line 29) | @NonNull
    method getPermissionPageType (line 35) | @NonNull
    method isDoNotAskAgainPermission (line 41) | @Override
    method getResultWaitTime (line 46) | @Override
    method isRegisterPermissionByManifestFile (line 74) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/AccessBackgroundLocationPermission.java
  class AccessBackgroundLocationPermission (line 28) | public final class AccessBackgroundLocationPermission extends DangerousP...
    method createFromParcel (line 35) | @Override
    method newArray (line 40) | @Override
    method AccessBackgroundLocationPermission (line 46) | public AccessBackgroundLocationPermission() {
    method AccessBackgroundLocationPermission (line 50) | private AccessBackgroundLocationPermission(Parcel in) {
    method getPermissionName (line 54) | @NonNull
    method getPermissionPageType (line 60) | @NonNull
    method getPermissionGroup (line 75) | @Override
    method getFromAndroidVersion (line 80) | @Override
    method getForegroundPermissions (line 85) | @NonNull
    method isBackgroundPermission (line 98) | @Override
    method isGrantedPermissionByStandardVersion (line 104) | @Override
    method isGrantedPermissionByLowVersion (line 121) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 126) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 145) | @Override
    method getRequestIntervalTime (line 150) | @Override
    method checkSelfByManifestFile (line 159) | @Override
    method checkSelfByRequestPermissions (line 179) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/AccessMediaLocationPermission.java
  class AccessMediaLocationPermission (line 22) | public final class AccessMediaLocationPermission extends DangerousPermis...
    method createFromParcel (line 29) | @Override
    method newArray (line 34) | @Override
    method AccessMediaLocationPermission (line 40) | public AccessMediaLocationPermission() {
    method AccessMediaLocationPermission (line 44) | private AccessMediaLocationPermission(Parcel in) {
    method getPermissionName (line 48) | @NonNull
    method getFromAndroidVersion (line 54) | @Override
    method isGrantedPermissionByStandardVersion (line 59) | @Override
    method isGrantedPermissionByLowVersion (line 65) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 70) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 76) | @Override
    method isGrantedReadMediaPermission (line 84) | private boolean isGrantedReadMediaPermission(@NonNull Context context,...
    method checkSelfByRequestPermissions (line 99) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothAdvertisePermission.java
  class BluetoothAdvertisePermission (line 25) | public final class BluetoothAdvertisePermission extends DangerousPermiss...
    method createFromParcel (line 32) | @Override
    method newArray (line 37) | @Override
    method BluetoothAdvertisePermission (line 43) | public BluetoothAdvertisePermission() {
    method BluetoothAdvertisePermission (line 47) | private BluetoothAdvertisePermission(Parcel in) {
    method getPermissionName (line 51) | @NonNull
    method getFromAndroidVersion (line 57) | @Override
    method getPermissionGroup (line 62) | @Override
    method getMinTargetSdkVersion (line 68) | @Override
    method checkSelfByManifestFile (line 76) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothConnectPermission.java
  class BluetoothConnectPermission (line 25) | public final class BluetoothConnectPermission extends DangerousPermission {
    method createFromParcel (line 32) | @Override
    method newArray (line 37) | @Override
    method BluetoothConnectPermission (line 43) | public BluetoothConnectPermission() {
    method BluetoothConnectPermission (line 47) | private BluetoothConnectPermission(Parcel in) {
    method getPermissionName (line 51) | @NonNull
    method getPermissionGroup (line 57) | @Override
    method getFromAndroidVersion (line 63) | @Override
    method getMinTargetSdkVersion (line 68) | @Override
    method checkSelfByManifestFile (line 76) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothScanPermission.java
  class BluetoothScanPermission (line 27) | public final class BluetoothScanPermission extends DangerousPermission {
    method createFromParcel (line 34) | @Override
    method newArray (line 39) | @Override
    method BluetoothScanPermission (line 45) | public BluetoothScanPermission() {
    method BluetoothScanPermission (line 49) | private BluetoothScanPermission(Parcel in) {
    method getPermissionName (line 53) | @NonNull
    method getPermissionGroup (line 59) | @Override
    method getFromAndroidVersion (line 65) | @Override
    method getMinTargetSdkVersion (line 70) | @Override
    method getOldPermissions (line 78) | @NonNull
    method isGrantedPermissionByLowVersion (line 85) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 90) | @Override
    method checkSelfByManifestFile (line 95) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/BodySensorsBackgroundPermission.java
  class BodySensorsBackgroundPermission (line 28) | public final class BodySensorsBackgroundPermission extends DangerousPerm...
    method createFromParcel (line 35) | @Override
    method newArray (line 40) | @Override
    method BodySensorsBackgroundPermission (line 46) | public BodySensorsBackgroundPermission() {
    method BodySensorsBackgroundPermission (line 50) | private BodySensorsBackgroundPermission(Parcel in) {
    method getPermissionName (line 54) | @NonNull
    method getPermissionPageType (line 60) | @NonNull
    method getPermissionGroup (line 71) | @Override
    method getFromAndroidVersion (line 76) | @Override
    method getForegroundPermissions (line 81) | @NonNull
    method isBackgroundPermission (line 87) | @Override
    method isGrantedPermissionByStandardVersion (line 93) | @Override
    method isGrantedPermissionByLowVersion (line 102) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 107) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 116) | @Override
    method getRequestIntervalTime (line 121) | @Override
    method checkSelfByManifestFile (line 129) | @Override
    method checkSelfByRequestPermissions (line 140) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/BodySensorsPermission.java
  class BodySensorsPermission (line 20) | public final class BodySensorsPermission extends DangerousPermission {
    method createFromParcel (line 27) | @Override
    method newArray (line 32) | @Override
    method BodySensorsPermission (line 38) | public BodySensorsPermission() {
    method BodySensorsPermission (line 42) | private BodySensorsPermission(Parcel in) {
    method getPermissionName (line 46) | @NonNull
    method getPermissionGroup (line 52) | @Override
    method getFromAndroidVersion (line 57) | @Override
    method checkSelfByRequestPermissions (line 62) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/GetInstalledAppsPermission.java
  class GetInstalledAppsPermission (line 35) | public final class GetInstalledAppsPermission extends DangerousPermission {
    method createFromParcel (line 47) | @Override
    method newArray (line 52) | @Override
    method GetInstalledAppsPermission (line 58) | public GetInstalledAppsPermission() {
    method GetInstalledAppsPermission (line 62) | private GetInstalledAppsPermission(Parcel in) {
    method getPermissionName (line 66) | @NonNull
    method getPermissionChannel (line 72) | @NonNull
    method getPermissionPageType (line 103) | @NonNull
    method getFromAndroidVersion (line 112) | @Override
    method isSupportRequestPermission (line 117) | @Override
    method isGrantedPermission (line 135) | @Override
    method isDoNotAskAgainPermission (line 169) | @Override
    method getPermissionSettingIntents (line 191) | @NonNull
    method checkSelfByManifestFile (line 221) | @Override
    method isSupportRequestPermissionBySystem (line 263) | @SuppressWarnings("deprecation")
    method isSupportRequestPermissionByMiui (line 297) | @RequiresApi(PermissionVersion.ANDROID_4_4)
    method isSupportRequestPermissionByOneUi (line 308) | @RequiresApi(PermissionVersion.ANDROID_6)
    method isSupportRequestPermissionByFlyme (line 337) | @RequiresApi(PermissionVersion.ANDROID_6)
    method getOpsNameByFlyme (line 352) | private String getOpsNameByFlyme(@NonNull Context context) {

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/HealthDataBasePermission.java
  class HealthDataBasePermission (line 32) | public abstract class HealthDataBasePermission extends DangerousPermissi...
    method HealthDataBasePermission (line 34) | protected HealthDataBasePermission() {
    method HealthDataBasePermission (line 38) | protected HealthDataBasePermission(Parcel in) {
    method getPermissionPageType (line 42) | @NonNull
    method getPermissionGroup (line 48) | @Override
    method getPermissionSettingIntents (line 53) | @NonNull
    method checkSelfByManifestFile (line 90) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/NearbyWifiDevicesPermission.java
  class NearbyWifiDevicesPermission (line 26) | public final class NearbyWifiDevicesPermission extends DangerousPermissi...
    method createFromParcel (line 33) | @Override
    method newArray (line 38) | @Override
    method NearbyWifiDevicesPermission (line 44) | public NearbyWifiDevicesPermission() {
    method NearbyWifiDevicesPermission (line 48) | private NearbyWifiDevicesPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getPermissionGroup (line 58) | @Override
    method getFromAndroidVersion (line 64) | @Override
    method getOldPermissions (line 69) | @NonNull
    method isGrantedPermissionByLowVersion (line 76) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 81) | @Override
    method checkSelfByManifestFile (line 86) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/PostNotificationsPermission.java
  class PostNotificationsPermission (line 23) | public final class PostNotificationsPermission extends DangerousPermissi...
    method createFromParcel (line 30) | @Override
    method newArray (line 35) | @Override
    method PostNotificationsPermission (line 41) | public PostNotificationsPermission() {
    method PostNotificationsPermission (line 45) | private PostNotificationsPermission(Parcel in) {
    method getPermissionName (line 49) | @NonNull
    method getFromAndroidVersion (line 55) | @Override
    method getOldPermissions (line 60) | @NonNull
    method isGrantedPermissionByLowVersion (line 67) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 72) | @Override
    method getPermissionSettingIntents (line 77) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadExternalStoragePermission.java
  class ReadExternalStoragePermission (line 28) | public final class ReadExternalStoragePermission extends DangerousPermis...
    method createFromParcel (line 37) | @Override
    method newArray (line 42) | @Override
    method ReadExternalStoragePermission (line 48) | public ReadExternalStoragePermission() {
    method ReadExternalStoragePermission (line 52) | private ReadExternalStoragePermission(Parcel in) {
    method getPermissionName (line 56) | @NonNull
    method getPermissionGroup (line 62) | @Override
    method getFromAndroidVersion (line 67) | @Override
    method isGrantedPermissionByStandardVersion (line 72) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 82) | @Override
    method checkSelfByManifestFile (line 92) | @Override
    method checkSelfByRequestPermissions (line 143) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthDataHistoryPermission.java
  class ReadHealthDataHistoryPermission (line 20) | public final class ReadHealthDataHistoryPermission extends HealthDataBas...
    method createFromParcel (line 27) | @Override
    method newArray (line 32) | @Override
    method ReadHealthDataHistoryPermission (line 38) | public ReadHealthDataHistoryPermission() {
    method ReadHealthDataHistoryPermission (line 42) | private ReadHealthDataHistoryPermission(Parcel in) {
    method getPermissionName (line 46) | @NonNull
    method getFromAndroidVersion (line 52) | @Override
    method checkSelfByRequestPermissions (line 57) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthDataInBackgroundPermission.java
  class ReadHealthDataInBackgroundPermission (line 24) | public final class ReadHealthDataInBackgroundPermission extends HealthDa...
    method createFromParcel (line 31) | @Override
    method newArray (line 36) | @Override
    method ReadHealthDataInBackgroundPermission (line 42) | public ReadHealthDataInBackgroundPermission() {
    method ReadHealthDataInBackgroundPermission (line 46) | private ReadHealthDataInBackgroundPermission(Parcel in) {
    method getPermissionName (line 50) | @NonNull
    method getFromAndroidVersion (line 56) | @Override
    method getOldPermissions (line 61) | @Nullable
    method checkSelfByManifestFile (line 74) | @Override
    method checkSelfByRequestPermissions (line 87) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthRatePermission.java
  class ReadHealthRatePermission (line 23) | public final class ReadHealthRatePermission extends HealthDataBasePermis...
    method createFromParcel (line 30) | @Override
    method newArray (line 35) | @Override
    method ReadHealthRatePermission (line 41) | public ReadHealthRatePermission() {
    method ReadHealthRatePermission (line 45) | private ReadHealthRatePermission(Parcel in) {
    method getPermissionName (line 49) | @NonNull
    method getFromAndroidVersion (line 55) | @Override
    method getOldPermissions (line 60) | @Override
    method checkSelfByManifestFile (line 65) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaAudioPermission.java
  class ReadMediaAudioPermission (line 25) | public final class ReadMediaAudioPermission extends DangerousPermission {
    method createFromParcel (line 32) | @Override
    method newArray (line 37) | @Override
    method ReadMediaAudioPermission (line 43) | public ReadMediaAudioPermission() {
    method ReadMediaAudioPermission (line 47) | private ReadMediaAudioPermission(Parcel in) {
    method getPermissionName (line 51) | @NonNull
    method getFromAndroidVersion (line 57) | @Override
    method getOldPermissions (line 62) | @NonNull
    method isGrantedPermissionByLowVersion (line 69) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 74) | @Override
    method checkSelfByManifestFile (line 79) | @Override
    method checkSelfByRequestPermissions (line 92) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaImagesPermission.java
  class ReadMediaImagesPermission (line 26) | public final class ReadMediaImagesPermission extends DangerousPermission {
    method createFromParcel (line 33) | @Override
    method newArray (line 38) | @Override
    method ReadMediaImagesPermission (line 44) | public ReadMediaImagesPermission() {
    method ReadMediaImagesPermission (line 48) | private ReadMediaImagesPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getPermissionGroup (line 58) | @Override
    method getFromAndroidVersion (line 63) | @Override
    method getOldPermissions (line 68) | @NonNull
    method isGrantedPermissionByStandardVersion (line 75) | @Override
    method isGrantedPermissionByLowVersion (line 87) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 92) | @Override
    method checkSelfByManifestFile (line 97) | @Override
    method checkSelfByRequestPermissions (line 110) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaVideoPermission.java
  class ReadMediaVideoPermission (line 26) | public final class ReadMediaVideoPermission extends DangerousPermission {
    method createFromParcel (line 33) | @Override
    method newArray (line 38) | @Override
    method ReadMediaVideoPermission (line 44) | public ReadMediaVideoPermission() {
    method ReadMediaVideoPermission (line 48) | private ReadMediaVideoPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getPermissionGroup (line 58) | @Override
    method getFromAndroidVersion (line 63) | @Override
    method getOldPermissions (line 68) | @NonNull
    method isGrantedPermissionByStandardVersion (line 75) | @Override
    method isGrantedPermissionByLowVersion (line 87) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 92) | @Override
    method checkSelfByManifestFile (line 97) | @Override
    method checkSelfByRequestPermissions (line 110) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaVisualUserSelectedPermission.java
  class ReadMediaVisualUserSelectedPermission (line 22) | public final class ReadMediaVisualUserSelectedPermission extends Dangero...
    method createFromParcel (line 29) | @Override
    method newArray (line 34) | @Override
    method ReadMediaVisualUserSelectedPermission (line 40) | public ReadMediaVisualUserSelectedPermission() {
    method ReadMediaVisualUserSelectedPermission (line 44) | private ReadMediaVisualUserSelectedPermission(Parcel in) {
    method getPermissionName (line 48) | @NonNull
    method getPermissionGroup (line 54) | @Override
    method getFromAndroidVersion (line 59) | @Override
    method getMinTargetSdkVersion (line 64) | @Override
    method checkSelfByRequestPermissions (line 72) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/ReadPhoneNumbersPermission.java
  class ReadPhoneNumbersPermission (line 26) | public final class ReadPhoneNumbersPermission extends DangerousPermission {
    method createFromParcel (line 33) | @Override
    method newArray (line 38) | @Override
    method ReadPhoneNumbersPermission (line 44) | public ReadPhoneNumbersPermission() {
    method ReadPhoneNumbersPermission (line 48) | private ReadPhoneNumbersPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getPermissionGroup (line 58) | @Override
    method getFromAndroidVersion (line 63) | @Override
    method getOldPermissions (line 68) | @NonNull
    method isGrantedPermissionByLowVersion (line 75) | @Override
    method isDoNotAskAgainPermissionByLowVersion (line 80) | @Override
    method checkSelfByManifestFile (line 85) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/StandardDangerousPermission.java
  class StandardDangerousPermission (line 17) | public final class StandardDangerousPermission extends DangerousPermissi...
    method createFromParcel (line 21) | @Override
    method newArray (line 26) | @Override
    method StandardDangerousPermission (line 41) | private StandardDangerousPermission(Parcel in) {
    method StandardDangerousPermission (line 45) | public StandardDangerousPermission(@NonNull String permissionName, int...
    method StandardDangerousPermission (line 49) | public StandardDangerousPermission(@NonNull String permissionName, @Nu...
    method writeToParcel (line 55) | @Override
    method getPermissionName (line 63) | @NonNull
    method getPermissionGroup (line 69) | @Nullable
    method getFromAndroidVersion (line 75) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/StandardFitnessAndWellnessDataPermission.java
  class StandardFitnessAndWellnessDataPermission (line 14) | public final class StandardFitnessAndWellnessDataPermission extends Heal...
    method createFromParcel (line 24) | @Override
    method newArray (line 29) | @Override
    method StandardFitnessAndWellnessDataPermission (line 35) | public StandardFitnessAndWellnessDataPermission(@NonNull String permis...
    method StandardFitnessAndWellnessDataPermission (line 40) | private StandardFitnessAndWellnessDataPermission(Parcel in) {
    method writeToParcel (line 44) | @Override
    method getPermissionName (line 51) | @NonNull
    method getFromAndroidVersion (line 57) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/StandardHealthRecordsPermission.java
  class StandardHealthRecordsPermission (line 14) | public final class StandardHealthRecordsPermission extends HealthDataBas...
    method createFromParcel (line 24) | @Override
    method newArray (line 29) | @Override
    method StandardHealthRecordsPermission (line 35) | public StandardHealthRecordsPermission(@NonNull String permissionName,...
    method StandardHealthRecordsPermission (line 40) | private StandardHealthRecordsPermission(Parcel in) {
    method writeToParcel (line 44) | @Override
    method getPermissionName (line 51) | @NonNull
    method getFromAndroidVersion (line 57) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/dangerous/WriteExternalStoragePermission.java
  class WriteExternalStoragePermission (line 28) | public final class WriteExternalStoragePermission extends DangerousPermi...
    method createFromParcel (line 37) | @Override
    method newArray (line 42) | @Override
    method WriteExternalStoragePermission (line 48) | public WriteExternalStoragePermission() {
    method WriteExternalStoragePermission (line 52) | private WriteExternalStoragePermission(Parcel in) {
    method getPermissionName (line 56) | @NonNull
    method getPermissionGroup (line 62) | @Override
    method getFromAndroidVersion (line 67) | @Override
    method isGrantedPermissionByStandardVersion (line 72) | @Override
    method isDoNotAskAgainPermissionByStandardVersion (line 95) | @Override
    method isRegisterPermissionByManifestFile (line 109) | @Override
    method checkSelfByManifestFile (line 115) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/AccessNotificationPolicyPermission.java
  class AccessNotificationPolicyPermission (line 23) | public final class AccessNotificationPolicyPermission extends SpecialPer...
    method createFromParcel (line 30) | @Override
    method newArray (line 35) | @Override
    method AccessNotificationPolicyPermission (line 41) | public AccessNotificationPolicyPermission() {
    method AccessNotificationPolicyPermission (line 45) | private AccessNotificationPolicyPermission(Parcel in) {
    method getPermissionName (line 49) | @NonNull
    method getFromAndroidVersion (line 55) | @Override
    method isGrantedPermission (line 60) | @Override
    method getPermissionSettingIntents (line 73) | @NonNull
    method isRegisterPermissionByManifestFile (line 123) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/BindAccessibilityServicePermission.java
  class BindAccessibilityServicePermission (line 33) | public final class BindAccessibilityServicePermission extends SpecialPer...
    method createFromParcel (line 40) | @Override
    method newArray (line 45) | @Override
    method BindAccessibilityServicePermission (line 55) | public BindAccessibilityServicePermission(@NonNull Class<? extends Acc...
    method BindAccessibilityServicePermission (line 59) | public BindAccessibilityServicePermission(@NonNull String accessibilit...
    method BindAccessibilityServicePermission (line 63) | private BindAccessibilityServicePermission(Parcel in) {
    method writeToParcel (line 67) | @Override
    method getPermissionName (line 73) | @NonNull
    method getFromAndroidVersion (line 79) | @Override
    method isGrantedPermission (line 84) | @Override
    method getPermissionSettingIntents (line 115) | @NonNull
    method checkCompliance (line 128) | @Override
    method checkSelfByManifestFile (line 139) | @Override
    method getAccessibilityServiceClassName (line 215) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/permission/special/BindDeviceAdminPermission.java
  class BindDeviceAdminPermission (line 33) | public final class BindDeviceAdminPermission extends SpecialPermission {
    method createFromParcel (line 37) | @Override
    method newArray (line 42) | @Override
    method BindDeviceAdminPermission (line 56) | public BindDeviceAdminPermission(@NonNull Class<? extends DeviceAdminR...
    method BindDeviceAdminPermission (line 60) | public BindDeviceAdminPermission(@NonNull String deviceAdminReceiverCl...
    method BindDeviceAdminPermission (line 65) | private BindDeviceAdminPermission(Parcel in) {
    method writeToParcel (line 69) | @Override
    method getPermissionName (line 76) | @NonNull
    method getFromAndroidVersion (line 82) | @Override
    method isGrantedPermission (line 87) | @Override
    method getPermissionSettingIntents (line 102) | @NonNull
    method checkCompliance (line 119) | @Override
    method checkSelfByManifestFile (line 130) | @Override
    method getDeviceAdminReceiverClassName (line 206) | @NonNull
    method getExtraAddExplanation (line 211) | @Nullable

FILE: library/src/main/java/com/hjq/permissions/permission/special/BindNotificationListenerServicePermission.java
  class BindNotificationListenerServicePermission (line 34) | public final class BindNotificationListenerServicePermission extends Spe...
    method createFromParcel (line 41) | @Override
    method newArray (line 46) | @Override
    method BindNotificationListenerServicePermission (line 59) | public BindNotificationListenerServicePermission(@NonNull Class<? exte...
    method BindNotificationListenerServicePermission (line 63) | public BindNotificationListenerServicePermission(@NonNull String notif...
    method BindNotificationListenerServicePermission (line 67) | private BindNotificationListenerServicePermission(Parcel in) {
    method writeToParcel (line 71) | @Override
    method getPermissionName (line 77) | @NonNull
    method getFromAndroidVersion (line 83) | @Override
    method isGrantedPermission (line 88) | @Override
    method getPermissionSettingIntents (line 133) | @NonNull
    method checkCompliance (line 162) | @Override
    method checkSelfByManifestFile (line 173) | @Override
    method getNotificationListenerServiceClassName (line 233) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/permission/special/BindVpnServicePermission.java
  class BindVpnServicePermission (line 31) | public final class BindVpnServicePermission extends SpecialPermission {
    method createFromParcel (line 38) | @Override
    method newArray (line 43) | @Override
    method BindVpnServicePermission (line 49) | public BindVpnServicePermission() {
    method BindVpnServicePermission (line 53) | private BindVpnServicePermission(Parcel in) {
    method getPermissionName (line 57) | @NonNull
    method getPermissionPageType (line 63) | @NonNull
    method getFromAndroidVersion (line 83) | @Override
    method isGrantedPermission (line 88) | @Override
    method getPermissionSettingIntents (line 93) | @NonNull
    method checkSelfByManifestFile (line 102) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/ManageExternalStoragePermission.java
  class ManageExternalStoragePermission (line 30) | public final class ManageExternalStoragePermission extends SpecialPermis...
    method createFromParcel (line 37) | @Override
    method newArray (line 42) | @Override
    method ManageExternalStoragePermission (line 48) | public ManageExternalStoragePermission() {
    method ManageExternalStoragePermission (line 52) | private ManageExternalStoragePermission(Parcel in) {
    method getPermissionName (line 56) | @NonNull
    method getFromAndroidVersion (line 62) | @Override
    method getOldPermissions (line 67) | @NonNull
    method isGrantedPermission (line 75) | @Override
    method getPermissionSettingIntents (line 91) | @NonNull
    method isRegisterPermissionByManifestFile (line 112) | @Override
    method checkSelfByManifestFile (line 118) | @Override
    method checkSelfByRequestPermissions (line 152) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/ManageMediaPermission.java
  class ManageMediaPermission (line 21) | public final class ManageMediaPermission extends SpecialPermission {
    method createFromParcel (line 28) | @Override
    method newArray (line 33) | @Override
    method ManageMediaPermission (line 39) | public ManageMediaPermission() {
    method ManageMediaPermission (line 43) | private ManageMediaPermission(Parcel in) {
    method getPermissionName (line 47) | @NonNull
    method getFromAndroidVersion (line 53) | @Override
    method isGrantedPermission (line 58) | @Override
    method getPermissionSettingIntents (line 66) | @NonNull
    method isRegisterPermissionByManifestFile (line 87) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/NotificationServicePermission.java
  class NotificationServicePermission (line 29) | public final class NotificationServicePermission extends SpecialPermissi...
    method createFromParcel (line 39) | @Override
    method newArray (line 44) | @Override
    method NotificationServicePermission (line 53) | public NotificationServicePermission() {
    method NotificationServicePermission (line 57) | public NotificationServicePermission(@Nullable String channelId) {
    method NotificationServicePermission (line 61) | private NotificationServicePermission(Parcel in) {
    method writeToParcel (line 65) | @Override
    method getPermissionName (line 71) | @NonNull
    method getFromAndroidVersion (line 77) | @Override
    method isGrantedPermission (line 82) | @Override
    method getPermissionSettingIntents (line 106) | @NonNull
    method getChannelId (line 169) | @Nullable
    method checkSelfByManifestFile (line 174) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/PackageUsageStatsPermission.java
  class PackageUsageStatsPermission (line 22) | public final class PackageUsageStatsPermission extends SpecialPermission {
    method createFromParcel (line 29) | @Override
    method newArray (line 34) | @Override
    method PackageUsageStatsPermission (line 40) | public PackageUsageStatsPermission() {
    method PackageUsageStatsPermission (line 44) | private PackageUsageStatsPermission(Parcel in) {
    method getPermissionName (line 48) | @NonNull
    method getFromAndroidVersion (line 54) | @Override
    method isGrantedPermission (line 59) | @Override
    method getPermissionSettingIntents (line 67) | @NonNull
    method isRegisterPermissionByManifestFile (line 92) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/PictureInPicturePermission.java
  class PictureInPicturePermission (line 27) | public final class PictureInPicturePermission extends SpecialPermission {
    method createFromParcel (line 34) | @Override
    method newArray (line 39) | @Override
    method PictureInPicturePermission (line 45) | public PictureInPicturePermission() {
    method PictureInPicturePermission (line 49) | private PictureInPicturePermission(Parcel in) {
    method getPermissionName (line 53) | @NonNull
    method getFromAndroidVersion (line 59) | @Override
    method isGrantedPermission (line 64) | @Override
    method getPermissionSettingIntents (line 72) | @NonNull
    method checkSelfByManifestFile (line 106) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/RequestIgnoreBatteryOptimizationsPermission.java
  class RequestIgnoreBatteryOptimizationsPermission (line 25) | public final class RequestIgnoreBatteryOptimizationsPermission extends S...
    method createFromParcel (line 32) | @Override
    method newArray (line 37) | @Override
    method RequestIgnoreBatteryOptimizationsPermission (line 43) | public RequestIgnoreBatteryOptimizationsPermission() {
    method RequestIgnoreBatteryOptimizationsPermission (line 47) | private RequestIgnoreBatteryOptimizationsPermission(Parcel in) {
    method getPermissionName (line 51) | @NonNull
    method getPermissionPageType (line 57) | @SuppressLint("BatteryLife")
    method getFromAndroidVersion (line 89) | @Override
    method isGrantedPermission (line 94) | @Override
    method getPermissionSettingIntents (line 107) | @SuppressLint("BatteryLife")
    method getResultWaitTime (line 184) | @Override
    method isRegisterPermissionByManifestFile (line 232) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/RequestInstallPackagesPermission.java
  class RequestInstallPackagesPermission (line 21) | public final class RequestInstallPackagesPermission extends SpecialPermi...
    method createFromParcel (line 28) | @Override
    method newArray (line 33) | @Override
    method RequestInstallPackagesPermission (line 39) | public RequestInstallPackagesPermission() {
    method RequestInstallPackagesPermission (line 43) | private RequestInstallPackagesPermission(Parcel in) {
    method getPermissionName (line 47) | @NonNull
    method getFromAndroidVersion (line 53) | @Override
    method isGrantedPermission (line 58) | @Override
    method getPermissionSettingIntents (line 66) | @NonNull
    method isRegisterPermissionByManifestFile (line 97) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/ScheduleExactAlarmPermission.java
  class ScheduleExactAlarmPermission (line 28) | public final class ScheduleExactAlarmPermission extends SpecialPermission {
    method createFromParcel (line 35) | @Override
    method newArray (line 40) | @Override
    method ScheduleExactAlarmPermission (line 46) | public ScheduleExactAlarmPermission() {
    method ScheduleExactAlarmPermission (line 50) | private ScheduleExactAlarmPermission(Parcel in) {
    method getPermissionName (line 54) | @NonNull
    method getFromAndroidVersion (line 60) | @Override
    method isGrantedPermission (line 65) | @Override
    method getPermissionSettingIntents (line 78) | @NonNull
    method isRegisterPermissionByManifestFile (line 109) | @Override
    method checkSelfByManifestFile (line 115) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/SystemAlertWindowPermission.java
  class SystemAlertWindowPermission (line 23) | public final class SystemAlertWindowPermission extends SpecialPermission {
    method createFromParcel (line 30) | @Override
    method newArray (line 35) | @Override
    method SystemAlertWindowPermission (line 44) | public SystemAlertWindowPermission() {
    method SystemAlertWindowPermission (line 48) | private SystemAlertWindowPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getFromAndroidVersion (line 58) | @Override
    method isGrantedPermission (line 65) | @Override
    method getPermissionSettingIntents (line 81) | @NonNull
    method isRegisterPermissionByManifestFile (line 235) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/UseFullScreenIntentPermission.java
  class UseFullScreenIntentPermission (line 26) | public final class UseFullScreenIntentPermission extends SpecialPermissi...
    method createFromParcel (line 33) | @Override
    method newArray (line 38) | @Override
    method UseFullScreenIntentPermission (line 44) | public UseFullScreenIntentPermission() {
    method UseFullScreenIntentPermission (line 48) | private UseFullScreenIntentPermission(Parcel in) {
    method getPermissionName (line 52) | @NonNull
    method getFromAndroidVersion (line 58) | @Override
    method isGrantedPermission (line 63) | @Override
    method getPermissionSettingIntents (line 76) | @NonNull
    method isRegisterPermissionByManifestFile (line 116) | @Override
    method checkSelfByRequestPermissions (line 122) | @Override

FILE: library/src/main/java/com/hjq/permissions/permission/special/WriteSettingsPermission.java
  class WriteSettingsPermission (line 21) | public final class WriteSettingsPermission extends SpecialPermission {
    method createFromParcel (line 28) | @Override
    method newArray (line 33) | @Override
    method WriteSettingsPermission (line 39) | public WriteSettingsPermission() {
    method WriteSettingsPermission (line 43) | private WriteSettingsPermission(Parcel in) {
    method getPermissionName (line 47) | @NonNull
    method getFromAndroidVersion (line 53) | @Override
    method isGrantedPermission (line 58) | @Override
    method getPermissionSettingIntents (line 66) | @NonNull
    method isRegisterPermissionByManifestFile (line 97) | @Override

FILE: library/src/main/java/com/hjq/permissions/start/IStartActivityDelegate.java
  type IStartActivityDelegate (line 12) | public interface IStartActivityDelegate {
    method startActivity (line 17) | void startActivity(Intent intent);
    method startActivityForResult (line 22) | void startActivityForResult(Intent intent, @IntRange(from = 1, to = 65...

FILE: library/src/main/java/com/hjq/permissions/start/StartActivityAgent.java
  class StartActivityAgent (line 21) | public final class StartActivityAgent {
    method startActivity (line 23) | public static void startActivity(@NonNull Context context,
    method startActivity (line 28) | public static void startActivity(@NonNull Activity activity,
    method startActivity (line 33) | @SuppressWarnings("deprecation")
    method startActivity (line 39) | public static void startActivity(@NonNull androidx.fragment.app.Fragme...
    method startActivity (line 44) | public static void startActivity(@NonNull Context context,
    method startActivityForResult (line 82) | public static void startActivityForResult(@NonNull Activity activity,
    method startActivityForResult (line 88) | @SuppressWarnings("deprecation")
    method startActivityForResult (line 95) | public static void startActivityForResult(@NonNull androidx.fragment.a...
    method startActivityForResult (line 101) | public static void startActivityForResult(@NonNull Context context,
    method startActivityForResult (line 108) | public static void startActivityForResult(@NonNull Context context,

FILE: library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByActivity.java
  class StartActivityDelegateByActivity (line 14) | public final class StartActivityDelegateByActivity implements IStartActi...
    method StartActivityDelegateByActivity (line 19) | public StartActivityDelegateByActivity(@NonNull Activity activity) {
    method startActivity (line 23) | @Override
    method startActivityForResult (line 28) | @Override

FILE: library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByContext.java
  class StartActivityDelegateByContext (line 16) | public final class StartActivityDelegateByContext implements IStartActiv...
    method StartActivityDelegateByContext (line 21) | public StartActivityDelegateByContext(@NonNull Context context) {
    method startActivity (line 25) | @Override
    method startActivityForResult (line 37) | @Override

FILE: library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByFragmentAndroid.java
  class StartActivityDelegateByFragmentAndroid (line 14) | @SuppressWarnings("deprecation")
    method StartActivityDelegateByFragmentAndroid (line 20) | public StartActivityDelegateByFragmentAndroid(@NonNull Fragment fragme...
    method startActivity (line 24) | @Override
    method startActivityForResult (line 29) | @Override

FILE: library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByFragmentAndroidX.java
  class StartActivityDelegateByFragmentAndroidX (line 14) | public final class StartActivityDelegateByFragmentAndroidX implements IS...
    method StartActivityDelegateByFragmentAndroidX (line 19) | public StartActivityDelegateByFragmentAndroidX(@NonNull Fragment fragm...
    method startActivity (line 23) | @Override
    method startActivityForResult (line 28) | @Override

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionApi.java
  class PermissionApi (line 19) | public final class PermissionApi {
    method isHealthPermission (line 24) | public static boolean isHealthPermission(@NonNull IPermission permissi...
    method containsPermissionByStartActivity (line 31) | public static boolean containsPermissionByStartActivity(@NonNull Conte...
    method isGrantedPermissions (line 47) | public static boolean isGrantedPermissions(@NonNull Context context, @...
    method getGrantedPermissions (line 64) | public static List<IPermission> getGrantedPermissions(@NonNull Context...
    method getDeniedPermissions (line 77) | public static List<IPermission> getDeniedPermissions(@NonNull Context ...
    method isDoNotAskAgainPermissions (line 92) | public static boolean isDoNotAskAgainPermissions(@NonNull Activity act...
    method getBestPermissionSettingIntent (line 104) | @NonNull
    method addOldPermissionsByNewPermissions (line 162) | public static synchronized void addOldPermissionsByNewPermissions(@Non...
    method getMaxIntervalTimeByPermissions (line 192) | public static int getMaxIntervalTimeByPermissions(@NonNull Context con...
    method getMaxWaitTimeByPermissions (line 210) | public static int getMaxWaitTimeByPermissions(@NonNull Context context...

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionChecker.java
  class PermissionChecker (line 21) | public final class PermissionChecker {
    method checkActivityStatus (line 26) | public static void checkActivityStatus(@Nullable Activity activity) {
    method checkAndroidXFragmentStatus (line 51) | public static void checkAndroidXFragmentStatus(@NonNull androidx.fragm...
    method checkAndroidFragmentStatus (line 68) | @SuppressWarnings("deprecation")
    method checkPermissionList (line 86) | public static void checkPermissionList(@NonNull Activity activity, @Nu...
    method checkPermissionParcelable (line 103) | public static void checkPermissionParcelable(@NonNull IPermission perm...

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionSettingPage.java
  class PermissionSettingPage (line 21) | public final class PermissionSettingPage {
    method getOneUiPermissionPageIntent (line 49) | @NonNull
    method getHuaWeiMobileManagerAppIntent (line 65) | @NonNull
    method getXiaoMiMobileManagerAppIntent (line 86) | @NonNull
    method getOppoSafeCenterAppIntent (line 116) | @NonNull
    method getVivoMobileManagerAppIntent (line 136) | @NonNull
    method getSmartisanSecurityCenterAppIntent (line 156) | @NonNull
    method getXiaoMiApplicationPermissionPageIntent (line 178) | @NonNull
    method getMeiZuApplicationPermissionPageIntent (line 187) | @NonNull
    method getSmartisanPermissionPageIntent (line 196) | @NonNull
    method getCommonPermissionSettingIntent (line 216) | @NonNull
    method getCommonPermissionSettingIntent (line 221) | @NonNull
    method getApplicationDetailsSettingsIntent (line 234) | @NonNull
    method getManageApplicationSettingsIntent (line 255) | @NonNull
    method getApplicationSettingsIntent (line 263) | @NonNull
    method getAndroidSettingsIntent (line 271) | @NonNull

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionTaskHandler.java
  class PermissionTaskHandler (line 14) | public final class PermissionTaskHandler {
    method sendTask (line 22) | public static void sendTask(@NonNull Runnable runnable, long delayMill...
    method sendTask (line 29) | public static void sendTask(@NonNull Runnable runnable, @NonNull Objec...
    method cancelTask (line 40) | public static void cancelTask(@NonNull Object token) {

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionUtils.java
  class PermissionUtils (line 25) | public final class PermissionUtils {
    method isDebugMode (line 30) | public static boolean isDebugMode(@NonNull Context context) {
    method asArrayList (line 41) | @SuppressWarnings("all")
    method findActivity (line 61) | @Nullable
    method isActivityUnavailable (line 81) | public static boolean isActivityUnavailable(@Nullable Activity activit...
    method isFragmentUnavailable (line 88) | @SuppressWarnings("deprecation")
    method isFragmentUnavailable (line 96) | @SuppressWarnings("deprecation")
    method areActivityIntent (line 104) | @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    method equalsString (line 125) | public static boolean equalsString(@Nullable String s1, @Nullable Stri...
    method reverseEqualsString (line 148) | public static boolean reverseEqualsString(@Nullable String s1, @Nullab...
    method equalsPermission (line 171) | public static boolean equalsPermission(@NonNull String permission1, @N...
    method equalsPermission (line 180) | public static boolean equalsPermission(@NonNull IPermission permission...
    method equalsPermission (line 186) | public static boolean equalsPermission(@NonNull IPermission permission...
    method containsPermission (line 195) | public static boolean containsPermission(@NonNull Collection<IPermissi...
    method containsPermission (line 211) | public static boolean containsPermission(@NonNull List<String> permiss...
    method containsPermission (line 227) | public static boolean containsPermission(@NonNull Collection<IPermissi...
    method convertPermissionList (line 243) | @NonNull
    method convertPermissionArray (line 258) | @NonNull
    method getPackageNameUri (line 273) | public static Uri getPackageNameUri(@NonNull Context context) {
    method isClassExist (line 280) | public static boolean isClassExist(@Nullable String className) {
    method equalsIntentList (line 301) | public static boolean equalsIntentList(@NonNull List<Intent> intentLis...

FILE: library/src/main/java/com/hjq/permissions/tools/PermissionVersion.java
  class PermissionVersion (line 13) | @SuppressLint("AnnotateVersionCheck")
    method getCurrentVersion (line 51) | public static int getCurrentVersion() {
    method getTargetVersion (line 58) | public static int getTargetVersion(Context context) {
    method isAndroid16 (line 65) | public static boolean isAndroid16() {
    method isAndroid15 (line 72) | public static boolean isAndroid15() {
    method isAndroid14 (line 79) | public static boolean isAndroid14() {
    method isAndroid13 (line 86) | public static boolean isAndroid13() {
    method isAndroid12 (line 93) | public static boolean isAndroid12() {
    method isAndroid11 (line 100) | public static boolean isAndroid11() {
    method isAndroid10 (line 107) | public static boolean isAndroid10() {
    method isAndroid9 (line 114) | public static boolean isAndroid9() {
    method isAndroid8_1 (line 121) | public static boolean isAndroid8_1() {
    method isAndroid8 (line 128) | public static boolean isAndroid8() {
    method isAndroid7_1 (line 135) | public static boolean isAndroid7_1() {
    method isAndroid7 (line 142) | public static boolean isAndroid7() {
    method isAndroid6 (line 149) | public static boolean isAndroid6() {
    method isAndroid5_1 (line 156) | public static boolean isAndroid5_1() {
    method isAndroid5 (line 163) | public static boolean isAndroid5() {
    method isAndroid4_4 (line 170) | public static boolean isAndroid4_4() {
    method isAndroid4_3 (line 177) | public static boolean isAndroid4_3() {
Condensed preview — 157 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,007K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 719,
    "preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 27,
    "preview": "blank_issues_enabled: false"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_en_template_bug.yml",
    "chars": 5449,
    "preview": "name: Submit Bug\ndescription: Please let me know the issues with the framework, and I will assist you in resolving them!"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_en_template_question.yml",
    "chars": 2283,
    "preview": "name: Ask a Question\ndescription: Ask your questions, and I will provide you with answers.\ntitle: \"[Question]:\"\nlabels: "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_en_template_suggest.yml",
    "chars": 2139,
    "preview": "name: Submit Suggestion\ndescription: Please let me know the shortcomings of the framework, so that I can improve it!\ntit"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_zh_template_bug.yml",
    "chars": 3683,
    "preview": "name: 提交 Bug\ndescription: 请告诉我框架存在的问题,我会协助你解决此问题!\ntitle: \"[Bug]:\"\nlabels: [\"bug\"]\n\nbody:\n  - type: markdown\n    attribut"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_zh_template_question.yml",
    "chars": 1459,
    "preview": "name: 提出疑问\ndescription: 提出你的困惑,我会给你解答\ntitle: \"[疑惑]:\"\nlabels: [\"question\"]\n\nbody:\n  - type: markdown\n    attributes:\n    "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue_zh_template_suggest.yml",
    "chars": 1337,
    "preview": "name: 提交建议\ndescription: 请告诉我框架的不足之处,让我做得更好!\ntitle: \"[建议]:\"\nlabels: [\"help wanted\"]\n\nbody:\n  - type: markdown\n    attribu"
  },
  {
    "path": ".github/workflows/android.yml",
    "chars": 216,
    "preview": "name: Android CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n   "
  },
  {
    "path": ".gitignore",
    "chars": 92,
    "preview": ".gradle\n.idea\n.cxx\n.externalNativeBuild\nbuild\ncaptures\n\n._*\n*.iml\n.DS_Store\nlocal.properties"
  },
  {
    "path": "Details-en.md",
    "chars": 47465,
    "preview": "#### Table of Contents\n\n* [Intent Extreme Jump Fallback Mechanism](#intent-extreme-jump-fallback-mechanism)\n\n* [Compatib"
  },
  {
    "path": "Details-zh.md",
    "chars": 26530,
    "preview": "#### 目录\n\n* [Intent 跳转极限兜底机制](#intent-跳转极限兜底机制)\n\n* [兼容请求权限 API 崩溃问题](#兼容请求权限-api-崩溃问题)\n\n* [规避系统权限回调空指针问题](#规避系统权限回调空指针问题)"
  },
  {
    "path": "HelpDoc-en.md",
    "chars": 21829,
    "preview": "#### Catalog\n\n* [Android 11 location permission adaptation](#android-11-location-permission-adaptation)\n\n* [Android 11 s"
  },
  {
    "path": "HelpDoc-zh.md",
    "chars": 14679,
    "preview": "#### 目录\n\n* [Android 11 定位权限适配](#android-11-定位权限适配)\n\n* [Android 11 存储权限适配](#android-11-存储权限适配)\n\n* [什么情况下需要适配分区存储特性](#什么情况"
  },
  {
    "path": "LICENSE",
    "chars": 11340,
    "preview": "\n                                 Apache License\n                           Version 2.0, June 2018\n                     "
  },
  {
    "path": "README-en.md",
    "chars": 25603,
    "preview": "# [中文文档](README.md)\n\n# Permission request framework\n\n![](logo.png)\n\n* project address: [Github](https://github.com/getAc"
  },
  {
    "path": "README.md",
    "chars": 21431,
    "preview": "# [English Doc](README-en.md)\n\n# 权限请求框架\n\n![](logo.png)\n\n* 项目地址:[Github](https://github.com/getActivity/XXPermissions)\n\n*"
  },
  {
    "path": "app/build.gradle",
    "chars": 1947,
    "preview": "apply plugin: 'com.android.application'\napply from : '../common.gradle'\n\nandroid {\n\n    namespace 'com.hjq.permissions.d"
  },
  {
    "path": "app/gradle.properties",
    "chars": 114,
    "preview": "StoreFile = AppSignature.jks\nStorePassword = AndroidProject\nKeyAlias = AndroidProject\nKeyPassword = AndroidProject"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 21843,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/AppApplication.java",
    "chars": 489,
    "preview": "package com.hjq.permissions.demo;\n\nimport android.app.Application;\n\nimport com.hjq.toast.Toaster;\nimport com.hjq.toast.s"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/HealthDataPrivacyPolicyActivity.java",
    "chars": 1779,
    "preview": "package com.hjq.permissions.demo;\n\nimport android.graphics.Insets;\nimport android.os.Build;\nimport android.os.Bundle;\nim"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/MainActivity.java",
    "chars": 52192,
    "preview": "package com.hjq.permissions.demo;\n\nimport android.app.NotificationChannel;\nimport android.app.NotificationManager;\nimpor"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/WindowLifecycleManager.java",
    "chars": 4173,
    "preview": "package com.hjq.permissions.demo;\n\nimport android.app.Activity;\nimport android.app.Application.ActivityLifecycleCallback"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/example/ExampleAccessibilityService.java",
    "chars": 4594,
    "preview": "package com.hjq.permissions.demo.example;\n\nimport android.accessibilityservice.AccessibilityService;\nimport android.util"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/example/ExampleDeviceAdminReceiver.java",
    "chars": 1928,
    "preview": "package com.hjq.permissions.demo.example;\n\nimport android.app.admin.DeviceAdminReceiver;\nimport android.content.Context;"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/example/ExampleNotificationListenerService.java",
    "chars": 1977,
    "preview": "package com.hjq.permissions.demo.example;\n\nimport android.app.Notification;\nimport android.os.Build;\nimport android.os.B"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/example/ExampleVpnService.java",
    "chars": 135,
    "preview": "package com.hjq.permissions.demo.example;\n\nimport android.net.VpnService;\n\npublic final class ExampleVpnService extends "
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/permission/PermissionConverter.java",
    "chars": 19098,
    "preview": "package com.hjq.permissions.demo.permission;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.te"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/permission/PermissionDescription.java",
    "chars": 10638,
    "preview": "package com.hjq.permissions.demo.permission;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport androi"
  },
  {
    "path": "app/src/main/java/com/hjq/permissions/demo/permission/PermissionInterceptor.java",
    "chars": 16533,
    "preview": "package com.hjq.permissions.demo.permission;\n\nimport android.app.Activity;\nimport android.app.AlertDialog.Builder;\nimpor"
  },
  {
    "path": "app/src/main/res/drawable/permission_description_popup_bg.xml",
    "chars": 312,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 13841,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/health_data_privacy_policy_activity.xml",
    "chars": 1377,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/permission_description_popup.xml",
    "chars": 1612,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 207,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#000000</color>\n    <color name=\"color"
  },
  {
    "path": "app/src/main/res/values/strings_demo.xml",
    "chars": 6964,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">XXPermissions</string>\n\n    <string name="
  },
  {
    "path": "app/src/main/res/values/strings_permission.xml",
    "chars": 13329,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"common_permission_description_title\">Permission de"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 526,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" pare"
  },
  {
    "path": "app/src/main/res/values-v21/styles.xml",
    "chars": 601,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" pare"
  },
  {
    "path": "app/src/main/res/values-zh/strings_demo.xml",
    "chars": 4459,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">XXPermissions</string>\n\n    <string name="
  },
  {
    "path": "app/src/main/res/values-zh/strings_permission.xml",
    "chars": 8727,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"common_permission_description_title\">权限说明</string>"
  },
  {
    "path": "app/src/main/res/xml/accessibility_service_config.xml",
    "chars": 527,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<accessibility-service xmlns:android=\"http://schemas.android.com/apk/res/android\""
  },
  {
    "path": "app/src/main/res/xml/device_admin_config.xml",
    "chars": 346,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<device-admin>\n    <uses-policies>\n        <!-- 限制密码类型 -->\n        <limit-passwor"
  },
  {
    "path": "app/src/main/res/xml/locales_config.xml",
    "chars": 308,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- https://developer.android.google.cn/about/versions/13/features/app-languages"
  },
  {
    "path": "build.gradle",
    "chars": 231,
    "preview": "plugins {\n    id 'com.android.application' version '8.4.2' apply false\n    id 'org.jetbrains.kotlin.android' version '1."
  },
  {
    "path": "common.gradle",
    "chars": 1073,
    "preview": "// 通用配置\nandroid {\n\n    // 编译源码版本\n    compileSdk 36\n    defaultConfig {\n        // Android 版本适配指南:https://github.com/getA"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 209,
    "preview": "zipStoreBase = GRADLE_USER_HOME\nzipStorePath = wrapper/dists\ndistributionBase = GRADLE_USER_HOME\ndistributionPath = wrap"
  },
  {
    "path": "gradle.properties",
    "chars": 878,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 8047,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "gradlew.bat",
    "chars": 2674,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "jitpack.yml",
    "chars": 18,
    "preview": "jdk:\n  - openjdk17"
  },
  {
    "path": "library/build.gradle",
    "chars": 1948,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'maven-publish'\napply from : '../common.gradle'\n\nandroid {\n\n    namesp"
  },
  {
    "path": "library/proguard-permissions.pro",
    "chars": 1627,
    "preview": "# 禁止混淆 IStartActivityDelegate 和 IFragmentMethodNative 接口及实现类涉及的方法名称\n# 这是因为框架拿 AndroidX 库中的 Fragment 和系统包下的 Fragment 实现了这"
  },
  {
    "path": "library/src/main/AndroidManifest.xml",
    "chars": 81,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.hjq.permissions\" />"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/DefaultPermissionDescription.java",
    "chars": 1154,
    "preview": "package com.hjq.permissions;\n\nimport android.app.Activity;\nimport androidx.annotation.NonNull;\nimport com.hjq.permission"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/DefaultPermissionInterceptor.java",
    "chars": 254,
    "preview": "package com.hjq.permissions;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity/XXPermissions"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/OnPermissionCallback.java",
    "chars": 566,
    "preview": "package com.hjq.permissions;\n\nimport androidx.annotation.NonNull;\nimport com.hjq.permissions.permission.base.IPermission"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/OnPermissionDescription.java",
    "chars": 1247,
    "preview": "package com.hjq.permissions;\n\nimport android.app.Activity;\nimport androidx.annotation.NonNull;\nimport com.hjq.permission"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/OnPermissionInterceptor.java",
    "chars": 2837,
    "preview": "package com.hjq.permissions;\n\nimport android.app.Activity;\nimport androidx.annotation.NonNull;\nimport androidx.annotatio"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/XXPermissions.java",
    "chars": 25361,
    "preview": "package com.hjq.permissions;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Context;\n"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/core/OnPermissionFragmentCallback.java",
    "chars": 559,
    "preview": "package com.hjq.permissions.core;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity/XXPermis"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/core/PermissionChannelImpl.java",
    "chars": 11977,
    "preview": "package com.hjq.permissions.core;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport androidx.annotation.Int"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/core/PermissionChannelImplByRequestPermissions.java",
    "chars": 2156,
    "preview": "package com.hjq.permissions.core;\n\nimport android.app.Activity;\nimport androidx.annotation.IntRange;\nimport androidx.ann"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/core/PermissionChannelImplByStartActivity.java",
    "chars": 2820,
    "preview": "package com.hjq.permissions.core;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport androidx.annotatio"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/core/PermissionRequestMainLogic.java",
    "chars": 16668,
    "preview": "package com.hjq.permissions.core;\n\nimport android.app.Activity;\nimport android.text.TextUtils;\nimport androidx.annotatio"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/IFragmentCallback.java",
    "chars": 834,
    "preview": "package com.hjq.permissions.fragment;\n\nimport android.content.Intent;\nimport androidx.annotation.Nullable;\n\n/**\n *    au"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/IFragmentMethod.java",
    "chars": 339,
    "preview": "package com.hjq.permissions.fragment;\n\nimport android.app.Activity;\n\n/**\n *    author : Android 轮子哥\n *    github : https"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/IFragmentMethodExtension.java",
    "chars": 928,
    "preview": "package com.hjq.permissions.fragment;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport c"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/IFragmentMethodNative.java",
    "chars": 1034,
    "preview": "package com.hjq.permissions.fragment;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport androidx.annotation"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactory.java",
    "chars": 3929,
    "preview": "package com.hjq.permissions.fragment.factory;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport androidx.an"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactoryByAndroid.java",
    "chars": 2261,
    "preview": "package com.hjq.permissions.fragment.factory;\n\nimport android.app.Activity;\nimport android.app.FragmentManager;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/factory/PermissionFragmentFactoryByAndroidX.java",
    "chars": 5249,
    "preview": "package com.hjq.permissions.fragment.factory;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragment.java",
    "chars": 2477,
    "preview": "package com.hjq.permissions.fragment.impl.android;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport and"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragmentByRequestPermissions.java",
    "chars": 835,
    "preview": "package com.hjq.permissions.fragment.impl.android;\n\nimport androidx.annotation.NonNull;\nimport com.hjq.permissions.core."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/android/PermissionAndroidFragmentByStartActivity.java",
    "chars": 853,
    "preview": "package com.hjq.permissions.fragment.impl.android;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\ni"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragment.java",
    "chars": 2641,
    "preview": "package com.hjq.permissions.fragment.impl.androidx;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\n"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragmentByRequestPermissions.java",
    "chars": 848,
    "preview": "package com.hjq.permissions.fragment.impl.androidx;\n\nimport androidx.annotation.NonNull;\nimport com.hjq.permissions.core"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/fragment/impl/androidx/PermissionAndroidXFragmentByStartActivity.java",
    "chars": 866,
    "preview": "package com.hjq.permissions.fragment.impl.androidx;\n\nimport android.content.Intent;\nimport androidx.annotation.NonNull;\n"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manager/ActivityOrientationManager.java",
    "chars": 4825,
    "preview": "package com.hjq.permissions.manager;\n\nimport android.app.Activity;\nimport android.content.pm.ActivityInfo;\nimport androi"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manager/AlreadyRequestPermissionsManager.java",
    "chars": 1549,
    "preview": "package com.hjq.permissions.manager;\n\nimport androidx.annotation.Nullable;\nimport com.hjq.permissions.permission.base.IP"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manager/PermissionRequestCodeManager.java",
    "chars": 2872,
    "preview": "package com.hjq.permissions.manager;\n\nimport androidx.annotation.IntRange;\nimport com.hjq.permissions.XXPermissions;\nimp"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/AndroidManifestInfo.java",
    "chars": 1585,
    "preview": "package com.hjq.permissions.manifest;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport c"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/AndroidManifestParser.java",
    "chars": 17775,
    "preview": "package com.hjq.permissions.manifest;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport an"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/ActivityManifestInfo.java",
    "chars": 659,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimp"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/ApplicationManifestInfo.java",
    "chars": 577,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimp"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/BroadcastReceiverManifestInfo.java",
    "chars": 685,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimp"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/IntentFilterManifestInfo.java",
    "chars": 507,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport java.util.ArrayList;\nimport java."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/MetaDataManifestInfo.java",
    "chars": 495,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/*"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/PermissionManifestInfo.java",
    "chars": 1134,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport android.content.pm.PackageInfo;\nimport com.hjq.permissions.tools.Perm"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/ServiceManifestInfo.java",
    "chars": 655,
    "preview": "package com.hjq.permissions.manifest.node;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimp"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/manifest/node/UsesSdkManifestInfo.java",
    "chars": 280,
    "preview": "package com.hjq.permissions.manifest.node;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/PermissionChannel.java",
    "chars": 444,
    "preview": "package com.hjq.permissions.permission;\n\nimport android.content.Intent;\n\n/**\n *    author : Android 轮子哥\n *    github : h"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/PermissionGroups.java",
    "chars": 9017,
    "preview": "package com.hjq.permissions.permission;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity/XX"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/PermissionLists.java",
    "chars": 84706,
    "preview": "package com.hjq.permissions.permission;\n\nimport android.Manifest;\nimport android.accessibilityservice.AccessibilityServi"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/PermissionNames.java",
    "chars": 32072,
    "preview": "package com.hjq.permissions.permission;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity/XX"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/PermissionPageType.java",
    "chars": 315,
    "preview": "package com.hjq.permissions.permission;\n\n/**\n *    author : Android 轮子哥\n *    github : https://github.com/getActivity/XX"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/base/BasePermission.java",
    "chars": 16490,
    "preview": "package com.hjq.permissions.permission.base;\n\nimport android.app.Activity;\nimport android.app.AppOpsManager;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/base/IPermission.java",
    "chars": 4067,
    "preview": "package com.hjq.permissions.permission.base;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androi"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/common/DangerousPermission.java",
    "chars": 6337,
    "preview": "package com.hjq.permissions.permission.common;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/common/SpecialPermission.java",
    "chars": 2110,
    "preview": "package com.hjq.permissions.permission.common;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/AccessBackgroundLocationPermission.java",
    "chars": 11080,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/AccessMediaLocationPermission.java",
    "chars": 9994,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothAdvertisePermission.java",
    "chars": 3520,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothConnectPermission.java",
    "chars": 3494,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/BluetoothScanPermission.java",
    "chars": 6333,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/BodySensorsBackgroundPermission.java",
    "chars": 7469,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/BodySensorsPermission.java",
    "chars": 2559,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/GetInstalledAppsPermission.java",
    "chars": 16123,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.Manifest.permission;\nimport android.app.Activity;\nimpo"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/HealthDataBasePermission.java",
    "chars": 6919,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/NearbyWifiDevicesPermission.java",
    "chars": 5838,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/PostNotificationsPermission.java",
    "chars": 2969,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadExternalStoragePermission.java",
    "chars": 8483,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthDataHistoryPermission.java",
    "chars": 2929,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthDataInBackgroundPermission.java",
    "chars": 5253,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadHealthRatePermission.java",
    "chars": 2928,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaAudioPermission.java",
    "chars": 4278,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaImagesPermission.java",
    "chars": 5139,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaVideoPermission.java",
    "chars": 5129,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadMediaVisualUserSelectedPermission.java",
    "chars": 3479,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/ReadPhoneNumbersPermission.java",
    "chars": 3749,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/StandardDangerousPermission.java",
    "chars": 2410,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/StandardFitnessAndWellnessDataPermission.java",
    "chars": 1877,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/StandardHealthRecordsPermission.java",
    "chars": 1793,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport andr"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/dangerous/WriteExternalStoragePermission.java",
    "chars": 9228,
    "preview": "package com.hjq.permissions.permission.dangerous;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/AccessNotificationPolicyPermission.java",
    "chars": 4728,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.NotificationManager;\nimport android.content.Context;"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/BindAccessibilityServicePermission.java",
    "chars": 9839,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.accessibilityservice.AccessibilityService;\nimport androi"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/BindDeviceAdminPermission.java",
    "chars": 9284,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.app.admin.DeviceAdminReceiv"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/BindNotificationListenerServicePermission.java",
    "chars": 10651,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.app.NotificationManager;\nim"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/BindVpnServicePermission.java",
    "chars": 6568,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport and"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/ManageExternalStoragePermission.java",
    "chars": 7902,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport and"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/ManageMediaPermission.java",
    "chars": 2699,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/NotificationServicePermission.java",
    "chars": 7567,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.app.NotificationChannel;\nim"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/PackageUsageStatsPermission.java",
    "chars": 2996,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.AppOpsManager;\nimport android.content.Context;\nimpor"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/PictureInPicturePermission.java",
    "chars": 4859,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.app.AppOpsManager;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/RequestIgnoreBatteryOptimizationsPermission.java",
    "chars": 9939,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/RequestInstallPackagesPermission.java",
    "chars": 3165,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/ScheduleExactAlarmPermission.java",
    "chars": 5382,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.Manifest.permission;\nimport android.app.Activity;\nimport"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/SystemAlertWindowPermission.java",
    "chars": 11420,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/UseFullScreenIntentPermission.java",
    "chars": 6208,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.app.Activity;\nimport android.app.NotificationManager;\nim"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/permission/special/WriteSettingsPermission.java",
    "chars": 3044,
    "preview": "package com.hjq.permissions.permission.special;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport a"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/IStartActivityDelegate.java",
    "chars": 519,
    "preview": "package com.hjq.permissions.start;\n\nimport android.content.Intent;\nimport androidx.annotation.IntRange;\n\n/**\n *    autho"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/StartActivityAgent.java",
    "chars": 7247,
    "preview": "package com.hjq.permissions.start;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Con"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByActivity.java",
    "chars": 916,
    "preview": "package com.hjq.permissions.start;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport androidx.annotati"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByContext.java",
    "chars": 1677,
    "preview": "package com.hjq.permissions.start;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByFragmentAndroid.java",
    "chars": 963,
    "preview": "package com.hjq.permissions.start;\n\nimport android.app.Fragment;\nimport android.content.Intent;\nimport androidx.annotati"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/start/StartActivityDelegateByFragmentAndroidX.java",
    "chars": 952,
    "preview": "package com.hjq.permissions.start;\n\nimport android.content.Intent;\nimport androidx.annotation.IntRange;\nimport androidx."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionApi.java",
    "chars": 8147,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content."
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionChecker.java",
    "chars": 6745,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.os.Parcelab"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionSettingPage.java",
    "chars": 9859,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.conten"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionTaskHandler.java",
    "chars": 1143,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.SystemClock;\n"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionUtils.java",
    "chars": 9498,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.content.Con"
  },
  {
    "path": "library/src/main/java/com/hjq/permissions/tools/PermissionVersion.java",
    "chars": 5339,
    "preview": "package com.hjq.permissions.tools;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport andro"
  },
  {
    "path": "settings.gradle",
    "chars": 1609,
    "preview": "pluginManagement {\n    repositories {\n        gradlePluginPortal()\n        // 阿里云云效仓库(Gradle 插件):https://maven.aliyun.co"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the getActivity/XXPermissions GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 157 files (942.7 KB), approximately 234.1k tokens, and a symbol index with 1092 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!