[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "## Basic Information\n\nDevice type: ________\nOS version: ________\nEasyPermissions version: ________\n\n## Describe the problem\n\nWhat happened?  What did you expect to happen?\n\n## Code and logs\n\n```\n// TODO(you): show the code that produces the problem,\n//            and any relevant logs.\n```\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: test\n\non:\n  - pull_request\n  - push\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: set up JDK 1.8\n        uses: actions/setup-java@v1\n        with:\n          java-version: 1.8\n      - name: Build with Gradle\n        run: |\n          ./gradlew build :easypermissions:test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Gradle files\n.gradle\nbuild\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# IntelliJ project files\n**.iml\n.idea\n\n# Android Studio captures folder\ncaptures/\n\n# Misc\n.DS_Store\n.classpath\n.project\n.settings\n.vscode\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Not Found\n"
  },
  {
    "path": "LICENSE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n   Copyright 2017 Google\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"
  },
  {
    "path": "PUBLISHING.md",
    "content": "## Publishing\n\n### Credentials\n\nThe library is published to Maven Central by the firebase-sonatype account, Googlers can find the\npassword for this account in [Valentine](http://valentine/)\n\n### GPG Key\n\nYou will need to create a private GPG keyring on your machine, if you don't have one do the\nfollowing steps:\n\n  1. Run `gpg --full-generate-key`\n  1. Choose `RSA and RSA` for the key type\n  1. Use `4096` for the key size\n  1. Use `0` for the expiration (never)\n  1. Use any name, email address, and password\n\nThis creates your key in `~/.gnupg/openpgp-revocs.d/` with `.rev` format. The last 8 characters\nbefore the `.rev` extension are your **Key ID**.\n\nTo export the key, run:\n\n```\ngpg --export-secret-keys -o $HOME/sonatype.gpg\n```\n\nFinally upload your key to the keyserver:\n\n```\ngpg --keyserver hkp://keys.openpgp.org --send-keys <YOUR KEY ID>\n```\n\n### Local Properties\n\nOpen your `$HOME/.gradle/gradle.properties` file at and fill in the values:\n\n```\nsigning.keyId=<KEY ID>\nsigning.password=<PASSWORD YOU CHOSE>\nsigning.secretKeyRingFile=<FULL PATH TO YOUR GPG FILE>\nmavenCentralRepositoryUsername=firebase-sonatype\nmavenCentralRepositoryUsername=<PASSWORD FROM VALENTINE>\n```\n\n### Publish\n\nTo publish, run:\n\n```\n./gradlew publish\n```\n\n### Release\n\nFollow [the instructions here](https://central.sonatype.org/pages/releasing-the-deployment.html):\n\n  1. Navigate to https://s01.oss.sonatype.org/ and **Log In**\n  1. On the left side click **Build Promotion** and look for the `com.firebase` repo\n  1. Click **Close** ... wait a few minutes (you can check status with **Refresh**)\n  1. Click **Release**\n"
  },
  {
    "path": "README.md",
    "content": "# EasyPermissions [![Build Status][1]][2] [![Android Weekly][3]][4]\n\nEasyPermissions is a wrapper library to simplify basic system permissions logic when targeting\nAndroid M or higher.\n\n**Note:** If your app is written in Kotlin consider the [easypermissions-ktx](https://github.com/VMadalin/easypermissions-ktx)\nlibrary which adds Kotlin extensions to the core EasyPermissions library.\n\n## Installation\n\nEasyPermissions is installed by adding the following dependency to your `build.gradle` file:\n\n```groovy\ndependencies {\n    // For developers using AndroidX in their applications\n    implementation 'pub.devrel:easypermissions:3.0.0'\n \n    // For developers using the Android Support Library\n    implementation 'pub.devrel:easypermissions:2.0.1'\n}\n```\n\n## Usage\n\n### Basic\n\nTo begin using EasyPermissions, have your `Activity` (or `Fragment`) override the `onRequestPermissionsResult` method:\n\n```java\npublic class MainActivity extends AppCompatActivity {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n\n        // Forward results to EasyPermissions\n        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);\n    }\n}\n```\n\n### Request Permissions\n\nThe example below shows how to request permissions for a method that requires both\n`CAMERA` and `ACCESS_FINE_LOCATION` permissions. There are a few things to note:\n\n  * Using `EasyPermissions#hasPermissions(...)` to check if the app already has the\n    required permissions. This method can take any number of permissions as its final\n    argument.\n  * Requesting permissions with `EasyPermissions#requestPermissions`. This method\n    will request the system permissions and show the rationale string provided if\n    necessary. The request code provided should be unique to this request, and the method\n    can take any number of permissions as its final argument.\n  * Use of the `AfterPermissionGranted` annotation. This is optional, but provided for\n    convenience. If all of the permissions in a given request are granted, *all* methods\n    annotated with the proper request code will be executed(be sure to have an unique request code). The annotated method needs to be *void* and *without input parameters* (instead, you can use *onSaveInstanceState* in order to keep the state of your suppressed parameters). This is to simplify the common\n    flow of needing to run the requesting method after all of its permissions have been granted.\n    This can also be achieved by adding logic on the `onPermissionsGranted` callback.\n\n```java\n@AfterPermissionGranted(RC_CAMERA_AND_LOCATION)\nprivate void methodRequiresTwoPermission() {\n    String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION};\n    if (EasyPermissions.hasPermissions(this, perms)) {\n        // Already have permission, do the thing\n        // ...\n    } else {\n        // Do not have permissions, request them now\n        EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale),\n                RC_CAMERA_AND_LOCATION, perms);\n    }\n}\n```\n\nOr for finer control over the rationale dialog, use a `PermissionRequest`:\n\n```java\nEasyPermissions.requestPermissions(\n        new PermissionRequest.Builder(this, RC_CAMERA_AND_LOCATION, perms)\n                .setRationale(R.string.camera_and_location_rationale)\n                .setPositiveButtonText(R.string.rationale_ask_ok)\n                .setNegativeButtonText(R.string.rationale_ask_cancel)\n                .setTheme(R.style.my_fancy_style)\n                .build());\n```\n\nOptionally, for a finer control, you can have your `Activity` / `Fragment` implement\nthe `PermissionCallbacks` interface.\n\n```java\npublic class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n\n        // Forward results to EasyPermissions\n        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, List<String> list) {\n        // Some permissions have been granted\n        // ...\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, List<String> list) {\n        // Some permissions have been denied\n        // ...\n    }\n}\n```\n\n### Required Permissions\n\nIn some cases your app will not function properly without certain permissions. If the user\ndenies these permissions with the \"Never Ask Again\" option, you will be unable to request\nthese permissions from the user and they must be changed in app settings. You can use the\nmethod `EasyPermissions.somePermissionPermanentlyDenied(...)` to display a dialog to the\nuser in this situation and direct them to the system setting screen for your app:\n\n**Note**: Due to a limitation in the information provided by the Android\nframework permissions API, the `somePermissionPermanentlyDenied` method only\nworks after the permission has been denied and your app has received\nthe `onPermissionsDenied` callback. Otherwise the library cannot distinguish\npermanent denial from the \"not yet denied\" case.\n\n```java\n@Override\npublic void onPermissionsDenied(int requestCode, List<String> perms) {\n    Log.d(TAG, \"onPermissionsDenied:\" + requestCode + \":\" + perms.size());\n\n    // (Optional) Check whether the user denied any permissions and checked \"NEVER ASK AGAIN.\"\n    // This will display a dialog directing them to enable the permission in app settings.\n    if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {\n        new AppSettingsDialog.Builder(this).build().show();\n    }\n}\n\n@Override\npublic void onActivityResult(int requestCode, int resultCode, Intent data) {\n    super.onActivityResult(requestCode, resultCode, data);\n\n    if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {\n        // Do something after user returned from app settings screen, like showing a Toast.\n        Toast.makeText(this, R.string.returned_from_app_settings_to_activity, Toast.LENGTH_SHORT)\n                .show();\n    }\n}\n```\n\n### Interacting with the rationale dialog\n\nImplement the `EasyPermissions.RationaleCallbacks` if you want to interact with the rationale dialog.\n\n```java\n@Override\npublic void onRationaleAccepted(int requestCode) {\n    // Rationale accepted to request some permissions\n    // ...\n}\n\n@Override\npublic void onRationaleDenied(int requestCode) {\n    // Rationale denied to request some permissions\n    // ...\n}\n```\n\nRationale callbacks don't necessarily imply permission changes. To check for those, see the `EasyPermissions.PermissionCallbacks`.\n\n## LICENSE\n\n```\n\tCopyright 2017 Google\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```\n\n[1]: https://github.com/googlesamples/easypermissions/workflows/test/badge.svg\n[2]: https://github.com/googlesamples/easypermissions/actions\n[3]: https://img.shields.io/badge/Android%20Weekly-%23185-2CB3E5.svg?style=flat\n[4]: http://androidweekly.net/issues/issue-185\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 30\n    testOptions.unitTests.includeAndroidResources = true\n\n    defaultConfig {\n        applicationId \"pub.devrel.easypermissions.sample\"\n        minSdkVersion 14\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        // Flag to enable support for the new language APIs\n        coreLibraryDesugaringEnabled false\n        // Sets Java compatibility to Java 8\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    implementation 'androidx.appcompat:appcompat:1.1.0'\n    implementation \"androidx.annotation:annotation:1.1.0\"\n    implementation project(':easypermissions')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"pub.devrel.easypermissions.sample\">\n\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n\n    <uses-permission android:name=\"android.permission.READ_SMS\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n\n    <application\n        android:label=\"@string/app_name\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:ignore=\"AllowBackup,GoogleAppIndexingWarning\">\n\n        <activity android:name=\".MainActivity\">\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    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/pub/devrel/easypermissions/sample/MainActivity.java",
    "content": "/*\n * Copyright Google Inc. All Rights Reserved.\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 pub.devrel.easypermissions.sample;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport java.util.List;\n\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.AppSettingsDialog;\nimport pub.devrel.easypermissions.EasyPermissions;\n\npublic class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,\n                                                               EasyPermissions.RationaleCallbacks{\n\n    private static final String TAG = \"MainActivity\";\n    private static final String[] LOCATION_AND_CONTACTS =\n            {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_CONTACTS};\n\n    private static final int RC_CAMERA_PERM = 123;\n    private static final int RC_LOCATION_CONTACTS_PERM = 124;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        // Button click listener that will request one permission.\n        findViewById(R.id.button_camera).setOnClickListener(v -> cameraTask());\n\n        // Button click listener that will request two permissions.\n        findViewById(R.id.button_location_and_contacts).setOnClickListener(v -> locationAndContactsTask());\n    }\n\n    private boolean hasCameraPermission() {\n        return EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA);\n    }\n\n    private boolean hasLocationAndContactsPermissions() {\n        return EasyPermissions.hasPermissions(this, LOCATION_AND_CONTACTS);\n    }\n\n    private boolean hasSmsPermission() {\n        return EasyPermissions.hasPermissions(this, Manifest.permission.READ_SMS);\n    }\n\n    private boolean hasStoragePermission() {\n        return EasyPermissions.hasPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);\n    }\n\n    @AfterPermissionGranted(RC_CAMERA_PERM)\n    public void cameraTask() {\n        if (hasCameraPermission()) {\n            // Have permission, do the thing!\n            Toast.makeText(this, \"TODO: Camera things\", Toast.LENGTH_LONG).show();\n        } else {\n            // Ask for one permission\n            EasyPermissions.requestPermissions(\n                    this,\n                    getString(R.string.rationale_camera),\n                    RC_CAMERA_PERM,\n                    Manifest.permission.CAMERA);\n        }\n    }\n\n    @AfterPermissionGranted(RC_LOCATION_CONTACTS_PERM)\n    public void locationAndContactsTask() {\n        if (hasLocationAndContactsPermissions()) {\n            // Have permissions, do the thing!\n            Toast.makeText(this, \"TODO: Location and Contacts things\", Toast.LENGTH_LONG).show();\n        } else {\n            // Ask for both permissions\n            EasyPermissions.requestPermissions(\n                    this,\n                    getString(R.string.rationale_location_contacts),\n                    RC_LOCATION_CONTACTS_PERM,\n                    LOCATION_AND_CONTACTS);\n        }\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           @NonNull String[] permissions,\n                                           @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n\n        // EasyPermissions handles the request result.\n        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n        Log.d(TAG, \"onPermissionsGranted:\" + requestCode + \":\" + perms.size());\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n        Log.d(TAG, \"onPermissionsDenied:\" + requestCode + \":\" + perms.size());\n\n        // (Optional) Check whether the user denied any permissions and checked \"NEVER ASK AGAIN.\"\n        // This will display a dialog directing them to enable the permission in app settings.\n        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {\n            new AppSettingsDialog.Builder(this).build().show();\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n\n        if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE) {\n            String yes = getString(R.string.yes);\n            String no = getString(R.string.no);\n\n            // Do something after user returned from app settings screen, like showing a Toast.\n            Toast.makeText(\n                    this,\n                    getString(R.string.returned_from_app_settings_to_activity,\n                              hasCameraPermission() ? yes : no,\n                              hasLocationAndContactsPermissions() ? yes : no,\n                              hasSmsPermission() ? yes : no),\n                    Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    @Override\n    public void onRationaleAccepted(int requestCode) {\n        Log.d(TAG, \"onRationaleAccepted:\" + requestCode);\n    }\n\n    @Override\n    public void onRationaleDenied(int requestCode) {\n        Log.d(TAG, \"onRationaleDenied:\" + requestCode);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/pub/devrel/easypermissions/sample/MainFragment.java",
    "content": "package pub.devrel.easypermissions.sample;\n\nimport android.Manifest;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.List;\n\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.EasyPermissions;\n\n/**\n * Created in {@link R.layout#activity_main}\n */\npublic class MainFragment extends Fragment implements EasyPermissions.PermissionCallbacks {\n\n    private static final String TAG = \"MainFragment\";\n    private static final int RC_SMS_PERM = 122;\n\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater,\n                             ViewGroup container,\n                             Bundle savedInstanceState) {\n        super.onCreateView(inflater, container, savedInstanceState);\n\n        // Create view\n        View v = inflater.inflate(R.layout.fragment_main, container);\n\n        // Button click listener\n        v.findViewById(R.id.button_sms).setOnClickListener(v1 -> smsTask());\n\n        return v;\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode,\n                                           @NonNull String[] permissions,\n                                           @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n\n        // EasyPermissions handles the request result.\n        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);\n    }\n\n    @AfterPermissionGranted(RC_SMS_PERM)\n    private void smsTask() {\n        if (EasyPermissions.hasPermissions(requireContext(), Manifest.permission.READ_SMS)) {\n            // Have permission, do the thing!\n            Toast.makeText(getActivity(), \"TODO: SMS things\", Toast.LENGTH_LONG).show();\n        } else {\n            // Request one permission\n            EasyPermissions.requestPermissions(this, getString(R.string.rationale_sms),\n                    RC_SMS_PERM, Manifest.permission.READ_SMS);\n        }\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n        Log.d(TAG, \"onPermissionsGranted:\" + requestCode + \":\" + perms.size());\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n        Log.d(TAG, \"onPermissionsDenied:\" + requestCode + \":\" + perms.size());\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_basic.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:context=\".BasicActivity\">\n\n    <Button\n        android:id=\"@+id/button_request\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Request\"\n        tools:ignore=\"HardcodedText\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\">\n\n    <Button\n        android:id=\"@+id/button_camera\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/camera\" />\n\n    <Button\n        android:id=\"@+id/button_location_and_contacts\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/location_and_contacts\" />\n\n    <fragment\n        android:id=\"@+id/fragment\"\n        android:name=\"pub.devrel.easypermissions.sample.MainFragment\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        tools:layout=\"@layout/fragment_main\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\">\n\n    <Button\n        android:id=\"@+id/button_sms\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/sms\" />\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">Easy Permissions</string>\n    <string name=\"yes\">Yes</string>\n    <string name=\"no\">No</string>\n\n    <string name=\"rationale_camera\">This app needs access to your camera so you can take pictures.</string>\n    <string name=\"rationale_location_contacts\">This app needs access to your location and contacts to know where and who you are.</string>\n    <string name=\"rationale_sms\">This app needs access to your sms to read all your great messages.</string>\n    <string name=\"returned_from_app_settings_to_activity\">\n        Returned from app settings to MainActivity with the following permissions:\n        \\n\\nCamera: %s\n        \\nLocation &amp; Contacts: %s\n        \\nSMS: %s\n    </string>\n    <string name=\"camera\">Camera</string>\n    <string name=\"location_and_contacts\">Location and Contacts</string>\n    <string name=\"sms\">SMS</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        jcenter()\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.3'\n        classpath 'com.vanniktech:gradle-maven-publish-plugin:0.14.2'\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "easypermissions/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\n// See: https://github.com/vanniktech/gradle-maven-publish-plugin/issues/206\next {\n  RELEASE_REPOSITORY_URL = \"https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/\"\n  SNAPSHOT_REPOSITORY_URL = \"https://s01.oss.sonatype.org/content/repositories/snapshots/\"\n}\n\napply plugin: 'com.vanniktech.maven.publish'\n\nandroid {\n    compileSdkVersion 30\n    testOptions.unitTests.includeAndroidResources = true\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 30\n        versionCode 1\n        versionName \"3.0.0\"\n    }\n\n    buildTypes {\n        debug {\n            testCoverageEnabled true\n        }\n        release {\n            minifyEnabled false\n            consumerProguardFiles 'proguard-rules.pro'\n        }\n    }\n\n    testOptions {\n        unitTests {\n            includeAndroidResources = true\n        }\n    }\n\n}\n\ndependencies {\n    api \"androidx.appcompat:appcompat:1.1.0\"\n    api \"androidx.annotation:annotation:1.1.0\"\n    api \"androidx.core:core:1.3.0\"\n    api \"androidx.fragment:fragment:1.2.5\"\n\n    testImplementation 'junit:junit:4.13'\n    testImplementation 'com.google.truth:truth:0.42'\n    testImplementation 'org.robolectric:robolectric:4.1'\n    testImplementation 'androidx.test:core:1.3.0-rc01'\n    testImplementation 'androidx.fragment:fragment-testing:1.2.5'\n    testImplementation 'org.mockito:mockito-core:2.23.4'\n}\n"
  },
  {
    "path": "easypermissions/gradle.properties",
    "content": "GROUP=pub.devrel\nPOM_ARTIFACT_ID=easypermissions\nVERSION_NAME=3.0.0\n\nPOM_NAME=EasyPermissions\nPOM_PACKAGING=aar\n\nPOM_DESCRIPTION=A wrapper library for basic Android M system permissions logic\n\nPOM_URL=https://github.com/googlesamples/easypermissions\nPOM_SCM_URL=https://github.com/googlesamples/easypermissions\nPOM_SCM_CONNECTION=https://github.com/googlesamples/easypermissions.git\n\nPOM_LICENCE_NAME=The Apache Software License, Version 2.0\nPOM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt\nPOM_LICENCE_DIST=repo\n\nPOM_DEVELOPER_NAME=Google\n"
  },
  {
    "path": "easypermissions/proguard-rules.pro",
    "content": "-keepclassmembers class * {\n    @pub.devrel.easypermissions.AfterPermissionGranted <methods>;\n}\n"
  },
  {
    "path": "easypermissions/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"pub.devrel.easypermissions\">\n\n    <application>\n        <activity\n            android:name=\"pub.devrel.easypermissions.AppSettingsDialogHolderActivity\"\n            android:exported=\"false\"\n            android:label=\"\"\n            android:theme=\"@style/EasyPermissions.Transparent\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/AfterPermissionGranted.java",
    "content": "/*\n * Copyright Google Inc. All Rights Reserved.\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 pub.devrel.easypermissions;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface AfterPermissionGranted {\n\n    int value();\n\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialog.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RestrictTo;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.Fragment;\n\n/**\n * Dialog to prompt the user to go to the app's settings screen and enable permissions. If the user\n * clicks 'OK' on the dialog, they are sent to the settings screen. The result is returned to the\n * Activity via {@see Activity#onActivityResult(int, int, Intent)}.\n * <p>\n * Use the {@link Builder} to create and display a dialog.\n */\npublic class AppSettingsDialog implements Parcelable {\n\n    private static final String TAG = \"EasyPermissions\";\n\n    public static final int DEFAULT_SETTINGS_REQ_CODE = 16061;\n\n    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)\n    public static final Parcelable.Creator<AppSettingsDialog> CREATOR = new Parcelable.Creator<AppSettingsDialog>() {\n        @Override\n        public AppSettingsDialog createFromParcel(Parcel in) {\n            return new AppSettingsDialog(in);\n        }\n\n        @Override\n        public AppSettingsDialog[] newArray(int size) {\n            return new AppSettingsDialog[size];\n        }\n    };\n\n    static final String EXTRA_APP_SETTINGS = \"extra_app_settings\";\n\n    @StyleRes\n    private final int mThemeResId;\n    private final String mRationale;\n    private final String mTitle;\n    private final String mPositiveButtonText;\n    private final String mNegativeButtonText;\n    private final int mRequestCode;\n    private final int mIntentFlags;\n\n    private Object mActivityOrFragment;\n    private Context mContext;\n\n    private AppSettingsDialog(Parcel in) {\n        mThemeResId = in.readInt();\n        mRationale = in.readString();\n        mTitle = in.readString();\n        mPositiveButtonText = in.readString();\n        mNegativeButtonText = in.readString();\n        mRequestCode = in.readInt();\n        mIntentFlags = in.readInt();\n    }\n\n    private AppSettingsDialog(@NonNull final Object activityOrFragment,\n                              @StyleRes int themeResId,\n                              @Nullable String rationale,\n                              @Nullable String title,\n                              @Nullable String positiveButtonText,\n                              @Nullable String negativeButtonText,\n                              int requestCode,\n                              int intentFlags) {\n        setActivityOrFragment(activityOrFragment);\n        mThemeResId = themeResId;\n        mRationale = rationale;\n        mTitle = title;\n        mPositiveButtonText = positiveButtonText;\n        mNegativeButtonText = negativeButtonText;\n        mRequestCode = requestCode;\n        mIntentFlags = intentFlags;\n    }\n\n    static AppSettingsDialog fromIntent(Intent intent, Activity activity) {\n        AppSettingsDialog dialog = intent.getParcelableExtra(AppSettingsDialog.EXTRA_APP_SETTINGS);\n\n        // It's not clear how this could happen, but in the case that it does we should try\n        // to avoid a runtime crash and just use the default dialog.\n        // https://github.com/googlesamples/easypermissions/issues/278\n        if (dialog == null) {\n            Log.e(TAG, \"Intent contains null value for EXTRA_APP_SETTINGS: \"\n                    + \"intent=\" + intent\n                    + \", \"\n                    + \"extras=\" + intent.getExtras());\n\n            dialog = new AppSettingsDialog.Builder(activity).build();\n        }\n\n        dialog.setActivityOrFragment(activity);\n        return dialog;\n    }\n\n    private void setActivityOrFragment(Object activityOrFragment) {\n        mActivityOrFragment = activityOrFragment;\n\n        if (activityOrFragment instanceof Activity) {\n            mContext = (Activity) activityOrFragment;\n        } else if (activityOrFragment instanceof Fragment) {\n            mContext = ((Fragment) activityOrFragment).getContext();\n        } else {\n            throw new IllegalStateException(\"Unknown object: \" + activityOrFragment);\n        }\n    }\n\n    private void startForResult(Intent intent) {\n        if (mActivityOrFragment instanceof Activity) {\n            ((Activity) mActivityOrFragment).startActivityForResult(intent, mRequestCode);\n        } else if (mActivityOrFragment instanceof Fragment) {\n            ((Fragment) mActivityOrFragment).startActivityForResult(intent, mRequestCode);\n        }\n    }\n\n    /**\n     * Display the built dialog.\n     */\n    public void show() {\n        startForResult(AppSettingsDialogHolderActivity.createShowDialogIntent(mContext, this));\n    }\n\n    /**\n     * Show the dialog. {@link #show()} is a wrapper to ensure backwards compatibility\n     */\n    AlertDialog showDialog(DialogInterface.OnClickListener positiveListener,\n                           DialogInterface.OnClickListener negativeListener) {\n        AlertDialog.Builder builder;\n        if (mThemeResId != -1) {\n            builder = new AlertDialog.Builder(mContext, mThemeResId);\n        } else {\n            builder = new AlertDialog.Builder(mContext);\n        }\n        return builder\n                .setCancelable(false)\n                .setTitle(mTitle)\n                .setMessage(mRationale)\n                .setPositiveButton(mPositiveButtonText, positiveListener)\n                .setNegativeButton(mNegativeButtonText, negativeListener)\n                .show();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mThemeResId);\n        dest.writeString(mRationale);\n        dest.writeString(mTitle);\n        dest.writeString(mPositiveButtonText);\n        dest.writeString(mNegativeButtonText);\n        dest.writeInt(mRequestCode);\n        dest.writeInt(mIntentFlags);\n    }\n\n    int getIntentFlags() {\n        return mIntentFlags;\n    }\n\n    /**\n     * Builder for an {@link AppSettingsDialog}.\n     */\n    public static class Builder {\n\n        private final Object mActivityOrFragment;\n        private final Context mContext;\n        @StyleRes\n        private int mThemeResId = -1;\n        private String mRationale;\n        private String mTitle;\n        private String mPositiveButtonText;\n        private String mNegativeButtonText;\n        private int mRequestCode = -1;\n        private boolean mOpenInNewTask = false;\n\n        /**\n         * Create a new Builder for an {@link AppSettingsDialog}.\n         *\n         * @param activity the {@link Activity} in which to display the dialog.\n         */\n        public Builder(@NonNull Activity activity) {\n            mActivityOrFragment = activity;\n            mContext = activity;\n        }\n\n        /**\n         * Create a new Builder for an {@link AppSettingsDialog}.\n         *\n         * @param fragment the {@link Fragment} in which to display the dialog.\n         */\n        public Builder(@NonNull Fragment fragment) {\n            mActivityOrFragment = fragment;\n            mContext = fragment.getContext();\n        }\n\n        /**\n         * Set the dialog theme.\n         */\n        @NonNull\n        public Builder setThemeResId(@StyleRes int themeResId) {\n            mThemeResId = themeResId;\n            return this;\n        }\n\n        /**\n         * Set the title dialog. Default is \"Permissions Required\".\n         */\n        @NonNull\n        public Builder setTitle(@Nullable String title) {\n            mTitle = title;\n            return this;\n        }\n\n        /**\n         * Set the title dialog. Default is \"Permissions Required\".\n         */\n        @NonNull\n        public Builder setTitle(@StringRes int title) {\n            mTitle = mContext.getString(title);\n            return this;\n        }\n\n        /**\n         * Set the rationale dialog. Default is\n         * \"This app may not work correctly without the requested permissions.\n         * Open the app settings screen to modify app permissions.\"\n         */\n        @NonNull\n        public Builder setRationale(@Nullable String rationale) {\n            mRationale = rationale;\n            return this;\n        }\n\n        /**\n         * Set the rationale dialog. Default is\n         * \"This app may not work correctly without the requested permissions.\n         * Open the app settings screen to modify app permissions.\"\n         */\n        @NonNull\n        public Builder setRationale(@StringRes int rationale) {\n            mRationale = mContext.getString(rationale);\n            return this;\n        }\n\n        /**\n         * Set the positive button text, default is {@link android.R.string#ok}.\n         */\n        @NonNull\n        public Builder setPositiveButton(@Nullable String text) {\n            mPositiveButtonText = text;\n            return this;\n        }\n\n        /**\n         * Set the positive button text, default is {@link android.R.string#ok}.\n         */\n        @NonNull\n        public Builder setPositiveButton(@StringRes int textId) {\n            mPositiveButtonText = mContext.getString(textId);\n            return this;\n        }\n\n        /**\n         * Set the negative button text, default is {@link android.R.string#cancel}.\n         * <p>\n         * To know if a user cancelled the request, check if your permissions were given with {@link\n         * EasyPermissions#hasPermissions(Context, String...)} in {@see\n         * Activity#onActivityResult(int, int, Intent)}. If you still don't have the right\n         * permissions, then the request was cancelled.\n         */\n        @NonNull\n        public Builder setNegativeButton(@Nullable String text) {\n            mNegativeButtonText = text;\n            return this;\n        }\n\n        /**\n         * Set the negative button text, default is {@link android.R.string#cancel}.\n         */\n        @NonNull\n        public Builder setNegativeButton(@StringRes int textId) {\n            mNegativeButtonText = mContext.getString(textId);\n            return this;\n        }\n\n        /**\n         * Set the request code use when launching the Settings screen for result, can be retrieved\n         * in the calling Activity's {@see Activity#onActivityResult(int, int, Intent)} method.\n         * Default is {@link #DEFAULT_SETTINGS_REQ_CODE}.\n         */\n        @NonNull\n        public Builder setRequestCode(int requestCode) {\n            mRequestCode = requestCode;\n            return this;\n        }\n\n        /**\n         * Set whether the settings screen should be opened in a separate task. This is achieved by\n         * setting {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK#FLAG_ACTIVITY_NEW_TASK} on\n         * the Intent used to open the settings screen.\n         */\n        @NonNull\n        public Builder setOpenInNewTask(boolean openInNewTask) {\n            mOpenInNewTask = openInNewTask;\n            return this;\n        }\n\n        /**\n         * Build the {@link AppSettingsDialog} from the specified options. Generally followed by a\n         * call to {@link AppSettingsDialog#show()}.\n         */\n        @NonNull\n        public AppSettingsDialog build() {\n            mRationale = TextUtils.isEmpty(mRationale) ?\n                    mContext.getString(R.string.rationale_ask_again) : mRationale;\n            mTitle = TextUtils.isEmpty(mTitle) ?\n                    mContext.getString(R.string.title_settings_dialog) : mTitle;\n            mPositiveButtonText = TextUtils.isEmpty(mPositiveButtonText) ?\n                    mContext.getString(android.R.string.ok) : mPositiveButtonText;\n            mNegativeButtonText = TextUtils.isEmpty(mNegativeButtonText) ?\n                    mContext.getString(android.R.string.cancel) : mNegativeButtonText;\n            mRequestCode = mRequestCode > 0 ? mRequestCode : DEFAULT_SETTINGS_REQ_CODE;\n\n            int intentFlags = 0;\n            if (mOpenInNewTask) {\n                intentFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;\n            }\n\n            return new AppSettingsDialog(\n                    mActivityOrFragment,\n                    mThemeResId,\n                    mRationale,\n                    mTitle,\n                    mPositiveButtonText,\n                    mNegativeButtonText,\n                    mRequestCode,\n                    intentFlags);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/AppSettingsDialogHolderActivity.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.Settings;\nimport androidx.annotation.RestrictTo;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.app.AppCompatActivity;\n\n@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)\npublic class AppSettingsDialogHolderActivity extends AppCompatActivity implements DialogInterface.OnClickListener {\n    private static final int APP_SETTINGS_RC = 7534;\n\n    private AlertDialog mDialog;\n    private int mIntentFlags;\n\n    public static Intent createShowDialogIntent(Context context, AppSettingsDialog dialog) {\n        Intent intent = new Intent(context, AppSettingsDialogHolderActivity.class);\n        intent.putExtra(AppSettingsDialog.EXTRA_APP_SETTINGS, dialog);\n        return intent;\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        AppSettingsDialog appSettingsDialog = AppSettingsDialog.fromIntent(getIntent(), this);\n        mIntentFlags = appSettingsDialog.getIntentFlags();\n        mDialog = appSettingsDialog.showDialog(this, this);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (mDialog != null && mDialog.isShowing()) {\n            mDialog.dismiss();\n        }\n    }\n\n    @Override\n    public void onClick(DialogInterface dialog, int which) {\n        if (which == Dialog.BUTTON_POSITIVE) {\n            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)\n                    .setData(Uri.fromParts(\"package\", getPackageName(), null));\n            intent.addFlags(mIntentFlags);\n            startActivityForResult(intent, APP_SETTINGS_RC);\n        } else if (which == Dialog.BUTTON_NEGATIVE) {\n            setResult(Activity.RESULT_CANCELED);\n            finish();\n        } else {\n            throw new IllegalStateException(\"Unknown button type: \" + which);\n        }\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        setResult(resultCode, data);\n        finish();\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/EasyPermissions.java",
    "content": "/*\n * Copyright Google Inc. All Rights Reserved.\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 pub.devrel.easypermissions;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Size;\nimport androidx.core.app.ActivityCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.core.content.ContextCompat;\nimport android.util.Log;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\nimport pub.devrel.easypermissions.helper.PermissionHelper;\n\n/**\n * Utility to request and check System permissions for apps targeting Android M (API &gt;= 23).\n */\npublic class EasyPermissions {\n\n    /**\n     * Callback interface to receive the results of {@code EasyPermissions.requestPermissions()}\n     * calls.\n     */\n    public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback {\n\n        void onPermissionsGranted(int requestCode, @NonNull List<String> perms);\n\n        void onPermissionsDenied(int requestCode, @NonNull List<String> perms);\n    }\n\n    /**\n     * Callback interface to receive button clicked events of the rationale dialog\n     */\n    public interface RationaleCallbacks {\n        void onRationaleAccepted(int requestCode);\n\n        void onRationaleDenied(int requestCode);\n    }\n\n    private static final String TAG = \"EasyPermissions\";\n\n    /**\n     * Check if the calling context has a set of permissions.\n     *\n     * @param context the calling context.\n     * @param perms   one ore more permissions, such as {@link Manifest.permission#CAMERA}.\n     * @return true if all permissions are already granted, false if at least one permission is not\n     * yet granted.\n     * @see Manifest.permission\n     */\n    public static boolean hasPermissions(@NonNull Context context,\n                                         @Size(min = 1) @NonNull String... perms) {\n        // Always return true for SDK < M, let the system deal with the permissions\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            Log.w(TAG, \"hasPermissions: API version < M, returning true by default\");\n\n            // DANGER ZONE!!! Changing this will break the library.\n            return true;\n        }\n\n        // Null context may be passed if we have detected Low API (less than M) so getting\n        // to this point with a null context should not be possible.\n        if (context == null) {\n            throw new IllegalArgumentException(\"Can't check permissions for null context\");\n        }\n\n        for (String perm : perms) {\n            if (ContextCompat.checkSelfPermission(context, perm)\n                    != PackageManager.PERMISSION_GRANTED) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Request a set of permissions, showing a rationale if the system requests it.\n     *\n     * @param host        requesting context.\n     * @param rationale   a message explaining why the application needs this set of permissions;\n     *                    will be displayed if the user rejects the request the first time.\n     * @param requestCode request code to track this request, must be &lt; 256.\n     * @param perms       a set of permissions to be requested.\n     * @see Manifest.permission\n     */\n    public static void requestPermissions(\n            @NonNull Activity host, @NonNull String rationale,\n            @IntRange(from = 0, to = 255) int requestCode, @Size(min = 1) @NonNull String... perms) {\n        requestPermissions(\n                new PermissionRequest.Builder(host, requestCode, perms)\n                        .setRationale(rationale)\n                        .build());\n    }\n\n    /**\n     * Request permissions from a Support Fragment with standard OK/Cancel buttons.\n     *\n     * @see #requestPermissions(Activity, String, int, String...)\n     */\n    public static void requestPermissions(\n            @NonNull Fragment host, @NonNull String rationale,\n            @IntRange(from = 0, to = 255) int requestCode, @Size(min = 1) @NonNull String... perms) {\n        requestPermissions(\n                new PermissionRequest.Builder(host, requestCode, perms)\n                        .setRationale(rationale)\n                        .build());\n    }\n\n    /**\n     * Request a set of permissions.\n     *\n     * @param request the permission request\n     * @see PermissionRequest\n     */\n    public static void requestPermissions(PermissionRequest request) {\n\n        // Check for permissions before dispatching the request\n        if (hasPermissions(request.getHelper().getContext(), request.getPerms())) {\n            notifyAlreadyHasPermissions(\n                    request.getHelper().getHost(), request.getRequestCode(), request.getPerms());\n            return;\n        }\n\n        // Request permissions\n        request.getHelper().requestPermissions(\n                request.getRationale(),\n                request.getPositiveButtonText(),\n                request.getNegativeButtonText(),\n                request.getTheme(),\n                request.getRequestCode(),\n                request.getPerms());\n    }\n\n    /**\n     * Handle the result of a permission request, should be called from the calling {@link\n     * Activity}'s {@link ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int,\n     * String[], int[])} method.\n     * <p>\n     * If any permissions were granted or denied, the {@code object} will receive the appropriate\n     * callbacks through {@link PermissionCallbacks} and methods annotated with {@link\n     * AfterPermissionGranted} will be run if appropriate.\n     *\n     * @param requestCode  requestCode argument to permission result callback.\n     * @param permissions  permissions argument to permission result callback.\n     * @param grantResults grantResults argument to permission result callback.\n     * @param receivers    an array of objects that have a method annotated with {@link\n     *                     AfterPermissionGranted} or implement {@link PermissionCallbacks}.\n     */\n    public static void onRequestPermissionsResult(@IntRange(from = 0, to = 255) int requestCode,\n                                                  @NonNull String[] permissions,\n                                                  @NonNull int[] grantResults,\n                                                  @NonNull Object... receivers) {\n        // Make a collection of granted and denied permissions from the request.\n        List<String> granted = new ArrayList<>();\n        List<String> denied = new ArrayList<>();\n        for (int i = 0; i < permissions.length; i++) {\n            String perm = permissions[i];\n            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {\n                granted.add(perm);\n            } else {\n                denied.add(perm);\n            }\n        }\n\n        // iterate through all receivers\n        for (Object object : receivers) {\n            // Report granted permissions, if any.\n            if (!granted.isEmpty()) {\n                if (object instanceof PermissionCallbacks) {\n                    ((PermissionCallbacks) object).onPermissionsGranted(requestCode, granted);\n                }\n            }\n\n            // Report denied permissions, if any.\n            if (!denied.isEmpty()) {\n                if (object instanceof PermissionCallbacks) {\n                    ((PermissionCallbacks) object).onPermissionsDenied(requestCode, denied);\n                }\n            }\n\n            // If 100% successful, call annotated methods\n            if (!granted.isEmpty() && denied.isEmpty()) {\n                runAnnotatedMethods(object, requestCode);\n            }\n        }\n    }\n\n    /**\n     * Check if at least one permission in the list of denied permissions has been permanently\n     * denied (user clicked \"Never ask again\").\n     *\n     * <b>Note</b>: Due to a limitation in the information provided by the Android\n     * framework permissions API, this method only works after the permission\n     * has been denied and your app has received the onPermissionsDenied callback.\n     * Otherwise the library cannot distinguish permanent denial from the\n     * \"not yet denied\" case.\n     *\n     * @param host              context requesting permissions.\n     * @param deniedPermissions list of denied permissions, usually from {@link\n     *                          PermissionCallbacks#onPermissionsDenied(int, List)}\n     * @return {@code true} if at least one permission in the list was permanently denied.\n     */\n    public static boolean somePermissionPermanentlyDenied(@NonNull Activity host,\n                                                          @NonNull List<String> deniedPermissions) {\n        return PermissionHelper.newInstance(host)\n                .somePermissionPermanentlyDenied(deniedPermissions);\n    }\n\n    /**\n     * @see #somePermissionPermanentlyDenied(Activity, List)\n     */\n    public static boolean somePermissionPermanentlyDenied(@NonNull Fragment host,\n                                                          @NonNull List<String> deniedPermissions) {\n        return PermissionHelper.newInstance(host)\n                .somePermissionPermanentlyDenied(deniedPermissions);\n    }\n\n    /**\n     * Check if a permission has been permanently denied (user clicked \"Never ask again\").\n     *\n     * @param host             context requesting permissions.\n     * @param deniedPermission denied permission.\n     * @return {@code true} if the permissions has been permanently denied.\n     */\n    public static boolean permissionPermanentlyDenied(@NonNull Activity host,\n                                                      @NonNull String deniedPermission) {\n        return PermissionHelper.newInstance(host).permissionPermanentlyDenied(deniedPermission);\n    }\n\n    /**\n     * @see #permissionPermanentlyDenied(Activity, String)\n     */\n    public static boolean permissionPermanentlyDenied(@NonNull Fragment host,\n                                                      @NonNull String deniedPermission) {\n        return PermissionHelper.newInstance(host).permissionPermanentlyDenied(deniedPermission);\n    }\n\n    /**\n     * See if some denied permission has been permanently denied.\n     *\n     * @param host  requesting context.\n     * @param perms array of permissions.\n     * @return true if the user has previously denied any of the {@code perms} and we should show a\n     * rationale, false otherwise.\n     */\n    public static boolean somePermissionDenied(@NonNull Activity host,\n                                               @NonNull String... perms) {\n        return PermissionHelper.newInstance(host).somePermissionDenied(perms);\n    }\n\n    /**\n     * @see #somePermissionDenied(Activity, String...)\n     */\n    public static boolean somePermissionDenied(@NonNull Fragment host,\n                                               @NonNull String... perms) {\n        return PermissionHelper.newInstance(host).somePermissionDenied(perms);\n    }\n\n    /**\n     * Run permission callbacks on an object that requested permissions but already has them by\n     * simulating {@link PackageManager#PERMISSION_GRANTED}.\n     *\n     * @param object      the object requesting permissions.\n     * @param requestCode the permission request code.\n     * @param perms       a list of permissions requested.\n     */\n    private static void notifyAlreadyHasPermissions(@NonNull Object object,\n                                                    int requestCode,\n                                                    @NonNull String[] perms) {\n        int[] grantResults = new int[perms.length];\n        for (int i = 0; i < perms.length; i++) {\n            grantResults[i] = PackageManager.PERMISSION_GRANTED;\n        }\n\n        onRequestPermissionsResult(requestCode, perms, grantResults, object);\n    }\n\n    /**\n     * Find all methods annotated with {@link AfterPermissionGranted} on a given object with the\n     * correct requestCode argument.\n     *\n     * @param object      the object with annotated methods.\n     * @param requestCode the requestCode passed to the annotation.\n     */\n    private static void runAnnotatedMethods(@NonNull Object object, int requestCode) {\n        Class clazz = object.getClass();\n        if (isUsingAndroidAnnotations(object)) {\n            clazz = clazz.getSuperclass();\n        }\n\n        while (clazz != null) {\n            for (Method method : clazz.getDeclaredMethods()) {\n                AfterPermissionGranted ann = method.getAnnotation(AfterPermissionGranted.class);\n                if (ann != null) {\n                    // Check for annotated methods with matching request code.\n                    if (ann.value() == requestCode) {\n                        // Method must be void so that we can invoke it\n                        if (method.getParameterTypes().length > 0) {\n                            throw new RuntimeException(\n                                    \"Cannot execute method \" + method.getName() + \" because it is non-void method and/or has input parameters.\");\n                        }\n\n                        try {\n                            // Make method accessible if private\n                            if (!method.isAccessible()) {\n                                method.setAccessible(true);\n                            }\n                            method.invoke(object);\n                        } catch (IllegalAccessException e) {\n                            Log.e(TAG, \"runDefaultMethod:IllegalAccessException\", e);\n                        } catch (InvocationTargetException e) {\n                            Log.e(TAG, \"runDefaultMethod:InvocationTargetException\", e);\n                        }\n                    }\n                }\n            }\n\n            clazz = clazz.getSuperclass();\n        }\n    }\n\n    /**\n     * Determine if the project is using the AndroidAnnotations library.\n     */\n    private static boolean isUsingAndroidAnnotations(@NonNull Object object) {\n        if (!object.getClass().getSimpleName().endsWith(\"_\")) {\n            return false;\n        }\n        try {\n            Class clazz = Class.forName(\"org.androidannotations.api.view.HasViews\");\n            return clazz.isInstance(object);\n        } catch (ClassNotFoundException e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/PermissionRequest.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Activity;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RestrictTo;\nimport androidx.annotation.Size;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.StyleRes;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.Arrays;\n\nimport pub.devrel.easypermissions.helper.PermissionHelper;\n\n/**\n * An immutable model object that holds all of the parameters associated with a permission request,\n * such as the permissions, request code, and rationale.\n *\n * @see EasyPermissions#requestPermissions(PermissionRequest)\n * @see PermissionRequest.Builder\n */\npublic final class PermissionRequest {\n    private final PermissionHelper mHelper;\n    private final String[] mPerms;\n    private final int mRequestCode;\n    private final String mRationale;\n    private final String mPositiveButtonText;\n    private final String mNegativeButtonText;\n    private final int mTheme;\n\n    private PermissionRequest(PermissionHelper helper,\n                              String[] perms,\n                              int requestCode,\n                              String rationale,\n                              String positiveButtonText,\n                              String negativeButtonText,\n                              int theme) {\n        mHelper = helper;\n        mPerms = perms.clone();\n        mRequestCode = requestCode;\n        mRationale = rationale;\n        mPositiveButtonText = positiveButtonText;\n        mNegativeButtonText = negativeButtonText;\n        mTheme = theme;\n    }\n\n    @NonNull\n    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)\n    public PermissionHelper getHelper() {\n        return mHelper;\n    }\n\n    @NonNull\n    public String[] getPerms() {\n        return mPerms.clone();\n    }\n\n    public int getRequestCode() {\n        return mRequestCode;\n    }\n\n    @NonNull\n    public String getRationale() {\n        return mRationale;\n    }\n\n    @NonNull\n    public String getPositiveButtonText() {\n        return mPositiveButtonText;\n    }\n\n    @NonNull\n    public String getNegativeButtonText() {\n        return mNegativeButtonText;\n    }\n\n    @StyleRes\n    public int getTheme() {\n        return mTheme;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        PermissionRequest request = (PermissionRequest) o;\n\n        return Arrays.equals(mPerms, request.mPerms) && mRequestCode == request.mRequestCode;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Arrays.hashCode(mPerms);\n        result = 31 * result + mRequestCode;\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"PermissionRequest{\" +\n                \"mHelper=\" + mHelper +\n                \", mPerms=\" + Arrays.toString(mPerms) +\n                \", mRequestCode=\" + mRequestCode +\n                \", mRationale='\" + mRationale + '\\'' +\n                \", mPositiveButtonText='\" + mPositiveButtonText + '\\'' +\n                \", mNegativeButtonText='\" + mNegativeButtonText + '\\'' +\n                \", mTheme=\" + mTheme +\n                '}';\n    }\n\n    /**\n     * Builder to build a permission request with variable options.\n     *\n     * @see PermissionRequest\n     */\n    public static final class Builder {\n        private final PermissionHelper mHelper;\n        private final int mRequestCode;\n        private final String[] mPerms;\n\n        private String mRationale;\n        private String mPositiveButtonText;\n        private String mNegativeButtonText;\n        private int mTheme = -1;\n\n        /**\n         * Construct a new permission request builder with a host, request code, and the requested\n         * permissions.\n         *\n         * @param activity    the permission request host\n         * @param requestCode request code to track this request; must be &lt; 256\n         * @param perms       the set of permissions to be requested\n         */\n        public Builder(@NonNull Activity activity, int requestCode,\n                       @NonNull @Size(min = 1) String... perms) {\n            mHelper = PermissionHelper.newInstance(activity);\n            mRequestCode = requestCode;\n            mPerms = perms;\n        }\n\n        /**\n         * @see #Builder(Activity, int, String...)\n         */\n        public Builder(@NonNull Fragment fragment, int requestCode,\n                       @NonNull @Size(min = 1) String... perms) {\n            mHelper = PermissionHelper.newInstance(fragment);\n            mRequestCode = requestCode;\n            mPerms = perms;\n        }\n\n        /**\n         * Set the rationale to display to the user if they don't allow your permissions on the\n         * first try. This rationale will be shown as long as the user has denied your permissions\n         * at least once, but has not yet permanently denied your permissions. Should the user\n         * permanently deny your permissions, use the {@link AppSettingsDialog} instead.\n         * <p>\n         * The default rationale text is {@link R.string#rationale_ask}.\n         *\n         * @param rationale the rationale to be displayed to the user should they deny your\n         *                  permission at least once\n         */\n        @NonNull\n        public Builder setRationale(@Nullable String rationale) {\n            mRationale = rationale;\n            return this;\n        }\n\n        /**\n         * @param resId the string resource to be used as a rationale\n         * @see #setRationale(String)\n         */\n        @NonNull\n        public Builder setRationale(@StringRes int resId) {\n            mRationale = mHelper.getContext().getString(resId);\n            return this;\n        }\n\n        /**\n         * Set the positive button text for the rationale dialog should it be shown.\n         * <p>\n         * The default is {@link android.R.string#ok}\n         */\n        @NonNull\n        public Builder setPositiveButtonText(@Nullable String positiveButtonText) {\n            mPositiveButtonText = positiveButtonText;\n            return this;\n        }\n\n        /**\n         * @see #setPositiveButtonText(String)\n         */\n        @NonNull\n        public Builder setPositiveButtonText(@StringRes int resId) {\n            mPositiveButtonText = mHelper.getContext().getString(resId);\n            return this;\n        }\n\n        /**\n         * Set the negative button text for the rationale dialog should it be shown.\n         * <p>\n         * The default is {@link android.R.string#cancel}\n         */\n        @NonNull\n        public Builder setNegativeButtonText(@Nullable String negativeButtonText) {\n            mNegativeButtonText = negativeButtonText;\n            return this;\n        }\n\n        /**\n         * @see #setNegativeButtonText(String)\n         */\n        @NonNull\n        public Builder setNegativeButtonText(@StringRes int resId) {\n            mNegativeButtonText = mHelper.getContext().getString(resId);\n            return this;\n        }\n\n        /**\n         * Set the theme to be used for the rationale dialog should it be shown.\n         *\n         * @param theme a style resource\n         */\n        @NonNull\n        public Builder setTheme(@StyleRes int theme) {\n            mTheme = theme;\n            return this;\n        }\n\n        /**\n         * Build the permission request.\n         *\n         * @return the permission request\n         * @see EasyPermissions#requestPermissions(PermissionRequest)\n         * @see PermissionRequest\n         */\n        @NonNull\n        public PermissionRequest build() {\n            if (mRationale == null) {\n                mRationale = mHelper.getContext().getString(R.string.rationale_ask);\n            }\n            if (mPositiveButtonText == null) {\n                mPositiveButtonText = mHelper.getContext().getString(android.R.string.ok);\n            }\n            if (mNegativeButtonText == null) {\n                mNegativeButtonText = mHelper.getContext().getString(android.R.string.cancel);\n            }\n\n            return new PermissionRequest(\n                    mHelper,\n                    mPerms,\n                    mRequestCode,\n                    mRationale,\n                    mPositiveButtonText,\n                    mNegativeButtonText,\n                    mTheme);\n        }\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogClickListener.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.Arrays;\n\nimport pub.devrel.easypermissions.helper.PermissionHelper;\n\n/**\n * Click listener for either {@link RationaleDialogFragment} or {@link RationaleDialogFragmentCompat}.\n */\nclass RationaleDialogClickListener implements Dialog.OnClickListener {\n\n    private Object mHost;\n    private RationaleDialogConfig mConfig;\n    private EasyPermissions.PermissionCallbacks mCallbacks;\n    private EasyPermissions.RationaleCallbacks mRationaleCallbacks;\n\n    RationaleDialogClickListener(RationaleDialogFragmentCompat compatDialogFragment,\n                                 RationaleDialogConfig config,\n                                 EasyPermissions.PermissionCallbacks callbacks,\n                                 EasyPermissions.RationaleCallbacks rationaleCallbacks) {\n\n        mHost = compatDialogFragment.getParentFragment() != null\n                ? compatDialogFragment.getParentFragment()\n                : compatDialogFragment.getActivity();\n\n        mConfig = config;\n        mCallbacks = callbacks;\n        mRationaleCallbacks = rationaleCallbacks;\n\n    }\n\n    RationaleDialogClickListener(RationaleDialogFragment dialogFragment,\n                                 RationaleDialogConfig config,\n                                 EasyPermissions.PermissionCallbacks callbacks,\n                                 EasyPermissions.RationaleCallbacks dialogCallback) {\n\n        mHost = dialogFragment.getActivity();\n\n        mConfig = config;\n        mCallbacks = callbacks;\n        mRationaleCallbacks = dialogCallback;\n    }\n\n    @Override\n    public void onClick(DialogInterface dialog, int which) {\n        int requestCode = mConfig.requestCode;\n        if (which == Dialog.BUTTON_POSITIVE) {\n            String[] permissions = mConfig.permissions;\n            if (mRationaleCallbacks != null) {\n                mRationaleCallbacks.onRationaleAccepted(requestCode);\n            }\n            if (mHost instanceof Fragment) {\n                PermissionHelper.newInstance((Fragment) mHost).directRequestPermissions(requestCode, permissions);\n            } else if (mHost instanceof Activity) {\n                PermissionHelper.newInstance((Activity) mHost).directRequestPermissions(requestCode, permissions);\n            } else {\n                throw new RuntimeException(\"Host must be an Activity or Fragment!\");\n            }\n        } else {\n            if (mRationaleCallbacks != null) {\n                mRationaleCallbacks.onRationaleDenied(requestCode);\n            }\n            notifyPermissionDenied();\n        }\n    }\n\n    private void notifyPermissionDenied() {\n        if (mCallbacks != null) {\n            mCallbacks.onPermissionsDenied(mConfig.requestCode, Arrays.asList(mConfig.permissions));\n        }\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogConfig.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.app.AlertDialog;\n\n/**\n * Configuration for either {@link RationaleDialogFragment} or {@link RationaleDialogFragmentCompat}.\n */\nclass RationaleDialogConfig {\n\n    private static final String KEY_POSITIVE_BUTTON = \"positiveButton\";\n    private static final String KEY_NEGATIVE_BUTTON = \"negativeButton\";\n    private static final String KEY_RATIONALE_MESSAGE = \"rationaleMsg\";\n    private static final String KEY_THEME = \"theme\";\n    private static final String KEY_REQUEST_CODE = \"requestCode\";\n    private static final String KEY_PERMISSIONS = \"permissions\";\n\n    String positiveButton;\n    String negativeButton;\n    int theme;\n    int requestCode;\n    String rationaleMsg;\n    String[] permissions;\n\n    RationaleDialogConfig(@NonNull String positiveButton,\n                          @NonNull String negativeButton,\n                          @NonNull String rationaleMsg,\n                          @StyleRes int theme,\n                          int requestCode,\n                          @NonNull String[] permissions) {\n\n        this.positiveButton = positiveButton;\n        this.negativeButton = negativeButton;\n        this.rationaleMsg = rationaleMsg;\n        this.theme = theme;\n        this.requestCode = requestCode;\n        this.permissions = permissions;\n    }\n\n    RationaleDialogConfig(Bundle bundle) {\n        positiveButton = bundle.getString(KEY_POSITIVE_BUTTON);\n        negativeButton = bundle.getString(KEY_NEGATIVE_BUTTON);\n        rationaleMsg = bundle.getString(KEY_RATIONALE_MESSAGE);\n        theme = bundle.getInt(KEY_THEME);\n        requestCode = bundle.getInt(KEY_REQUEST_CODE);\n        permissions = bundle.getStringArray(KEY_PERMISSIONS);\n    }\n\n    Bundle toBundle() {\n        Bundle bundle = new Bundle();\n        bundle.putString(KEY_POSITIVE_BUTTON, positiveButton);\n        bundle.putString(KEY_NEGATIVE_BUTTON, negativeButton);\n        bundle.putString(KEY_RATIONALE_MESSAGE, rationaleMsg);\n        bundle.putInt(KEY_THEME, theme);\n        bundle.putInt(KEY_REQUEST_CODE, requestCode);\n        bundle.putStringArray(KEY_PERMISSIONS, permissions);\n\n        return bundle;\n    }\n\n    AlertDialog createSupportDialog(Context context, Dialog.OnClickListener listener) {\n        AlertDialog.Builder builder;\n        if (theme > 0) {\n            builder = new AlertDialog.Builder(context, theme);\n        } else {\n            builder = new AlertDialog.Builder(context);\n        }\n        return builder\n                .setCancelable(false)\n                .setPositiveButton(positiveButton, listener)\n                .setNegativeButton(negativeButton, listener)\n                .setMessage(rationaleMsg)\n                .create();\n    }\n\n    android.app.AlertDialog createFrameworkDialog(Context context, Dialog.OnClickListener listener) {\n        android.app.AlertDialog.Builder builder;\n        if (theme > 0) {\n            builder = new android.app.AlertDialog.Builder(context, theme);\n        } else {\n            builder = new android.app.AlertDialog.Builder(context);\n        }\n        return builder\n                .setCancelable(false)\n                .setPositiveButton(positiveButton, listener)\n                .setNegativeButton(negativeButton, listener)\n                .setMessage(rationaleMsg)\n                .create();\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragment.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Dialog;\nimport android.app.DialogFragment;\nimport android.app.FragmentManager;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RestrictTo;\nimport androidx.annotation.StyleRes;\n\n/**\n * {@link DialogFragment} to display rationale for permission requests when the request comes from\n * a Fragment or Activity that can host a Fragment.\n */\n@RestrictTo(RestrictTo.Scope.LIBRARY)\npublic class RationaleDialogFragment extends DialogFragment {\n\n    public static final String TAG = \"RationaleDialogFragment\";\n\n    private EasyPermissions.PermissionCallbacks mPermissionCallbacks;\n    private EasyPermissions.RationaleCallbacks mRationaleCallbacks;\n    private boolean mStateSaved = false;\n\n    public static RationaleDialogFragment newInstance(\n            @NonNull String positiveButton,\n            @NonNull String negativeButton,\n            @NonNull String rationaleMsg,\n            @StyleRes int theme,\n            int requestCode,\n            @NonNull String[] permissions) {\n\n        // Create new Fragment\n        RationaleDialogFragment dialogFragment = new RationaleDialogFragment();\n\n        // Initialize configuration as arguments\n        RationaleDialogConfig config = new RationaleDialogConfig(\n                positiveButton, negativeButton, rationaleMsg, theme, requestCode, permissions);\n        dialogFragment.setArguments(config.toBundle());\n\n        return dialogFragment;\n    }\n\n    @Override\n    public void onAttach(Context context) {\n        super.onAttach(context);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && getParentFragment() != null) {\n            if (getParentFragment() instanceof EasyPermissions.PermissionCallbacks) {\n                mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment();\n            }\n            if (getParentFragment() instanceof EasyPermissions.RationaleCallbacks){\n                mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) getParentFragment();\n            }\n\n        }\n\n        if (context instanceof EasyPermissions.PermissionCallbacks) {\n            mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context;\n        }\n\n        if (context instanceof EasyPermissions.RationaleCallbacks) {\n            mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) context;\n        }\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        mStateSaved = true;\n        super.onSaveInstanceState(outState);\n    }\n\n    /**\n     * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException\n     * would otherwise occur.\n     */\n    public void showAllowingStateLoss(FragmentManager manager, String tag) {\n        // API 26 added this convenient method\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            if (manager.isStateSaved()) {\n                return;\n            }\n        }\n\n        if (mStateSaved) {\n            return;\n        }\n\n        show(manager, tag);\n    }\n\n    @Override\n    public void onDetach() {\n        super.onDetach();\n        mPermissionCallbacks = null;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(Bundle savedInstanceState) {\n        // Rationale dialog should not be cancelable\n        setCancelable(false);\n\n        // Get config from arguments, create click listener\n        RationaleDialogConfig config = new RationaleDialogConfig(getArguments());\n        RationaleDialogClickListener clickListener =\n                new RationaleDialogClickListener(this, config, mPermissionCallbacks, mRationaleCallbacks);\n\n        // Create an AlertDialog\n        return config.createFrameworkDialog(getActivity(), clickListener);\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/RationaleDialogFragmentCompat.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.os.Bundle;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RestrictTo;\nimport androidx.annotation.StyleRes;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.appcompat.app.AppCompatDialogFragment;\n\n/**\n * {@link AppCompatDialogFragment} to display rationale for permission requests when the request\n * comes from a Fragment or Activity that can host a Fragment.\n */\n@RestrictTo(RestrictTo.Scope.LIBRARY)\npublic class RationaleDialogFragmentCompat extends AppCompatDialogFragment {\n\n    public static final String TAG = \"RationaleDialogFragmentCompat\";\n\n    private EasyPermissions.PermissionCallbacks mPermissionCallbacks;\n    private EasyPermissions.RationaleCallbacks mRationaleCallbacks;\n\n    public static RationaleDialogFragmentCompat newInstance(\n            @NonNull String rationaleMsg,\n            @NonNull String positiveButton,\n            @NonNull String negativeButton,\n            @StyleRes int theme,\n            int requestCode,\n            @NonNull String[] permissions) {\n\n        // Create new Fragment\n        RationaleDialogFragmentCompat dialogFragment = new RationaleDialogFragmentCompat();\n\n        // Initialize configuration as arguments\n        RationaleDialogConfig config = new RationaleDialogConfig(\n                positiveButton, negativeButton, rationaleMsg, theme, requestCode, permissions);\n        dialogFragment.setArguments(config.toBundle());\n\n        return dialogFragment;\n    }\n\n    /**\n     * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException\n     * would otherwise occur.\n     */\n    public void showAllowingStateLoss(FragmentManager manager, String tag) {\n        if (manager.isStateSaved()) {\n            return;\n        }\n\n        show(manager, tag);\n    }\n\n    @Override\n    public void onAttach(Context context) {\n        super.onAttach(context);\n        if (getParentFragment() != null) {\n            if (getParentFragment() instanceof EasyPermissions.PermissionCallbacks) {\n                mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) getParentFragment();\n            }\n            if (getParentFragment() instanceof EasyPermissions.RationaleCallbacks){\n                mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) getParentFragment();\n            }\n        }\n\n        if (context instanceof EasyPermissions.PermissionCallbacks) {\n            mPermissionCallbacks = (EasyPermissions.PermissionCallbacks) context;\n        }\n\n        if (context instanceof EasyPermissions.RationaleCallbacks) {\n            mRationaleCallbacks = (EasyPermissions.RationaleCallbacks) context;\n        }\n    }\n\n    @Override\n    public void onDetach() {\n        super.onDetach();\n        mPermissionCallbacks = null;\n        mRationaleCallbacks = null;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(Bundle savedInstanceState) {\n        // Rationale dialog should not be cancelable\n        setCancelable(false);\n\n        // Get config from arguments, create click listener\n        RationaleDialogConfig config = new RationaleDialogConfig(getArguments());\n        RationaleDialogClickListener clickListener =\n                new RationaleDialogClickListener(this, config, mPermissionCallbacks, mRationaleCallbacks);\n\n        // Create an AlertDialog\n        return config.createSupportDialog(getContext(), clickListener);\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/ActivityPermissionHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport android.app.Activity;\nimport android.app.Fragment;\nimport android.app.FragmentManager;\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StyleRes;\nimport androidx.core.app.ActivityCompat;\nimport android.util.Log;\n\nimport pub.devrel.easypermissions.RationaleDialogFragment;\n\n/**\n * Permissions helper for {@link Activity}.\n */\nclass ActivityPermissionHelper extends PermissionHelper<Activity> {\n    private static final String TAG = \"ActPermissionHelper\";\n\n    public ActivityPermissionHelper(Activity host) {\n        super(host);\n    }\n\n    @Override\n    public void directRequestPermissions(int requestCode, @NonNull String... perms) {\n        ActivityCompat.requestPermissions(getHost(), perms, requestCode);\n    }\n\n    @Override\n    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {\n        return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm);\n    }\n\n    @Override\n    public Context getContext() {\n        return getHost();\n    }\n\n    @Override\n    public void showRequestPermissionRationale(@NonNull String rationale,\n                                               @NonNull String positiveButton,\n                                               @NonNull String negativeButton,\n                                               @StyleRes int theme,\n                                               int requestCode,\n                                               @NonNull String... perms) {\n        FragmentManager fm = getHost().getFragmentManager();\n\n        // Check if fragment is already showing\n        Fragment fragment = fm.findFragmentByTag(RationaleDialogFragment.TAG);\n        if (fragment instanceof RationaleDialogFragment) {\n            Log.d(TAG, \"Found existing fragment, not showing rationale.\");\n            return;\n        }\n\n        RationaleDialogFragment\n                .newInstance(positiveButton, negativeButton, rationale, theme, requestCode, perms)\n                .showAllowingStateLoss(fm, RationaleDialogFragment.TAG);\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/AppCompatActivityPermissionsHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.core.app.ActivityCompat;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.appcompat.app.AppCompatActivity;\n\n/**\n * Permissions helper for {@link AppCompatActivity}.\n */\nclass AppCompatActivityPermissionsHelper extends BaseSupportPermissionsHelper<AppCompatActivity> {\n\n    public AppCompatActivityPermissionsHelper(AppCompatActivity host) {\n        super(host);\n    }\n\n    @Override\n    public FragmentManager getSupportFragmentManager() {\n        return getHost().getSupportFragmentManager();\n    }\n\n    @Override\n    public void directRequestPermissions(int requestCode, @NonNull String... perms) {\n        ActivityCompat.requestPermissions(getHost(), perms, requestCode);\n    }\n\n    @Override\n    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {\n        return ActivityCompat.shouldShowRequestPermissionRationale(getHost(), perm);\n    }\n\n    @Override\n    public Context getContext() {\n        return getHost();\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/BaseSupportPermissionsHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StyleRes;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\nimport android.util.Log;\n\nimport pub.devrel.easypermissions.RationaleDialogFragmentCompat;\n\n/**\n * Implementation of {@link PermissionHelper} for Support Library host classes.\n */\npublic abstract class BaseSupportPermissionsHelper<T> extends PermissionHelper<T> {\n\n    private static final String TAG = \"BSPermissionsHelper\";\n\n    public BaseSupportPermissionsHelper(@NonNull T host) {\n        super(host);\n    }\n\n    public abstract FragmentManager getSupportFragmentManager();\n\n    @Override\n    public void showRequestPermissionRationale(@NonNull String rationale,\n                                               @NonNull String positiveButton,\n                                               @NonNull String negativeButton,\n                                               @StyleRes int theme,\n                                               int requestCode,\n                                               @NonNull String... perms) {\n\n        FragmentManager fm = getSupportFragmentManager();\n\n        // Check if fragment is already showing\n        Fragment fragment = fm.findFragmentByTag(RationaleDialogFragmentCompat.TAG);\n        if (fragment instanceof RationaleDialogFragmentCompat) {\n            Log.d(TAG, \"Found existing fragment, not showing rationale.\");\n            return;\n        }\n\n        RationaleDialogFragmentCompat\n                .newInstance(rationale, positiveButton, negativeButton, theme, requestCode, perms)\n                .showAllowingStateLoss(fm, RationaleDialogFragmentCompat.TAG);\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/LowApiPermissionsHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StyleRes;\nimport androidx.fragment.app.Fragment;\n\n/**\n * Permissions helper for apps built against API < 23, which do not need runtime permissions.\n */\nclass LowApiPermissionsHelper<T> extends PermissionHelper<T> {\n    public LowApiPermissionsHelper(@NonNull T host) {\n        super(host);\n    }\n\n    @Override\n    public void directRequestPermissions(int requestCode, @NonNull String... perms) {\n        throw new IllegalStateException(\"Should never be requesting permissions on API < 23!\");\n    }\n\n    @Override\n    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {\n        return false;\n    }\n\n    @Override\n    public void showRequestPermissionRationale(@NonNull String rationale,\n                                               @NonNull String positiveButton,\n                                               @NonNull String negativeButton,\n                                               @StyleRes int theme,\n                                               int requestCode,\n                                               @NonNull String... perms) {\n        throw new IllegalStateException(\"Should never be requesting permissions on API < 23!\");\n    }\n\n    @Override\n    public Context getContext() {\n        if (getHost() instanceof Activity) {\n            return (Context) getHost();\n        } else if (getHost() instanceof Fragment) {\n            return ((Fragment) getHost()).getContext();\n        } else {\n            throw new IllegalStateException(\"Unknown host: \" + getHost());\n        }\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/PermissionHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.Build;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StyleRes;\nimport androidx.fragment.app.Fragment;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport java.util.List;\n\n/**\n * Delegate class to make permission calls based on the 'host' (Fragment, Activity, etc).\n */\npublic abstract class PermissionHelper<T> {\n\n    private T mHost;\n\n    @NonNull\n    public static PermissionHelper<? extends Activity> newInstance(Activity host) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return new LowApiPermissionsHelper<>(host);\n        }\n\n        if (host instanceof AppCompatActivity)\n            return new AppCompatActivityPermissionsHelper((AppCompatActivity) host);\n        else {\n            return new ActivityPermissionHelper(host);\n        }\n    }\n\n    @NonNull\n    public static PermissionHelper<Fragment> newInstance(Fragment host) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return new LowApiPermissionsHelper<>(host);\n        }\n\n        return new SupportFragmentPermissionHelper(host);\n    }\n\n    // ============================================================================\n    // Public concrete methods\n    // ============================================================================\n\n    public PermissionHelper(@NonNull T host) {\n        mHost = host;\n    }\n\n    private boolean shouldShowRationale(@NonNull String... perms) {\n        for (String perm : perms) {\n            if (shouldShowRequestPermissionRationale(perm)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public void requestPermissions(@NonNull String rationale,\n                                   @NonNull String positiveButton,\n                                   @NonNull String negativeButton,\n                                   @StyleRes int theme,\n                                   int requestCode,\n                                   @NonNull String... perms) {\n        if (shouldShowRationale(perms)) {\n            showRequestPermissionRationale(\n                    rationale, positiveButton, negativeButton, theme, requestCode, perms);\n        } else {\n            directRequestPermissions(requestCode, perms);\n        }\n    }\n\n    public boolean somePermissionPermanentlyDenied(@NonNull List<String> perms) {\n        for (String deniedPermission : perms) {\n            if (permissionPermanentlyDenied(deniedPermission)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public boolean permissionPermanentlyDenied(@NonNull String perms) {\n        return !shouldShowRequestPermissionRationale(perms);\n    }\n\n    public boolean somePermissionDenied(@NonNull String... perms) {\n        return shouldShowRationale(perms);\n    }\n\n    @NonNull\n    public T getHost() {\n        return mHost;\n    }\n\n    // ============================================================================\n    // Public abstract methods\n    // ============================================================================\n\n    public abstract void directRequestPermissions(int requestCode, @NonNull String... perms);\n\n    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String perm);\n\n    public abstract void showRequestPermissionRationale(@NonNull String rationale,\n                                                        @NonNull String positiveButton,\n                                                        @NonNull String negativeButton,\n                                                        @StyleRes int theme,\n                                                        int requestCode,\n                                                        @NonNull String... perms);\n\n    public abstract Context getContext();\n\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/SupportFragmentPermissionHelper.java",
    "content": "package pub.devrel.easypermissions.helper;\n\nimport android.content.Context;\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\n/**\n * Permissions helper for {@link Fragment} from the support library.\n */\nclass SupportFragmentPermissionHelper extends BaseSupportPermissionsHelper<Fragment> {\n\n    public SupportFragmentPermissionHelper(@NonNull Fragment host) {\n        super(host);\n    }\n\n    @Override\n    public FragmentManager getSupportFragmentManager() {\n        return getHost().getChildFragmentManager();\n    }\n\n    @Override\n    public void directRequestPermissions(int requestCode, @NonNull String... perms) {\n        getHost().requestPermissions(perms, requestCode);\n    }\n\n    @Override\n    public boolean shouldShowRequestPermissionRationale(@NonNull String perm) {\n        return getHost().shouldShowRequestPermissionRationale(perm);\n    }\n\n    @Override\n    public Context getContext() {\n        return getHost().getActivity();\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/main/java/pub/devrel/easypermissions/helper/package-info.java",
    "content": "@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)\npackage pub.devrel.easypermissions.helper;\n\nimport androidx.annotation.RestrictTo;\n"
  },
  {
    "path": "easypermissions/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Use system defaults for devs not using AppCompat -->\n    <color name=\"colorPrimary\">#ff212121</color>\n    <color name=\"colorPrimaryDark\">@android:color/black</color>\n    <color name=\"colorAccent\">#ff80cbc4</color>\n</resources>\n"
  },
  {
    "path": "easypermissions/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"rationale_ask\">This app may not work correctly without the requested permissions.</string>\n    <string name=\"rationale_ask_again\">\n        This app may not work correctly without the requested permissions.\n        Open the app settings screen to modify app permissions.\n    </string>\n    <string name=\"title_settings_dialog\">Permissions Required</string>\n</resources>\n"
  },
  {
    "path": "easypermissions/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <style name=\"EasyPermissions\" parent=\"Theme.AppCompat.DayNight.DarkActionBar\">\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"EasyPermissions.Transparent\">\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowIsFloating\">true</item>\n        <item name=\"android:backgroundDimEnabled\">false</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/AppSettingsDialogTest.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.app.Application;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.widget.Button;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\nimport org.mockito.MockitoAnnotations;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.annotation.Config;\nimport org.robolectric.shadows.ShadowApplication;\nimport org.robolectric.shadows.ShadowIntent;\n\nimport java.util.Objects;\n\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.test.core.app.ApplicationProvider;\nimport pub.devrel.easypermissions.testhelper.ActivityController;\nimport pub.devrel.easypermissions.testhelper.FragmentController;\nimport pub.devrel.easypermissions.testhelper.TestActivity;\nimport pub.devrel.easypermissions.testhelper.TestFragment;\n\nimport static com.google.common.truth.Truth.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.robolectric.Shadows.shadowOf;\nimport static pub.devrel.easypermissions.AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE;\n\n@RunWith(RobolectricTestRunner.class)\n@Config(sdk = 23)\npublic class AppSettingsDialogTest {\n\n    private static final String TITLE = \"TITLE\";\n    private static final String RATIONALE = \"RATIONALE\";\n    private static final String NEGATIVE = \"NEGATIVE\";\n    private static final String POSITIVE = \"POSITIVE\";\n    private ShadowApplication shadowApp;\n    private TestActivity spyActivity;\n    private TestFragment spyFragment;\n    private FragmentController<TestFragment> fragmentController;\n    private ActivityController<TestActivity> activityController;\n    @Mock\n    private DialogInterface.OnClickListener positiveListener;\n    @Mock\n    private DialogInterface.OnClickListener negativeListener;\n    @Captor\n    private ArgumentCaptor<Integer> integerCaptor;\n    @Captor\n    private ArgumentCaptor<Intent> intentCaptor;\n\n    @Before\n    public void setUp() {\n        MockitoAnnotations.initMocks(this);\n        shadowApp = shadowOf((Application) ApplicationProvider.getApplicationContext());\n\n        activityController = new ActivityController<>(TestActivity.class);\n        fragmentController = new FragmentController<>(TestFragment.class);\n\n        spyActivity = Mockito.spy(activityController.resume());\n        spyFragment = Mockito.spy(fragmentController.resume());\n    }\n\n    // ------ From Activity ------\n\n    @Test\n    public void shouldShowExpectedSettingsDialog_whenBuildingFromActivity() {\n        new AppSettingsDialog.Builder(spyActivity)\n                .setTitle(android.R.string.dialog_alert_title)\n                .setRationale(android.R.string.unknownName)\n                .setPositiveButton(android.R.string.ok)\n                .setNegativeButton(android.R.string.cancel)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .show();\n\n        verify(spyActivity, times(1))\n                .startActivityForResult(intentCaptor.capture(), integerCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(DEFAULT_SETTINGS_REQ_CODE);\n        assertThat(Objects.requireNonNull(intentCaptor.getValue().getComponent()).getClassName())\n                .isEqualTo(AppSettingsDialogHolderActivity.class.getName());\n\n        Intent startedIntent = shadowApp.getNextStartedActivity();\n        ShadowIntent shadowIntent = shadowOf(startedIntent);\n        assertThat(shadowIntent.getIntentClass()).isEqualTo(AppSettingsDialogHolderActivity.class);\n    }\n\n    @Test\n    public void shouldPositiveListener_whenClickingPositiveButtonFromActivity() {\n        AlertDialog alertDialog = new AppSettingsDialog.Builder(spyActivity)\n                .setTitle(TITLE)\n                .setRationale(RATIONALE)\n                .setPositiveButton(POSITIVE)\n                .setNegativeButton(NEGATIVE)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .showDialog(positiveListener, negativeListener);\n        Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);\n        positive.performClick();\n\n        verify(positiveListener, times(1))\n                .onClick(any(DialogInterface.class), anyInt());\n    }\n\n    @Test\n    public void shouldNegativeListener_whenClickingPositiveButtonFromActivity() {\n        AlertDialog alertDialog = new AppSettingsDialog.Builder(spyActivity)\n                .setTitle(TITLE)\n                .setRationale(RATIONALE)\n                .setPositiveButton(POSITIVE)\n                .setNegativeButton(NEGATIVE)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .showDialog(positiveListener, negativeListener);\n        Button positive = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);\n        positive.performClick();\n\n        verify(negativeListener, times(1))\n                .onClick(any(DialogInterface.class), anyInt());\n    }\n\n    @Test\n    public void shouldShowExpectedSettingsDialog_whenBuildingFromSupportFragment() {\n        new AppSettingsDialog.Builder(spyFragment)\n                .setTitle(android.R.string.dialog_alert_title)\n                .setRationale(android.R.string.unknownName)\n                .setPositiveButton(android.R.string.ok)\n                .setNegativeButton(android.R.string.cancel)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .show();\n\n        verify(spyFragment, times(1))\n                .startActivityForResult(intentCaptor.capture(), integerCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(DEFAULT_SETTINGS_REQ_CODE);\n        assertThat(Objects.requireNonNull(intentCaptor.getValue().getComponent()).getClassName())\n                .isEqualTo(AppSettingsDialogHolderActivity.class.getName());\n\n        Intent startedIntent = shadowApp.getNextStartedActivity();\n        ShadowIntent shadowIntent = shadowOf(startedIntent);\n        assertThat(shadowIntent.getIntentClass()).isEqualTo(AppSettingsDialogHolderActivity.class);\n    }\n\n    @Test\n    public void shouldPositiveListener_whenClickingPositiveButtonFromSupportFragment() {\n        AlertDialog alertDialog = new AppSettingsDialog.Builder(spyFragment)\n                .setTitle(TITLE)\n                .setRationale(RATIONALE)\n                .setPositiveButton(POSITIVE)\n                .setNegativeButton(NEGATIVE)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .showDialog(positiveListener, negativeListener);\n        Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);\n        positive.performClick();\n\n        verify(positiveListener, times(1))\n                .onClick(any(DialogInterface.class), anyInt());\n    }\n\n    @Test\n    public void shouldNegativeListener_whenClickingPositiveButtonFromSupportFragment() {\n        AlertDialog alertDialog = new AppSettingsDialog.Builder(spyFragment)\n                .setTitle(TITLE)\n                .setRationale(RATIONALE)\n                .setPositiveButton(POSITIVE)\n                .setNegativeButton(NEGATIVE)\n                .setThemeResId(R.style.Theme_AppCompat)\n                .build()\n                .showDialog(positiveListener, negativeListener);\n        Button positive = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);\n        positive.performClick();\n\n        verify(negativeListener, times(1))\n                .onClick(any(DialogInterface.class), anyInt());\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsLowApiTest.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.Manifest;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.Mockito;\nimport org.mockito.MockitoAnnotations;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.annotation.Config;\n\nimport java.util.ArrayList;\n\nimport androidx.test.core.app.ApplicationProvider;\nimport pub.devrel.easypermissions.testhelper.ActivityController;\nimport pub.devrel.easypermissions.testhelper.FragmentController;\nimport pub.devrel.easypermissions.testhelper.TestActivity;\nimport pub.devrel.easypermissions.testhelper.TestAppCompatActivity;\nimport pub.devrel.easypermissions.testhelper.TestFragment;\nimport pub.devrel.easypermissions.testhelper.TestSupportFragmentActivity;\n\nimport static com.google.common.truth.Truth.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n/**\n * Low-API (SDK = 19) tests for {@link pub.devrel.easypermissions.EasyPermissions}.\n */\n@RunWith(RobolectricTestRunner.class)\n@Config(sdk = 19)\npublic class EasyPermissionsLowApiTest {\n\n    private static final String RATIONALE = \"RATIONALE\";\n    private static final String[] ALL_PERMS = new String[]{\n            Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION};\n\n    private TestActivity spyActivity;\n    private TestSupportFragmentActivity spySupportFragmentActivity;\n    private TestAppCompatActivity spyAppCompatActivity;\n    private TestFragment spyFragment;\n    private FragmentController<TestFragment> fragmentController;\n    private ActivityController<TestActivity> activityController;\n    private ActivityController<TestSupportFragmentActivity> supportFragmentActivityController;\n    private ActivityController<TestAppCompatActivity> appCompatActivityController;\n    @Captor\n    private ArgumentCaptor<Integer> integerCaptor;\n    @Captor\n    private ArgumentCaptor<ArrayList<String>> listCaptor;\n\n    @Before\n    public void setUp() {\n        MockitoAnnotations.initMocks(this);\n\n        activityController = new ActivityController<>(TestActivity.class);\n        supportFragmentActivityController = new ActivityController<>(TestSupportFragmentActivity.class);\n        appCompatActivityController = new ActivityController<>(TestAppCompatActivity.class);\n        fragmentController = new FragmentController<>(TestFragment.class);\n\n        spyActivity = Mockito.spy(activityController.resume());\n        spySupportFragmentActivity = Mockito.spy(supportFragmentActivityController.resume());\n        spyAppCompatActivity = Mockito.spy(appCompatActivityController.resume());\n        spyFragment = Mockito.spy(fragmentController.resume());\n    }\n\n    // ------ General tests ------\n\n    @Test\n    public void shouldHavePermission_whenHasPermissionsBeforeMarshmallow() {\n        assertThat(EasyPermissions.hasPermissions(ApplicationProvider.getApplicationContext(),\n                Manifest.permission.ACCESS_COARSE_LOCATION)).isTrue();\n    }\n\n    // ------ From Activity ------\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestFromActivity() {\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n    // ------ From Support Activity ------\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestFromSupportFragmentActivity() {\n        EasyPermissions.requestPermissions(spySupportFragmentActivity, RATIONALE, TestSupportFragmentActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spySupportFragmentActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestSupportFragmentActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestFromAppCompatActivity() {\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyAppCompatActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestFromFragment() {\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyFragment, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/EasyPermissionsTest.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.Manifest;\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.app.Fragment;\nimport android.content.pm.PackageManager;\nimport android.widget.TextView;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.Mockito;\nimport org.mockito.MockitoAnnotations;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.annotation.Config;\nimport org.robolectric.shadows.ShadowApplication;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport androidx.test.core.app.ApplicationProvider;\nimport pub.devrel.easypermissions.testhelper.ActivityController;\nimport pub.devrel.easypermissions.testhelper.FragmentController;\nimport pub.devrel.easypermissions.testhelper.TestActivity;\nimport pub.devrel.easypermissions.testhelper.TestAppCompatActivity;\nimport pub.devrel.easypermissions.testhelper.TestFragment;\nimport pub.devrel.easypermissions.testhelper.TestSupportFragmentActivity;\n\nimport static com.google.common.truth.Truth.assertThat;\nimport static junit.framework.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\nimport static org.robolectric.Shadows.shadowOf;\n\n/**\n * Basic Robolectric tests for {@link pub.devrel.easypermissions.EasyPermissions}.\n */\n@RunWith(RobolectricTestRunner.class)\n@Config(sdk = 23)\npublic class EasyPermissionsTest {\n\n    private static final String RATIONALE = \"RATIONALE\";\n    private static final String POSITIVE = \"POSITIVE\";\n    private static final String NEGATIVE = \"NEGATIVE\";\n    private static final String[] ONE_PERM = new String[]{Manifest.permission.READ_SMS};\n    private static final String[] ALL_PERMS = new String[]{\n            Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION};\n    private static final int[] SMS_DENIED_RESULT = new int[]{\n            PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED};\n\n    private ShadowApplication shadowApp;\n    private Application app;\n    private TestActivity spyActivity;\n    private TestSupportFragmentActivity spySupportFragmentActivity;\n    private TestAppCompatActivity spyAppCompatActivity;\n    private TestFragment spyFragment;\n    private FragmentController<TestFragment> fragmentController;\n    private ActivityController<TestActivity> activityController;\n    private ActivityController<TestSupportFragmentActivity> supportFragmentActivityController;\n    private ActivityController<TestAppCompatActivity> appCompatActivityController;\n    @Captor\n    private ArgumentCaptor<Integer> integerCaptor;\n    @Captor\n    private ArgumentCaptor<ArrayList<String>> listCaptor;\n\n    @Before\n    public void setUp() {\n        MockitoAnnotations.initMocks(this);\n        app = ApplicationProvider.getApplicationContext();\n        shadowApp = shadowOf(app);\n\n        activityController = new ActivityController<>(TestActivity.class);\n        supportFragmentActivityController = new ActivityController<>(TestSupportFragmentActivity.class);\n        appCompatActivityController = new ActivityController<>(TestAppCompatActivity.class);\n        fragmentController = new FragmentController<>(TestFragment.class);\n\n        spyActivity = Mockito.spy(activityController.resume());\n        spySupportFragmentActivity = Mockito.spy(supportFragmentActivityController.resume());\n        spyAppCompatActivity = Mockito.spy(appCompatActivityController.resume());\n        spyFragment = Mockito.spy(fragmentController.resume());\n    }\n\n    // ------ General tests ------\n\n    @Test\n    public void shouldNotHavePermissions_whenNoPermissionsGranted() {\n        assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isFalse();\n    }\n\n    @Test\n    public void shouldNotHavePermissions_whenNotAllPermissionsGranted() {\n        shadowApp.grantPermissions(ONE_PERM);\n        assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isFalse();\n    }\n\n    @Test\n    public void shouldHavePermissions_whenAllPermissionsGranted() {\n        shadowApp.grantPermissions(ALL_PERMS);\n        assertThat(EasyPermissions.hasPermissions(app, ALL_PERMS)).isTrue();\n    }\n\n    @SuppressWarnings(\"ConstantConditions\")\n    @Test\n    public void shouldThrowException_whenHasPermissionsWithNullContext() {\n        try {\n            EasyPermissions.hasPermissions(null, ALL_PERMS);\n            fail(\"IllegalStateException expected because of null context.\");\n        } catch (IllegalArgumentException e) {\n            assertThat(e).hasMessageThat()\n                    .isEqualTo(\"Can't check permissions for null context\");\n        }\n    }\n\n    // ------ From Activity ------\n\n    @Test\n    public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromActivity() {\n        EasyPermissions.onRequestPermissionsResult(TestActivity.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT, spyActivity);\n\n        verify(spyActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION)));\n\n        verify(spyActivity, times(1))\n                .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS)));\n\n        verify(spyActivity, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromActivity() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        verify(spyActivity, never()).requestPermissions(any(String[].class), anyInt());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n    @Test\n    public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFromActivity() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well\n        verify(spyActivity, times(2)).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromActivity() {\n        grantPermissions(ONE_PERM);\n\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyActivity, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldRequestPermissions_whenMissingPermissionAndNotShowRationaleFromActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(false, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyActivity, times(1))\n                .requestPermissions(ALL_PERMS, TestActivity.REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyActivity, RATIONALE, TestActivity.REQUEST_CODE, ALL_PERMS);\n\n        Fragment dialogFragment = spyActivity.getFragmentManager()\n                .findFragmentByTag(RationaleDialogFragment.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class);\n\n        Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog();\n        assertThatHasExpectedRationale(dialog, RATIONALE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        PermissionRequest request = new PermissionRequest.Builder(spyActivity, TestActivity.REQUEST_CODE, ALL_PERMS)\n                .setPositiveButtonText(android.R.string.ok)\n                .setNegativeButtonText(android.R.string.cancel)\n                .setRationale(android.R.string.unknownName)\n                .setTheme(R.style.Theme_AppCompat)\n                .build();\n        EasyPermissions.requestPermissions(request);\n\n        Fragment dialogFragment = spyActivity.getFragmentManager()\n                .findFragmentByTag(RationaleDialogFragment.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class);\n\n        Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog();\n        assertThatHasExpectedButtonsAndRationale(dialog, android.R.string.unknownName,\n                android.R.string.ok, android.R.string.cancel);\n    }\n\n    @Test\n    public void shouldHaveSomePermissionDenied_whenShowRationaleFromActivity() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyActivity, ALL_PERMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromActivity() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyActivity, ALL_PERMS)).isFalse();\n    }\n\n    @Test\n    public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromActivity() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyActivity, Arrays.asList(ALL_PERMS))).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromActivity() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyActivity, Arrays.asList(ALL_PERMS))).isFalse();\n    }\n\n    @Test\n    public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromActivity() {\n        showRationale(false, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyActivity, Manifest.permission.READ_SMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromActivity() {\n        showRationale(true, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyActivity, Manifest.permission.READ_SMS)).isFalse();\n    }\n\n    @Test\n    public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromAppCompatActivity() {\n        EasyPermissions.onRequestPermissionsResult(TestAppCompatActivity.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT, spyAppCompatActivity);\n\n        verify(spyAppCompatActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION)));\n\n        verify(spyAppCompatActivity, times(1))\n                .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS)));\n\n        verify(spyAppCompatActivity, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromAppCompatActivity() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyAppCompatActivity, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        verify(spyAppCompatActivity, never()).requestPermissions(any(String[].class), anyInt());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestAppCompatActivity.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n    @Test\n    public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFromAppCompatActivity() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well\n        verify(spyAppCompatActivity, times(2)).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromAppCompatActivity() {\n        grantPermissions(ONE_PERM);\n\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyAppCompatActivity, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldRequestPermissions_whenMissingPermissionAndNotShowRationaleFromAppCompatActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(false, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyAppCompatActivity, times(1))\n                .requestPermissions(ALL_PERMS, TestAppCompatActivity.REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromAppCompatActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyAppCompatActivity, RATIONALE, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS);\n\n        androidx.fragment.app.Fragment dialogFragment = spyAppCompatActivity.getSupportFragmentManager()\n                .findFragmentByTag(RationaleDialogFragmentCompat.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class);\n\n        Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog();\n        assertThatHasExpectedRationale(dialog, RATIONALE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromSupportFragmentActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spySupportFragmentActivity, RATIONALE, TestSupportFragmentActivity.REQUEST_CODE, ALL_PERMS);\n\n        Fragment dialogFragment = spySupportFragmentActivity.getFragmentManager()\n                .findFragmentByTag(RationaleDialogFragment.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragment.class);\n\n        Dialog dialog = ((RationaleDialogFragment) dialogFragment).getDialog();\n        assertThatHasExpectedRationale(dialog, RATIONALE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromAppCompatActivity() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        PermissionRequest request = new PermissionRequest.Builder(spyAppCompatActivity, TestAppCompatActivity.REQUEST_CODE, ALL_PERMS)\n                .setPositiveButtonText(android.R.string.ok)\n                .setNegativeButtonText(android.R.string.cancel)\n                .setRationale(android.R.string.unknownName)\n                .setTheme(R.style.Theme_AppCompat)\n                .build();\n        EasyPermissions.requestPermissions(request);\n\n        androidx.fragment.app.Fragment dialogFragment = spyAppCompatActivity.getSupportFragmentManager()\n                .findFragmentByTag(RationaleDialogFragmentCompat.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class);\n\n        Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog();\n        assertThatHasExpectedButtonsAndRationale(dialog, android.R.string.unknownName,\n                android.R.string.ok, android.R.string.cancel);\n    }\n\n    @Test\n    public void shouldHaveSomePermissionDenied_whenShowRationaleFromAppCompatActivity() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyAppCompatActivity, ALL_PERMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromAppCompatActivity() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyAppCompatActivity, ALL_PERMS)).isFalse();\n    }\n\n    @Test\n    public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromAppCompatActivity() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyAppCompatActivity, Arrays.asList(ALL_PERMS))).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromAppCompatActivity() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyAppCompatActivity, Arrays.asList(ALL_PERMS))).isFalse();\n    }\n\n    @Test\n    public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromAppCompatActivity() {\n        showRationale(false, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyAppCompatActivity, Manifest.permission.READ_SMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromAppCompatActivity() {\n        showRationale(true, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyAppCompatActivity, Manifest.permission.READ_SMS)).isFalse();\n    }\n\n    @Test\n    public void shouldCorrectlyCallback_whenOnRequestPermissionResultCalledFromFragment() {\n        EasyPermissions.onRequestPermissionsResult(TestFragment.REQUEST_CODE, ALL_PERMS, SMS_DENIED_RESULT,\n                spyFragment);\n\n        verify(spyFragment, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION)));\n\n        verify(spyFragment, times(1))\n                .onPermissionsDenied(integerCaptor.capture(), listCaptor.capture());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE);\n        assertThat(listCaptor.getValue())\n                .containsAllIn(new ArrayList<>(Collections.singletonList(Manifest.permission.READ_SMS)));\n\n        verify(spyFragment, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldCallbackOnPermissionGranted_whenRequestAlreadyGrantedPermissionsFromFragment() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE,\n                TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyFragment, times(1))\n                .onPermissionsGranted(integerCaptor.capture(), listCaptor.capture());\n        verify(spyFragment, never()).requestPermissions(any(String[].class), anyInt());\n        assertThat(integerCaptor.getValue()).isEqualTo(TestFragment.REQUEST_CODE);\n        assertThat(listCaptor.getValue()).containsAllIn(ALL_PERMS);\n    }\n\n    @Test\n    public void shouldCallbackAfterPermissionGranted_whenRequestAlreadyGrantedPermissionsFragment() {\n        grantPermissions(ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        // Called 2 times because this is a spy and library implementation invokes super classes annotated methods as well\n        verify(spyFragment, times(2)).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldNotCallbackAfterPermissionGranted_whenRequestNotGrantedPermissionsFromFragment() {\n        grantPermissions(ONE_PERM);\n\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyFragment, never()).afterPermissionGranted();\n    }\n\n    @Test\n    public void shouldRequestPermissions_whenMissingPermissionsAndNotShowRationaleFromFragment() {\n        grantPermissions(ONE_PERM);\n        showRationale(false, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        verify(spyFragment, times(1))\n                .requestPermissions(ALL_PERMS, TestFragment.REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialog_whenMissingPermissionsAndShowRationaleFromFragment() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        EasyPermissions.requestPermissions(spyFragment, RATIONALE, TestFragment.REQUEST_CODE, ALL_PERMS);\n\n        androidx.fragment.app.Fragment dialogFragment = spyFragment.getChildFragmentManager()\n                .findFragmentByTag(RationaleDialogFragmentCompat.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class);\n\n        Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog();\n        assertThatHasExpectedRationale(dialog, RATIONALE);\n    }\n\n    @Test\n    public void shouldShowCorrectDialogUsingRequest_whenMissingPermissionsAndShowRationaleFromFragment() {\n        grantPermissions(ONE_PERM);\n        showRationale(true, ALL_PERMS);\n\n        PermissionRequest request = new PermissionRequest.Builder(spyFragment, TestFragment.REQUEST_CODE, ALL_PERMS)\n                .setPositiveButtonText(POSITIVE)\n                .setNegativeButtonText(NEGATIVE)\n                .setRationale(RATIONALE)\n                .setTheme(R.style.Theme_AppCompat)\n                .build();\n        EasyPermissions.requestPermissions(request);\n\n        androidx.fragment.app.Fragment dialogFragment = spyFragment.getChildFragmentManager()\n                .findFragmentByTag(RationaleDialogFragmentCompat.TAG);\n        assertThat(dialogFragment).isInstanceOf(RationaleDialogFragmentCompat.class);\n\n        Dialog dialog = ((RationaleDialogFragmentCompat) dialogFragment).getDialog();\n        assertThatHasExpectedButtonsAndRationale(dialog, RATIONALE, POSITIVE, NEGATIVE);\n    }\n\n    @Test\n    public void shouldHaveSomePermissionDenied_whenShowRationaleFromFragment() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyFragment, ALL_PERMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionDenied_whenNotShowRationaleFromFragment() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionDenied(spyFragment, ALL_PERMS)).isFalse();\n    }\n\n    @Test\n    public void shouldHaveSomePermissionPermanentlyDenied_whenNotShowRationaleFromFragment() {\n        showRationale(false, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyFragment, Arrays.asList(ALL_PERMS))).isTrue();\n    }\n\n    @Test\n    public void shouldNotHaveSomePermissionPermanentlyDenied_whenShowRationaleFromFragment() {\n        showRationale(true, ALL_PERMS);\n\n        assertThat(EasyPermissions.somePermissionPermanentlyDenied(spyFragment, Arrays.asList(ALL_PERMS))).isFalse();\n    }\n\n\n    @Test\n    public void shouldHavePermissionPermanentlyDenied_whenNotShowRationaleFromFragment() {\n        showRationale(false, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyFragment, Manifest.permission.READ_SMS)).isTrue();\n    }\n\n    @Test\n    public void shouldNotHavePermissionPermanentlyDenied_whenShowRationaleFromFragment() {\n        showRationale(true, Manifest.permission.READ_SMS);\n\n        assertThat(EasyPermissions.permissionPermanentlyDenied(spyFragment, Manifest.permission.READ_SMS)).isFalse();\n    }\n\n    private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, int rationale,\n                                                          int positive, int negative) {\n        TextView dialogMessage = dialog.findViewById(android.R.id.message);\n        assertThat(dialogMessage.getText().toString()).isEqualTo(app.getString(rationale));\n        TextView positiveMessage = dialog.findViewById(android.R.id.button1);\n        assertThat(positiveMessage.getText().toString()).isEqualTo(app.getString(positive));\n        TextView negativeMessage = dialog.findViewById(android.R.id.button2);\n        assertThat(negativeMessage.getText().toString()).isEqualTo(app.getString(negative));\n    }\n\n    private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, String rationale,\n                                                          int positive, int negative) {\n        TextView dialogMessage = dialog.findViewById(android.R.id.message);\n        assertThat(dialogMessage.getText().toString()).isEqualTo(rationale);\n        TextView positiveMessage = dialog.findViewById(android.R.id.button1);\n        assertThat(positiveMessage.getText().toString()).isEqualTo(app.getString(positive));\n        TextView negativeMessage = dialog.findViewById(android.R.id.button2);\n        assertThat(negativeMessage.getText().toString()).isEqualTo(app.getString(negative));\n    }\n\n    private void assertThatHasExpectedButtonsAndRationale(Dialog dialog, String rationale,\n                                                          String positive, String negative) {\n        TextView dialogMessage = dialog.findViewById(android.R.id.message);\n        assertThat(dialogMessage.getText().toString()).isEqualTo(rationale);\n        TextView positiveMessage = dialog.findViewById(android.R.id.button1);\n        assertThat(positiveMessage.getText().toString()).isEqualTo(positive);\n        TextView negativeMessage = dialog.findViewById(android.R.id.button2);\n        assertThat(negativeMessage.getText().toString()).isEqualTo(negative);\n    }\n\n    private void assertThatHasExpectedRationale(Dialog dialog, String rationale) {\n        TextView dialogMessage = dialog.findViewById(android.R.id.message);\n        assertThat(dialogMessage.getText().toString()).isEqualTo(rationale);\n    }\n\n    private void grantPermissions(String[] perms) {\n        shadowApp.grantPermissions(perms);\n    }\n\n    private void showRationale(boolean show, String... perms) {\n        for (String perm : perms) {\n            when(spyActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show);\n            when(spySupportFragmentActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show);\n            when(spyAppCompatActivity.shouldShowRequestPermissionRationale(perm)).thenReturn(show);\n            when(spyFragment.shouldShowRequestPermissionRationale(perm)).thenReturn(show);\n        }\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/RationaleDialogClickListenerTest.java",
    "content": "package pub.devrel.easypermissions;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.app.Dialog;\nimport android.content.DialogInterface;\n\nimport androidx.fragment.app.Fragment;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.annotation.Config;\n\nimport java.util.Arrays;\n\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@RunWith(RobolectricTestRunner.class)\n@Config(sdk = 23)\npublic class RationaleDialogClickListenerTest {\n\n    private static final int REQUEST_CODE = 5;\n    private static final String[] PERMS = new String[]{\n            Manifest.permission.READ_SMS, Manifest.permission.ACCESS_FINE_LOCATION};\n    @Mock\n    private RationaleDialogFragment dialogFragment;\n    @Mock\n    private RationaleDialogFragmentCompat dialogFragmentCompat;\n    @Mock\n    private RationaleDialogConfig dialogConfig;\n    @Mock\n    private EasyPermissions.PermissionCallbacks permissionCallbacks;\n    @Mock\n    private EasyPermissions.RationaleCallbacks rationaleCallbacks;\n    @Mock\n    private DialogInterface dialogInterface;\n    @Mock\n    private Activity activity;\n    @Mock\n    private Fragment fragment;\n\n    @Before\n    public void setUp() {\n        MockitoAnnotations.initMocks(this);\n\n        when(dialogFragment.getActivity()).thenReturn(activity);\n        dialogConfig.requestCode = REQUEST_CODE;\n        dialogConfig.permissions = PERMS;\n    }\n\n    @Test\n    public void shouldOnRationaleAccepted_whenPositiveButtonWithRationaleCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE);\n\n        verify(rationaleCallbacks, times(1)).onRationaleAccepted(REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldNotOnRationaleAccepted_whenPositiveButtonWithoutRationaleCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, null);\n        listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE);\n\n        verify(rationaleCallbacks, never()).onRationaleAccepted(anyInt());\n    }\n\n    @Test\n    public void shouldRequestPermissions_whenPositiveButtonFromActivity() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE);\n\n        verify(activity, times(1)).requestPermissions(PERMS, REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldRequestPermissions_whenPositiveButtonFromFragment() {\n        when(dialogFragmentCompat.getParentFragment()).thenReturn(fragment);\n\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragmentCompat, dialogConfig,\n                permissionCallbacks, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_POSITIVE);\n\n        verify(fragment, times(1)).requestPermissions(PERMS, REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldOnRationaleDenied_whenNegativeButtonWithRationaleCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE);\n\n        verify(rationaleCallbacks, times(1)).onRationaleDenied(REQUEST_CODE);\n    }\n\n    @Test\n    public void shouldNotOnRationaleDenied_whenNegativeButtonWithoutRationaleCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, null);\n        listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE);\n\n        verify(rationaleCallbacks, never()).onRationaleDenied(anyInt());\n    }\n\n    @Test\n    public void shouldOnPermissionsDenied_whenNegativeButtonWithPermissionCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                permissionCallbacks, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE);\n\n        verify(permissionCallbacks, times(1))\n                .onPermissionsDenied(REQUEST_CODE, Arrays.asList(PERMS));\n    }\n\n    @Test\n    public void shouldNotOnPermissionsDenied_whenNegativeButtonWithoutPermissionCallbacks() {\n        RationaleDialogClickListener listener = new RationaleDialogClickListener(dialogFragment, dialogConfig,\n                null, rationaleCallbacks);\n        listener.onClick(dialogInterface, Dialog.BUTTON_NEGATIVE);\n\n        verify(permissionCallbacks, never()).onPermissionsDenied(anyInt(), ArgumentMatchers.<String>anyList());\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/ActivityController.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport android.app.Activity;\n\nimport androidx.annotation.NonNull;\nimport androidx.test.core.app.ActivityScenario;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\n/**\n * Helper class to allow starting Activity, similar to the Robolectric ActivityConroller.\n */\npublic class ActivityController<T extends Activity> {\n\n    private ActivityScenario<T> scenario;\n\n    public ActivityController(Class<T> clazz) {\n        scenario = ActivityScenario.launch(clazz);\n    }\n\n    public synchronized T resume() {\n        final CompletableFuture<T> ActivityFuture = new CompletableFuture<>();\n\n        scenario.onActivity(new ActivityScenario.ActivityAction<T>() {\n            @Override\n            public void perform(@NonNull T activity) {\n                ActivityFuture.complete(activity);\n            }\n        });\n\n        try {\n            return ActivityFuture.get();\n        } catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        } catch (ExecutionException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void reset() {\n        scenario.recreate();\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/FragmentController.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport androidx.annotation.NonNull;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.testing.FragmentScenario;\n\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\n\n/**\n * Helper class to allow starting Fragments, similar to the old SupportFragmentController.\n */\npublic class FragmentController<T extends Fragment> {\n\n    private FragmentScenario<T> scenario;\n\n    public FragmentController(Class<T> clazz) {\n        scenario = FragmentScenario.launch(clazz);\n    }\n\n    public synchronized T resume() {\n        final CompletableFuture<T> fragmentFuture = new CompletableFuture<>();\n\n        scenario.onFragment(new FragmentScenario.FragmentAction<T>() {\n            @Override\n            public void perform(@NonNull T fragment) {\n                fragmentFuture.complete(fragment);\n            }\n        });\n\n        try {\n            return fragmentFuture.get();\n        } catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        } catch (ExecutionException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void reset() {\n        scenario.recreate();\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestActivity.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport android.app.Activity;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.EasyPermissions;\n\npublic class TestActivity extends Activity\n        implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks {\n\n    public static final int REQUEST_CODE = 1;\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @AfterPermissionGranted(REQUEST_CODE)\n    public void afterPermissionGranted() {\n\n    }\n\n    @Override\n    public void onRationaleAccepted(int requestCode) {\n\n    }\n\n    @Override\n    public void onRationaleDenied(int requestCode) {\n\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestAppCompatActivity.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport android.os.Bundle;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.EasyPermissions;\nimport pub.devrel.easypermissions.R;\n\npublic class TestAppCompatActivity extends AppCompatActivity\n        implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks {\n\n    public static final int REQUEST_CODE = 3;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        getTheme().applyStyle(R.style.Theme_AppCompat, true);\n        super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @AfterPermissionGranted(REQUEST_CODE)\n    public void afterPermissionGranted() {\n\n    }\n\n    @Override\n    public void onRationaleAccepted(int requestCode) {\n\n    }\n\n    @Override\n    public void onRationaleDenied(int requestCode) {\n\n    }\n\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestFragment.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.EasyPermissions;\nimport pub.devrel.easypermissions.R;\n\npublic class TestFragment extends Fragment\n        implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks {\n\n    public static final int REQUEST_CODE = 4;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater,\n                             @Nullable ViewGroup container,\n                             @Nullable Bundle savedInstanceState) {\n        getContext().getTheme().applyStyle(R.style.Theme_AppCompat, true);\n        return super.onCreateView(inflater, container, savedInstanceState);\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @AfterPermissionGranted(REQUEST_CODE)\n    public void afterPermissionGranted() {\n\n    }\n\n    @Override\n    public void onRationaleAccepted(int requestCode) {\n\n    }\n\n    @Override\n    public void onRationaleDenied(int requestCode) {\n\n    }\n}\n"
  },
  {
    "path": "easypermissions/src/test/java/pub/devrel/easypermissions/testhelper/TestSupportFragmentActivity.java",
    "content": "package pub.devrel.easypermissions.testhelper;\n\nimport android.os.Bundle;\n\nimport java.util.List;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentActivity;\nimport pub.devrel.easypermissions.AfterPermissionGranted;\nimport pub.devrel.easypermissions.EasyPermissions;\n\npublic class TestSupportFragmentActivity extends FragmentActivity\n        implements EasyPermissions.PermissionCallbacks, EasyPermissions.RationaleCallbacks {\n\n    public static final int REQUEST_CODE = 5;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n      super.onCreate(savedInstanceState);\n    }\n\n    @Override\n    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @Override\n    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {\n\n    }\n\n    @AfterPermissionGranted(REQUEST_CODE)\n    public void afterPermissionGranted() {\n\n    }\n\n    @Override\n    public void onRationaleAccepted(int requestCode) {\n\n    }\n\n    @Override\n    public void onRationaleDenied(int requestCode) {\n\n    }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.8.3-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\n# Configure on demand\norg.gradle.configureondemand=true\n\n# Required by Robolectric 4.x\n#android.enableUnitTestBinaryResources=true\n\n# Move transitive dependencies to AndroidX\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\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#      https://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\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\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\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\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='\"-Xmx64m\" \"-Xms64m\"'\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\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\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\" -a \"$nonstop\" = \"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 or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\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=`expr $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# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':easypermissions'\n"
  }
]