[
  {
    "path": ".gitignore",
    "content": "*.iml\n/.idea/\n/build/\n.gradle\n/local.properties\n.DS_Store\n/captures\n.externalNativeBuild"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to AndPermission\nFirst off, thanks for taking the time to contribute.  \n\nThe following is a set of guidelines for contributing to AndPermission. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.\n\n1. All your actions in AndPermission should be in English, not in other languages.\n2. Please keep AndPermission the existing code style, not according to your habits.\n3. Just modify the code you are sure need to be optimized, not all the different code from your ideas.\n4. Before launching a pull request, you should test your commit code adequately.\n5. Please commit new code to the [dev](https://github.com/yanzhenjie/AndPermission/tree/dev) branch instead of the master branch."
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Zhenjie Yan\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.md",
    "content": "﻿# AndPermission\n1. Request for runtime permissions.  \n2. Share private files.  \n3. Request to install unknown source apk.  \n  `android.permission.REQUEST_INSTALL_PACKAGES`\n4. Request to draw at the top of other apps.  \n  `android.permission.SYSTEM_ALERT_WINDOW`\n5. Request to show notifications.  \n6. Request to access notifications.  \n  `android.permission.BIND_NOTIFICATION_LISTENER_SERVICE`\n7. Request to modify system setting.  \n  `android.permission.WRITE_SETTINGS`\n\n```java\nAndPermission.with(this)\n  .runtime()\n  .permission(Permission.Group.STORAGE)\n  .onGranted(permissions -> {\n    // Storage permission are allowed.\n  })\n  .onDenied(permissions -> {\n    // Storage permission are not allowed.\n  })\n  .start();\n```\n\nFor documentation and additional information see [the website](https://yanzhenjie.com/AndPermission).\n\n## Download\nIt only supports androidx, add dependencies in your gradle:\n\n```groovy\nimplementation 'com.yanzhenjie:permission:2.0.3'\n```\n\nAndPermission requires at minimum Android 4.0(Api level 14) .\n\n## Contributing\nBefore submitting pull requests, contributors must abide by the [agreement](CONTRIBUTING.md) .\n\n## License\n```text\nCopyright 2019 Zhenjie Yan\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```"
  },
  {
    "path": "build.gradle",
    "content": "apply from: \"config.gradle\"\n\nbuildscript {\n    repositories {\n        google()\n        jcenter {url 'https://maven.aliyun.com/repository/jcenter'}\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.5.1'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter {url 'https://maven.aliyun.com/repository/jcenter'}\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "config.gradle",
    "content": "ext {\n    plugins = [application: 'com.android.application',\n               library    : 'com.android.library',\n               maven      : 'com.github.dcendents.android-maven',\n               bintray    : 'com.jfrog.bintray']\n\n    android = [applicationId    : \"com.yanzhenjie.permission.sample\",\n               compileSdkVersion: 29,\n               buildToolsVersion: \"29.0.2\",\n               minSdkVersion    : 14,\n               targetSdkVersion : 29,\n               versionCode      : 108,\n               versionName      : \"2.0.3\"]\n\n    bintray = [version       : \"2.0.3\",\n\n               siteUrl       : 'https://github.com/yanzhenjie/AndPermission',\n               gitUrl        : 'https://github.com/yanzhenjie/AndPermission.git',\n\n               group         : \"com.yanzhenjie\",\n\n               packaging     : 'aar',\n               name          : 'Permission',\n               description   : 'Permission manager for Android',\n\n               licenseName   : 'The Apache Software License, Version 2.0',\n               licenseUrl    : 'http://www.apache.org/licenses/LICENSE-2.0.txt',\n\n               developerId   : 'yanzhenjie',\n               developerName : 'yanzhenjie',\n               developerEmail: 'im.yanzhenjie@gmail.com',\n\n               binrayLibrary : \"permission\",\n               bintrayRepo   : \"maven\",\n               bintrayUser   : 'yolanda',\n               bintrayLicense: \"Apache-2.0\"]\n\n    dependencies = [\n        fragment: 'androidx.appcompat:appcompat:1.1.0'\n    ]\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip"
  },
  {
    "path": "gradle.properties",
    "content": "android.useAndroidX=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "permission/.gitignore",
    "content": "/build"
  },
  {
    "path": "permission/build.gradle",
    "content": "apply plugin: rootProject.ext.plugins.library\n\nandroid {\n    compileSdkVersion rootProject.ext.android.compileSdkVersion\n    buildToolsVersion rootProject.ext.android.buildToolsVersion\n\n    defaultConfig {\n        minSdkVersion rootProject.ext.android.minSdkVersion\n        targetSdkVersion rootProject.ext.android.targetSdkVersion\n    }\n\n    resourcePrefix 'permission'\n}\n\ndependencies {\n    api rootProject.ext.dependencies.fragment\n}"
  },
  {
    "path": "permission/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.yanzhenjie.permission\">\n\n    <permission\n        android:name=\"${applicationId}.andpermission.bridge\"\n        android:permissionGroup=\"${applicationId}.andpermission\"\n        android:protectionLevel=\"signature\" />\n\n    <uses-permission android:name=\"${applicationId}.andpermission.bridge\" />\n\n    <application>\n        <service\n            android:name=\".bridge.BridgeService\"\n            android:exported=\"false\"\n            android:permission=\"${applicationId}.andpermission.bridge\"\n            android:process=\":permission\">\n            <intent-filter>\n                <action android:name=\"${applicationId}.andpermission.bridge\" />\n            </intent-filter>\n        </service>\n\n        <activity\n            android:name=\".bridge.BridgeActivity\"\n            android:configChanges=\"orientation\"\n            android:exported=\"false\"\n            android:permission=\"${applicationId}.andpermission.bridge\"\n            android:process=\":permission\"\n            android:theme=\"@style/Permission.Theme.Activity.Transparent\" />\n\n        <provider\n            android:name=\".FileProvider\"\n            android:authorities=\"${applicationId}.file.path.share\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/permission_file_paths\" />\n        </provider>\n    </application>\n\n</manifest>"
  },
  {
    "path": "permission/src/main/aidl/com/yanzhenjie/permission/bridge/IBridge.aidl",
    "content": "package com.yanzhenjie.permission.bridge;\n\ninterface IBridge {\n    /**\n     * Request for permissions.\n     */\n    void requestAppDetails(in String suffix);\n\n    /**\n     * Request for permissions.\n     */\n    void requestPermission(in String suffix, in String[] permissions);\n\n    /**\n     * Request for package install.\n     */\n    void requestInstall(in String suffix);\n\n   /**\n    * Request for overlay.\n    */\n    void requestOverlay(in String suffix);\n\n   /**\n    * Request for alert window.\n    */\n    void requestAlertWindow(in String suffix);\n\n   /**\n    * Request for notify.\n    */\n    void requestNotify(in String suffix);\n\n   /**\n    * Request for notification listener.\n    */\n    void requestNotificationListener(in String suffix);\n\n   /**\n    * Request for write system setting.\n    */\n    void requestWriteSetting(in String suffix);\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/Action.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\n/**\n * Created by Zhenjie Yan on 2018/1/1.\n */\npublic interface Action<T> {\n\n    /**\n     * An action.\n     *\n     * @param data the data.\n     */\n    void onAction(T data);\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/AndPermission.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport androidx.fragment.app.Fragment;\n\nimport com.yanzhenjie.permission.checker.DoubleChecker;\nimport com.yanzhenjie.permission.checker.PermissionChecker;\nimport com.yanzhenjie.permission.option.Option;\nimport com.yanzhenjie.permission.source.ActivitySource;\nimport com.yanzhenjie.permission.source.ContextSource;\nimport com.yanzhenjie.permission.source.FragmentSource;\nimport com.yanzhenjie.permission.source.Source;\nimport com.yanzhenjie.permission.source.XFragmentSource;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2016/9/9.\n */\npublic class AndPermission {\n\n    private static final String ACTION_BRIDGE_SUFFIX = \".andpermission.bridge\";\n\n    public static String bridgeAction(Context context, String suffix) {\n        return context.getPackageName() + ACTION_BRIDGE_SUFFIX + (TextUtils.isEmpty(suffix) ? \"\" : \".\" + suffix);\n    }\n\n    /**\n     * With context.\n     *\n     * @param context {@link Context}.\n     * @return {@link Option}.\n     */\n    public static Option with(Context context) {\n        return new Boot(getContextSource(context));\n    }\n\n    /**\n     * With {@link Fragment}.\n     *\n     * @param fragment {@link Fragment}.\n     * @return {@link Option}.\n     */\n    public static Option with(Fragment fragment) {\n        return new Boot(new XFragmentSource(fragment));\n    }\n\n    /**\n     * With {@link android.app.Fragment}.\n     *\n     * @param fragment {@link android.app.Fragment}.\n     * @return {@link Option}.\n     */\n    public static Option with(android.app.Fragment fragment) {\n        return new Boot(new FragmentSource(fragment));\n    }\n\n    /**\n     * With activity.\n     *\n     * @param activity {@link Activity}.\n     * @return {@link Option}.\n     */\n    public static Option with(Activity activity) {\n        return new Boot(new ActivitySource(activity));\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param context           {@link Context}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Context context, List<String> deniedPermissions) {\n        return hasAlwaysDeniedPermission(getContextSource(context), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param fragment          {@link Fragment}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Fragment fragment, List<String> deniedPermissions) {\n        return hasAlwaysDeniedPermission(new XFragmentSource(fragment), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param fragment          {@link android.app.Fragment}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(android.app.Fragment fragment, List<String> deniedPermissions) {\n        return hasAlwaysDeniedPermission(new FragmentSource(fragment), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param activity          {@link Activity}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Activity activity, List<String> deniedPermissions) {\n        return hasAlwaysDeniedPermission(new ActivitySource(activity), deniedPermissions);\n    }\n\n    /**\n     * Has always been denied permission.\n     */\n    private static boolean hasAlwaysDeniedPermission(Source source, List<String> deniedPermissions) {\n        for (String permission : deniedPermissions) {\n            if (!source.isShowRationalePermission(permission)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param context           {@link Context}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Context context, String... deniedPermissions) {\n        return hasAlwaysDeniedPermission(getContextSource(context), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param fragment          {@link Fragment}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Fragment fragment, String... deniedPermissions) {\n        return hasAlwaysDeniedPermission(new XFragmentSource(fragment), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param fragment          {@link android.app.Fragment}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(android.app.Fragment fragment, String... deniedPermissions) {\n        return hasAlwaysDeniedPermission(new FragmentSource(fragment), deniedPermissions);\n    }\n\n    /**\n     * Some privileges permanently disabled, may need to set up in the execute.\n     *\n     * @param activity          {@link Activity}.\n     * @param deniedPermissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasAlwaysDeniedPermission(Activity activity, String... deniedPermissions) {\n        return hasAlwaysDeniedPermission(new ActivitySource(activity), deniedPermissions);\n    }\n\n    /**\n     * Has always been denied permission.\n     */\n    private static boolean hasAlwaysDeniedPermission(Source source, String... deniedPermissions) {\n        for (String permission : deniedPermissions) {\n            if (!source.isShowRationalePermission(permission)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Classic permission checker.\n     */\n    private static final PermissionChecker PERMISSION_CHECKER = new DoubleChecker();\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param context     {@link Context}.\n     * @param permissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Context context, String... permissions) {\n        return PERMISSION_CHECKER.hasPermission(context, permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param fragment    {@link Fragment}.\n     * @param permissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Fragment fragment, String... permissions) {\n        return hasPermissions(fragment.getActivity(), permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param fragment    {@link android.app.Fragment}.\n     * @param permissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(android.app.Fragment fragment, String... permissions) {\n        return hasPermissions(fragment.getActivity(), permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param activity    {@link Activity}.\n     * @param permissions one or more permissions.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Activity activity, String... permissions) {\n        return PERMISSION_CHECKER.hasPermission(activity, permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param context     {@link Context}.\n     * @param permissions one or more permission groups.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Context context, String[]... permissions) {\n        for (String[] permission : permissions) {\n            boolean hasPermission = PERMISSION_CHECKER.hasPermission(context, permission);\n            if (!hasPermission) return false;\n        }\n        return true;\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param fragment    {@link Fragment}.\n     * @param permissions one or more permission groups.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Fragment fragment, String[]... permissions) {\n        return hasPermissions(fragment.getActivity(), permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param fragment    {@link android.app.Fragment}.\n     * @param permissions one or more permission groups.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(android.app.Fragment fragment, String[]... permissions) {\n        return hasPermissions(fragment.getActivity(), permissions);\n    }\n\n    /**\n     * Judgment already has the target permission.\n     *\n     * @param activity    {@link Activity}.\n     * @param permissions one or more permission groups.\n     * @return true, other wise is false.\n     */\n    public static boolean hasPermissions(Activity activity, String[]... permissions) {\n        for (String[] permission : permissions) {\n            boolean hasPermission = PERMISSION_CHECKER.hasPermission(activity, permission);\n            if (!hasPermission) return false;\n        }\n        return true;\n    }\n\n    /**\n     * Get compatible Android 7.0 and lower versions of Uri.\n     *\n     * @param context {@link Context}.\n     * @param file    apk file.\n     * @return uri.\n     */\n    public static Uri getFileUri(Context context, File file) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return FileProvider.getUriForFile(context, context.getPackageName() + \".file.path.share\", file);\n        }\n        return Uri.fromFile(file);\n    }\n\n    /**\n     * Get compatible Android 7.0 and lower versions of Uri.\n     *\n     * @param fragment {@link Fragment}.\n     * @param file     apk file.\n     * @return uri.\n     */\n    public static Uri getFileUri(Fragment fragment, File file) {\n        return getFileUri(fragment.getContext(), file);\n    }\n\n    /**\n     * Get compatible Android 7.0 and lower versions of Uri.\n     *\n     * @param fragment {@link android.app.Fragment}.\n     * @param file     apk file.\n     * @return uri.\n     */\n    public static Uri getFileUri(android.app.Fragment fragment, File file) {\n        return getFileUri(fragment.getActivity(), file);\n    }\n\n    private static Source getContextSource(Context context) {\n        if (context instanceof Activity) {\n            return new ActivitySource((Activity) context);\n        } else if (context instanceof ContextWrapper) {\n            return getContextSource(((ContextWrapper) context).getBaseContext());\n        }\n        return new ContextSource(context);\n    }\n\n    private AndPermission() {\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/Boot.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\nimport android.os.Build;\n\nimport com.yanzhenjie.permission.install.InstallRequest;\nimport com.yanzhenjie.permission.install.NRequestFactory;\nimport com.yanzhenjie.permission.install.ORequestFactory;\nimport com.yanzhenjie.permission.notify.Notify;\nimport com.yanzhenjie.permission.notify.option.NotifyOption;\nimport com.yanzhenjie.permission.option.Option;\nimport com.yanzhenjie.permission.overlay.LRequestFactory;\nimport com.yanzhenjie.permission.overlay.MRequestFactory;\nimport com.yanzhenjie.permission.overlay.OverlayRequest;\nimport com.yanzhenjie.permission.runtime.Runtime;\nimport com.yanzhenjie.permission.runtime.option.RuntimeOption;\nimport com.yanzhenjie.permission.setting.Setting;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class Boot implements Option {\n\n    private static final InstallRequestFactory INSTALL_REQUEST_FACTORY;\n    private static final OverlayRequestFactory OVERLAY_REQUEST_FACTORY;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            INSTALL_REQUEST_FACTORY = new ORequestFactory();\n        } else {\n            INSTALL_REQUEST_FACTORY = new NRequestFactory();\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            OVERLAY_REQUEST_FACTORY = new MRequestFactory();\n        } else {\n            OVERLAY_REQUEST_FACTORY = new LRequestFactory();\n        }\n    }\n\n    public interface InstallRequestFactory {\n\n        /**\n         * Create apk installer request.\n         */\n        InstallRequest create(Source source);\n    }\n\n    public interface OverlayRequestFactory {\n\n        /**\n         * Create overlay request.\n         */\n        OverlayRequest create(Source source);\n    }\n\n    private Source mSource;\n\n    public Boot(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public RuntimeOption runtime() {\n        return new Runtime(mSource);\n    }\n\n    @Override\n    public InstallRequest install() {\n        return INSTALL_REQUEST_FACTORY.create(mSource);\n    }\n\n    @Override\n    public OverlayRequest overlay() {\n        return OVERLAY_REQUEST_FACTORY.create(mSource);\n    }\n\n    @Override\n    public NotifyOption notification() {\n        return new Notify(mSource);\n    }\n\n    @Override\n    public Setting setting() {\n        return new Setting(mSource);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/FileProvider.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.res.XmlResourceParser;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.ParcelFileDescriptor;\nimport android.provider.OpenableColumns;\nimport android.text.TextUtils;\nimport android.webkit.MimeTypeMap;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\n\n/**\n * <p>Copied from the support library v27.1.1.</p>\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class FileProvider extends ContentProvider {\n\n    private static final String[] COLUMNS = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};\n\n    private static final String META_DATA_FILE_PROVIDER_PATHS = \"android.support.FILE_PROVIDER_PATHS\";\n\n    private static final String TAG_ROOT_PATH = \"root-path\";\n    private static final String TAG_FILES_PATH = \"files-path\";\n    private static final String TAG_CACHE_PATH = \"cache-path\";\n    private static final String TAG_EXTERNAL = \"external-path\";\n    private static final String TAG_EXTERNAL_FILES = \"external-files-path\";\n    private static final String TAG_EXTERNAL_CACHE = \"external-cache-path\";\n    private static final String TAG_EXTERNAL_MEDIA = \"external-media-path\";\n\n    private static final String ATTR_NAME = \"name\";\n    private static final String ATTR_PATH = \"path\";\n\n    private static final File DEVICE_ROOT = new File(\"/\");\n\n    private static final HashMap<String, PathStrategy> sCache = new HashMap<>();\n\n    private PathStrategy mStrategy;\n\n    @Override\n    public boolean onCreate() {\n        return true;\n    }\n\n    @Override\n    public void attachInfo(Context context, ProviderInfo info) {\n        super.attachInfo(context, info);\n        if (info.exported) {\n            throw new SecurityException(\"Provider must not be exported\");\n        }\n        if (!info.grantUriPermissions) {\n            throw new SecurityException(\"Provider must grant uri permissions\");\n        }\n\n        mStrategy = getPathStrategy(context, info.authority);\n    }\n\n    public static Uri getUriForFile(Context context, String authority, File file) {\n        final PathStrategy strategy = getPathStrategy(context, authority);\n        return strategy.getUriForFile(file);\n    }\n\n    @Override\n    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {\n        final File file = mStrategy.getFileForUri(uri);\n        if (projection == null) {\n            projection = COLUMNS;\n        }\n\n        String[] cols = new String[projection.length];\n        Object[] values = new Object[projection.length];\n        int i = 0;\n        for (String col : projection) {\n            if (OpenableColumns.DISPLAY_NAME.equals(col)) {\n                cols[i] = OpenableColumns.DISPLAY_NAME;\n                values[i++] = file.getName();\n            } else if (OpenableColumns.SIZE.equals(col)) {\n                cols[i] = OpenableColumns.SIZE;\n                values[i++] = file.length();\n            }\n        }\n\n        cols = copyOf(cols, i);\n        values = copyOf(values, i);\n\n        final MatrixCursor cursor = new MatrixCursor(cols, 1);\n        cursor.addRow(values);\n        return cursor;\n    }\n\n    @Override\n    public String getType(Uri uri) {\n        final File file = mStrategy.getFileForUri(uri);\n\n        final int lastDot = file.getName().lastIndexOf('.');\n        if (lastDot >= 0) {\n            final String extension = file.getName().substring(lastDot + 1);\n            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n            if (mime != null) {\n                return mime;\n            }\n        }\n        return \"application/octet-stream\";\n    }\n\n    @Override\n    public Uri insert(Uri uri, ContentValues values) {\n        throw new UnsupportedOperationException(\"No external inserts\");\n    }\n\n    @Override\n    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        throw new UnsupportedOperationException(\"No external updates\");\n    }\n\n    @Override\n    public int delete(Uri uri, String selection, String[] selectionArgs) {\n        final File file = mStrategy.getFileForUri(uri);\n        return file.delete() ? 1 : 0;\n    }\n\n    @Override\n    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {\n        final File file = mStrategy.getFileForUri(uri);\n        final int fileMode = modeToMode(mode);\n        return ParcelFileDescriptor.open(file, fileMode);\n    }\n\n    private static PathStrategy getPathStrategy(Context context, String authority) {\n        PathStrategy strategy;\n        synchronized (sCache) {\n            strategy = sCache.get(authority);\n            if (strategy == null) {\n                try {\n                    strategy = parsePathStrategy(context, authority);\n                } catch (IOException e) {\n                    throw new IllegalArgumentException(\n                        \"Failed to parse \" + META_DATA_FILE_PROVIDER_PATHS + \" meta-data\", e);\n                } catch (XmlPullParserException e) {\n                    throw new IllegalArgumentException(\n                        \"Failed to parse \" + META_DATA_FILE_PROVIDER_PATHS + \" meta-data\", e);\n                }\n                sCache.put(authority, strategy);\n            }\n        }\n        return strategy;\n    }\n\n    private static PathStrategy parsePathStrategy(Context context, String authority)\n        throws IOException, XmlPullParserException {\n        final SimplePathStrategy strategy = new SimplePathStrategy(authority);\n        final ProviderInfo info = context.getPackageManager()\n            .resolveContentProvider(authority, PackageManager.GET_META_DATA);\n        final XmlResourceParser in = info.loadXmlMetaData(context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);\n        if (in == null) {\n            throw new IllegalArgumentException(\"Missing \" + META_DATA_FILE_PROVIDER_PATHS + \" meta-data\");\n        }\n\n        int type;\n        while ((type = in.next()) != END_DOCUMENT) {\n            if (type == START_TAG) {\n                final String tag = in.getName();\n\n                final String name = in.getAttributeValue(null, ATTR_NAME);\n                String path = in.getAttributeValue(null, ATTR_PATH);\n\n                File target = null;\n                if (TAG_ROOT_PATH.equals(tag)) {\n                    target = DEVICE_ROOT;\n                } else if (TAG_FILES_PATH.equals(tag)) {\n                    target = context.getFilesDir();\n                } else if (TAG_CACHE_PATH.equals(tag)) {\n                    target = context.getCacheDir();\n                } else if (TAG_EXTERNAL.equals(tag)) {\n                    target = Environment.getExternalStorageDirectory();\n                } else if (TAG_EXTERNAL_FILES.equals(tag)) {\n                    File[] externalFilesDirs = getExternalFilesDirs(context, null);\n                    if (externalFilesDirs.length > 0) {\n                        target = externalFilesDirs[0];\n                    }\n                } else if (TAG_EXTERNAL_CACHE.equals(tag)) {\n                    File[] externalCacheDirs = getExternalCacheDirs(context);\n                    if (externalCacheDirs.length > 0) {\n                        target = externalCacheDirs[0];\n                    }\n                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && TAG_EXTERNAL_MEDIA.equals(tag)) {\n                    File[] externalMediaDirs = context.getExternalMediaDirs();\n                    if (externalMediaDirs.length > 0) {\n                        target = externalMediaDirs[0];\n                    }\n                }\n\n                if (target != null) {\n                    strategy.addRoot(name, buildPath(target, path));\n                }\n            }\n        }\n\n        return strategy;\n    }\n\n    interface PathStrategy {\n\n        Uri getUriForFile(File file);\n\n        File getFileForUri(Uri uri);\n    }\n\n    static class SimplePathStrategy implements PathStrategy {\n\n        private final String mAuthority;\n        private final HashMap<String, File> mRoots = new HashMap<String, File>();\n\n        SimplePathStrategy(String authority) {\n            mAuthority = authority;\n        }\n\n        void addRoot(String name, File root) {\n            if (TextUtils.isEmpty(name)) {\n                throw new IllegalArgumentException(\"Name must not be empty\");\n            }\n\n            try {\n                root = root.getCanonicalFile();\n            } catch (IOException e) {\n                throw new IllegalArgumentException(\"Failed to resolve canonical path for \" + root, e);\n            }\n\n            mRoots.put(name, root);\n        }\n\n        @Override\n        public Uri getUriForFile(File file) {\n            String path;\n            try {\n                path = file.getCanonicalPath();\n            } catch (IOException e) {\n                throw new IllegalArgumentException(\"Failed to resolve canonical path for \" + file);\n            }\n\n            Map.Entry<String, File> mostSpecific = null;\n            for (Map.Entry<String, File> root : mRoots.entrySet()) {\n                final String rootPath = root.getValue().getPath();\n                boolean invalidMost = mostSpecific == null ||\n                    rootPath.length() > mostSpecific.getValue().getPath().length();\n                if (path.startsWith(rootPath) && invalidMost) {\n                    mostSpecific = root;\n                }\n            }\n\n            if (mostSpecific == null) {\n                throw new IllegalArgumentException(\"Failed to find configured root that contains \" + path);\n            }\n\n            final String rootPath = mostSpecific.getValue().getPath();\n            if (rootPath.endsWith(\"/\")) {\n                path = path.substring(rootPath.length());\n            } else {\n                path = path.substring(rootPath.length() + 1);\n            }\n\n            path = Uri.encode(mostSpecific.getKey()) + '/' + Uri.encode(path, \"/\");\n            return new Uri.Builder().scheme(\"content\").authority(mAuthority).encodedPath(path).build();\n        }\n\n        @Override\n        public File getFileForUri(Uri uri) {\n            String path = uri.getEncodedPath();\n\n            final int splitIndex = path.indexOf('/', 1);\n            final String tag = Uri.decode(path.substring(1, splitIndex));\n            path = Uri.decode(path.substring(splitIndex + 1));\n\n            final File root = mRoots.get(tag);\n            if (root == null) {\n                throw new IllegalArgumentException(\"Unable to find configured root for \" + uri);\n            }\n\n            File file = new File(root, path);\n            try {\n                file = file.getCanonicalFile();\n            } catch (IOException e) {\n                throw new IllegalArgumentException(\"Failed to resolve canonical path for \" + file);\n            }\n\n            if (!file.getPath().startsWith(root.getPath())) {\n                throw new SecurityException(\"Resolved path jumped beyond configured root\");\n            }\n            return file;\n        }\n    }\n\n    private static int modeToMode(String mode) {\n        int modeBits;\n        if (\"r\".equals(mode)) {\n            modeBits = ParcelFileDescriptor.MODE_READ_ONLY;\n        } else if (\"w\".equals(mode) || \"wt\".equals(mode)) {\n            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE |\n                ParcelFileDescriptor.MODE_TRUNCATE;\n        } else if (\"wa\".equals(mode)) {\n            modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE |\n                ParcelFileDescriptor.MODE_APPEND;\n        } else if (\"rw\".equals(mode)) {\n            modeBits = ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE;\n        } else if (\"rwt\".equals(mode)) {\n            modeBits = ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE |\n                ParcelFileDescriptor.MODE_TRUNCATE;\n        } else {\n            throw new IllegalArgumentException(\"Invalid mode: \" + mode);\n        }\n        return modeBits;\n    }\n\n    private static File buildPath(File base, String... segments) {\n        File cur = base;\n        for (String segment : segments) {\n            if (segment != null) {\n                cur = new File(cur, segment);\n            }\n        }\n        return cur;\n    }\n\n    private static String[] copyOf(String[] original, int newLength) {\n        final String[] result = new String[newLength];\n        System.arraycopy(original, 0, result, 0, newLength);\n        return result;\n    }\n\n    private static Object[] copyOf(Object[] original, int newLength) {\n        final Object[] result = new Object[newLength];\n        System.arraycopy(original, 0, result, 0, newLength);\n        return result;\n    }\n\n    private static File[] getExternalFilesDirs(Context context, String type) {\n        if (Build.VERSION.SDK_INT >= 19) {\n            return context.getExternalFilesDirs(type);\n        } else {\n            return new File[] {context.getExternalFilesDir(type)};\n        }\n    }\n\n    public static File[] getExternalCacheDirs(Context context) {\n        if (Build.VERSION.SDK_INT >= 19) {\n            return context.getExternalCacheDirs();\n        } else {\n            return new File[] {context.getExternalCacheDir()};\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/Rationale.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\nimport android.content.Context;\n\n/**\n * Created by Zhenjie Yan on 2016/9/10.\n */\npublic interface Rationale<T> {\n\n    /**\n     * Show rationale to user.\n     *\n     * @param context context.\n     * @param data the data.\n     * @param executor executor.\n     */\n    void showRationale(Context context, T data, RequestExecutor executor);\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/RequestExecutor.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission;\n\n/**\n * <p>Request executor.</p>\n * Created by Zhenjie Yan on 2016/9/10.\n */\npublic interface RequestExecutor {\n\n    /**\n     * Go request permission.\n     */\n    void execute();\n\n    /**\n     * Cancel the operation.\n     */\n    void cancel();\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/BridgeActivity.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.Settings;\nimport android.view.KeyEvent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.yanzhenjie.permission.overlay.setting.LSettingPage;\nimport com.yanzhenjie.permission.overlay.setting.MSettingPage;\nimport com.yanzhenjie.permission.source.ActivitySource;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * <p>\n * Request permission.\n * </p>\n * Created by Zhenjie Yan on 2017/4/27.\n */\npublic final class BridgeActivity extends Activity {\n\n    private static final String KEY_TYPE = \"KEY_TYPE\";\n    private static final String KEY_PERMISSIONS = \"KEY_PERMISSIONS\";\n    private static final String KEY_ACTION_SUFFIX = \"KEY_ACTION_SUFFIX\";\n\n    /**\n     * Request for permissions.\n     */\n    static void requestAppDetails(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_APP_DETAILS);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for permissions.\n     */\n    static void requestPermission(Source source, String suffix, String[] permissions) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_PERMISSION);\n        intent.putExtra(KEY_PERMISSIONS, permissions);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for package install.\n     */\n    static void requestInstall(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_INSTALL);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for overlay.\n     */\n    static void requestOverlay(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_OVERLAY);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for alert window.\n     */\n    static void requestAlertWindow(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_ALERT_WINDOW);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for notify.\n     */\n    static void requestNotify(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_NOTIFY);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for notification listener.\n     */\n    static void requestNotificationListener(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_NOTIFY_LISTENER);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    /**\n     * Request for write system setting.\n     */\n    static void requestWriteSetting(Source source, String suffix) {\n        Intent intent = new Intent(source.getContext(), BridgeActivity.class);\n        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_WRITE_SETTING);\n        intent.putExtra(KEY_ACTION_SUFFIX, suffix);\n        source.startActivity(intent);\n    }\n\n    private String mActionSuffix;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (savedInstanceState != null) return;\n\n        Intent intent = getIntent();\n        int operation = intent.getIntExtra(KEY_TYPE, -1);\n        mActionSuffix = intent.getStringExtra(KEY_ACTION_SUFFIX);\n        switch (operation) {\n            case BridgeRequest.TYPE_APP_DETAILS: {\n                Intent appDetailsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\n                appDetailsIntent.setData(Uri.fromParts(\"package\", getPackageName(), null));\n                startActivityForResult(appDetailsIntent, BridgeRequest.TYPE_APP_DETAILS);\n                break;\n            }\n            case BridgeRequest.TYPE_PERMISSION: {\n                String[] permissions = intent.getStringArrayExtra(KEY_PERMISSIONS);\n                requestPermissions(permissions, BridgeRequest.TYPE_PERMISSION);\n                break;\n            }\n            case BridgeRequest.TYPE_INSTALL: {\n                Intent manageIntent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);\n                manageIntent.setData(Uri.fromParts(\"package\", getPackageName(), null));\n                startActivityForResult(manageIntent, BridgeRequest.TYPE_INSTALL);\n                break;\n            }\n            case BridgeRequest.TYPE_OVERLAY: {\n                MSettingPage settingPage = new MSettingPage(new ActivitySource(this));\n                settingPage.start(BridgeRequest.TYPE_OVERLAY);\n                break;\n            }\n            case BridgeRequest.TYPE_ALERT_WINDOW: {\n                LSettingPage settingPage = new LSettingPage(new ActivitySource(this));\n                settingPage.start(BridgeRequest.TYPE_ALERT_WINDOW);\n                break;\n            }\n            case BridgeRequest.TYPE_NOTIFY: {\n                Intent settingIntent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);\n                settingIntent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());\n                settingIntent.setData(Uri.fromParts(\"package\", getPackageName(), null));\n                startActivityForResult(settingIntent, BridgeRequest.TYPE_NOTIFY);\n                break;\n            }\n            case BridgeRequest.TYPE_NOTIFY_LISTENER: {\n                Intent settingIntent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);\n                settingIntent.setData(Uri.fromParts(\"package\", getPackageName(), null));\n                startActivityForResult(settingIntent, BridgeRequest.TYPE_NOTIFY_LISTENER);\n                break;\n            }\n            case BridgeRequest.TYPE_WRITE_SETTING: {\n                Intent settingIntent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);\n                settingIntent.setData(Uri.fromParts(\"package\", getPackageName(), null));\n                startActivityForResult(settingIntent, BridgeRequest.TYPE_WRITE_SETTING);\n                break;\n            }\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {\n        Messenger.send(this, mActionSuffix);\n        finish();\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        super.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        Messenger.send(this, mActionSuffix);\n        finish();\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (keyCode == KeyEvent.KEYCODE_BACK) {\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/BridgeRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport com.yanzhenjie.permission.source.Source;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2/13/19.\n */\npublic final class BridgeRequest {\n\n    public static final int TYPE_APP_DETAILS = 1;\n    public static final int TYPE_PERMISSION = 2;\n    public static final int TYPE_INSTALL = 3;\n    public static final int TYPE_OVERLAY = 4;\n    public static final int TYPE_ALERT_WINDOW = 5;\n    public static final int TYPE_NOTIFY = 6;\n    public static final int TYPE_NOTIFY_LISTENER = 7;\n    public static final int TYPE_WRITE_SETTING = 8;\n\n    private final Source mSource;\n\n    private int mType;\n    private Callback mCallback;\n    private List<String> mPermissions;\n\n    public BridgeRequest(Source source) {\n        this.mSource = source;\n    }\n\n    public Source getSource() {\n        return mSource;\n    }\n\n    public int getType() {\n        return mType;\n    }\n\n    public void setType(int type) {\n        mType = type;\n    }\n\n    public Callback getCallback() {\n        return mCallback;\n    }\n\n    public void setCallback(Callback callback) {\n        mCallback = callback;\n    }\n\n    public List<String> getPermissions() {\n        return mPermissions;\n    }\n\n    public void setPermissions(List<String> permissions) {\n        mPermissions = permissions;\n    }\n\n    public interface Callback {\n\n        void onCallback();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/BridgeService.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport androidx.annotation.Nullable;\n\nimport com.yanzhenjie.permission.source.ContextSource;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2019-08-30.\n */\npublic class BridgeService extends Service {\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return mStub.asBinder();\n    }\n\n    private IBridge.Stub mStub = new IBridge.Stub() {\n\n        private Source mSource = new ContextSource(BridgeService.this);\n\n        @Override\n        public void requestAppDetails(String suffix) throws RemoteException {\n            BridgeActivity.requestAppDetails(mSource, suffix);\n        }\n\n        @Override\n        public void requestPermission(String suffix, String[] permissions) throws RemoteException {\n            BridgeActivity.requestPermission(mSource, suffix, permissions);\n        }\n\n        @Override\n        public void requestInstall(String suffix) throws RemoteException {\n            BridgeActivity.requestInstall(mSource, suffix);\n        }\n\n        @Override\n        public void requestOverlay(String suffix) throws RemoteException {\n            BridgeActivity.requestOverlay(mSource, suffix);\n        }\n\n        @Override\n        public void requestAlertWindow(String suffix) throws RemoteException {\n            BridgeActivity.requestAlertWindow(mSource, suffix);\n        }\n\n        @Override\n        public void requestNotify(String suffix) throws RemoteException {\n            BridgeActivity.requestNotify(mSource, suffix);\n        }\n\n        @Override\n        public void requestNotificationListener(String suffix) throws RemoteException {\n            BridgeActivity.requestNotificationListener(mSource, suffix);\n        }\n\n        @Override\n        public void requestWriteSetting(String suffix) throws RemoteException {\n            BridgeActivity.requestWriteSetting(mSource, suffix);\n        }\n    };\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/Messenger.java",
    "content": "/*\n * Copyright © 2018 Zhenjie Yan.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\n\nimport com.yanzhenjie.permission.AndPermission;\n\n/**\n * Created by Zhenjie Yan on 2018/6/9.\n */\nclass Messenger extends BroadcastReceiver {\n\n    public static void send(Context context, String suffix) {\n        Intent broadcast = new Intent(AndPermission.bridgeAction(context, suffix));\n        context.sendBroadcast(broadcast);\n    }\n\n    private final Context mContext;\n    private final Callback mCallback;\n\n    public Messenger(Context context, Callback callback) {\n        this.mContext = context;\n        this.mCallback = callback;\n    }\n\n    public void register(String suffix) {\n        IntentFilter filter = new IntentFilter(AndPermission.bridgeAction(mContext, suffix));\n        mContext.registerReceiver(this, filter);\n    }\n\n    public void unRegister() {\n        mContext.unregisterReceiver(this);\n    }\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        mCallback.onCallback();\n    }\n\n    public interface Callback {\n\n        void onCallback();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/RequestExecutor.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.yanzhenjie.permission.AndPermission;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2/13/19.\n */\nfinal class RequestExecutor extends Thread implements Messenger.Callback {\n\n    private BridgeRequest mRequest;\n    private Messenger mMessenger;\n\n    public RequestExecutor(BridgeRequest request) {\n        this.mRequest = request;\n    }\n\n    @Override\n    public void run() {\n        Context context = mRequest.getSource().getContext();\n\n        mMessenger = new Messenger(context, this);\n        mMessenger.register(getName());\n\n        Intent intent = new Intent();\n        intent.setAction(AndPermission.bridgeAction(context, null));\n        intent.setPackage(context.getPackageName());\n        context.bindService(intent, mConnection, Service.BIND_AUTO_CREATE);\n    }\n\n    private ServiceConnection mConnection = new ServiceConnection() {\n        @Override\n        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {\n            IBridge iBridge = IBridge.Stub.asInterface(iBinder);\n            try {\n                executeCurrent(iBridge);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName componentName) {\n        }\n    };\n\n    private void executeCurrent(IBridge iBridge) throws RemoteException {\n        switch (mRequest.getType()) {\n            case BridgeRequest.TYPE_APP_DETAILS: {\n                iBridge.requestAppDetails(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_PERMISSION: {\n                List<String> permissions = mRequest.getPermissions();\n                String[] array = permissions.toArray(new String[0]);\n                iBridge.requestPermission(getName(), array);\n                break;\n            }\n            case BridgeRequest.TYPE_INSTALL: {\n                iBridge.requestInstall(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_OVERLAY: {\n                iBridge.requestOverlay(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_ALERT_WINDOW: {\n                iBridge.requestAlertWindow(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_NOTIFY: {\n                iBridge.requestNotify(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_NOTIFY_LISTENER: {\n                iBridge.requestNotificationListener(getName());\n                break;\n            }\n            case BridgeRequest.TYPE_WRITE_SETTING: {\n                iBridge.requestWriteSetting(getName());\n                break;\n            }\n        }\n    }\n\n\n    @Override\n    public void onCallback() {\n        synchronized (this) {\n            mMessenger.unRegister();\n            mRequest.getCallback().onCallback();\n            mRequest.getSource().getContext().unbindService(mConnection);\n            mMessenger = null;\n            mRequest = null;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/bridge/RequestManager.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.bridge;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\n\n/**\n * Created by Zhenjie Yan on 2/13/19.\n */\npublic class RequestManager {\n\n    private static RequestManager sManager;\n\n    public static RequestManager get() {\n        if (sManager == null) {\n            synchronized (RequestManager.class) {\n                if (sManager == null) {\n                    sManager = new RequestManager();\n                }\n            }\n        }\n        return sManager;\n    }\n\n    private final Executor mExecutor;\n\n    private RequestManager() {\n        this.mExecutor = Executors.newCachedThreadPool();\n    }\n\n    public void add(BridgeRequest request) {\n        mExecutor.execute(new RequestExecutor(request));\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/CalendarReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.provider.CalendarContract;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass CalendarReadTest implements PermissionTest {\n\n    private ContentResolver mResolver;\n\n    CalendarReadTest(Context context) {\n        mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        String[] projection = new String[] {CalendarContract.Calendars._ID, CalendarContract.Calendars.NAME};\n        Cursor cursor = mResolver.query(CalendarContract.Calendars.CONTENT_URI, projection, null, null, null);\n        if (cursor != null) {\n            try {\n                CursorTest.read(cursor);\n            } finally {\n                cursor.close();\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/CalendarWriteTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.provider.CalendarContract;\n\nimport com.yanzhenjie.permission.util.StringUtils;\n\nimport java.util.TimeZone;\n\n/**\n * Created by Zhenjie Yan on 2018/1/15.\n */\nclass CalendarWriteTest implements PermissionTest {\n\n    private static final String NAME = StringUtils.hexToText(\"5045524D495353494F4E\");\n    private static final String ACCOUNT = StringUtils.hexToText(\"7065726D697373696F6E40676D61696C2E636F6D\");\n\n    private ContentResolver mResolver;\n\n    CalendarWriteTest(Context context) {\n        this.mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        try {\n            TimeZone timeZone = TimeZone.getDefault();\n            ContentValues value = new ContentValues();\n            value.put(CalendarContract.Calendars.NAME, NAME);\n            value.put(CalendarContract.Calendars.ACCOUNT_NAME, ACCOUNT);\n            value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL);\n            value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, NAME);\n            value.put(CalendarContract.Calendars.VISIBLE, 1);\n            value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE);\n            value.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER);\n            value.put(CalendarContract.Calendars.SYNC_EVENTS, 1);\n            value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID());\n            value.put(CalendarContract.Calendars.OWNER_ACCOUNT, NAME);\n            value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0);\n\n            Uri insertUri = CalendarContract.Calendars.CONTENT_URI.buildUpon()\n                .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, \"true\")\n                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, NAME)\n                .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL)\n                .build();\n            Uri resourceUri = mResolver.insert(insertUri, value);\n            return ContentUris.parseId(resourceUri) > 0;\n        } finally {\n            Uri deleteUri = CalendarContract.Calendars.CONTENT_URI.buildUpon().build();\n            mResolver.delete(deleteUri, CalendarContract.Calendars.ACCOUNT_NAME + \"=?\", new String[]{ACCOUNT});\n        }\n    }\n}\n"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/CallLogReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.provider.CallLog;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass CallLogReadTest implements PermissionTest {\n\n    private ContentResolver mResolver;\n\n    CallLogReadTest(Context context) {\n        mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        String[] projection = new String[] {CallLog.Calls._ID, CallLog.Calls.NUMBER, CallLog.Calls.TYPE};\n        Cursor cursor = mResolver.query(CallLog.Calls.CONTENT_URI, projection, null, null, null);\n        if (cursor != null) {\n            try {\n                CursorTest.read(cursor);\n            } finally {\n                cursor.close();\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/CallLogWriteTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.provider.CallLog;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\nclass CallLogWriteTest implements PermissionTest {\n\n    private ContentResolver mResolver;\n\n    CallLogWriteTest(Context context) {\n        this.mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        try {\n            ContentValues content = new ContentValues();\n            content.put(CallLog.Calls.TYPE, CallLog.Calls.INCOMING_TYPE);\n            content.put(CallLog.Calls.NUMBER, \"1\");\n            content.put(CallLog.Calls.DATE, 20080808);\n            content.put(CallLog.Calls.NEW, \"0\");\n            Uri resourceUri = mResolver.insert(CallLog.Calls.CONTENT_URI, content);\n            return ContentUris.parseId(resourceUri) > 0;\n        } finally {\n            mResolver.delete(CallLog.Calls.CONTENT_URI, CallLog.Calls.NUMBER + \"=?\", new String[] {\"1\"});\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/CameraTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.hardware.Camera;\n\n/**\n * Created by Zhenjie Yan on 2018/1/15.\n */\nclass CameraTest implements PermissionTest {\n\n    private Context mContext;\n\n    CameraTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        Camera camera = null;\n        try {\n            int cameraCount = Camera.getNumberOfCameras();\n            if (cameraCount <= 0) return true;\n\n            camera = Camera.open(cameraCount - 1);\n            Camera.Parameters parameters = camera.getParameters();\n            camera.setParameters(parameters);\n            camera.setPreviewCallback(PREVIEW_CALLBACK);\n            camera.startPreview();\n            return true;\n        } catch (Throwable e) {\n            PackageManager packageManager = mContext.getPackageManager();\n            return !packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA);\n        } finally {\n            if (camera != null) {\n                camera.stopPreview();\n                camera.setPreviewCallback(null);\n                camera.release();\n            }\n        }\n    }\n\n    private static final Camera.PreviewCallback PREVIEW_CALLBACK = new Camera.PreviewCallback() {\n        @Override\n        public void onPreviewFrame(byte[] data, Camera camera) {\n        }\n    };\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/ContactsReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.provider.ContactsContract;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass ContactsReadTest implements PermissionTest {\n\n    private ContentResolver mResolver;\n\n    ContactsReadTest(Context context) {\n        mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        String[] projection = new String[] {ContactsContract.Data._ID, ContactsContract.Data.DATA1};\n        Cursor cursor = mResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null,\n            null);\n        if (cursor != null) {\n            try {\n                CursorTest.read(cursor);\n            } finally {\n                cursor.close();\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/ContactsWriteTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.provider.ContactsContract;\n\nimport androidx.annotation.Nullable;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\nclass ContactsWriteTest implements PermissionTest {\n\n    private static final String DISPLAY_NAME = \"PERMISSION\";\n\n    private ContentResolver mResolver;\n\n    ContactsWriteTest(ContentResolver resolver) {\n        this.mResolver = resolver;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        long[] idArray = insert();\n        long rawContactId = idArray[0];\n        long dataId = idArray[1];\n        if (rawContactId > 0 && dataId > 0) {\n            return delete(rawContactId, dataId);\n        }\n        return false;\n    }\n\n    private long[] insert() {\n        ContentValues values = new ContentValues();\n        Uri rawContractUri = mResolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);\n        long rawContactId = ContentUris.parseId(rawContractUri);\n\n        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);\n        values.put(ContactsContract.Data.DATA1, DISPLAY_NAME);\n        values.put(ContactsContract.Data.DATA2, DISPLAY_NAME);\n        values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);\n        Uri dataUri = mResolver.insert(ContactsContract.Data.CONTENT_URI, values);\n        long dataId = ContentUris.parseId(dataUri);\n        return new long[]{rawContactId, dataId};\n    }\n\n    private boolean delete(long rawContactId, long dataId) {\n        int dataCount = mResolver.delete(ContactsContract.Data.CONTENT_URI, ContactsContract.Data._ID + \"=?\",\n            new String[]{Long.toString(dataId)});\n        int rawContactCount = mResolver.delete(ContactsContract.RawContacts.CONTENT_URI, ContactsContract.RawContacts._ID + \"=?\",\n            new String[]{Long.toString(rawContactId)});\n        return rawContactCount > 0 && dataCount > 0;\n    }\n\n    private boolean update(long rawContactId) {\n        ContentValues values = new ContentValues();\n        values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);\n        values.put(ContactsContract.Data.DATA1, DISPLAY_NAME);\n        values.put(ContactsContract.Data.DATA2, DISPLAY_NAME);\n        values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);\n        Uri dataUri = mResolver.insert(ContactsContract.Data.CONTENT_URI, values);\n        return ContentUris.parseId(dataUri) > 0;\n    }\n\n    @Nullable\n    private long[] query() {\n        Cursor cursor = mResolver.query(ContactsContract.Data.CONTENT_URI,\n            new String[]{ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.Data._ID},\n            ContactsContract.Data.MIMETYPE + \"=? and \" + ContactsContract.Data.DATA1 + \"=?\",\n            new String[]{ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, DISPLAY_NAME}, null);\n        if (cursor != null) {\n            if (cursor.moveToFirst()) {\n                long rawContactId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));\n                long dataId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data._ID));\n                return new long[]{rawContactId, dataId};\n            }\n        }\n        return null;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/DoubleChecker.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/27.\n */\npublic final class DoubleChecker implements PermissionChecker {\n\n    private static final PermissionChecker STANDARD_CHECKER = new StandardChecker();\n    private static final PermissionChecker STRICT_CHECKER = new StrictChecker();\n\n    @Override\n    public boolean hasPermission(Context context, String... permissions) {\n        return STRICT_CHECKER.hasPermission(context, permissions) &&\n            STANDARD_CHECKER.hasPermission(context, permissions);\n    }\n\n    @Override\n    public boolean hasPermission(Context context, List<String> permissions) {\n        return STRICT_CHECKER.hasPermission(context, permissions) &&\n            STANDARD_CHECKER.hasPermission(context, permissions);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/LocationCoarseTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.location.LocationManager;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\nclass LocationCoarseTest implements PermissionTest {\n\n    private Context mContext;\n\n    LocationCoarseTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        LocationManager locationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);\n        List<String> providers = locationManager.getProviders(true);\n        boolean networkProvider = providers.contains(LocationManager.NETWORK_PROVIDER);\n        if (networkProvider) {\n            return true;\n        }\n\n        PackageManager packageManager = mContext.getPackageManager();\n        boolean networkHardware = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_NETWORK);\n        if (!networkHardware) return true;\n\n        return !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/LocationFineTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.location.LocationManager;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\nclass LocationFineTest implements PermissionTest {\n\n    private Context mContext;\n\n    LocationFineTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        LocationManager locationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);\n        List<String> providers = locationManager.getProviders(true);\n        boolean gpsProvider = providers.contains(LocationManager.GPS_PROVIDER);\n        boolean passiveProvider = providers.contains(LocationManager.PASSIVE_PROVIDER);\n        if (gpsProvider || passiveProvider) {\n            return true;\n        }\n\n        PackageManager packageManager = mContext.getPackageManager();\n        boolean gpsHardware = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);\n        if (!gpsHardware) return true;\n\n        return !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/PermissionChecker.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/7.\n */\npublic interface PermissionChecker {\n\n    /**\n     * Check if the calling context has a set of permissions.\n     *\n     * @param context {@link Context}.\n     * @param permissions one or more permissions.\n     *\n     * @return true, other wise is false.\n     */\n    boolean hasPermission(Context context, String... permissions);\n\n    /**\n     * Check if the calling context has a set of permissions.\n     *\n     * @param context {@link Context}.\n     * @param permissions one or more permissions.\n     *\n     * @return true, other wise is false.\n     */\n    boolean hasPermission(Context context, List<String> permissions);\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/PermissionTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.database.Cursor;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\ninterface PermissionTest {\n\n    boolean test() throws Throwable;\n\n    class CursorTest {\n\n        public static void read(Cursor cursor) {\n            int count = cursor.getCount();\n            if (count > 0) {\n                cursor.moveToFirst();\n                int type = cursor.getType(0);\n                switch (type) {\n                    case Cursor.FIELD_TYPE_BLOB:\n                    case Cursor.FIELD_TYPE_NULL: {\n                        break;\n                    }\n                    case Cursor.FIELD_TYPE_INTEGER:\n                    case Cursor.FIELD_TYPE_FLOAT:\n                    case Cursor.FIELD_TYPE_STRING:\n                    default: {\n                        cursor.getString(0);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/PhoneStateReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.telephony.TelephonyManager;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass PhoneStateReadTest implements PermissionTest {\n\n    private Context mContext;\n\n    PhoneStateReadTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        PackageManager packageManager = mContext.getPackageManager();\n        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) return true;\n\n        TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) telephonyManager.getDeviceId();\n        else telephonyManager.getDeviceSoftwareVersion();\n        return true;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/RecordAudioTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.media.AudioFormat;\nimport android.media.AudioRecord;\nimport android.media.MediaRecorder;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * Created by Zhenjie Yan on 2018/1/14.\n */\nclass RecordAudioTest implements PermissionTest {\n\n    private static final int[] RATES = new int[]{8000, 11025, 22050, 44100};\n\n    private Context mContext;\n\n    RecordAudioTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        AudioRecord audioRecord = null;\n        File file = null;\n        FileOutputStream fos = null;\n        try {\n            int[] params = findAudioParameters();\n            if (params == null) return !existMicrophone(mContext);\n\n            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, params[0], params[1], params[2], params[3]);\n            int state = audioRecord.getState();\n            if (state != AudioRecord.STATE_INITIALIZED) return !existMicrophone(mContext);\n\n            int recordState = audioRecord.getRecordingState();\n            if (recordState != AudioRecord.RECORDSTATE_STOPPED) return true;\n\n            audioRecord.startRecording();\n            if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) return true;\n\n            File cacheDir = new File(mContext.getCacheDir(), \"_andpermission_audio_record_test_\");\n            cacheDir.mkdirs();\n\n            file = new File(cacheDir, Long.toString(System.currentTimeMillis()));\n            if (file.exists()) file.createNewFile();\n\n            fos = new FileOutputStream(file);\n            byte[] buffer = new byte[params[3]];\n\n            int len = audioRecord.read(buffer, 0, params[3]);\n            fos.write(buffer, 0, len);\n            fos.flush();\n        } catch (Throwable e) {\n            return !existMicrophone(mContext);\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                } catch (IOException ignored) {\n                }\n            }\n            if (file != null && file.exists()) {\n                file.delete();\n            }\n            if (audioRecord != null) {\n                audioRecord.release();\n            }\n        }\n        return true;\n    }\n\n    public static boolean existMicrophone(Context context) {\n        PackageManager packageManager = context.getPackageManager();\n        return packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);\n    }\n\n    public static int[] findAudioParameters() {\n        for (int rate : RATES) {\n            for (int channel : new int[]{AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO}) {\n                for (int format : new int[]{AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT}) {\n                    int buffer = AudioRecord.getMinBufferSize(rate, channel, format);\n                    if (buffer != AudioRecord.ERROR_BAD_VALUE) {\n                        return new int[]{rate, channel, format, buffer};\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/SensorActivityTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.hardware.Sensor;\nimport android.hardware.SensorEvent;\nimport android.hardware.SensorEventListener;\nimport android.hardware.SensorManager;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass SensorActivityTest implements PermissionTest {\n\n    private Context mContext;\n\n    SensorActivityTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        SensorManager sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);\n        try {\n            Sensor heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);\n            sensorManager.registerListener(SENSOR_EVENT_LISTENER, heartRateSensor, 3);\n            sensorManager.unregisterListener(SENSOR_EVENT_LISTENER, heartRateSensor);\n        } catch (Throwable e) {\n            PackageManager packageManager = mContext.getPackageManager();\n            return !packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);\n        }\n        return true;\n    }\n\n    private static final SensorEventListener SENSOR_EVENT_LISTENER = new SensorEventListener() {\n        @Override\n        public void onSensorChanged(SensorEvent event) {\n        }\n\n        @Override\n        public void onAccuracyChanged(Sensor sensor, int accuracy) {\n        }\n    };\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/SensorHeartTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.hardware.Sensor;\nimport android.hardware.SensorEvent;\nimport android.hardware.SensorEventListener;\nimport android.hardware.SensorManager;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass SensorHeartTest implements PermissionTest {\n\n    private Context mContext;\n\n    SensorHeartTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        SensorManager sensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);\n        try {\n            Sensor heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);\n            sensorManager.registerListener(SENSOR_EVENT_LISTENER, heartRateSensor, 3);\n            sensorManager.unregisterListener(SENSOR_EVENT_LISTENER, heartRateSensor);\n        } catch (Throwable e) {\n            PackageManager packageManager = mContext.getPackageManager();\n            return !packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE);\n        }\n        return true;\n    }\n\n    private static final SensorEventListener SENSOR_EVENT_LISTENER = new SensorEventListener() {\n        @Override\n        public void onSensorChanged(SensorEvent event) {\n        }\n\n        @Override\n        public void onAccuracyChanged(Sensor sensor, int accuracy) {\n        }\n    };\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/SipTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.net.sip.SipManager;\nimport android.net.sip.SipProfile;\n\nimport com.yanzhenjie.permission.util.StringUtils;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass SipTest implements PermissionTest {\n\n    private static final String USER = StringUtils.hexToText(\"5065726D697373696F6E\");\n    private static final String IP = StringUtils.hexToText(\"3132372E302E302E31\");\n    private static final String PASSWORD = StringUtils.textToHex(\"70617373776F7264\");\n\n    private Context mContext;\n\n    SipTest(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        if (!SipManager.isApiSupported(mContext)) {\n            return true;\n        }\n        SipManager manager = SipManager.newInstance(mContext);\n        if (manager == null) {\n            return true;\n        }\n        SipProfile.Builder builder = new SipProfile.Builder(USER, IP);\n        builder.setPassword(PASSWORD);\n        SipProfile profile = builder.build();\n        manager.open(profile);\n        manager.close(profile.getUriString());\n        return true;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/SmsReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.provider.Telephony;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass SmsReadTest implements PermissionTest {\n\n    private ContentResolver mResolver;\n\n    SmsReadTest(Context context) {\n        mResolver = context.getContentResolver();\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        String[] projection = new String[] {Telephony.Sms._ID, Telephony.Sms.ADDRESS, Telephony.Sms.PERSON,\n            Telephony.Sms.BODY};\n        Cursor cursor = mResolver.query(Telephony.Sms.CONTENT_URI, projection, null, null, null);\n        if (cursor != null) {\n            try {\n                CursorTest.read(cursor);\n            } finally {\n                cursor.close();\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/StandardChecker.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.app.AppOpsManager;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/7.\n */\npublic final class StandardChecker implements PermissionChecker {\n\n    private static final int MODE_ASK = 4;\n    private static final int MODE_COMPAT = 5;\n\n    public StandardChecker() {\n    }\n\n    @Override\n    public boolean hasPermission(Context context, String... permissions) {\n        return hasPermission(context, Arrays.asList(permissions));\n    }\n\n    @Override\n    public boolean hasPermission(Context context, List<String> permissions) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;\n\n        AppOpsManager opsManager = null;\n        for (String permission : permissions) {\n            int result = context.checkPermission(permission, android.os.Process.myPid(), android.os.Process.myUid());\n            if (result == PackageManager.PERMISSION_DENIED) {\n                return false;\n            }\n\n            String op = AppOpsManager.permissionToOp(permission);\n            if (TextUtils.isEmpty(op)) {\n                continue;\n            }\n\n            if (opsManager == null) opsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);\n            result = opsManager.checkOpNoThrow(op, android.os.Process.myUid(), context.getPackageName());\n            if (result != AppOpsManager.MODE_ALLOWED && result != MODE_ASK && result != MODE_COMPAT) {\n                return false;\n            }\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/StorageReadTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.os.Build;\nimport android.os.Environment;\nimport android.text.TextUtils;\n\nimport java.io.File;\n\n/**\n * Created by Zhenjie Yan on 2018/1/16.\n */\nclass StorageReadTest implements PermissionTest {\n\n    StorageReadTest() {\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !Environment.isExternalStorageLegacy()) return true;\n\n        if (!TextUtils.equals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState())) return true;\n\n        File directory = Environment.getExternalStorageDirectory();\n        if (!directory.exists()) return true;\n\n        long modified = directory.lastModified();\n        String[] pathList = directory.list();\n        return modified > 0 && pathList != null;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/StorageWriteTest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.text.TextUtils;\n\nimport java.io.File;\n\n/**\n * Created by Zhenjie Yan on 2018/1/16.\n */\nclass StorageWriteTest implements PermissionTest {\n\n    private Context mContext;\n\n    StorageWriteTest(Context c) {\n        mContext = c;\n    }\n\n    @Override\n    public boolean test() throws Throwable {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !Environment.isExternalStorageLegacy()) return true;\n\n        if (!TextUtils.equals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState())) return true;\n\n        File directory = mContext.getExternalFilesDir(null);\n\n        if (!directory.exists()) return true;\n\n        File parent = new File(directory, \"Android\");\n        if (parent.exists() && parent.isFile()) {\n            if (!parent.delete()) return false;\n        }\n        if (!parent.exists()) {\n            if (!parent.mkdirs()) return false;\n        }\n        File file = new File(parent, \"ANDROID.PERMISSION.TEST\");\n        if (file.exists()) {\n            return file.delete();\n        } else {\n            return file.createNewFile();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/checker/StrictChecker.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.checker;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.yanzhenjie.permission.runtime.Permission;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/7.\n */\npublic final class StrictChecker implements PermissionChecker {\n\n    public StrictChecker() {\n    }\n\n    @Override\n    public boolean hasPermission(Context context, String... permissions) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return true;\n\n        for (String permission : permissions) {\n            if (!hasPermission(context, permission)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public boolean hasPermission(Context context, List<String> permissions) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return true;\n\n        for (String permission : permissions) {\n            if (!hasPermission(context, permission)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private boolean hasPermission(Context context, String permission) {\n        try {\n            switch (permission) {\n                case Permission.READ_CALENDAR:\n                    return checkReadCalendar(context);\n                case Permission.WRITE_CALENDAR:\n                    return checkWriteCalendar(context);\n                case Permission.CAMERA:\n                    return checkCamera(context);\n                case Permission.READ_CONTACTS:\n                    return checkReadContacts(context);\n                case Permission.WRITE_CONTACTS:\n                    return checkWriteContacts(context);\n                case Permission.GET_ACCOUNTS:\n                    return true;\n                case Permission.ACCESS_COARSE_LOCATION:\n                    return checkCoarseLocation(context);\n                case Permission.ACCESS_FINE_LOCATION:\n                    return checkFineLocation(context);\n                case Permission.RECORD_AUDIO:\n                    return checkRecordAudio(context);\n                case Permission.READ_PHONE_STATE:\n                    return checkReadPhoneState(context);\n                case Permission.CALL_PHONE:\n                    return true;\n                case Permission.READ_CALL_LOG:\n                    return checkReadCallLog(context);\n                case Permission.WRITE_CALL_LOG:\n                    return checkWriteCallLog(context);\n                case Permission.ADD_VOICEMAIL:\n                    return true;\n                case Permission.USE_SIP:\n                    return checkSip(context);\n                case Permission.PROCESS_OUTGOING_CALLS:\n                    return true;\n                case Permission.BODY_SENSORS:\n                    return checkSensorHeart(context);\n                case Permission.ACTIVITY_RECOGNITION:\n                    return checkSensorActivity(context);\n                case Permission.SEND_SMS:\n                case Permission.RECEIVE_MMS:\n                    return true;\n                case Permission.READ_SMS:\n                    return checkReadSms(context);\n                case Permission.RECEIVE_WAP_PUSH:\n                case Permission.RECEIVE_SMS:\n                    return true;\n                case Permission.READ_EXTERNAL_STORAGE:\n                    return checkReadStorage();\n                case Permission.WRITE_EXTERNAL_STORAGE:\n                    return checkWriteStorage(context);\n            }\n        } catch (Throwable e) {\n            return false;\n        }\n        return true;\n    }\n\n    private static boolean checkReadCalendar(Context context) throws Throwable {\n        PermissionTest test = new CalendarReadTest(context);\n        return test.test();\n    }\n\n    private static boolean checkWriteCalendar(Context context) throws Throwable {\n        PermissionTest test = new CalendarWriteTest(context);\n        return test.test();\n    }\n\n    private static boolean checkCamera(Context context) throws Throwable {\n        PermissionTest test = new CameraTest(context);\n        return test.test();\n    }\n\n    private static boolean checkReadContacts(Context context) throws Throwable {\n        PermissionTest test = new ContactsReadTest(context);\n        return test.test();\n    }\n\n    private static boolean checkWriteContacts(Context context) throws Throwable {\n        ContentResolver resolver = context.getContentResolver();\n        PermissionTest test = new ContactsWriteTest(resolver);\n        return test.test();\n    }\n\n    private static boolean checkCoarseLocation(Context context) throws Throwable {\n        PermissionTest test = new LocationCoarseTest(context);\n        return test.test();\n    }\n\n    private static boolean checkFineLocation(Context context) throws Throwable {\n        PermissionTest test = new LocationFineTest(context);\n        return test.test();\n    }\n\n    private static boolean checkRecordAudio(Context context) throws Throwable {\n        PermissionTest test = new RecordAudioTest(context);\n        return test.test();\n    }\n\n    private static boolean checkReadPhoneState(Context context) throws Throwable {\n        PermissionTest test = new PhoneStateReadTest(context);\n        return test.test();\n    }\n\n    private static boolean checkReadCallLog(Context context) throws Throwable {\n        PermissionTest test = new CallLogReadTest(context);\n        return test.test();\n    }\n\n    private static boolean checkWriteCallLog(Context context) throws Throwable {\n        PermissionTest test = new CallLogWriteTest(context);\n        return test.test();\n    }\n\n    private static boolean checkSip(Context context) throws Throwable {\n        PermissionTest test = new SipTest(context);\n        return test.test();\n    }\n\n    private static boolean checkSensorHeart(Context context) throws Throwable {\n        PermissionTest test = new SensorHeartTest(context);\n        return test.test();\n    }\n\n    private static boolean checkSensorActivity(Context context) throws Throwable {\n        PermissionTest test = new SensorActivityTest(context);\n        return test.test();\n    }\n\n    private static boolean checkReadSms(Context context) throws Throwable {\n        PermissionTest test = new SmsReadTest(context);\n        return test.test();\n    }\n\n    private static boolean checkReadStorage() throws Throwable {\n        PermissionTest test = new StorageReadTest();\n        return test.test();\n    }\n\n    private static boolean checkWriteStorage(Context context) throws Throwable {\n        PermissionTest test = new StorageWriteTest(context);\n        return test.test();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/BaseRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.AndPermission;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\nimport java.io.File;\n\n/**\n * Created by Zhenjie Yan on 2018/6/1.\n */\nabstract class BaseRequest implements InstallRequest {\n\n    private Source mSource;\n\n    private File mFile;\n    private Rationale<File> mRationale = new Rationale<File>() {\n        @Override\n        public void showRationale(Context context, File data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<File> mGranted;\n    private Action<File> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public final InstallRequest file(File file) {\n        this.mFile = file;\n        return this;\n    }\n\n    @Override\n    public final InstallRequest rationale(Rationale<File> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public final InstallRequest onGranted(Action<File> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public final InstallRequest onDenied(Action<File> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), null, executor);\n    }\n\n    /**\n     * Start the installation.\n     */\n    final void install() {\n        if (mFile != null) {\n            Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);\n            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n            Uri uri = AndPermission.getFileUri(mSource.getContext(), mFile);\n            intent.setDataAndType(uri, \"application/vnd.android.package-archive\");\n            mSource.startActivity(intent);\n        }\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed() {\n        if (mGranted != null) {\n            mGranted.onAction(mFile);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed() {\n        if (mDenied != null) {\n            mDenied.onAction(mFile);\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/InstallRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\nimport java.io.File;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic interface InstallRequest {\n\n    /**\n     * The apk file.\n     *\n     * @param file apk file.\n     */\n    InstallRequest file(File file);\n\n    /**\n     * Set request rationale.\n     */\n    InstallRequest rationale(Rationale<File> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    InstallRequest onGranted(Action<File> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    InstallRequest onDenied(Action<File> denied);\n\n    /**\n     * Start install.\n     */\n    void start();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/NRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\nclass NRequest extends BaseRequest {\n\n    NRequest(Source source) {\n        super(source);\n    }\n\n    @Override\n    public void start() {\n        callbackSucceed();\n        install();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/NRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport com.yanzhenjie.permission.Boot;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class NRequestFactory implements Boot.InstallRequestFactory {\n\n    @Override\n    public InstallRequest create(Source source) {\n        return new NRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/ORequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\nclass ORequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    ORequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canRequestPackageInstalls()) {\n            callbackSucceed();\n            install();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_INSTALL);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canRequestPackageInstalls()) {\n            callbackSucceed();\n            install();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/install/ORequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.install;\n\nimport com.yanzhenjie.permission.Boot;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class ORequestFactory implements Boot.InstallRequestFactory {\n\n    @Override\n    public InstallRequest create(Source source) {\n        return new ORequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/BaseRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport android.content.Context;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/6/1.\n */\nabstract class BaseRequest implements PermissionRequest {\n\n    private Source mSource;\n\n    private Rationale<Void> mRationale = new Rationale<Void>() {\n        @Override\n        public void showRationale(Context context, Void data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<Void> mGranted;\n    private Action<Void> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public final PermissionRequest rationale(Rationale<Void> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public final PermissionRequest onGranted(Action<Void> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public final PermissionRequest onDenied(Action<Void> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), null, executor);\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed() {\n        if (mGranted != null) {\n            mGranted.onAction(null);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed() {\n        if (mDenied != null) {\n            mDenied.onAction(null);\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/NRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass NRequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    NRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canNotify()) {\n            callbackSucceed();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_APP_DETAILS);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canNotify()) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/NRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class NRequestFactory implements Notify.PermissionRequestFactory {\n\n    @Override\n    public PermissionRequest create(Source source) {\n        return new NRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/Notify.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport android.os.Build;\n\nimport com.yanzhenjie.permission.notify.listener.J1RequestFactory;\nimport com.yanzhenjie.permission.notify.listener.J2RequestFactory;\nimport com.yanzhenjie.permission.notify.listener.ListenerRequest;\nimport com.yanzhenjie.permission.notify.option.NotifyOption;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2/22/19.\n */\npublic class Notify implements NotifyOption {\n\n    private static final PermissionRequestFactory PERMISSION_REQUEST_FACTORY;\n    private static final ListenerRequestFactory LISTENER_REQUEST_FACTORY;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            PERMISSION_REQUEST_FACTORY = new ORequestFactory();\n        } else {\n            PERMISSION_REQUEST_FACTORY = new NRequestFactory();\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            LISTENER_REQUEST_FACTORY = new J2RequestFactory();\n        } else {\n            LISTENER_REQUEST_FACTORY = new J1RequestFactory();\n        }\n    }\n\n    public interface PermissionRequestFactory {\n\n        /**\n         * Create notify request.\n         */\n        PermissionRequest create(Source source);\n    }\n\n    public interface ListenerRequestFactory {\n\n        /**\n         * Create notification listener request.\n         */\n        ListenerRequest create(Source source);\n    }\n\n    private Source mSource;\n\n    public Notify(Source source) {\n        this.mSource = source;\n    }\n\n    public PermissionRequest permission() {\n        return PERMISSION_REQUEST_FACTORY.create(mSource);\n    }\n\n    public ListenerRequest listener() {\n        return LISTENER_REQUEST_FACTORY.create(mSource);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/ORequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass ORequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    ORequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canNotify()) {\n            callbackSucceed();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_NOTIFY);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canNotify()) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/ORequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class ORequestFactory implements Notify.PermissionRequestFactory {\n\n    @Override\n    public PermissionRequest create(Source source) {\n        return new ORequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/PermissionRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\n/**\n * Created by Zhenjie Yan on 2/14/19.\n */\npublic interface PermissionRequest {\n\n    /**\n     * Set request rationale.\n     */\n    PermissionRequest rationale(Rationale<Void> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    PermissionRequest onGranted(Action<Void> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    PermissionRequest onDenied(Action<Void> denied);\n\n    /**\n     * Start install.\n     */\n    void start();\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/BaseRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport android.content.Context;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/6/1.\n */\nabstract class BaseRequest implements ListenerRequest {\n\n    private Source mSource;\n\n    private Rationale<Void> mRationale = new Rationale<Void>() {\n        @Override\n        public void showRationale(Context context, Void data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<Void> mGranted;\n    private Action<Void> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public final ListenerRequest rationale(Rationale<Void> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public final ListenerRequest onGranted(Action<Void> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public final ListenerRequest onDenied(Action<Void> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), null, executor);\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed() {\n        if (mGranted != null) {\n            mGranted.onAction(null);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed() {\n        if (mDenied != null) {\n            mDenied.onAction(null);\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/J1Request.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass J1Request extends BaseRequest implements RequestExecutor {\n\n    J1Request(Source source) {\n        super(source);\n    }\n\n    @Override\n    public void start() {\n        callbackSucceed();\n    }\n\n    @Override\n    public void execute() {\n        // Nothing.\n    }\n\n    @Override\n    public void cancel() {\n        // Nothing.\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/J1RequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport com.yanzhenjie.permission.notify.Notify;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class J1RequestFactory implements Notify.ListenerRequestFactory {\n\n    @Override\n    public ListenerRequest create(Source source) {\n        return new J1Request(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/J2Request.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass J2Request extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    J2Request(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canListenerNotification()) {\n            callbackSucceed();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_NOTIFY_LISTENER);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canListenerNotification()) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/J2RequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport com.yanzhenjie.permission.notify.Notify;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class J2RequestFactory implements Notify.ListenerRequestFactory {\n\n    @Override\n    public ListenerRequest create(Source source) {\n        return new J2Request(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/listener/ListenerRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.listener;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\n/**\n * Created by Zhenjie Yan on 2/14/19.\n */\npublic interface ListenerRequest {\n\n    /**\n     * Set request rationale.\n     */\n    ListenerRequest rationale(Rationale<Void> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    ListenerRequest onGranted(Action<Void> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    ListenerRequest onDenied(Action<Void> denied);\n\n    /**\n     * Start install.\n     */\n    void start();\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/notify/option/NotifyOption.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.notify.option;\n\nimport com.yanzhenjie.permission.notify.PermissionRequest;\nimport com.yanzhenjie.permission.notify.listener.ListenerRequest;\n\n/**\n * Created by Zhenjie Yan on 2/14/19.\n */\npublic interface NotifyOption {\n\n    /**\n     * Handle permissions.\n     */\n    PermissionRequest permission();\n\n    /**\n     * Handle notify listener.\n     */\n    ListenerRequest listener();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/option/Option.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.option;\n\nimport com.yanzhenjie.permission.install.InstallRequest;\nimport com.yanzhenjie.permission.notify.option.NotifyOption;\nimport com.yanzhenjie.permission.overlay.OverlayRequest;\nimport com.yanzhenjie.permission.runtime.option.RuntimeOption;\nimport com.yanzhenjie.permission.setting.Setting;\n\n/**\n * Created by Zhenjie Yan on 2/22/19.\n */\npublic interface Option {\n\n    /**\n     * Handle runtime permissions.\n     */\n    RuntimeOption runtime();\n\n    /**\n     * Handle request package install permission.\n     */\n    InstallRequest install();\n\n    /**\n     * Handle overlay permission.\n     */\n    OverlayRequest overlay();\n\n    /**\n     * Handle notification permission.\n     */\n    NotifyOption notification();\n\n    /**\n     * Handle system setting.\n     */\n    Setting setting();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/BaseRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.os.Build;\nimport android.view.Window;\nimport android.view.WindowManager;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.R;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/6/1.\n */\nabstract class BaseRequest implements OverlayRequest {\n\n    private Source mSource;\n\n    private Rationale<Void> mRationale = new Rationale<Void>() {\n        @Override\n        public void showRationale(Context context, Void data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<Void> mGranted;\n    private Action<Void> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public final OverlayRequest rationale(Rationale<Void> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public final OverlayRequest onGranted(Action<Void> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public final OverlayRequest onDenied(Action<Void> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), null, executor);\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed() {\n        if (mGranted != null) {\n            mGranted.onAction(null);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed() {\n        if (mDenied != null) {\n            mDenied.onAction(null);\n        }\n    }\n\n    static boolean tryDisplayDialog(Context context) {\n        Dialog dialog = new Dialog(context, R.style.Permission_Theme_Dialog_Transparent);\n        Window window = dialog.getWindow();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);\n        } else {\n            window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);\n        }\n        try {\n            dialog.show();\n        } catch (Exception e) {\n            return false;\n        } finally {\n            if (dialog.isShowing()) dialog.dismiss();\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/LRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass LRequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    LRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (tryDisplayDialog(mSource.getContext())) {\n            callbackSucceed();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_ALERT_WINDOW);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (tryDisplayDialog(mSource.getContext())) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/LRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport com.yanzhenjie.permission.Boot;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class LRequestFactory implements Boot.OverlayRequestFactory {\n\n    @Override\n    public OverlayRequest create(Source source) {\n        return new LRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/MRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\nclass MRequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    MRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canDrawOverlays()) {\n            onCallback();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_OVERLAY);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canDrawOverlays() && tryDisplayDialog(mSource.getContext())) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/MRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport com.yanzhenjie.permission.Boot;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class MRequestFactory implements Boot.OverlayRequestFactory {\n\n    @Override\n    public OverlayRequest create(Source source) {\n        return new MRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/OverlayRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic interface OverlayRequest {\n\n    /**\n     * Set request rationale.\n     */\n    OverlayRequest rationale(Rationale<Void> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    OverlayRequest onGranted(Action<Void> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    OverlayRequest onDenied(Action<Void> denied);\n\n    /**\n     * Start request.\n     */\n    void start();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/setting/LSettingPage.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay.setting;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.Settings;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/29.\n */\npublic class LSettingPage {\n\n    private static final String MARK = Build.MANUFACTURER.toLowerCase();\n\n    private Source mSource;\n\n    public LSettingPage(Source source) {\n        this.mSource = source;\n    }\n\n    public void start(int requestCode) {\n        Intent intent;\n        if (MARK.contains(\"huawei\")) {\n            intent = huaweiApi(mSource.getContext());\n        } else if (MARK.contains(\"xiaomi\")) {\n            intent = xiaomiApi(mSource.getContext());\n        } else if (MARK.contains(\"oppo\")) {\n            intent = oppoApi(mSource.getContext());\n        } else if (MARK.contains(\"vivo\")) {\n            intent = vivoApi(mSource.getContext());\n        } else if (MARK.contains(\"meizu\")) {\n            intent = meizuApi(mSource.getContext());\n        } else {\n            intent = defaultApi(mSource.getContext());\n        }\n\n        try {\n            mSource.startActivityForResult(intent, requestCode);\n        } catch (Exception e) {\n            intent = defaultApi(mSource.getContext());\n            mSource.startActivityForResult(intent, requestCode);\n        }\n    }\n\n    private static Intent defaultApi(Context context) {\n        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\n        intent.setData(Uri.fromParts(\"package\", context.getPackageName(), null));\n        return intent;\n    }\n\n    private Intent huaweiApi(Context context) {\n        Intent intent = new Intent();\n        intent.putExtra(\"package\", context.getPackageName());\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setData(Uri.fromParts(\"package\", context.getPackageName(), null));\n        intent.setClassName(\"com.huawei.systemmanager\", \"com.huawei.permissionmanager.ui.MainActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.huawei.systemmanager\", \"com.huawei.systemmanager.addviewmonitor.AddViewMonitorActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.huawei.systemmanager\", \"com.huawei.notificationmanager.ui.NotificationManagmentActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private Intent xiaomiApi(Context context) {\n        Intent intent = new Intent(\"miui.intent.action.APP_PERM_EDITOR\");\n        intent.putExtra(\"extra_pkgname\", context.getPackageName());\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.miui.securitycenter\", \"com.miui.permcenter.permissions.AppPermissionsEditorActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private Intent oppoApi(Context context) {\n        Intent intent = new Intent();\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setClassName(\"com.color.safecenter\",\n            \"com.color.safecenter.permission.floatwindow.FloatWindowListActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.coloros.safecenter\", \"com.coloros.safecenter.sysfloatwindow.FloatWindowListActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.oppo.safe\", \"com.oppo.safe.permission.PermissionAppListActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private Intent vivoApi(Context context) {\n        Intent intent = new Intent();\n        intent.setClassName(\"com.iqoo.secure\", \"com.iqoo.secure.ui.phoneoptimize.FloatWindowManager\");\n        intent.putExtra(\"packagename\", context.getPackageName());\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.iqoo.secure\", \"com.iqoo.secure.safeguard.SoftPermissionDetailActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private Intent meizuApi(Context context) {\n        Intent intent = new Intent(\"com.meizu.safe.security.SHOW_APPSEC\");\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setComponent(new ComponentName(\"com.meizu.safe\", \"com.meizu.safe.security.AppSecActivity\"));\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static boolean hasActivity(Context context, Intent intent) {\n        PackageManager packageManager = context.getPackageManager();\n        return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/overlay/setting/MSettingPage.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.overlay.setting;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.Settings;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class MSettingPage {\n\n    private static final String MARK = Build.MANUFACTURER.toLowerCase();\n\n    private Source mSource;\n\n    public MSettingPage(Source source) {\n        this.mSource = source;\n    }\n\n    public void start(int requestCode) {\n        Intent intent;\n        if (MARK.contains(\"meizu\")) {\n            intent = meiZuApi(mSource.getContext());\n        } else {\n            intent = defaultApi(mSource.getContext());\n        }\n\n        try {\n            mSource.startActivityForResult(intent, requestCode);\n        } catch (Exception e) {\n            intent = appDetailsApi(mSource.getContext());\n            mSource.startActivityForResult(intent, requestCode);\n        }\n    }\n\n    private static Intent appDetailsApi(Context context) {\n        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\n        intent.setData(Uri.fromParts(\"package\", context.getPackageName(), null));\n        return intent;\n    }\n\n    private static Intent defaultApi(Context context) {\n        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);\n        intent.setData(Uri.fromParts(\"package\", context.getPackageName(), null));\n        if (hasActivity(context, intent)) return intent;\n\n        return appDetailsApi(context);\n    }\n\n    private static Intent meiZuApi(Context context) {\n        Intent intent = new Intent(\"com.meizu.safe.security.SHOW_APPSEC\");\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setClassName(\"com.meizu.safe\", \"com.meizu.safe.security.AppSecActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static boolean hasActivity(Context context, Intent intent) {\n        PackageManager packageManager = context.getPackageManager();\n        return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/BaseRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.checker.PermissionChecker;\nimport com.yanzhenjie.permission.source.Source;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Created Zhenjie Yan on 2019-10-10.\n */\nabstract class BaseRequest implements PermissionRequest {\n\n    private Source mSource;\n\n    private Rationale<List<String>> mRationale = new Rationale<List<String>>() {\n        @Override\n        public void showRationale(Context context, List<String> data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<List<String>> mGranted;\n    private Action<List<String>> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public PermissionRequest rationale(@NonNull Rationale<List<String>> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public PermissionRequest onGranted(@NonNull Action<List<String>> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public PermissionRequest onDenied(@NonNull Action<List<String>> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(List<String> rationaleList, RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), rationaleList, executor);\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed(List<String> grantedList) {\n        if (mGranted != null) {\n            mGranted.onAction(grantedList);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed(List<String> deniedList) {\n        if (mDenied != null) {\n            mDenied.onAction(deniedList);\n        }\n    }\n\n    /**\n     * Filter the permissions you want to apply; remove unsupported and duplicate permissions.\n     */\n    public static List<String> filterPermissions(List<String> permissions) {\n        permissions = new ArrayList<>(new HashSet<>(permissions));\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            permissions.remove(Permission.READ_PHONE_NUMBERS);\n            permissions.remove(Permission.ANSWER_PHONE_CALLS);\n        }\n\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {\n            permissions.remove(Permission.ACTIVITY_RECOGNITION);\n            permissions.remove(Permission.ACCESS_BACKGROUND_LOCATION);\n        }\n        return permissions;\n    }\n\n    /**\n     * Get denied permissions.\n     */\n    public static List<String> getDeniedPermissions(PermissionChecker checker, Source source, List<String> permissions) {\n        List<String> deniedList = new ArrayList<>(1);\n        for (String permission : permissions) {\n            if (!checker.hasPermission(source.getContext(), permission)) {\n                deniedList.add(permission);\n            }\n        }\n        return deniedList;\n    }\n\n    /**\n     * Get permissions to show rationale.\n     */\n    public static List<String> getRationalePermissions(Source source, List<String> deniedPermissions) {\n        List<String> rationaleList = new ArrayList<>(1);\n        for (String permission : deniedPermissions) {\n            if (source.isShowRationalePermission(permission)) {\n                rationaleList.add(permission);\n            }\n        }\n        return rationaleList;\n    }\n}\n"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/LRequest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.checker.PermissionChecker;\nimport com.yanzhenjie.permission.checker.StrictChecker;\nimport com.yanzhenjie.permission.source.Source;\nimport com.yanzhenjie.permission.task.TaskExecutor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/25.\n */\nclass LRequest extends BaseRequest {\n\n    private static final PermissionChecker STRICT_CHECKER = new StrictChecker();\n\n    private Source mSource;\n\n    private List<String> mPermissions;\n\n    LRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String... permissions) {\n        mPermissions = new ArrayList<>();\n        mPermissions.addAll(Arrays.asList(permissions));\n        return this;\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String[]... groups) {\n        mPermissions = new ArrayList<>();\n        for (String[] group : groups) {\n            mPermissions.addAll(Arrays.asList(group));\n        }\n        return this;\n    }\n\n    @Override\n    public void start() {\n        mPermissions = filterPermissions(mPermissions);\n\n        new TaskExecutor<List<String>>(mSource.getContext()) {\n            @Override\n            protected List<String> doInBackground(Void... voids) {\n                return getDeniedPermissions(STRICT_CHECKER, mSource, mPermissions);\n            }\n\n            @Override\n            protected void onFinish(List<String> deniedList) {\n                if (deniedList.isEmpty()) {\n                    callbackSucceed(mPermissions);\n                } else {\n                    callbackFailed(deniedList);\n                }\n            }\n        }.execute();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/LRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class LRequestFactory implements Runtime.PermissionRequestFactory {\n\n    @Override\n    public PermissionRequest create(Source source) {\n        return new LRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/MRequest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.checker.DoubleChecker;\nimport com.yanzhenjie.permission.checker.PermissionChecker;\nimport com.yanzhenjie.permission.checker.StandardChecker;\nimport com.yanzhenjie.permission.source.Source;\nimport com.yanzhenjie.permission.task.TaskExecutor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2016/9/9.\n */\nclass MRequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private static final PermissionChecker STANDARD_CHECKER = new StandardChecker();\n    private static final PermissionChecker DOUBLE_CHECKER = new DoubleChecker();\n\n    private Source mSource;\n\n    private List<String> mPermissions;\n\n    private List<String> mDeniedPermissions;\n\n    MRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String... permissions) {\n        mPermissions = new ArrayList<>();\n        mPermissions.addAll(Arrays.asList(permissions));\n        return this;\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String[]... groups) {\n        mPermissions = new ArrayList<>();\n        for (String[] group : groups) {\n            mPermissions.addAll(Arrays.asList(group));\n        }\n        return this;\n    }\n\n    @Override\n    public void start() {\n        mPermissions = filterPermissions(mPermissions);\n\n        mDeniedPermissions = getDeniedPermissions(STANDARD_CHECKER, mSource, mPermissions);\n        if (mDeniedPermissions.size() > 0) {\n            List<String> rationaleList = getRationalePermissions(mSource, mDeniedPermissions);\n            if (rationaleList.size() > 0) {\n                showRationale(rationaleList, this);\n            } else {\n                execute();\n            }\n        } else {\n            onCallback();\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_PERMISSION);\n        request.setPermissions(mDeniedPermissions);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        onCallback();\n    }\n\n    @Override\n    public void onCallback() {\n        new TaskExecutor<List<String>>(mSource.getContext()) {\n            @Override\n            protected List<String> doInBackground(Void... voids) {\n                return getDeniedPermissions(DOUBLE_CHECKER, mSource, mPermissions);\n            }\n\n            @Override\n            protected void onFinish(List<String> deniedList) {\n                if (deniedList.isEmpty()) {\n                    callbackSucceed(mPermissions);\n                } else {\n                    callbackFailed(deniedList);\n                }\n            }\n        }.execute();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/MRequestFactory.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/28.\n */\npublic class MRequestFactory implements Runtime.PermissionRequestFactory {\n\n    @Override\n    public PermissionRequest create(Source source) {\n        return new MRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/Permission.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport com.yanzhenjie.permission.R;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * <p>Permissions.</p>\n * Created by Zhenjie Yan on 2017/8/4.\n */\npublic class Permission {\n\n    public static final String READ_CALENDAR = \"android.permission.READ_CALENDAR\";\n    public static final String WRITE_CALENDAR = \"android.permission.WRITE_CALENDAR\";\n\n    public static final String CAMERA = \"android.permission.CAMERA\";\n\n    public static final String READ_CONTACTS = \"android.permission.READ_CONTACTS\";\n    public static final String WRITE_CONTACTS = \"android.permission.WRITE_CONTACTS\";\n    public static final String GET_ACCOUNTS = \"android.permission.GET_ACCOUNTS\";\n\n    public static final String ACCESS_FINE_LOCATION = \"android.permission.ACCESS_FINE_LOCATION\";\n    public static final String ACCESS_COARSE_LOCATION = \"android.permission.ACCESS_COARSE_LOCATION\";\n    public static final String ACCESS_BACKGROUND_LOCATION = \"android.permission.ACCESS_BACKGROUND_LOCATION\";\n\n    public static final String RECORD_AUDIO = \"android.permission.RECORD_AUDIO\";\n\n    public static final String READ_PHONE_STATE = \"android.permission.READ_PHONE_STATE\";\n    public static final String CALL_PHONE = \"android.permission.CALL_PHONE\";\n    public static final String USE_SIP = \"android.permission.USE_SIP\";\n    public static final String READ_PHONE_NUMBERS = \"android.permission.READ_PHONE_NUMBERS\";\n    public static final String ANSWER_PHONE_CALLS = \"android.permission.ANSWER_PHONE_CALLS\";\n    public static final String ADD_VOICEMAIL = \"com.android.voicemail.permission.ADD_VOICEMAIL\";\n\n    public static final String READ_CALL_LOG = \"android.permission.READ_CALL_LOG\";\n    public static final String WRITE_CALL_LOG = \"android.permission.WRITE_CALL_LOG\";\n    public static final String PROCESS_OUTGOING_CALLS = \"android.permission.PROCESS_OUTGOING_CALLS\";\n\n    public static final String BODY_SENSORS = \"android.permission.BODY_SENSORS\";\n    public static final String ACTIVITY_RECOGNITION = \"android.permission.ACTIVITY_RECOGNITION\";\n\n    public static final String SEND_SMS = \"android.permission.SEND_SMS\";\n    public static final String RECEIVE_SMS = \"android.permission.RECEIVE_SMS\";\n    public static final String READ_SMS = \"android.permission.READ_SMS\";\n    public static final String RECEIVE_WAP_PUSH = \"android.permission.RECEIVE_WAP_PUSH\";\n    public static final String RECEIVE_MMS = \"android.permission.RECEIVE_MMS\";\n\n    public static final String READ_EXTERNAL_STORAGE = \"android.permission.READ_EXTERNAL_STORAGE\";\n    public static final String WRITE_EXTERNAL_STORAGE = \"android.permission.WRITE_EXTERNAL_STORAGE\";\n\n    public static final class Group {\n\n        public static final String[] CALENDAR = new String[]{Permission.READ_CALENDAR, Permission.WRITE_CALENDAR};\n\n        public static final String[] CAMERA = new String[]{Permission.CAMERA};\n\n        public static final String[] CONTACTS = new String[]{Permission.READ_CONTACTS, Permission.WRITE_CONTACTS, Permission.GET_ACCOUNTS};\n\n        public static final String[] LOCATION = new String[]{Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION,\n            Permission.ACCESS_BACKGROUND_LOCATION};\n\n        public static final String[] MICROPHONE = new String[]{Permission.RECORD_AUDIO};\n\n        public static final String[] PHONE = new String[]{Permission.READ_PHONE_STATE, Permission.CALL_PHONE, Permission.USE_SIP,\n            Permission.READ_PHONE_NUMBERS, Permission.ANSWER_PHONE_CALLS, Permission.ADD_VOICEMAIL};\n\n        public static final String[] CALL_LOG = new String[]{Permission.READ_CALL_LOG, Permission.WRITE_CALL_LOG,\n            Permission.PROCESS_OUTGOING_CALLS};\n\n        public static final String[] SENSORS = new String[]{Permission.BODY_SENSORS};\n\n        public static final String[] ACTIVITY_RECOGNITION = new String[]{Permission.ACTIVITY_RECOGNITION};\n\n        public static final String[] SMS = new String[]{Permission.SEND_SMS, Permission.RECEIVE_SMS, Permission.READ_SMS,\n            Permission.RECEIVE_WAP_PUSH, Permission.RECEIVE_MMS};\n\n        public static final String[] STORAGE = new String[]{Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE};\n    }\n\n    /**\n     * Turn permissions into text.\n     */\n    public static List<String> transformText(Context context, String... permissions) {\n        return transformText(context, Arrays.asList(permissions));\n    }\n\n    /**\n     * Turn permissions into text.\n     */\n    public static List<String> transformText(Context context, String[]... groups) {\n        List<String> permissionList = new ArrayList<>();\n        for (String[] group : groups) {\n            permissionList.addAll(Arrays.asList(group));\n        }\n        return transformText(context, permissionList);\n    }\n\n    /**\n     * Turn permissions into text.\n     */\n    public static List<String> transformText(Context context, List<String> permissions) {\n        List<String> textList = new ArrayList<>();\n        for (String permission : permissions) {\n            switch (permission) {\n                case Permission.READ_CALENDAR:\n                case Permission.WRITE_CALENDAR: {\n                    String message = context.getString(R.string.permission_name_calendar);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n\n                case Permission.CAMERA: {\n                    String message = context.getString(R.string.permission_name_camera);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.GET_ACCOUNTS:\n                case Permission.READ_CONTACTS:\n                case Permission.WRITE_CONTACTS: {\n                    String message = context.getString(R.string.permission_name_contacts);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.ACCESS_FINE_LOCATION:\n                case Permission.ACCESS_COARSE_LOCATION: {\n                    String message = context.getString(R.string.permission_name_location);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.RECORD_AUDIO: {\n                    String message = context.getString(R.string.permission_name_microphone);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.READ_PHONE_STATE:\n                case Permission.CALL_PHONE:\n                case Permission.ADD_VOICEMAIL:\n                case Permission.USE_SIP:\n                case Permission.READ_PHONE_NUMBERS:\n                case Permission.ANSWER_PHONE_CALLS: {\n                    String message = context.getString(R.string.permission_name_phone);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.READ_CALL_LOG:\n                case Permission.WRITE_CALL_LOG:\n                case Permission.PROCESS_OUTGOING_CALLS: {\n                    int messageId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?\n                        R.string.permission_name_call_log : R.string.permission_name_phone;\n                    String message = context.getString(messageId);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.BODY_SENSORS: {\n                    String message = context.getString(R.string.permission_name_sensors);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.ACTIVITY_RECOGNITION: {\n                    String message = context.getString(R.string.permission_name_activity_recognition);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.SEND_SMS:\n                case Permission.RECEIVE_SMS:\n                case Permission.READ_SMS:\n                case Permission.RECEIVE_WAP_PUSH:\n                case Permission.RECEIVE_MMS: {\n                    String message = context.getString(R.string.permission_name_sms);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n                case Permission.READ_EXTERNAL_STORAGE:\n                case Permission.WRITE_EXTERNAL_STORAGE: {\n                    String message = context.getString(R.string.permission_name_storage);\n                    if (!textList.contains(message)) {\n                        textList.add(message);\n                    }\n                    break;\n                }\n            }\n        }\n        return textList;\n    }\n\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/PermissionDef.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport androidx.annotation.StringDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Created Zhenjie Yan on 2019-10-10.\n */\n@StringDef({\n    Permission.READ_CALENDAR,\n    Permission.WRITE_CALENDAR,\n    Permission.CAMERA,\n    Permission.READ_CONTACTS,\n    Permission.WRITE_CONTACTS,\n    Permission.GET_ACCOUNTS,\n    Permission.ACCESS_FINE_LOCATION,\n    Permission.ACCESS_COARSE_LOCATION,\n    Permission.ACCESS_BACKGROUND_LOCATION,\n    Permission.RECORD_AUDIO,\n    Permission.READ_PHONE_STATE,\n    Permission.CALL_PHONE,\n    Permission.ADD_VOICEMAIL,\n    Permission.USE_SIP,\n    Permission.READ_PHONE_NUMBERS,\n    Permission.ANSWER_PHONE_CALLS,\n    Permission.READ_CALL_LOG,\n    Permission.WRITE_CALL_LOG,\n    Permission.PROCESS_OUTGOING_CALLS,\n    Permission.BODY_SENSORS,\n    Permission.ACTIVITY_RECOGNITION,\n    Permission.SEND_SMS,\n    Permission.RECEIVE_SMS,\n    Permission.READ_SMS,\n    Permission.RECEIVE_WAP_PUSH,\n    Permission.RECEIVE_MMS,\n    Permission.READ_EXTERNAL_STORAGE,\n    Permission.WRITE_EXTERNAL_STORAGE\n})\n@Retention(RetentionPolicy.SOURCE)\npublic @interface PermissionDef {\n}\n"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/PermissionRequest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\nimport java.util.List;\n\n/**\n * <p>Permission request.</p>\n * Created by Zhenjie Yan on 2016/9/9.\n */\npublic interface PermissionRequest {\n\n    /**\n     * One or more permissions.\n     */\n    PermissionRequest permission(@NonNull @PermissionDef String... permissions);\n\n    /**\n     * One or more permissions group.\n     *\n     * @param groups use constants in {@link Permission.Group}.\n     */\n    PermissionRequest permission(@NonNull String[]... groups);\n\n    /**\n     * Set request rationale.\n     */\n    PermissionRequest rationale(@NonNull Rationale<List<String>> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    PermissionRequest onGranted(@NonNull Action<List<String>> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    PermissionRequest onDenied(@NonNull Action<List<String>> denied);\n\n    /**\n     * Request permission.\n     */\n    void start();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/Runtime.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.runtime.option.RuntimeOption;\nimport com.yanzhenjie.permission.runtime.setting.AllRequest;\nimport com.yanzhenjie.permission.runtime.setting.SettingRequest;\nimport com.yanzhenjie.permission.source.Source;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/5/2.\n */\npublic class Runtime implements RuntimeOption {\n\n    private static final String ADD_VOICEMAIL_MANIFEST = \"android.permission.ADD_VOICEMAIL\";\n\n    private static final PermissionRequestFactory FACTORY;\n    private static List<String> sAppPermissions;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            FACTORY = new MRequestFactory();\n        } else {\n            FACTORY = new LRequestFactory();\n        }\n    }\n\n    public interface PermissionRequestFactory {\n\n        /**\n         * Create permission request.\n         */\n        PermissionRequest create(Source source);\n    }\n\n    private Source mSource;\n\n    public Runtime(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String... permissions) {\n        checkPermissions(permissions);\n        return FACTORY.create(mSource).permission(permissions);\n    }\n\n    @Override\n    public PermissionRequest permission(@NonNull String[]... groups) {\n        List<String> permissionList = new ArrayList<>();\n        for (String[] group : groups) {\n            checkPermissions(group);\n            permissionList.addAll(Arrays.asList(group));\n        }\n        String[] permissions = permissionList.toArray(new String[0]);\n        return permission(permissions);\n    }\n\n    @Override\n    public SettingRequest setting() {\n        return new AllRequest(mSource);\n    }\n\n    /**\n     * Check if the permissions are valid and each permission has been registered in manifest.xml. This method will\n     * throw a exception if permissions are invalid or there is any permission which is not registered in manifest.xml.\n     *\n     * @param permissions permissions which will be checked.\n     */\n    private void checkPermissions(String... permissions) {\n        if (sAppPermissions == null) {\n            sAppPermissions = new ArrayList<>(getManifestPermissions(mSource.getContext()));\n            if (sAppPermissions.contains(ADD_VOICEMAIL_MANIFEST)) {\n                sAppPermissions.add(Permission.ADD_VOICEMAIL);\n            }\n        }\n\n        if (permissions.length == 0) {\n            throw new IllegalArgumentException(\"Please enter at least one permission.\");\n        }\n\n        for (String target : permissions) {\n            if (!sAppPermissions.contains(target)) {\n                throw new IllegalStateException(String.format(\"The permission %1$s is not registered in manifest.xml\", target));\n            }\n        }\n    }\n\n    /**\n     * Get a list of permissions in the manifest.\n     */\n    public static List<String> getManifestPermissions(Context context) {\n        try {\n            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);\n            String[] permissions = packageInfo.requestedPermissions;\n            if (permissions == null || permissions.length == 0) {\n                throw new IllegalStateException(\"You did not register any permissions in the manifest.xml.\");\n            }\n            return Arrays.asList(permissions);\n        } catch (PackageManager.NameNotFoundException e) {\n            throw new AssertionError(\"Package name cannot be found.\");\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/option/RuntimeOption.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime.option;\n\nimport androidx.annotation.NonNull;\n\nimport com.yanzhenjie.permission.runtime.Permission;\nimport com.yanzhenjie.permission.runtime.PermissionDef;\nimport com.yanzhenjie.permission.runtime.PermissionRequest;\nimport com.yanzhenjie.permission.runtime.setting.SettingRequest;\n\n/**\n * Created by Zhenjie Yan on 2/22/19.\n */\npublic interface RuntimeOption {\n\n    /**\n     * One or more permissions.\n     */\n    PermissionRequest permission(@NonNull @PermissionDef String... permissions);\n\n    /**\n     * One or more permission groups.\n     *\n     * @param groups use constants in {@link Permission.Group}.\n     */\n    PermissionRequest permission(@NonNull String[]... groups);\n\n    /**\n     * Permission settings.\n     */\n    SettingRequest setting();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/setting/AllRequest.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime.setting;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * <p>SettingRequest executor.</p>\n * Created by Zhenjie Yan on 2016/12/28.\n */\npublic class AllRequest implements SettingRequest {\n\n    private Source mSource;\n\n    public AllRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public void start(int requestCode) {\n        SettingPage setting = new SettingPage(mSource);\n        setting.start(requestCode);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/setting/SettingPage.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime.setting;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.Settings;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/4/30.\n */\npublic class SettingPage {\n\n    private static final String MARK = Build.MANUFACTURER.toLowerCase();\n\n    private Source mSource;\n\n    public SettingPage(Source source) {\n        this.mSource = source;\n    }\n\n    /**\n     * Start.\n     *\n     * @param requestCode this code will be returned in onActivityResult() when the activity exits.\n     */\n    public void start(int requestCode) {\n        Intent intent;\n        if (MARK.contains(\"huawei\")) {\n            intent = huaweiApi(mSource.getContext());\n        } else if (MARK.contains(\"xiaomi\")) {\n            intent = xiaomiApi(mSource.getContext());\n        } else if (MARK.contains(\"oppo\")) {\n            intent = oppoApi(mSource.getContext());\n        } else if (MARK.contains(\"vivo\")) {\n            intent = vivoApi(mSource.getContext());\n        } else if (MARK.contains(\"meizu\")) {\n            intent = meizuApi(mSource.getContext());\n        } else {\n            intent = defaultApi(mSource.getContext());\n        }\n        try {\n            mSource.startActivityForResult(intent, requestCode);\n        } catch (Exception e) {\n            intent = defaultApi(mSource.getContext());\n            mSource.startActivityForResult(intent, requestCode);\n        }\n    }\n\n    private static Intent defaultApi(Context context) {\n        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);\n        intent.setData(Uri.fromParts(\"package\", context.getPackageName(), null));\n        return intent;\n    }\n\n    private static Intent huaweiApi(Context context) {\n        Intent intent = new Intent();\n        intent.setClassName(\"com.huawei.systemmanager\", \"com.huawei.permissionmanager.ui.MainActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static Intent xiaomiApi(Context context) {\n        Intent intent = new Intent(\"miui.intent.action.APP_PERM_EDITOR\");\n        intent.putExtra(\"extra_pkgname\", context.getPackageName());\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.miui.securitycenter\", \"com.miui.permcenter.permissions.AppPermissionsEditorActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.miui.securitycenter\", \"com.miui.permcenter.permissions.PermissionsEditorActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static Intent vivoApi(Context context) {\n        Intent intent = new Intent();\n        intent.putExtra(\"packagename\", context.getPackageName());\n        intent.setClassName(\"com.vivo.permissionmanager\", \"com.vivo.permissionmanager.activity.SoftPermissionDetailActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.iqoo.secure\", \"com.iqoo.secure.safeguard.SoftPermissionDetailActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static Intent oppoApi(Context context) {\n        Intent intent = new Intent();\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setClassName(\"com.color.safecenter\", \"com.color.safecenter.permission.PermissionManagerActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        intent.setClassName(\"com.oppo.safe\", \"com.oppo.safe.permission.PermissionAppListActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static Intent meizuApi(Context context) {\n        Intent intent = new Intent(\"com.meizu.safe.security.SHOW_APPSEC\");\n        intent.putExtra(\"packageName\", context.getPackageName());\n        intent.setClassName(\"com.meizu.safe\", \"com.meizu.safe.security.AppSecActivity\");\n        if (hasActivity(context, intent)) return intent;\n\n        return defaultApi(context);\n    }\n\n    private static boolean hasActivity(Context context, Intent intent) {\n        PackageManager packageManager = context.getPackageManager();\n        return packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/runtime/setting/SettingRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.runtime.setting;\n\n/**\n * Created by Zhenjie Yan on 2018/4/30.\n */\npublic interface SettingRequest {\n\n    /**\n     * Start the setup.\n     */\n    void start(int requestCode);\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/Setting.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting;\n\nimport android.os.Build;\n\nimport com.yanzhenjie.permission.setting.write.LWriteRequestFactory;\nimport com.yanzhenjie.permission.setting.write.MWriteRequestFactory;\nimport com.yanzhenjie.permission.setting.write.WriteRequest;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class Setting {\n\n    private static final SettingRequestFactory SETTING_REQUEST_FACTORY;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            SETTING_REQUEST_FACTORY = new MWriteRequestFactory();\n        } else {\n            SETTING_REQUEST_FACTORY = new LWriteRequestFactory();\n        }\n    }\n\n    public interface SettingRequestFactory {\n\n        WriteRequest create(Source source);\n    }\n\n    private Source mSource;\n\n    public Setting(Source source) {\n        this.mSource = source;\n    }\n\n    /**\n     * Handle write system settings.\n     */\n    public WriteRequest write() {\n        return SETTING_REQUEST_FACTORY.create(mSource);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/BaseRequest.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport android.content.Context;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 2018/6/1.\n */\nabstract class BaseRequest implements WriteRequest {\n\n    private Source mSource;\n\n    private Rationale<Void> mRationale = new Rationale<Void>() {\n        @Override\n        public void showRationale(Context context, Void data, RequestExecutor executor) {\n            executor.execute();\n        }\n    };\n    private Action<Void> mGranted;\n    private Action<Void> mDenied;\n\n    BaseRequest(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public final WriteRequest rationale(Rationale<Void> rationale) {\n        this.mRationale = rationale;\n        return this;\n    }\n\n    @Override\n    public final WriteRequest onGranted(Action<Void> granted) {\n        this.mGranted = granted;\n        return this;\n    }\n\n    @Override\n    public final WriteRequest onDenied(Action<Void> denied) {\n        this.mDenied = denied;\n        return this;\n    }\n\n    /**\n     * Why permissions are required.\n     */\n    final void showRationale(RequestExecutor executor) {\n        mRationale.showRationale(mSource.getContext(), null, executor);\n    }\n\n    /**\n     * Callback acceptance status.\n     */\n    final void callbackSucceed() {\n        if (mGranted != null) {\n            mGranted.onAction(null);\n        }\n    }\n\n    /**\n     * Callback rejected state.\n     */\n    final void callbackFailed() {\n        if (mDenied != null) {\n            mDenied.onAction(null);\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/LWriteRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class LWriteRequest extends BaseRequest {\n\n    public LWriteRequest(Source source) {\n        super(source);\n    }\n\n    @Override\n    public void start() {\n        callbackSucceed();\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/LWriteRequestFactory.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport com.yanzhenjie.permission.setting.Setting;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class LWriteRequestFactory implements Setting.SettingRequestFactory {\n\n    @Override\n    public WriteRequest create(Source source) {\n        return new LWriteRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/MWriteRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.bridge.BridgeRequest;\nimport com.yanzhenjie.permission.bridge.RequestManager;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class MWriteRequest extends BaseRequest implements RequestExecutor, BridgeRequest.Callback {\n\n    private Source mSource;\n\n    public MWriteRequest(Source source) {\n        super(source);\n        this.mSource = source;\n    }\n\n    @Override\n    public void start() {\n        if (mSource.canWriteSetting()) {\n            callbackSucceed();\n        } else {\n            showRationale(this);\n        }\n    }\n\n    @Override\n    public void execute() {\n        BridgeRequest request = new BridgeRequest(mSource);\n        request.setType(BridgeRequest.TYPE_WRITE_SETTING);\n        request.setCallback(this);\n        RequestManager.get().add(request);\n    }\n\n    @Override\n    public void cancel() {\n        callbackFailed();\n    }\n\n    @Override\n    public void onCallback() {\n        if (mSource.canWriteSetting()) {\n            callbackSucceed();\n        } else {\n            callbackFailed();\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/MWriteRequestFactory.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport com.yanzhenjie.permission.setting.Setting;\nimport com.yanzhenjie.permission.source.Source;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class MWriteRequestFactory implements Setting.SettingRequestFactory {\n\n    @Override\n    public WriteRequest create(Source source) {\n        return new MWriteRequest(source);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/setting/write/WriteRequest.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.setting.write;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.Rationale;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic interface WriteRequest {\n\n    /**\n     * Set request rationale.\n     */\n    WriteRequest rationale(Rationale<Void> rationale);\n\n    /**\n     * Action to be taken when all permissions are granted.\n     */\n    WriteRequest onGranted(Action<Void> granted);\n\n    /**\n     * Action to be taken when all permissions are denied.\n     */\n    WriteRequest onDenied(Action<Void> denied);\n\n    /**\n     * Start install.\n     */\n    void start();\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/ActivitySource.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\n/**\n * <p>Context Wrapper.</p>\n * Created by Zhenjie Yan on 2017/5/1.\n */\npublic class ActivitySource extends Source {\n\n    private Activity mActivity;\n\n    public ActivitySource(Activity activity) {\n        this.mActivity = activity;\n    }\n\n    @Override\n    public Context getContext() {\n        return mActivity;\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        mActivity.startActivity(intent);\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        mActivity.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    public boolean isShowRationalePermission(String permission) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;\n\n        return mActivity.shouldShowRequestPermissionRationale(permission);\n    }\n}\n"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/ContextSource.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport java.lang.reflect.Method;\n\n/**\n * <p>Context Wrapper.</p>\n * Created by Zhenjie Yan on 2017/5/1.\n */\npublic class ContextSource extends Source {\n\n    private Context mContext;\n\n    public ContextSource(Context context) {\n        this.mContext = context;\n    }\n\n    @Override\n    public Context getContext() {\n        return mContext;\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        mContext.startActivity(intent);\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        throw new UnsupportedOperationException(\"Unsupported operation.\");\n    }\n\n    @Override\n    public boolean isShowRationalePermission(String permission) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;\n\n        PackageManager packageManager = mContext.getPackageManager();\n        Class<?> pkManagerClass = packageManager.getClass();\n        try {\n            Method method = pkManagerClass.getMethod(\"shouldShowRequestPermissionRationale\", String.class);\n            if (!method.isAccessible()) method.setAccessible(true);\n            return (boolean)method.invoke(packageManager, permission);\n        } catch (Exception ignored) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/FragmentSource.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.app.Fragment;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\n/**\n * <p>android.app.Fragment Wrapper.</p>\n * Created by Zhenjie Yan on 2017/5/1.\n */\npublic class FragmentSource extends Source {\n\n    private Fragment mFragment;\n\n    public FragmentSource(Fragment fragment) {\n        this.mFragment = fragment;\n    }\n\n    @Override\n    public Context getContext() {\n        return mFragment.getActivity();\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        mFragment.startActivity(intent);\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        mFragment.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    public boolean isShowRationalePermission(String permission) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;\n        return mFragment.shouldShowRequestPermissionRationale(permission);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/Source.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.app.AppOpsManager;\nimport android.app.NotificationManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.provider.Settings;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\n/**\n * <p>The source of the request.</p>\n * Created by Zhenjie Yan on 2017/5/1.\n */\npublic abstract class Source {\n\n    private static final int MODE_ASK = 4;\n    private static final int MODE_COMPAT = 5;\n\n    private static final String CHECK_OP_NO_THROW = \"checkOpNoThrow\";\n    private static final String OP_REQUEST_INSTALL_PACKAGES = \"OP_REQUEST_INSTALL_PACKAGES\";\n    private static final String OP_SYSTEM_ALERT_WINDOW = \"OP_SYSTEM_ALERT_WINDOW\";\n    private static final String OP_POST_NOTIFICATION = \"OP_POST_NOTIFICATION\";\n    private static final String OP_ACCESS_NOTIFICATIONS = \"OP_ACCESS_NOTIFICATIONS\";\n    private static final String OP_WRITE_SETTINGS = \"OP_WRITE_SETTINGS\";\n\n    private int mTargetSdkVersion;\n    private String mPackageName;\n    private PackageManager mPackageManager;\n    private AppOpsManager mAppOpsManager;\n    private NotificationManager mNotificationManager;\n\n    public abstract Context getContext();\n\n    public abstract void startActivity(Intent intent);\n\n    public abstract void startActivityForResult(Intent intent, int requestCode);\n\n    public abstract boolean isShowRationalePermission(String permission);\n\n    public int getTargetSdkVersion() {\n        if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            mTargetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;\n        }\n        return mTargetSdkVersion;\n    }\n\n    public String getPackageName() {\n        if (mPackageName == null) {\n            mPackageName = getContext().getApplicationContext().getPackageName();\n        }\n        return mPackageName;\n    }\n\n    private PackageManager getPackageManager() {\n        if (mPackageManager == null) {\n            mPackageManager = getContext().getPackageManager();\n        }\n        return mPackageManager;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.KITKAT)\n    private AppOpsManager getAppOpsManager() {\n        if (mAppOpsManager == null) {\n            mAppOpsManager = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);\n        }\n        return mAppOpsManager;\n    }\n\n    private NotificationManager getNotificationManager() {\n        if (mNotificationManager == null) {\n            mNotificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);\n        }\n        return mNotificationManager;\n    }\n\n    public final boolean canRequestPackageInstalls() {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return true;\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            if (getTargetSdkVersion() < Build.VERSION_CODES.O) {\n                return reflectionOps(OP_REQUEST_INSTALL_PACKAGES);\n            }\n            return getPackageManager().canRequestPackageInstalls();\n        }\n        return true;\n    }\n\n    public final boolean canDrawOverlays() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            Context context = getContext();\n            if (getTargetSdkVersion() >= Build.VERSION_CODES.M) {\n                return Settings.canDrawOverlays(context);\n            }\n\n            return reflectionOps(OP_SYSTEM_ALERT_WINDOW);\n        }\n        return true;\n    }\n\n    public final boolean canNotify() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return getNotificationManager().areNotificationsEnabled();\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            return reflectionOps(OP_POST_NOTIFICATION);\n        } else {\n            return true;\n        }\n    }\n\n    public final boolean canListenerNotification() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            return reflectionOps(OP_ACCESS_NOTIFICATIONS);\n        }\n\n        Context context = getContext();\n        String flat = Settings.Secure.getString(context.getContentResolver(), \"enabled_notification_listeners\");\n        return flat != null && flat.contains(getPackageName());\n    }\n\n    public final boolean canWriteSetting() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            Context context = getContext();\n            if (getTargetSdkVersion() >= Build.VERSION_CODES.M) {\n                return Settings.System.canWrite(context);\n            }\n\n            return reflectionOps(OP_WRITE_SETTINGS);\n        }\n        return true;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.KITKAT)\n    private boolean reflectionOps(String opFieldName) {\n        int uid = getContext().getApplicationInfo().uid;\n        try {\n            Class<AppOpsManager> appOpsClass = AppOpsManager.class;\n            Method method = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);\n            Field opField = appOpsClass.getDeclaredField(opFieldName);\n            int opValue = (int) opField.get(Integer.class);\n            int result = (int) method.invoke(getAppOpsManager(), opValue, uid, getPackageName());\n            return result == AppOpsManager.MODE_ALLOWED || result == MODE_ASK || result == MODE_COMPAT;\n        } catch (Throwable e) {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/WrapperSource.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Created by Zhenjie Yan on 2/22/19.\n */\npublic class WrapperSource extends Source {\n\n    private Source mSource;\n\n    public WrapperSource(Source source) {\n        this.mSource = source;\n    }\n\n    @Override\n    public Context getContext() {\n        return mSource.getContext();\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        mSource.startActivity(intent);\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        mSource.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    public boolean isShowRationalePermission(String permission) {\n        return mSource.isShowRationalePermission(permission);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/source/XFragmentSource.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.source;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\nimport androidx.fragment.app.Fragment;\n\n/**\n * <p>android.support.v4.app.Fragment Wrapper.</p>\n * Created by Zhenjie Yan on 2017/5/1.\n */\npublic class XFragmentSource extends Source {\n\n    private Fragment mFragment;\n\n    public XFragmentSource(Fragment fragment) {\n        this.mFragment = fragment;\n    }\n\n    @Override\n    public Context getContext() {\n        return mFragment.getContext();\n    }\n\n    @Override\n    public void startActivity(Intent intent) {\n        mFragment.startActivity(intent);\n    }\n\n    @Override\n    public void startActivityForResult(Intent intent, int requestCode) {\n        mFragment.startActivityForResult(intent, requestCode);\n    }\n\n    @Override\n    public boolean isShowRationalePermission(String permission) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;\n        return mFragment.shouldShowRequestPermissionRationale(permission);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/task/TaskExecutor.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.task;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.os.AsyncTask;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\n\n/**\n * Created by Zhenjie Yan on 2019-09-23.\n */\npublic abstract class TaskExecutor<T> extends AsyncTask<Void, Void, T> {\n\n    private static Executor sExecutor = Executors.newSingleThreadExecutor();\n\n    private Dialog mDialog;\n\n    public TaskExecutor(Context context) {\n        this.mDialog = new WaitDialog(context);\n        this.mDialog.setCancelable(false);\n    }\n\n    @Override\n    protected final void onPreExecute() {\n        if (!mDialog.isShowing()) {\n            mDialog.show();\n        }\n    }\n\n    @Override\n    protected final void onPostExecute(T t) {\n        if (mDialog.isShowing()) {\n            mDialog.dismiss();\n        }\n        onFinish(t);\n    }\n\n    protected abstract void onFinish(T t);\n\n    /**\n     * Just call this method.\n     */\n    public final void execute() {\n        executeOnExecutor(sExecutor);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/task/WaitDialog.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.task;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatDialog;\n\nimport com.yanzhenjie.permission.R;\n\n/**\n * Created by Zhenjie Yan on 2019-09-23.\n */\npublic class WaitDialog extends AppCompatDialog {\n\n    public WaitDialog(@NonNull Context context) {\n        super(context, R.style.Permission_Theme_Dialog_Wait);\n        setContentView(R.layout.permission_dialog_wait);\n    }\n}"
  },
  {
    "path": "permission/src/main/java/com/yanzhenjie/permission/util/StringUtils.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.util;\n\n/**\n * Created Zhenjie Yan on 2019-10-02.\n */\npublic class StringUtils {\n\n    private static final String DIGITS_TEXT = \"0123456789ABCDEF\";\n    private static final char[] DIGITS_ARRAY = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n\n    public static String textToHex(String text) {\n        StringBuilder builder = new StringBuilder();\n        byte[] textBytes = text.getBytes();\n        int bit;\n\n        for (int i = 0; i < textBytes.length; i++) {\n            bit = (textBytes[i] & 0x0f0) >> 4;\n            builder.append(DIGITS_ARRAY[bit]);\n            bit = textBytes[i] & 0x0f;\n            builder.append(DIGITS_ARRAY[bit]);\n        }\n        return builder.toString().trim();\n    }\n\n    public static String hexToText(String hexText) {\n        char[] hexArray = hexText.toCharArray();\n        byte[] hexBytes = new byte[hexText.length() / 2];\n        for (int i = 0; i < hexBytes.length; i++) {\n            int n = DIGITS_TEXT.indexOf(hexArray[2 * i]) * 16;\n            n += DIGITS_TEXT.indexOf(hexArray[2 * i + 1]);\n            hexBytes[i] = (byte) (n & 0xff);\n        }\n        return new String(hexBytes);\n    }\n}\n"
  },
  {
    "path": "permission/src/main/res/drawable/permission_shape_wait_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2019 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <corners android:radius=\"@dimen/permission_dp_3\" />\n\n    <solid android:color=\"@android:color/background_dark\" />\n\n</shape>"
  },
  {
    "path": "permission/src/main/res/layout/permission_dialog_wait.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Permission.MatchParent\"\n    android:gravity=\"center\"\n    android:paddingStart=\"@dimen/permission_dp_20\"\n    android:paddingTop=\"@dimen/permission_dp_5\"\n    android:paddingEnd=\"@dimen/permission_dp_20\"\n    android:paddingBottom=\"@dimen/permission_dp_5\"\n    tools:background=\"@android:color/background_dark\">\n\n    <ProgressBar\n        style=\"@style/Permission.Widget.Progress.Wait\"\n        android:layout_width=\"@dimen/permission_dp_30\"\n        android:layout_height=\"@dimen/permission_dp_30\" />\n\n    <TextView\n        style=\"@style/Permission.WrapContent\"\n        android:layout_marginStart=\"@dimen/permission_dp_10\"\n        android:layout_marginLeft=\"@dimen/permission_dp_10\"\n        android:text=\"@string/permission_requesting\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"@dimen/permission_sp_16\" />\n\n</LinearLayout>"
  },
  {
    "path": "permission/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <dimen name=\"permission_dp_3\">3dp</dimen>\n    <dimen name=\"permission_dp_5\">5dp</dimen>\n    <dimen name=\"permission_dp_10\">10dp</dimen>\n    <dimen name=\"permission_dp_15\">15dp</dimen>\n    <dimen name=\"permission_dp_20\">20dp</dimen>\n    <dimen name=\"permission_dp_25\">25dp</dimen>\n    <dimen name=\"permission_dp_30\">30dp</dimen>\n    <dimen name=\"permission_dp_35\">35dp</dimen>\n    <dimen name=\"permission_dp_40\">40dp</dimen>\n\n    <dimen name=\"permission_sp_12\">12sp</dimen>\n    <dimen name=\"permission_sp_14\">14sp</dimen>\n    <dimen name=\"permission_sp_16\">16sp</dimen>\n    <dimen name=\"permission_sp_18\">18sp</dimen>\n    <dimen name=\"permission_sp_20\">20sp</dimen>\n\n</resources>"
  },
  {
    "path": "permission/src/main/res/values/string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"permission_name_calendar\">Calendar</string>\n    <string name=\"permission_name_camera\">Camera</string>\n    <string name=\"permission_name_contacts\">Accounts/Contacts</string>\n    <string name=\"permission_name_location\">Location</string>\n    <string name=\"permission_name_microphone\">Microphone</string>\n    <string name=\"permission_name_phone\">Phone</string>\n    <string name=\"permission_name_call_log\">Call Log</string>\n    <string name=\"permission_name_sensors\">Body Sensors</string>\n    <string name=\"permission_name_activity_recognition\">Activity Recognition</string>\n    <string name=\"permission_name_sms\">SMS</string>\n    <string name=\"permission_name_storage\">Storage</string>\n\n    <string name=\"permission_requesting\">Requesting permissions…</string>\n</resources>"
  },
  {
    "path": "permission/src/main/res/values/style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2019 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <style name=\"Permission\" />\n\n    <style name=\"Permission.Theme\" />\n\n    <style name=\"Permission.Theme.Activity\">\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowDisablePreview\">true</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:backgroundDimEnabled\">false</item>\n    </style>\n\n    <style name=\"Permission.Theme.Activity.Transparent\">\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n    </style>\n\n    <style name=\"Permission.Theme.Dialog\" parent=\"android:Theme.Holo.Dialog.NoActionBar\" />\n\n    <style name=\"Permission.Theme.Dialog.Wait\">\n        <item name=\"android:backgroundDimEnabled\">false</item>\n        <item name=\"android:windowBackground\">@drawable/permission_shape_wait_background</item>\n        <item name=\"android:windowCloseOnTouchOutside\">false</item>\n    </style>\n\n    <style name=\"Permission.Theme.Dialog.Transparent\">\n        <item name=\"android:backgroundDimEnabled\">false</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowCloseOnTouchOutside\">false</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n    </style>\n\n    <style name=\"Permission.Widget\" />\n\n    <style name=\"Permission.Widget.Progress\" parent=\"@android:style/Widget.Holo.ProgressBar\" />\n\n    <style name=\"Permission.Widget.Progress.Wait\">\n        <item name=\"android:indeterminateOnly\">true</item>\n    </style>\n\n    <style name=\"Permission.WrapContent\">\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n    </style>\n\n    <style name=\"Permission.MatchParent\">\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:layout_width\">match_parent</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "permission/src/main/res/values-v21/style.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2019 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <style name=\"Permission.Theme.Activity.Transparent\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n    </style>\n\n    <style name=\"Permission.Theme.Dialog\" parent=\"android:Theme.Material.Dialog.NoActionBar\" />\n\n    <style name=\"Permission.Widget.Progress\" parent=\"@android:style/Widget.Material.ProgressBar\" />\n\n    <style name=\"Permission.Widget.Progress.Wait\">\n        <item name=\"android:indeterminateOnly\">true</item>\n        <item name=\"android:indeterminateTint\">@android:color/white</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "permission/src/main/res/values-zh/string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"permission_name_calendar\">日历</string>\n    <string name=\"permission_name_camera\">相机</string>\n    <string name=\"permission_name_contacts\">手机账号/通讯录</string>\n    <string name=\"permission_name_location\">位置信息</string>\n    <string name=\"permission_name_microphone\">麦克风</string>\n    <string name=\"permission_name_phone\">电话</string>\n    <string name=\"permission_name_call_log\">通话记录</string>\n    <string name=\"permission_name_sensors\">身体传感器</string>\n    <string name=\"permission_name_activity_recognition\">健身运动</string>\n    <string name=\"permission_name_sms\">短信</string>\n    <string name=\"permission_name_storage\">存储空间</string>\n\n    <string name=\"permission_requesting\">正在请求授权…</string>\n</resources>"
  },
  {
    "path": "permission/src/main/res/values-zh-RHK/string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"permission_name_calendar\">日曆</string>\n    <string name=\"permission_name_camera\">相機</string>\n    <string name=\"permission_name_contacts\">手機賬號/通訊錄</string>\n    <string name=\"permission_name_location\">位置信息</string>\n    <string name=\"permission_name_microphone\">麥克風</string>\n    <string name=\"permission_name_phone\">電話</string>\n    <string name=\"permission_name_call_log\">通話記錄</string>\n    <string name=\"permission_name_sensors\">身體傳感器</string>\n    <string name=\"permission_name_activity_recognition\">健身運動</string>\n    <string name=\"permission_name_sms\">短訊</string>\n    <string name=\"permission_name_storage\">存儲空間</string>\n\n    <string name=\"permission_requesting\">正在請求授權…</string>\n</resources>"
  },
  {
    "path": "permission/src/main/res/values-zh-RTW/string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"permission_name_calendar\">日曆</string>\n    <string name=\"permission_name_camera\">相機</string>\n    <string name=\"permission_name_contacts\">手機賬號/通訊錄</string>\n    <string name=\"permission_name_location\">位置信息</string>\n    <string name=\"permission_name_microphone\">麥克風</string>\n    <string name=\"permission_name_phone\">電話</string>\n    <string name=\"permission_name_call_log\">通話記錄</string>\n    <string name=\"permission_name_sensors\">身體感測器</string>\n    <string name=\"permission_name_activity_recognition\">健身運動</string>\n    <string name=\"permission_name_sms\">簡訊</string>\n    <string name=\"permission_name_storage\">存儲空間</string>\n\n    <string name=\"permission_requesting\">正在請求授權…</string>\n</resources>"
  },
  {
    "path": "permission/src/main/res/xml/permission_file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n    Copyright 2018 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<paths>\n    <root-path\n        name=\"root_path\"\n        path=\".\" />\n\n    <files-path\n        name=\"file_path\"\n        path=\".\" />\n\n    <cache-path\n        name=\"cache_path\"\n        path=\".\" />\n\n    <external-path\n        name=\"external_path\"\n        path=\".\" />\n\n    <external-files-path\n        name=\"external_files_path\"\n        path=\".\" />\n\n    <external-cache-path\n        name=\"external_cache_path\"\n        path=\".\" />\n\n    <external-media-path\n        name=\"external_media_path\"\n        path=\".\" />\n</paths>"
  },
  {
    "path": "sample/.gitignore",
    "content": "/build"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: rootProject.ext.plugins.application\n\nandroid {\n    compileSdkVersion rootProject.ext.android.compileSdkVersion\n    buildToolsVersion rootProject.ext.android.buildToolsVersion\n\n    defaultConfig {\n        applicationId rootProject.ext.android.applicationId\n        minSdkVersion rootProject.ext.android.minSdkVersion\n        targetSdkVersion rootProject.ext.android.targetSdkVersion\n        versionCode rootProject.ext.android.versionCode\n        versionName rootProject.ext.android.versionName\n    }\n}\n\ndependencies {\n    implementation project(':permission')\n\n    implementation rootProject.ext.dependencies.fragment\n}"
  },
  {
    "path": "sample/proguard-rules.pro",
    "content": "-optimizationpasses 5\n-ignorewarnings\n-dontusemixedcaseclassnames\n-dontskipnonpubliclibraryclasses\n-dontskipnonpubliclibraryclassmembers\n-useuniqueclassmembernames\n-allowaccessmodification\n-dontpreverify\n-verbose\n-dontoptimize\n-renamesourcefileattribute SourceFile\n-keepattributes SourceFile,LineNumberTable\n-keepattributes Signature\n-keepattributes *Annotation*\n-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*\n-keepclassmembers class * extends android.app.Activity {\n   public void *(android.view.View);\n}\n-keepclassmembers enum * {\n  public static **[] values();\n  public static ** valueOf(java.lang.String);\n}\n-keep public class **.R$*{\n    public static final int *;\n}\n-keepclassmembers class **.R$* {\n    public static <fields>;\n}\n-keepclassmembers class * {\n    native <methods>;\n}\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context);\n    public <init>(android.content.Context, android.util.AttributeSet);\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n    public void set*(***);\n    public *** set*(***);\n    public *** get*(***);\n    public *** get*();\n}\n-keep class android.support.annotation.Keep\n-keep @android.support.annotation.Keep class * {*;}\n-keepclasseswithmembers class * {\n    @android.support.annotation.Keep <methods>;\n}\n-keepclasseswithmembers class * {\n    @android.support.annotation.Keep <fields>;\n}\n-keepclasseswithmembers class * {\n    @android.support.annotation.Keep <init>(...);\n}\n-keep public class * implements android.os.Parcelable{*;}\n-keepclasseswithmembers class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n-keep public class android.support.v7.widget.SearchView{*;}\n-keep public class * extends android.support.v4.view.ActionProvider{*;}"
  },
  {
    "path": "sample/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.yanzhenjie.permission.sample\">\n\n    <uses-permission android:name=\"android.permission.READ_CALENDAR\" />\n    <uses-permission android:name=\"android.permission.WRITE_CALENDAR\" />\n\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.WRITE_CONTACTS\" />\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" />\n\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission android:name=\"android.permission.CALL_PHONE\" />\n    <uses-permission android:name=\"android.permission.ADD_VOICEMAIL\" />\n    <uses-permission android:name=\"android.permission.USE_SIP\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_NUMBERS\" />\n    <uses-permission android:name=\"android.permission.ANSWER_PHONE_CALLS\" />\n\n    <uses-permission android:name=\"android.permission.READ_CALL_LOG\" />\n    <uses-permission android:name=\"android.permission.WRITE_CALL_LOG\" />\n    <uses-permission android:name=\"android.permission.PROCESS_OUTGOING_CALLS\" />\n\n    <uses-permission android:name=\"android.permission.BODY_SENSORS\" />\n    <uses-permission android:name=\"android.permission.ACTIVITY_RECOGNITION\" />\n\n    <uses-permission android:name=\"android.permission.SEND_SMS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_SMS\" />\n    <uses-permission android:name=\"android.permission.READ_SMS\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_WAP_PUSH\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_MMS\" />\n\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" />\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />\n\n    <uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />\n\n    <application\n        android:name=\".App\"\n        android:allowBackup=\"false\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"false\"\n        android:theme=\"@style/Permission.Theme.Sample\">\n\n        <activity\n            android:name=\".app.MainActivity\"\n            android:configChanges=\"orientation\"\n            android:label=\"@string/app_name\"\n            android:theme=\"@style/Permission.Theme.Sample.Activity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\".app.NotifyListenerService\"\n            android:label=\"@string/app_name\"\n            android:permission=\"android.permission.BIND_NOTIFICATION_LISTENER_SERVICE\">\n            <intent-filter>\n                <action android:name=\"android.service.notification.NotificationListenerService\" />\n            </intent-filter>\n        </service>\n    </application>\n\n</manifest>"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/App.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.Application;\nimport android.view.View;\n\nimport com.yanzhenjie.permission.sample.widget.AlertWindow;\nimport com.yanzhenjie.permission.sample.widget.LauncherView;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class App extends Application {\n\n    private static App _instance;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        _instance = this;\n    }\n\n    public static App get() {\n        return _instance;\n    }\n\n    public void showLauncherView() {\n        final AlertWindow alertWindow = new AlertWindow(this);\n        LauncherView view = new LauncherView(this);\n        view.setCancelClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                alertWindow.dismiss();\n            }\n        });\n        alertWindow.setContentView(view);\n        alertWindow.show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/InstallRationale.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\nimport java.io.File;\n\n/**\n * Created by Zhenjie Yan on 2018/4/29.\n */\npublic class InstallRationale implements Rationale<File> {\n\n    @Override\n    public void showRationale(Context context, File data, final RequestExecutor executor) {\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(R.string.message_install_failed)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/NotifyListenerRationale.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class NotifyListenerRationale implements Rationale<Void> {\n\n    @Override\n    public void showRationale(Context context, Void data, final RequestExecutor executor) {\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(R.string.message_notification_listener_rationale)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/NotifyRationale.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class NotifyRationale implements Rationale<Void> {\n\n    @Override\n    public void showRationale(Context context, Void data, final RequestExecutor executor) {\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(R.string.message_notification_rationale)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/OverlayRationale.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class OverlayRationale implements Rationale<Void> {\n\n    @Override\n    public void showRationale(Context context, Void data, final RequestExecutor executor) {\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(R.string.message_overlay_failed)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/RuntimeRationale.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.text.TextUtils;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\nimport com.yanzhenjie.permission.runtime.Permission;\n\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2018/1/1.\n */\npublic final class RuntimeRationale implements Rationale<List<String>> {\n\n    @Override\n    public void showRationale(Context context, List<String> permissions, final RequestExecutor executor) {\n        List<String> permissionNames = Permission.transformText(context, permissions);\n        String message = context.getString(R.string.message_permission_rationale,\n            TextUtils.join(\"\\n\", permissionNames));\n\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(message)\n            .setPositiveButton(R.string.resume, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/WriteSettingRationale.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\n\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\n/**\n * Created by Zhenjie Yan on 3/1/19.\n */\npublic class WriteSettingRationale implements Rationale<Void> {\n\n    @Override\n    public void showRationale(Context context, Void data, final RequestExecutor executor) {\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(R.string.message_write_setting_failed)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.execute();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    executor.cancel();\n                }\n            })\n            .show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/app/MainActivity.java",
    "content": "/*\n * Copyright © Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.app;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.appcompat.widget.Toolbar;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.AndPermission;\nimport com.yanzhenjie.permission.runtime.Permission;\nimport com.yanzhenjie.permission.runtime.PermissionDef;\nimport com.yanzhenjie.permission.sample.App;\nimport com.yanzhenjie.permission.sample.InstallRationale;\nimport com.yanzhenjie.permission.sample.NotifyListenerRationale;\nimport com.yanzhenjie.permission.sample.NotifyRationale;\nimport com.yanzhenjie.permission.sample.OverlayRationale;\nimport com.yanzhenjie.permission.sample.R;\nimport com.yanzhenjie.permission.sample.RuntimeRationale;\nimport com.yanzhenjie.permission.sample.WriteSettingRationale;\nimport com.yanzhenjie.permission.sample.util.FileUtils;\nimport com.yanzhenjie.permission.sample.util.IOUtils;\nimport com.yanzhenjie.permission.task.TaskExecutor;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.List;\n\n/**\n * Created by Zhenjie Yan on 2016/9/17.\n */\npublic class MainActivity extends AppCompatActivity implements View.OnClickListener {\n\n    private static final int REQUEST_CODE_SETTING = 1;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        Toolbar toolbar = findViewById(R.id.toolbar);\n        setSupportActionBar(toolbar);\n\n        findViewById(R.id.btn_request_camera).setOnClickListener(this);\n        findViewById(R.id.btn_request_contact).setOnClickListener(this);\n        findViewById(R.id.btn_request_location).setOnClickListener(this);\n        findViewById(R.id.btn_request_calendar).setOnClickListener(this);\n        findViewById(R.id.btn_request_microphone).setOnClickListener(this);\n        findViewById(R.id.btn_request_storage).setOnClickListener(this);\n        findViewById(R.id.btn_request_phone).setOnClickListener(this);\n        findViewById(R.id.btn_request_call_log).setOnClickListener(this);\n        findViewById(R.id.btn_request_sensors).setOnClickListener(this);\n        findViewById(R.id.btn_request_activity_recognition).setOnClickListener(this);\n        findViewById(R.id.btn_request_sms).setOnClickListener(this);\n        findViewById(R.id.btn_setting).setOnClickListener(this);\n\n        findViewById(R.id.btn_notification).setOnClickListener(this);\n        findViewById(R.id.btn_notification_listener).setOnClickListener(this);\n\n        findViewById(R.id.btn_install).setOnClickListener(this);\n        findViewById(R.id.btn_overlay).setOnClickListener(this);\n        findViewById(R.id.btn_write_setting).setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        switch (v.getId()) {\n            case R.id.btn_request_camera: {\n                requestPermission(Permission.Group.CAMERA);\n                break;\n            }\n            case R.id.btn_request_contact: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.contacts));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getItemId();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.READ_CONTACTS);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.WRITE_CONTACTS);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.GET_ACCOUNTS);\n                                break;\n                            }\n                            case 3: {\n                                requestPermission(Permission.Group.CONTACTS);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_location: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.location));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getItemId();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.ACCESS_FINE_LOCATION);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.ACCESS_COARSE_LOCATION);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.Group.LOCATION);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_calendar: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.calendar));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getOrder();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.READ_CALENDAR);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.WRITE_CALENDAR);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.Group.CALENDAR);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_microphone: {\n                requestPermission(Permission.Group.MICROPHONE);\n                break;\n            }\n            case R.id.btn_request_storage: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.storage));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getOrder();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.READ_EXTERNAL_STORAGE);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.WRITE_EXTERNAL_STORAGE);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.Group.STORAGE);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_phone: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.phone));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getOrder();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.READ_PHONE_STATE);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.CALL_PHONE);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.READ_PHONE_NUMBERS);\n                                break;\n                            }\n                            case 3: {\n                                requestPermission(Permission.ANSWER_PHONE_CALLS);\n                                break;\n                            }\n                            case 4: {\n                                requestPermission(Permission.USE_SIP);\n                                break;\n                            }\n                            case 5: {\n                                requestPermission(Permission.ADD_VOICEMAIL);\n                                break;\n                            }\n                            case 6: {\n                                // ADD_VOICEMAIL is special, not shown here.\n                                requestPermission(Permission.READ_PHONE_STATE, Permission.CALL_PHONE, Permission.READ_PHONE_NUMBERS,\n                                    Permission.ANSWER_PHONE_CALLS, Permission.USE_SIP);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_call_log: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.call_log));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getOrder();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.READ_CALL_LOG);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.WRITE_CALL_LOG);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.PROCESS_OUTGOING_CALLS);\n                                break;\n                            }\n                            case 3: {\n                                requestPermission(Permission.Group.CALL_LOG);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_request_sensors: {\n                requestPermission(Permission.Group.SENSORS);\n                break;\n            }\n            case R.id.btn_request_activity_recognition: {\n                requestPermission(Permission.Group.ACTIVITY_RECOGNITION);\n                break;\n            }\n            case R.id.btn_request_sms: {\n                PopupMenu popupMenu = createMenu(v, getResources().getStringArray(R.array.sms));\n                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {\n                    @Override\n                    public boolean onMenuItemClick(MenuItem item) {\n                        int order = item.getOrder();\n                        switch (order) {\n                            case 0: {\n                                requestPermission(Permission.SEND_SMS);\n                                break;\n                            }\n                            case 1: {\n                                requestPermission(Permission.RECEIVE_SMS);\n                                break;\n                            }\n                            case 2: {\n                                requestPermission(Permission.READ_SMS);\n                                break;\n                            }\n                            case 3: {\n                                requestPermission(Permission.RECEIVE_WAP_PUSH);\n                                break;\n                            }\n                            case 4: {\n                                requestPermission(Permission.RECEIVE_MMS);\n                                break;\n                            }\n                            case 5: {\n                                requestPermission(Permission.Group.SMS);\n                                break;\n                            }\n                        }\n                        return true;\n                    }\n                });\n                popupMenu.show();\n                break;\n            }\n            case R.id.btn_setting: {\n                setPermission();\n                break;\n            }\n            case R.id.btn_notification: {\n                requestNotification();\n                break;\n            }\n            case R.id.btn_notification_listener: {\n                requestNotificationListener();\n                break;\n            }\n            case R.id.btn_install: {\n                requestPermissionForInstallPackage();\n                break;\n            }\n            case R.id.btn_overlay: {\n                requestPermissionForAlertWindow();\n                break;\n            }\n            case R.id.btn_write_setting: {\n                requestWriteSystemSetting();\n                break;\n            }\n        }\n    }\n\n    /**\n     * Request permissions.\n     */\n    private void requestPermission(@PermissionDef String... permissions) {\n        AndPermission.with(this)\n            .runtime()\n            .permission(permissions)\n            .rationale(new RuntimeRationale())\n            .onGranted(new Action<List<String>>() {\n                @Override\n                public void onAction(List<String> permissions) {\n                    toast(R.string.successfully);\n                }\n            })\n            .onDenied(new Action<List<String>>() {\n                @Override\n                public void onAction(@NonNull List<String> permissions) {\n                    toast(R.string.failure);\n                    if (AndPermission.hasAlwaysDeniedPermission(MainActivity.this, permissions)) {\n                        showSettingDialog(MainActivity.this, permissions);\n                    }\n                }\n            })\n            .start();\n    }\n\n    /**\n     * Display setting dialog.\n     */\n    public void showSettingDialog(Context context, final List<String> permissions) {\n        List<String> permissionNames = Permission.transformText(context, permissions);\n        String message = context.getString(R.string.message_permission_always_failed,\n            TextUtils.join(\"\\n\", permissionNames));\n\n        new AlertDialog.Builder(context).setCancelable(false)\n            .setTitle(R.string.title_dialog)\n            .setMessage(message)\n            .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                    setPermission();\n                }\n            })\n            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {\n                @Override\n                public void onClick(DialogInterface dialog, int which) {\n                }\n            })\n            .show();\n    }\n\n    /**\n     * Set permissions.\n     */\n    private void setPermission() {\n        AndPermission.with(this).runtime().setting().start(REQUEST_CODE_SETTING);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        switch (requestCode) {\n            case REQUEST_CODE_SETTING: {\n                Toast.makeText(MainActivity.this, R.string.message_setting_comeback, Toast.LENGTH_SHORT).show();\n                break;\n            }\n        }\n    }\n\n    /**\n     * Request notification permission.\n     */\n    private void requestNotification() {\n        AndPermission.with(this)\n            .notification()\n            .permission()\n            .rationale(new NotifyRationale())\n            .onGranted(new Action<Void>() {\n                @Override\n                public void onAction(Void data) {\n                    toast(R.string.successfully);\n                }\n            })\n            .onDenied(new Action<Void>() {\n                @Override\n                public void onAction(Void data) {\n                    toast(R.string.failure);\n                }\n            })\n            .start();\n    }\n\n    /**\n     * Request notification listener.\n     */\n    private void requestNotificationListener() {\n        AndPermission.with(this)\n            .notification()\n            .listener()\n            .rationale(new NotifyListenerRationale())\n            .onGranted(new Action<Void>() {\n                @Override\n                public void onAction(Void data) {\n                    toast(R.string.successfully);\n                }\n            })\n            .onDenied(new Action<Void>() {\n                @Override\n                public void onAction(Void data) {\n                    toast(R.string.failure);\n                }\n            })\n            .start();\n    }\n\n    /**\n     * Request to read and write external storage permissions.\n     */\n    private void requestPermissionForInstallPackage() {\n        if (!FileUtils.externalAvailable()) {\n            new AlertDialog.Builder(this)\n                .setTitle(R.string.title_dialog)\n                .setMessage(R.string.message_error_storeage_inavailable)\n                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        dialog.dismiss();\n                    }\n                })\n                .show();\n            return;\n        }\n\n        AndPermission.with(this)\n            .runtime()\n            .permission(Permission.Group.STORAGE)\n            .rationale(new RuntimeRationale())\n            .onGranted(new Action<List<String>>() {\n                @Override\n                public void onAction(List<String> data) {\n                    writeApkForInstallPackage();\n                }\n            })\n            .onDenied(new Action<List<String>>() {\n                @Override\n                public void onAction(List<String> data) {\n                    toast(R.string.message_install_failed);\n                }\n            })\n            .start();\n    }\n\n    private void writeApkForInstallPackage() {\n        new TaskExecutor<File>(MainActivity.this) {\n            @Override\n            protected File doInBackground(Void... voids) {\n                try {\n                    InputStream input = getAssets().open(\"android.apk\");\n                    File apk = new File(FileUtils.getExternalDir(App.get(), Environment.DIRECTORY_DOWNLOADS), \"AndPermission.apk\");\n                    if (apk.exists()) return apk;\n\n                    OutputStream output = new BufferedOutputStream(new FileOutputStream(apk));\n\n                    IOUtils.write(input, output);\n                    IOUtils.close(output);\n\n                    return apk;\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n\n                return null;\n            }\n\n            @Override\n            protected void onFinish(File apkFile) {\n                if (apkFile == null) {\n                    new AlertDialog.Builder(MainActivity.this)\n                        .setTitle(R.string.title_dialog)\n                        .setMessage(R.string.message_error_save_failed)\n                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {\n                            @Override\n                            public void onClick(DialogInterface dialog, int which) {\n                            }\n                        })\n                        .show();\n                } else {\n                    installPackage(apkFile);\n                }\n            }\n        }.execute();\n    }\n\n    /**\n     * Install package.\n     */\n    private void installPackage(File apkFile) {\n        AndPermission.with(this)\n            .install()\n            .file(apkFile)\n            .rationale(new InstallRationale())\n            .onGranted(new Action<File>() {\n                @Override\n                public void onAction(File data) {\n                    // Installing.\n                }\n            })\n            .onDenied(new Action<File>() {\n                @Override\n                public void onAction(File data) {\n                    // The user refused to install.\n                }\n            })\n            .start();\n    }\n\n    private void requestPermissionForAlertWindow() {\n        AndPermission.with(this).overlay().rationale(new OverlayRationale()).onGranted(new Action<Void>() {\n            @Override\n            public void onAction(Void data) {\n                showAlertWindow();\n            }\n        }).onDenied(new Action<Void>() {\n            @Override\n            public void onAction(Void data) {\n                toast(R.string.message_overlay_failed);\n            }\n        }).start();\n    }\n\n    private void requestWriteSystemSetting() {\n        AndPermission.with(this).setting().write().rationale(new WriteSettingRationale()).onGranted(new Action<Void>() {\n            @Override\n            public void onAction(Void data) {\n                toast(R.string.successfully);\n            }\n        }).onDenied(new Action<Void>() {\n            @Override\n            public void onAction(Void data) {\n                toast(R.string.failure);\n            }\n        }).start();\n    }\n\n    private void showAlertWindow() {\n        App.get().showLauncherView();\n\n        Intent backHome = new Intent(Intent.ACTION_MAIN);\n        backHome.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        backHome.addCategory(Intent.CATEGORY_HOME);\n        startActivity(backHome);\n    }\n\n    /**\n     * Create menu.\n     */\n    private PopupMenu createMenu(View v, String[] menuArray) {\n        PopupMenu popupMenu = new PopupMenu(this, v);\n        Menu menu = popupMenu.getMenu();\n        for (int i = 0; i < menuArray.length; i++) {\n            String menuText = menuArray[i];\n            menu.add(0, i, i, menuText);\n        }\n        return popupMenu;\n    }\n\n    protected void toast(@StringRes int message) {\n        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/app/NotifyListenerService.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.app;\n\nimport android.os.Build;\nimport android.service.notification.NotificationListenerService;\nimport android.service.notification.StatusBarNotification;\n\nimport androidx.annotation.RequiresApi;\n\n/**\n * Created by Zhenjie Yan on 2/14/19.\n */\n@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)\npublic class NotifyListenerService extends NotificationListenerService {\n\n    @Override\n    public void onNotificationPosted(StatusBarNotification sbn) {\n    }\n\n    @Override\n    public void onNotificationRemoved(StatusBarNotification sbn) {\n    }\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/util/FileUtils.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.util;\n\nimport android.content.Context;\nimport android.os.Environment;\nimport android.text.TextUtils;\n\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\n\n/**\n * Created Zhenjie Yan on 2019-10-10.\n */\npublic class FileUtils {\n\n    public static File getFileDir(Context context) {\n        return getFileDir(context, null);\n    }\n\n    public static File getFileDir(Context context, @Nullable String type) {\n        File root = context.getFilesDir();\n        if (TextUtils.isEmpty(type)) {\n            return root;\n        } else {\n            File dir = new File(root, type);\n            createDir(dir);\n            return dir;\n        }\n    }\n\n    public static boolean externalAvailable() {\n        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());\n    }\n\n    public static File getExternalDir(Context context) {\n        return getExternalDir(context, null);\n    }\n\n    public static File getExternalDir(Context context, @Nullable String type) {\n        if (externalAvailable()) {\n            if (TextUtils.isEmpty(type)) {\n                return context.getExternalFilesDir(null);\n            }\n\n            File dir = context.getExternalFilesDir(type);\n            if (dir == null) {\n                dir = context.getExternalFilesDir(null);\n                dir = new File(dir, type);\n                createDir(dir);\n            }\n\n            return dir;\n        }\n        throw new RuntimeException(\"External storage device is not available.\");\n    }\n\n    public static File getRootDir() {\n        return getRootDir(null);\n    }\n\n    public static File getRootDir(@Nullable String type) {\n        if (externalAvailable()) {\n            File root = Environment.getExternalStorageDirectory();\n            File appRoot = new File(root, \"AndPermission\");\n            createDir(appRoot);\n\n            if (TextUtils.isEmpty(type)) {\n                return appRoot;\n            }\n\n            File dir = new File(appRoot, type);\n            createDir(dir);\n\n            return dir;\n        }\n        throw new RuntimeException(\"External storage device is not available.\");\n    }\n\n    public static void createDir(File dir) {\n        if (dir.exists()) {\n            if (!dir.isDirectory()) {\n                dir.delete();\n            }\n        }\n        if (!dir.exists()) {\n            dir.mkdirs();\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/util/IOUtils.java",
    "content": "/*\n * Copyright 2019 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.util;\n\nimport java.io.Closeable;\nimport java.io.Flushable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Created Zhenjie Yan on 2019-10-10.\n */\npublic class IOUtils {\n\n    public static void write(InputStream in, OutputStream out) throws IOException {\n        byte[] buffer = new byte[2048];\n        int len;\n        while ((len = in.read(buffer)) != -1) {\n            out.write(buffer, 0, len);\n            out.flush();\n        }\n    }\n\n    public static void close(Closeable closeable) {\n        try {\n            closeable.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void flush(Flushable flushable) {\n        try {\n            flushable.flush();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/widget/AlertWindow.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.widget;\n\nimport android.content.Context;\nimport android.graphics.PixelFormat;\nimport android.os.Build;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.WindowManager;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class AlertWindow {\n\n    private Context mContext;\n    private WindowManager mWindowManager;\n    private WindowManager.LayoutParams mParams;\n    private View mContentView;\n\n    private boolean isShowing;\n\n    public AlertWindow(Context context) {\n        this.mContext = context.getApplicationContext();\n        this.create();\n    }\n\n    private void create() {\n        this.mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);\n        this.mParams = new WindowManager.LayoutParams();\n\n        mParams.packageName = mContext.getPackageName();\n        mParams.width = WindowManager.LayoutParams.MATCH_PARENT;\n        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;\n        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |\n            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |\n            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;\n\n        int overlay = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;\n        int alertWindow = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;\n        mParams.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? overlay : alertWindow;\n        mParams.format = PixelFormat.RGBA_8888;\n\n        mParams.gravity = Gravity.TOP;\n    }\n\n    /**\n     * Set the view to show.\n     *\n     * @param layoutId target layout id.\n     */\n    public void setContentView(int layoutId) {\n        setContentView(LayoutInflater.from(mContext).inflate(layoutId, null, false));\n    }\n\n    /**\n     * Set the view to show.\n     *\n     * @param view target view.\n     */\n    public void setContentView(View view) {\n        this.mContentView = view;\n        ViewGroup.LayoutParams params = view.getLayoutParams();\n        if (params == null) {\n            params = new ViewGroup.LayoutParams(-1, -2);\n        } else {\n            params.width = -1;\n            params.height = -2;\n        }\n        this.mContentView.setLayoutParams(params);\n    }\n\n    /**\n     * AlertWindow is displayed.\n     *\n     * @return true, otherwise is false.\n     */\n    public boolean isShowing() {\n        return isShowing;\n    }\n\n    /**\n     * Display the alert window.\n     */\n    public void show() {\n        if (isShowing) {\n            Log.w(\"AlertWindow\", \"AlertWindow is already displayed.\");\n        } else {\n            isShowing = true;\n            mWindowManager.addView(mContentView, mParams);\n        }\n    }\n\n    /**\n     * Dismiss the\n     */\n    public void dismiss() {\n        if (!isShowing) {\n            Log.w(\"AlertWindow\", \"AlertWindow is not displayed.\");\n        } else if (mContentView != null) {\n            isShowing = false;\n            mWindowManager.removeViewImmediate(mContentView);\n        }\n    }\n\n}"
  },
  {
    "path": "sample/src/main/java/com/yanzhenjie/permission/sample/widget/LauncherView.java",
    "content": "/*\n * Copyright 2018 Zhenjie Yan\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.yanzhenjie.permission.sample.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.RelativeLayout;\n\nimport com.yanzhenjie.permission.sample.R;\n\n/**\n * Created by Zhenjie Yan on 2018/5/30.\n */\npublic class LauncherView extends RelativeLayout implements View.OnClickListener {\n\n    private View.OnClickListener mCancelClickListener;\n\n    public LauncherView(Context context) {\n        this(context, null, 0);\n    }\n\n    public LauncherView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public LauncherView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        inflate(context, R.layout.window_launcher, this);\n        findViewById(R.id.btn_cancel).setOnClickListener(this);\n    }\n\n    @Override\n    public void onClick(View v) {\n        int id = v.getId();\n        switch (id) {\n            case R.id.btn_cancel: {\n                if (mCancelClickListener != null) {\n                    mCancelClickListener.onClick(v);\n                }\n                break;\n            }\n        }\n    }\n\n    public void setCancelClickListener(OnClickListener cancelClickListener) {\n        this.mCancelClickListener = cancelClickListener;\n    }\n}"
  },
  {
    "path": "sample/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/Permission.MatchParent\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.Toolbar\n        android:id=\"@+id/toolbar\"\n        style=\"@style/Permission.Toolbar\"\n        android:background=\"?attr/colorPrimary\" />\n\n    <TableLayout style=\"@style/Permission.MatchParent\">\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_camera\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_camera\" />\n\n            <Button\n                android:id=\"@+id/btn_request_contact\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_contact\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_location\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_location\" />\n\n            <Button\n                android:id=\"@+id/btn_request_calendar\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_calendar\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_microphone\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_microphone\" />\n\n            <Button\n                android:id=\"@+id/btn_request_storage\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_storage\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_phone\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_phone\" />\n\n            <Button\n                android:id=\"@+id/btn_request_call_log\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_call_log\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_sensors\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_sensors\" />\n\n            <Button\n                android:id=\"@+id/btn_request_activity_recognition\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_activity_recognition\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_request_sms\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_sms\" />\n\n            <Button\n                android:id=\"@+id/btn_setting\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_setting\" />\n        </TableRow>\n\n        <TableRow>\n\n            <View style=\"@style/Permission.Line\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_notification\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_notification\" />\n\n            <Button\n                android:id=\"@+id/btn_notification_listener\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_notification_listener\" />\n        </TableRow>\n\n        <TableRow>\n\n            <View style=\"@style/Permission.Line\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_install\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_install\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_overlay\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_overlay\" />\n        </TableRow>\n\n        <TableRow>\n\n            <Button\n                android:id=\"@+id/btn_write_setting\"\n                style=\"@style/Permission.Button.Weight.Horizontal\"\n                android:text=\"@string/permission_write_setting\" />\n        </TableRow>\n    </TableLayout>\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/window_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/dp_120\"\n    android:background=\"@color/colorAccent\"\n    android:padding=\"@dimen/dp_10\">\n\n    <androidx.appcompat.widget.AppCompatButton\n        android:id=\"@+id/btn_cancel\"\n        style=\"@style/Permission.Button\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignParentBottom=\"true\"\n        android:text=\"@string/cancel\"/>\n\n    <TextView\n        style=\"@style/Permission.WrapContent\"\n        android:layout_above=\"@id/btn_cancel\"\n        android:layout_centerHorizontal=\"true\"\n        android:text=\"@string/app_name\"\n        android:textColor=\"@color/white\"\n        android:textSize=\"@dimen/sp_20\"/>\n\n</RelativeLayout>"
  },
  {
    "path": "sample/src/main/res/values/array_string.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright 2017 Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string-array name=\"calendar\">\n        <item>Read_Calendar</item>\n        <item>Write_Calendar</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"contacts\">\n        <item>Read_Contacts</item>\n        <item>Write_Contacts</item>\n        <item>Get_Accounts</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"location\">\n        <item>Fine Location</item>\n        <item>Coarse Location</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"phone\">\n        <item>Read_Phone_State</item>\n        <item>Call_Phone</item>\n        <item>Read_Phone_Numbers</item>\n        <item>Answer_Phone_Calls</item>\n        <item>Use_Sip</item>\n        <item>Add_Voicemail</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"call_log\">\n        <item>Read_Call_Log</item>\n        <item>Write_Call_Log</item>\n        <item>Process_Outgoing_Calls</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"sms\">\n        <item>Send_SMS</item>\n        <item>Receive_SMS</item>\n        <item>Read_SMS</item>\n        <item>Receive_Wap_Push</item>\n        <item>Receive_MMS</item>\n        <item>All</item>\n    </string-array>\n\n    <string-array name=\"storage\">\n        <item>Read_External_Storage</item>\n        <item>Write_External_Storage</item>\n        <item>All</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n\n    <color name=\"white\">#FFF</color>\n</resources>\n"
  },
  {
    "path": "sample/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <dimen name=\"dp_1\">1dp</dimen>\n    <dimen name=\"dp_10\">10dp</dimen>\n    <dimen name=\"dp_20\">20dp</dimen>\n    <dimen name=\"dp_100\">100dp</dimen>\n    <dimen name=\"dp_120\">120dp</dimen>\n    <dimen name=\"dp_150\">150dp</dimen>\n\n    <dimen name=\"sp_14\">14sp</dimen>\n    <dimen name=\"sp_16\">16sp</dimen>\n    <dimen name=\"sp_18\">18sp</dimen>\n    <dimen name=\"sp_20\">20sp</dimen>\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n    <string name=\"app_name\">AndPermission</string>\n\n    <string name=\"setting\">Setting</string>\n    <string name=\"resume\">Resume</string>\n    <string name=\"cancel\">Cancel</string>\n    <string name=\"ok\">@android:string/ok</string>\n\n    <string name=\"successfully\">Successful</string>\n    <string name=\"failure\">Failure</string>\n\n    <string name=\"permission_camera\">Camera</string>\n    <string name=\"permission_contact\">Contact</string>\n    <string name=\"permission_location\">Location</string>\n\n    <string name=\"permission_calendar\">Calendar</string>\n    <string name=\"permission_microphone\">Microphone</string>\n    <string name=\"permission_storage\">Storage</string>\n\n    <string name=\"permission_phone\">Phone</string>\n    <string name=\"permission_call_log\">Call Log</string>\n    <string name=\"permission_activity_recognition\">Activity Recognition</string>\n    <string name=\"permission_sensors\">Sensors</string>\n    <string name=\"permission_sms\">SMS</string>\n    <string name=\"permission_setting\">Permission Setting</string>\n\n    <string name=\"permission_notification\">Notification</string>\n    <string name=\"permission_notification_listener\">Notification Listener</string>\n\n    <string name=\"permission_install\">Install Apk</string>\n    <string name=\"permission_overlay\">AlertWindow</string>\n\n    <string name=\"permission_write_setting\">Write System Setting</string>\n\n    <string name=\"title_dialog\">Tips</string>\n    <string name=\"message_permission_rationale\">Grant the following permissions to continue the program:\\n\\n%1$s</string>\n    <string name=\"message_permission_always_failed\">Please give us permission in the settings:\\n\\n%1$s</string>\n    <string name=\"message_setting_comeback\">The user comes back from the settings page.</string>\n\n    <string name=\"message_notification_rationale\">Your device does not allow us to pop up notifications.</string>\n    <string name=\"message_notification_listener_rationale\">Your device does not allow us to access notifications.</string>\n\n    <string name=\"message_install_failed\">Your device is not allowed us to install apps.</string>\n\n    <string name=\"message_overlay_failed\">Your device is not allowed us to draw on other applications.</string>\n\n    <string name=\"message_write_setting_failed\">Your device is not allowed us to modify the system settings.</string>\n\n    <string name=\"message_error_storage\">Please check the external storage device.</string>\n    <string name=\"message_error_storeage_inavailable\">External storage device is not available.</string>\n\n    <string name=\"message_error_save_failed\">Save failed, please try again.</string>\n\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n    Copyright © Zhenjie Yan\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n-->\n<resources>\n\n    <style name=\"Permission.Theme.Sample\" parent=\"Theme.AppCompat.Light.DarkActionBar\"/>\n\n    <style name=\"Permission.Theme.Sample.Activity\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"android:textAllCaps\">false</item>\n        <item name=\"android:windowDisablePreview\">true</item>\n    </style>\n\n    <style name=\"Permission.WrapContent\">\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n    </style>\n\n    <style name=\"Permission.WrapContent.WidthMatchParent\">\n        <item name=\"android:layout_width\">match_parent</item>\n    </style>\n\n    <style name=\"Permission.MatchParent\">\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:layout_width\">match_parent</item>\n    </style>\n\n    <style name=\"Permission.Toolbar\" parent=\"Permission.WrapContent.WidthMatchParent\">\n        <item name=\"android:theme\">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>\n        <item name=\"popupTheme\">@style/ThemeOverlay.AppCompat.Light</item>\n    </style>\n\n    <style name=\"Permission.Theme.Sample.Button\" parent=\"Widget.AppCompat.Button\"/>\n\n    <style name=\"Permission.Button\" parent=\"Permission.WrapContent\">\n        <item name=\"android:theme\">@style/Permission.Theme.Sample.Button</item>\n        <item name=\"android:layout_margin\">@dimen/dp_1</item>\n    </style>\n\n    <style name=\"Permission.Button.Weight\">\n        <item name=\"android:layout_weight\">1</item>\n    </style>\n\n    <style name=\"Permission.Button.Weight.Horizontal\">\n        <item name=\"android:layout_weight\">1</item>\n    </style>\n\n    <style name=\"Permission.Line\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">@dimen/dp_1</item>\n        <item name=\"android:background\">@color/colorAccent</item>\n        <item name=\"android:layout_weight\">1</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "settings.gradle",
    "content": "include ':permission', ':sample'"
  }
]