Repository: greysonp/permiso Branch: master Commit: 77717e27564e Files: 40 Total size: 70.5 KB Directory structure: gitextract_tjgmdgdi/ ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── greysonparrelli/ │ │ └── permisodemo/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── greysonparrelli/ │ │ │ └── permisodemo/ │ │ │ ├── MainActivity.java │ │ │ └── NonPermisoActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ └── activity_non_permiso.xml │ │ ├── menu/ │ │ │ └── menu_main.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v21/ │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── com/ │ └── greysonparrelli/ │ └── permisodemo/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ ├── bintray.gradle │ ├── maven.gradle │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── permiso/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── greysonparrelli/ │ │ └── permiso/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── greysonparrelli/ │ │ │ └── permiso/ │ │ │ ├── Permiso.java │ │ │ ├── PermisoActivity.java │ │ │ └── PermisoDialogFragment.java │ │ └── res/ │ │ └── values/ │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── greysonparrelli/ │ └── permiso/ │ └── ExampleUnitTest.java └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Android local.properties # IntelliJ *.iml .idea/ # OS X .DS_Store # Gradle build /reports /.gradle ================================================ FILE: .travis.yml ================================================ language: android jdk: oraclejdk8 android: components: # Uncomment the lines below if you want to # use the latest revision of Android SDK Tools - platform-tools - tools # The BuildTools version used by your project - build-tools-26.0.2 # The SDK version used to compile your project - android-26 # Additional components - extra-google-google_play_services - extra-google-m2repository - extra-android-m2repository - addon-google_apis-google-19 # Specify at least one system image, # if you need to run emulator(s) during your tests # - sys-img-armeabi-v7a-android-19 # - sys-img-x86-android-17 script: ./gradlew assembleDebug ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Greyson Parrelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ Permiso [![Build Status](https://travis-ci.org/greysonp/permiso.svg?branch=master)](https://travis-ci.org/greysonp/permiso) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Permiso-green.svg?style=true)](https://android-arsenal.com/details/1/2818) [![Join the chat at https://gitter.im/permiso/Lobby](https://badges.gitter.im/permiso/Lobby.svg)](https://gitter.im/permiso/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ======= Permiso is an Android library that makes requesting runtime permissions a whole lot easier. Have you seen the [docs](http://developer.android.com/training/permissions/requesting.html) for how to request runtime permissions? Who wants to do *that* every time you request a permission? Let's clean this up! Features -------- * Localizes permission requests so you can handle everything using a simple callback mechanism. * Can easily make permission requests outside of the context of an Activity. * Simplifies showing the user your rationale for requesting a permission. * Can request multiple permissions at once. * Merges simultaneous requests for the same permission into a single request. Usage ----- If your Activity subclasses ```PermisoActivity```, requesting a permission is as simple as: ```java Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { if (resultSet.areAllPermissionsGranted()) { // Permission granted! } else { // Permission denied. } } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { Permiso.getInstance().showRationaleInDialog("Title", "Message", null, callback); } }, Manifest.permission.READ_EXTERNAL_STORAGE); ``` ### Requesting Multiple Permissions Requesting multiple permissions at once is just as easy. ```java Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { if (resultSet.isPermissionGranted(Manifest.permission.READ_CONTACTS)) { // Contact permission granted! } if (resultSet.isPermissionGranted(Manifest.permission.READ_CALENDAR)) { // Calendar permission granted! } } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { Permiso.getInstance().showRationaleInDialog("Title", "Message", null, callback); } }, Manifest.permission.READ_CONTACTS, Manifest.permission.READ_CALENDAR); ``` Gradle ------ ### Latest Stable Version ```java dependencies { compile 'com.greysonparrelli.permiso:permiso:0.3.0' } ``` ### Latest Dev Version ```java // In your top-level build.gradle repositories { maven { url "https://www.jitpack.io" } } // In your module's build.gradle dependencies { compile 'com.github.greysonp:permiso:master-SNAPSHOT' } ``` FAQ --- **I don't want my Activity to subclass ```PermisoActivity```. Do I have to?** Of course not! Permiso requires very little boilerplate, and therefore ```PermisoActivity``` does very little. If you don't want to subclass ```PermisoActivity```, all you have to do is make sure you do the two following things: * In ```onCreate()``` and ```onResume()```, invoke ```Permiso.getInstance().setActivity(this)```. * Forward the results of ```Activity.onRequestPermissionsResult()``` to ```Permiso.getInstance().onRequestPermissionResult()```. Here's an example: ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Permiso.getInstance().setActivity(this); } @Override protected void onResume() { super.onResume(); Permiso.getInstance().setActivity(this); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); Permiso.getInstance().onRequestPermissionResult(requestCode, permissions, grantResults); } ``` **I don't want to show any rationale for my permissions.** According to the Android Guidelines you probably should, but there's no hard requirement. If you don't want to show a rationale, simply invoke the callback and do nothing else: ```java @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { callback.onRationaleProvided(); } ``` **I want to do some complicated logic with the results of my permission request, but the ResultSet doesn't let me.** Fear not! The ```ResultSet``` object has a method called ```toMap()```, which will give you back a mapping of permissions -> ```Permiso.Result``` that you can iterate over to your heart's content. **What do you mean when you say that Permiso merges simultaneous requests for the same permission into a single request?** If you request the same permission in two places simultaneously, Permiso will automatically merge them into one request. You might think this is a rare scenario, but before you know it, you have master and detail fragments that both need access to the user's contacts, and now you have to manage your permissions so their simultaneous requests don't cause two separate pop-ups! Don't worry, Permiso handles this for you. **I request a permission but nothing happens? What's up?** Did you make sure to declare your permissions in your ```AndroidManifest.xml```? If you don't, permission requests fail silently. That's an Android thing - not much Permiso can do there. ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion '26.0.2' defaultConfig { applicationId "com.greysonparrelli.permisodemo" minSdkVersion 14 targetSdkVersion 26 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support:design:26.1.0' compile project(':permiso') } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/greyson/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: app/src/androidTest/java/com/greysonparrelli/permisodemo/ApplicationTest.java ================================================ package com.greysonparrelli.permisodemo; import android.app.Application; import android.test.ApplicationTestCase; /** * Testing Fundamentals */ public class ApplicationTest extends ApplicationTestCase { public ApplicationTest() { super(Application.class); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/greysonparrelli/permisodemo/MainActivity.java ================================================ package com.greysonparrelli.permisodemo; import android.Manifest; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Toast; import com.greysonparrelli.permiso.Permiso; import com.greysonparrelli.permiso.PermisoActivity; import com.greysonparrelli.permiso.PermisoDialogFragment; /** * An activity that demonstrates the features of {@link Permiso}. This activity extends {@link PermisoActivity} in order * to handle some boilerplate. If you don't want to extend {@link PermisoActivity}, check out * {@link NonPermisoActivity}. */ public class MainActivity extends PermisoActivity { // ===================================================================== // Overrides // ===================================================================== @SuppressWarnings("ConstantConditions") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set click listeners findViewById(R.id.btn_single).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onSingleClick(); } }); findViewById(R.id.btn_multiple).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onMultipleClick(); } }); findViewById(R.id.btn_duplicate).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onDuplicateClick(); } }); findViewById(R.id.btn_non_permiso).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onNonPermisoClick(); } }); } // ===================================================================== // Click Listeners // ===================================================================== /** * Request a single permission and display whether or not it was granted or denied. */ private void onSingleClick() { // A request for a single permission Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { if (resultSet.isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Toast.makeText(MainActivity.this, R.string.permission_granted, Toast.LENGTH_SHORT).show(); } else if (resultSet.isPermissionPermanentlyDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)){ Toast.makeText(MainActivity.this, R.string.permission_permanently_denied, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, R.string.permission_denied, Toast.LENGTH_SHORT).show(); } } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { PermisoDialogFragment.Builder builder = new PermisoDialogFragment.Builder( R.string.permission_rationale, R.string.needed_for_html_demo_purposes, android.R.string.ok); builder.setHtmlInterpretation(true); Permiso.getInstance().showRationaleInDialog(builder, callback); } }, Manifest.permission.WRITE_EXTERNAL_STORAGE); } /** * Request multiple permissions and display how many were granted. */ private void onMultipleClick() { // A request for two permissions Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { int numGranted = 0; if (resultSet.isPermissionGranted(Manifest.permission.READ_CONTACTS)) { numGranted++; } if (resultSet.isPermissionGranted(Manifest.permission.READ_CALENDAR)) { numGranted++; } String message = getString(R.string.x_permissions_granted, numGranted); Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { Permiso.getInstance().showRationaleInDialog( getString(R.string.permission_rationale), getString(R.string.needed_for_demo_purposes), null, callback); } }, Manifest.permission.READ_CONTACTS, Manifest.permission.READ_CALENDAR); } /** * Make two simultaneous requests for the same permission. Only one dialog will pop up, and the results from that * one request will be given to both callbacks. */ private void onDuplicateClick() { // First request requestPermissions("1"); // Second request for the same permission requestPermissions("2"); } private void requestPermissions(final String requestNumber) { Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { if (resultSet.areAllPermissionsGranted()) { Toast.makeText( MainActivity.this, getString(R.string.permission_granted) + " (" + requestNumber + ")", Toast.LENGTH_SHORT).show(); } else { Toast.makeText( MainActivity.this, getString(R.string.permission_denied) + " (" + requestNumber + ")", Toast.LENGTH_SHORT).show(); } } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { Permiso.getInstance().showRationaleInDialog( getString(R.string.permission_rationale), getString(R.string.needed_for_demo_purposes), null, callback); } }, Manifest.permission.CAMERA); } /** * Starts {@link NonPermisoActivity}. */ private void onNonPermisoClick() { startActivity(new Intent(this, NonPermisoActivity.class)); } } ================================================ FILE: app/src/main/java/com/greysonparrelli/permisodemo/NonPermisoActivity.java ================================================ package com.greysonparrelli.permisodemo; import android.Manifest; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; import com.greysonparrelli.permiso.Permiso; /** * Created to demonstrate how to use Permiso without extending PermisoActivity. */ public class NonPermisoActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_non_permiso); // // First, tell Permiso that you're using this activity // Permiso.getInstance().setActivity(this); findViewById(R.id.btn_request).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onRequestClick(); } }); } @Override protected void onResume() { super.onResume(); // // Second, we also have to set the activity here to handle transitioning between activities // Permiso.getInstance().setActivity(this); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // // Third, forward the results of this method to Permiso // Permiso.getInstance().onRequestPermissionResult(requestCode, permissions, grantResults); } private void onRequestClick() { // // And that's it! Now you can make permission requests as usual // Permiso.getInstance().requestPermissions(new Permiso.IOnPermissionResult() { @Override public void onPermissionResult(Permiso.ResultSet resultSet) { if (resultSet.isPermissionGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { Toast.makeText(NonPermisoActivity.this, R.string.permission_granted, Toast.LENGTH_SHORT).show(); } else if (resultSet.isPermissionPermanentlyDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)){ Toast.makeText(NonPermisoActivity.this, R.string.permission_permanently_denied, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(NonPermisoActivity.this, R.string.permission_denied, Toast.LENGTH_SHORT).show(); } } @Override public void onRationaleRequested(Permiso.IOnRationaleProvided callback, String... permissions) { Permiso.getInstance().showRationaleInDialog(getString(R.string.permission_rationale), getString(R.string.needed_for_demo_purposes), null, callback); } }, Manifest.permission.WRITE_EXTERNAL_STORAGE); } } ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================