├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── stale.yml └── workflows │ └── android.yml ├── .gitignore ├── BACKERS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mukesh │ │ └── permissionsexample │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── mukesh │ └── permissions │ ├── EasyPermissions.java │ └── OnPermissionListener.java ├── params.json ├── screenshot └── android-working-with-marshmallow-permissions.png └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: mukeshsolanki 2 | custom: https://www.paypal.me/mukeshsolanki 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: mukeshsolanki 7 | 8 | --- 9 | 10 | ### Subject of the issue 11 | Describe your issue here. 12 | 13 | ### Steps to reproduce 14 | Tell us how to reproduce this issue. Please provide a working demo. 15 | 16 | ### Expected behaviour 17 | Tell us what should happen 18 | 19 | ### Actual behaviour 20 | Tell us what happens instead 21 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # issues only: 4 | issues: 5 | 6 | # Number of days of inactivity before an Issue or Pull Request becomes stale 7 | daysUntilStale: 60 8 | 9 | # Number of days of inactivity before a stale Issue or Pull Request is closed. 10 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 11 | daysUntilClose: 7 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - pinned 16 | - security 17 | - enchangements 18 | - "[Status] Maybe Later" 19 | 20 | # Set to true to ignore issues in a project (defaults to false) 21 | exemptProjects: false 22 | 23 | # Set to true to ignore issues in a milestone (defaults to false) 24 | exemptMilestones: false 25 | 26 | # Label to use when marking as stale 27 | staleLabel: stale 28 | 29 | # Comment to post when marking as stale. Set to `false` to disable 30 | markComment: > 31 | This issue has been automatically marked as stale because it has not had 32 | recent activity. It will be closed if no further activity occurs. Thank you 33 | for your contributions. 34 | # Comment to post when removing the stale label. 35 | # unmarkComment: > 36 | # Your comment here. 37 | 38 | # Comment to post when closing a stale Issue or Pull Request. 39 | closeComment: > 40 | This has been closed with no activity 41 | # Limit the number of actions per hour, from 1-30. Default is 30 42 | limitPerRun: 30 43 | 44 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 45 | # pulls: 46 | # daysUntilStale: 30 47 | # markComment: > 48 | # This pull request has been automatically marked as stale because it has not had 49 | # recent activity. It will be closed if no further activity occurs. Thank you 50 | # for your contributions. 51 | 52 | # issues: 53 | # exemptLabels: 54 | # - confirmed -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - 'master' 7 | push: 8 | branches: 9 | - 'master' 10 | 11 | jobs: 12 | apk: 13 | name: Generate APK 14 | runs-on: ubuntu-18.04 15 | 16 | steps: 17 | - uses: actions/checkout@v1 18 | - name: set up JDK 1.8 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 1.8 22 | - name: Build debug APK 23 | run: bash ./gradlew assembleDebug --stacktrace 24 | - name: Upload APK 25 | uses: actions/upload-artifact@v1 26 | with: 27 | name: SampleApp 28 | path: app/build/outputs/apk/debug/app-debug.apk -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea/* 10 | -------------------------------------------------------------------------------- /BACKERS.md: -------------------------------------------------------------------------------- 1 | # Backers 2 | 3 | Easy Permissions is an independent project with ongoing development and support made possible thanks to donations made by these awesome backers. If you'd like to join them, please consider: 4 | 5 | - [Become a backer or sponsor on Patreon](https://www.patreon.com/mukeshsolanki). 6 | - [One-time donation via PayPal](https://www.paypal.me/mukeshsolanki) 7 | 8 | 9 | 10 | Thank you to everyone who has donated their time, money, and support! 11 | 12 | ## Backers ($1 per month) 13 | - Be the first to back this project -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at mukesh@madapps.in. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | [![GitHub contributors](https://img.shields.io/github/contributors/mukeshsolanki/easypermissions-android.svg)](https://github.com/mukeshsolanki/easypermissions-android/graphs/contributors) 2 | 3 | * Bug reports and pull requests are welcome. 4 | * Make sure you use [square/java-code-styles](https://github.com/square/java-code-styles) to format your code. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mukesh Solanki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Proposed changes 2 | 3 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. 4 | 5 | ## Types of changes 6 | 7 | What types of changes does your code introduce? 8 | _Put an `x` in the boxes that apply_ 9 | 10 | - [ ] Bugfix (non-breaking change which fixes an issue) 11 | - [ ] New feature (non-breaking change which adds functionality) 12 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 13 | 14 | ## Checklist 15 | 16 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ 17 | 18 | - [ ] I have read the [CONTRIBUTING](CONTRIBUTING.md) doc 19 | - [ ] I have added necessary documentation (if appropriate) 20 | - [ ] Any dependent changes have been merged and published in downstream modules 21 | 22 | ## Further comments 23 | 24 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Runtime Permission Library(Android)

2 |

3 | 4 | 5 | 6 | 7 | 8 |

A simple library that will remove all the boilerplate code and speed up your work with new Runtime Permissions introduced in Android M. 9 | 10 | 11 | # Supporting Android Easy Permissions 12 | 13 | Android Easy Permissions is an independent project with ongoing development and support made possible thanks to donations made by [these awesome backers](BACKERS.md#sponsors). If you'd like to join them, please consider: 14 | 15 | - [Become a backer or sponsor on Patreon](https://www.patreon.com/mukeshsolanki). 16 | - [One-time donation via PayPal](https://www.paypal.me/mukeshsolanki) 17 | 18 | 19 | 20 | ## What are Runtime Permissions? 21 | 22 | 23 | 24 | Google docs is [here](https://developer.android.com/preview/features/runtime-permissions.html). Unlike the traditional way of asking permission Android M increased its security by enforcing apps to ask permissions on the fly as and when the user requests for a feature that requires those permissions. These permissions can also be revoked by the user at any time. 25 | ## How to integrate into your app? 26 | Integrating the library into you app is extremely easy. A few changes in the build gradle and your all ready to user Runtime permissions library. Make the following changes to build.gradle inside you app. 27 | 28 | Step 1. Add the JitPack repository to your build file. Add it in your root build.gradle at the end of repositories: 29 | 30 | ```java 31 | allprojects { 32 | repositories { 33 | ... 34 | maven { url "https://jitpack.io" } 35 | } 36 | } 37 | ``` 38 | Step 2. Add the dependency 39 | ```java 40 | dependencies { 41 | implementation 'com.github.mukeshsolanki:easypermissions-android:' 42 | } 43 | ``` 44 | 45 | ## How to use the library? 46 | Okay seems like you integrated the library in your project but **how do you use it**? Well its really easy just follow the steps below. 47 | 48 | ``` 49 | EasyPermissions easyPermissions = new EasyPermissions.Builder() 50 | .with(this) //Activity 51 | .listener( 52 | new OnPermissionListener() { 53 | @Override public void onAllPermissionsGranted(@NonNull List permissions) { 54 | // Triggered if all permissions were given 55 | } 56 | 57 | @Override public void onPermissionsGranted(@NonNull List permissions) { 58 | // Lists all the permissions that were granted 59 | } 60 | 61 | @Override public void onPermissionsDenied(@NonNull List permissions) { 62 | // Lists all the permissions that were denied 63 | } 64 | }) 65 | .build(); 66 | ``` 67 | 68 | **Dont forget to override the onRequestPermissionsResult and pass teh result to the library like wise** 69 | ``` 70 | @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 71 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 72 | easyPermissions.onRequestPermissionsResult(permissions, grantResults); 73 | } 74 | ``` 75 | 76 | ### Check Permissions 77 | To check if the app already has permissions use 78 | * `easyPermissions.hasPermission(String Permissions)` - To check one permission at a time 79 | * `easyPermissions.hasPermission(String[] Permissions)` - To check multiple permissions at the same time 80 | 81 | ### Request Permissions 82 | * `easyPermissions.request(String permission)` - To request one permission at a time 83 | * `easyPermissions.request(String[] permission)` - To request multiple permissions at the same time. 84 | 85 | That's pretty much it and your all wrapped up. 86 | 87 | ## Author 88 | Maintained by [Mukesh Solanki](https://www.github.com/mukeshsolanki) 89 | 90 | ## Contribution 91 | [![GitHub contributors](https://img.shields.io/github/contributors/mukeshsolanki/App-Runtime-Permissions-Android.svg)](https://github.com/mukeshsolanki/App-Runtime-Permissions-Android/graphs/contributors) 92 | 93 | * Bug reports and pull requests are welcome. 94 | * Make sure you use [square/java-code-styles](https://github.com/square/java-code-styles) to format your code. 95 | 96 | ## License 97 | ``` 98 | Copyright (c) 2018 Mukesh Solanki 99 | 100 | Permission is hereby granted, free of charge, to any person obtaining a copy 101 | of this software and associated documentation files (the "Software"), to deal 102 | in the Software without restriction, including without limitation the rights 103 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 104 | copies of the Software, and to permit persons to whom the Software is 105 | furnished to do so, subject to the following conditions: 106 | 107 | The above copyright notice and this permission notice shall be included in all 108 | copies or substantial portions of the Software. 109 | 110 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 111 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 112 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 113 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 114 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 115 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 116 | SOFTWARE. 117 | ``` 118 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | 6 | defaultConfig { 7 | applicationId "com.mukesh.permissionsexample" 8 | minSdkVersion 23 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'androidx.appcompat:appcompat:1.2.0' 24 | implementation project(':library') 25 | } 26 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/mukesh/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/mukesh/permissionsexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mukesh.permissionsexample; 2 | 3 | import android.Manifest; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.Toast; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | 12 | import com.mukesh.permissions.EasyPermissions; 13 | import com.mukesh.permissions.OnPermissionListener; 14 | import java.util.List; 15 | 16 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 17 | 18 | private static final String[] ALL_PERMISSIONS = { 19 | Manifest.permission.READ_SMS, Manifest.permission.WRITE_EXTERNAL_STORAGE, 20 | Manifest.permission.CAMERA 21 | }; 22 | 23 | private Button mStorageButton, mCameraButton, mSmsButton, mAllButton; 24 | private EasyPermissions permissions; 25 | 26 | @Override protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | permissions = new EasyPermissions.Builder() 30 | .with(this) 31 | .listener( 32 | new OnPermissionListener() { 33 | @Override public void onAllPermissionsGranted(@NonNull List permissions) { 34 | Toast.makeText(MainActivity.this, "All permissions granted", Toast.LENGTH_SHORT) 35 | .show(); 36 | } 37 | 38 | @Override public void onPermissionsGranted(@NonNull List permissions) { 39 | Toast.makeText(MainActivity.this, "permissions granted", Toast.LENGTH_SHORT) 40 | .show(); 41 | } 42 | 43 | @Override public void onPermissionsDenied(@NonNull List permissions) { 44 | Toast.makeText(MainActivity.this, "permissions denied", Toast.LENGTH_SHORT) 45 | .show(); 46 | } 47 | }) 48 | .build(); 49 | initializeUI(); 50 | setListener(); 51 | } 52 | 53 | private void setListener() { 54 | mStorageButton.setOnClickListener(this); 55 | mCameraButton.setOnClickListener(this); 56 | mSmsButton.setOnClickListener(this); 57 | mAllButton.setOnClickListener(this); 58 | } 59 | 60 | private void initializeUI() { 61 | mStorageButton = findViewById(R.id.storage_button); 62 | mCameraButton = findViewById(R.id.camera_button); 63 | mSmsButton = findViewById(R.id.sms_button); 64 | mAllButton = findViewById(R.id.all_button); 65 | } 66 | 67 | @Override 68 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 69 | @NonNull int[] grantResults) { 70 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 71 | this.permissions.onRequestPermissionsResult(permissions, grantResults); 72 | } 73 | 74 | @Override public void onClick(View v) { 75 | if (v.equals(mCameraButton)) { 76 | if (permissions.hasPermission(Manifest.permission.CAMERA)) { 77 | Toast.makeText(MainActivity.this, Manifest.permission.CAMERA + " already granted", 78 | Toast.LENGTH_SHORT).show(); 79 | } else { 80 | permissions.request(Manifest.permission.CAMERA); 81 | } 82 | } else if (v.equals(mStorageButton)) { 83 | if (permissions.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { 84 | Toast.makeText(MainActivity.this, 85 | Manifest.permission.WRITE_EXTERNAL_STORAGE + " already granted", 86 | Toast.LENGTH_SHORT).show(); 87 | } else { 88 | permissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE); 89 | } 90 | } else if (v.equals(mSmsButton)) { 91 | if (permissions.hasPermission(Manifest.permission.READ_SMS)) { 92 | Toast.makeText(MainActivity.this, Manifest.permission.READ_SMS + " already granted", 93 | Toast.LENGTH_SHORT).show(); 94 | } else { 95 | permissions.request(Manifest.permission.READ_SMS); 96 | } 97 | } else if (v.equals(mAllButton)) { 98 | if (permissions.hasPermission(ALL_PERMISSIONS)) { 99 | Toast.makeText(MainActivity.this, "all permissions already granted", 100 | Toast.LENGTH_SHORT).show(); 101 | } else { 102 | permissions.request(ALL_PERMISSIONS); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 |