From 6ef4be9fa56da9135c7b0ec60ea063ea7b1dfb5e Mon Sep 17 00:00:00 2001 From: Dhruv Nagarajan Date: Tue, 29 Oct 2019 15:06:21 +0530 Subject: [PATCH 1/5] Add support for Kt Extensions --- .idea/codeStyles/Project.xml | 134 ++++++++++++++---- .idea/gradle.xml | 1 + build.gradle | 2 + permissions/build.gradle | 6 + .../nabinbhandari/android/permissions/Ext.kt | 16 +++ sample/build.gradle | 10 +- .../permissions/sample/MainActivity.java | 71 ---------- .../permissions/sample/MainActivity.kt | 64 +++++++++ 8 files changed, 206 insertions(+), 98 deletions(-) create mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/Ext.kt delete mode 100644 sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.java create mode 100644 sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.kt diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 30aa626..ae78c11 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,29 +1,113 @@ - - - - - - - - - - + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
\ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 5b97d69..e79407b 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -13,6 +13,7 @@ diff --git a/build.gradle b/build.gradle index 0928e2b..a87cc9c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.50' repositories { jcenter() google() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // Uncomment following two lines only during publishing. // classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' diff --git a/permissions/build.gradle b/permissions/build.gradle index 5b12744..06d953f 100644 --- a/permissions/build.gradle +++ b/permissions/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' ext { bintrayRepo = 'android' @@ -38,6 +40,10 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} +repositories { + mavenCentral() } // Uncomment following two lines only during publishing. diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/Ext.kt b/permissions/src/main/java/com/nabinbhandari/android/permissions/Ext.kt new file mode 100644 index 0000000..02c0e12 --- /dev/null +++ b/permissions/src/main/java/com/nabinbhandari/android/permissions/Ext.kt @@ -0,0 +1,16 @@ +package com.nabinbhandari.android.permissions + +import android.app.Activity + +/** + * @author Dhruvaraj Nagarajan + */ +fun Activity.checkPermission(permissions: Array, rationale: String?, + options: Permissions.Options?, handler: PermissionHandler) { + Permissions.check(this, permissions, rationale, options, handler) +} + + +fun Activity.checkPermission(permissions: String, rationale: String?, handler: PermissionHandler) { + Permissions.check(this, permissions, rationale, handler) +} \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 114a2d4..2630e9f 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' android { compileSdkVersion 27 @@ -15,6 +17,10 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - // implementation project(':permissions') - implementation 'com.nabinbhandari.android:permissions:3.8' + implementation project(':permissions') +// implementation 'com.nabinbhandari.android:permissions:3.8' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} +repositories { + mavenCentral() } diff --git a/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.java b/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.java deleted file mode 100644 index c1a60e8..0000000 --- a/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.nabinbhandari.permissions.sample; - -import android.Manifest; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.provider.Settings; -import android.view.View; -import android.widget.Toast; - -import com.nabinbhandari.android.permissions.PermissionHandler; -import com.nabinbhandari.android.permissions.Permissions; - -import java.util.ArrayList; - -public class MainActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - } - - public void requestPhone(View view) { - Permissions.check(this, Manifest.permission.CALL_PHONE, null, new PermissionHandler() { - @Override - public void onGranted() { - Toast.makeText(MainActivity.this, "Phone granted.", Toast.LENGTH_SHORT).show(); - } - }); - } - - public void requestCameraAndStorage(View view) { - String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; - Permissions.check(this, permissions, null, null, new PermissionHandler() { - @Override - public void onGranted() { - Toast.makeText(MainActivity.this, "Camera+Storage granted.", Toast.LENGTH_SHORT).show(); - } - }); - } - - public void requestLocation(View view) { - String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION}; - String rationale = "Please provide location permission so that you can ..."; - Permissions.Options options = new Permissions.Options() - .setRationaleDialogTitle("Info") - .setSettingsDialogTitle("Warning"); - - Permissions.check(this, permissions, rationale, options, new PermissionHandler() { - @Override - public void onGranted() { - Toast.makeText(MainActivity.this, "Location granted.", Toast.LENGTH_SHORT).show(); - } - - @Override - public void onDenied(Context context, ArrayList deniedPermissions) { - Toast.makeText(MainActivity.this, "Location denied.", Toast.LENGTH_SHORT).show(); - } - }); - } - - public void openSettings(View view) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.fromParts("package", getPackageName(), null)); - startActivity(intent); - } - -} diff --git a/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.kt b/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.kt new file mode 100644 index 0000000..af16ffa --- /dev/null +++ b/sample/src/main/java/com/nabinbhandari/permissions/sample/MainActivity.kt @@ -0,0 +1,64 @@ +package com.nabinbhandari.permissions.sample + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.view.View +import android.widget.Toast +import com.nabinbhandari.android.permissions.PermissionHandler +import com.nabinbhandari.android.permissions.Permissions +import com.nabinbhandari.android.permissions.checkPermission +import java.util.* + +class MainActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + } + + fun requestPhone(view: View) { + checkPermission(Manifest.permission.CALL_PHONE, null, object : PermissionHandler() { + override fun onGranted() { + Toast.makeText(this@MainActivity, "Phone granted.", Toast.LENGTH_SHORT).show() + } + }) + } + + fun requestCameraAndStorage(view: View) { + val permissions = arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE) + checkPermission(permissions, null, null, object : PermissionHandler() { + override fun onGranted() { + Toast.makeText(this@MainActivity, "Camera+Storage granted.", Toast.LENGTH_SHORT).show() + } + }) + } + + fun requestLocation(view: View) { + val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) + val rationale = "Please provide location permission so that you can ..." + val options = Permissions.Options() + .setRationaleDialogTitle("Info") + .setSettingsDialogTitle("Warning") + + checkPermission(permissions, rationale, options, object : PermissionHandler() { + override fun onGranted() { + Toast.makeText(this@MainActivity, "Location granted.", Toast.LENGTH_SHORT).show() + } + + override fun onDenied(context: Context, deniedPermissions: ArrayList) { + Toast.makeText(this@MainActivity, "Location denied.", Toast.LENGTH_SHORT).show() + } + }) + } + + fun openSettings(view: View) { + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", packageName, null)) + startActivity(intent) + } +} From b633dc8a765173e35734155e4685b35fdaed8265 Mon Sep 17 00:00:00 2001 From: Dhruv Nagarajan Date: Tue, 29 Oct 2019 15:08:46 +0530 Subject: [PATCH 2/5] Update gitignore --- permissions/.gitignore | 66 +++++++++++++++++++++++++++++++++++++++++- sample/.gitignore | 66 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/permissions/.gitignore b/permissions/.gitignore index 796b96d..3c117df 100644 --- a/permissions/.gitignore +++ b/permissions/.gitignore @@ -1 +1,65 @@ -/build +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md \ No newline at end of file diff --git a/sample/.gitignore b/sample/.gitignore index 796b96d..3c117df 100644 --- a/sample/.gitignore +++ b/sample/.gitignore @@ -1 +1,65 @@ -/build +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md \ No newline at end of file From e4841e563335d557c5b6b157197947fe89d2fc57 Mon Sep 17 00:00:00 2001 From: Dhruv Nagarajan Date: Tue, 29 Oct 2019 15:29:46 +0530 Subject: [PATCH 3/5] Update readme --- .idea/modules.xml | 3 +++ readme.md | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.idea/modules.xml b/.idea/modules.xml index 4f20aba..b7b589e 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,9 @@ + + + diff --git a/readme.md b/readme.md index 3942dc1..b3406f6 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,23 @@ implementation 'com.nabinbhandari.android:permissions:3.8' Usage: ------ +All call types shown below can be made directly from Activity as they are extensions as well. + +Example: +```kotlin +override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + checkPermission(Manifest.permission.CALL_PHONE, null, object: PermissionHandler { + override fun onGranted() { + // do your task. + } + }) +} +``` + + First declare your permissions in the manifest. Example: From 786083f9db703b7c3dcfb8607204dbc2ebad51eb Mon Sep 17 00:00:00 2001 From: Dhruv Nagarajan Date: Tue, 29 Oct 2019 15:34:03 +0530 Subject: [PATCH 4/5] Target SDK 29 --- .idea/codeStyles/Project.xml | 3 +++ .idea/compiler.xml | 22 ----------------- .idea/copyright/profiles_settings.xml | 3 --- .idea/misc.xml | 34 +-------------------------- .idea/modules.xml | 5 +--- .idea/vcs.xml | 7 +----- permissions/build.gradle | 4 ++-- sample/build.gradle | 6 ++--- 8 files changed, 11 insertions(+), 73 deletions(-) delete mode 100644 .idea/compiler.xml delete mode 100644 .idea/copyright/profiles_settings.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index ae78c11..681f41a 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,6 +1,9 @@ + +
diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 96cc43e..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f3d13dd..0d45e8d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,36 +1,4 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index b7b589e..8c9a46a 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,10 +2,7 @@ - - - - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 5fc0921..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,11 +1,6 @@ - - - - + \ No newline at end of file diff --git a/permissions/build.gradle b/permissions/build.gradle index 06d953f..a39a537 100644 --- a/permissions/build.gradle +++ b/permissions/build.gradle @@ -27,12 +27,12 @@ ext { } android { - compileSdkVersion 27 + compileSdkVersion 29 defaultConfig { //noinspection MinSdkTooLow minSdkVersion 1 - targetSdkVersion 27 + targetSdkVersion 29 versionCode 3 versionName "$libraryVersion" } diff --git a/sample/build.gradle b/sample/build.gradle index 2630e9f..20a0a4d 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { - compileSdkVersion 27 + compileSdkVersion 29 defaultConfig { applicationId "com.nabinbhandari.permissions.sample" minSdkVersion 14 - targetSdkVersion 27 + targetSdkVersion 29 versionCode 1 versionName "1.0" } From 2bff370ee6e996d9449600cfc930926692094463 Mon Sep 17 00:00:00 2001 From: Dhruv Nagarajan Date: Tue, 29 Oct 2019 15:49:29 +0530 Subject: [PATCH 5/5] Convert PermissionsHandler and PermissionsActivity to Kt --- .../permissions/PermissionHandler.java | 88 ------- .../android/permissions/PermissionHandler.kt | 87 +++++++ .../android/permissions/Permissions.java | 235 ----------------- .../android/permissions/Permissions.kt | 236 ++++++++++++++++++ .../permissions/PermissionsActivity.java | 232 ----------------- .../permissions/PermissionsActivity.kt | 193 ++++++++++++++ 6 files changed, 516 insertions(+), 555 deletions(-) delete mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.java create mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.kt delete mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.java create mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.kt delete mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.java create mode 100644 permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.kt diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.java b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.java deleted file mode 100644 index dd32dc9..0000000 --- a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.nabinbhandari.android.permissions; - -import android.content.Context; -import android.widget.Toast; - -import java.util.ArrayList; - -/** - * The class for handling permission callbacks. - *

- * Created on 7/16/2017 on 3:42 PM - * - * @author Nabin Bhandari - */ -@SuppressWarnings("WeakerAccess") -public abstract class PermissionHandler { - - /** - * This method will be called if all of the requested permissions are granted. - */ - public abstract void onGranted(); - - /** - * This method will be called if some of the requested permissions have been denied. - * - * @param context The application context. - * @param deniedPermissions The list of permissions which have been denied. - */ - public void onDenied(Context context, ArrayList deniedPermissions) { - if (Permissions.loggingEnabled) { - StringBuilder builder = new StringBuilder(); - builder.append("Denied:"); - for (String permission : deniedPermissions) { - builder.append(" "); - builder.append(permission); - } - Permissions.log(builder.toString()); - } - Toast.makeText(context, "Permission Denied.", Toast.LENGTH_SHORT).show(); - } - - /** - * This method will be called if some permissions have previously been set not to ask again. - * - * @param context the application context. - * @param blockedList the list of permissions which have been set not to ask again. - * @return The overrider of this method should return true if no further action is needed, - * and should return false if the default action is to be taken, i.e. send user to settings. - *

- * Note: If the option {@link Permissions.Options#sendDontAskAgainToSettings(boolean)} has been - * set to false, the user won't be sent to settings by default. - */ - @SuppressWarnings("UnusedParameters") - public boolean onBlocked(Context context, ArrayList blockedList) { - if (Permissions.loggingEnabled) { - StringBuilder builder = new StringBuilder(); - builder.append("Set not to ask again:"); - for (String permission : blockedList) { - builder.append(" "); - builder.append(permission); - } - Permissions.log(builder.toString()); - } - return false; - } - - /** - * This method will be called if some permissions have just been set not to ask again. - * - * @param context The application context. - * @param justBlockedList The list of permissions which have just been set not to ask again. - * @param deniedPermissions The list of currently unavailable permissions. - */ - public void onJustBlocked(Context context, ArrayList justBlockedList, - ArrayList deniedPermissions) { - if (Permissions.loggingEnabled) { - StringBuilder builder = new StringBuilder(); - builder.append("Just set not to ask again:"); - for (String permission : justBlockedList) { - builder.append(" "); - builder.append(permission); - } - Permissions.log(builder.toString()); - } - onDenied(context, deniedPermissions); - } - -} diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.kt b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.kt new file mode 100644 index 0000000..9082d51 --- /dev/null +++ b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionHandler.kt @@ -0,0 +1,87 @@ +package com.nabinbhandari.android.permissions + +import android.content.Context +import android.widget.Toast + +import java.util.ArrayList + +/** + * The class for handling permission callbacks. + * + * + * Created on 7/16/2017 on 3:42 PM + * + * @author Nabin Bhandari + */ +abstract class PermissionHandler { + + /** + * This method will be called if all of the requested permissions are granted. + */ + abstract fun onGranted() + + /** + * This method will be called if some of the requested permissions have been denied. + * + * @param context The application context. + * @param deniedPermissions The list of permissions which have been denied. + */ + open fun onDenied(context: Context, deniedPermissions: ArrayList) { + if (Permissions.loggingEnabled) { + val builder = StringBuilder() + builder.append("Denied:") + for (permission in deniedPermissions) { + builder.append(" ") + builder.append(permission) + } + Permissions.log(builder.toString()) + } + Toast.makeText(context, "Permission Denied.", Toast.LENGTH_SHORT).show() + } + + /** + * This method will be called if some permissions have previously been set not to ask again. + * + * @param context the application context. + * @param blockedList the list of permissions which have been set not to ask again. + * @return The overrider of this method should return true if no further action is needed, + * and should return false if the default action is to be taken, i.e. send user to settings. + *



+ * Note: If the option [Permissions.Options.sendDontAskAgainToSettings] has been + * set to false, the user won't be sent to settings by default. + */ + fun onBlocked(context: Context, blockedList: ArrayList): Boolean { + if (Permissions.loggingEnabled) { + val builder = StringBuilder() + builder.append("Set not to ask again:") + for (permission in blockedList) { + builder.append(" ") + builder.append(permission) + } + Permissions.log(builder.toString()) + } + return false + } + + /** + * This method will be called if some permissions have just been set not to ask again. + * + * @param context The application context. + * @param justBlockedList The list of permissions which have just been set not to ask again. + * @param deniedPermissions The list of currently unavailable permissions. + */ + fun onJustBlocked(context: Context, justBlockedList: ArrayList, + deniedPermissions: ArrayList) { + if (Permissions.loggingEnabled) { + val builder = StringBuilder() + builder.append("Just set not to ask again:") + for (permission in justBlockedList) { + builder.append(" ") + builder.append(permission) + } + Permissions.log(builder.toString()) + } + onDenied(context, deniedPermissions) + } + +} diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.java b/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.java deleted file mode 100644 index 35ca0ff..0000000 --- a/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.java +++ /dev/null @@ -1,235 +0,0 @@ -package com.nabinbhandari.android.permissions; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Build; -import android.util.Log; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - *

- * Helper class for handling runtime permissions.
- * Created on 6/11/2017 on 9:32 PM
- * 
- * - * @author Nabin Bhandari - */ -@SuppressWarnings({"WeakerAccess", "unused"}) -public class Permissions { - - static boolean loggingEnabled = true; - - /** - * Disable logs. - */ - public static void disableLogging() { - loggingEnabled = false; - } - - static void log(String message) { - if (loggingEnabled) Log.d("Permissions", message); - } - - /** - * Check/Request a permission and call the callback methods of permission handler accordingly. - * - * @param context the android context. - * @param permission the permission to be requested. - * @param rationale Explanation to be shown to user if s/he has denied permission earlier. - * If this parameter is null, permissions will be requested without showing - * the rationale dialog. - * @param handler The permission handler object for handling callbacks of various user - * actions such as permission granted, permission denied, etc. - */ - public static void check(Context context, String permission, String rationale, - PermissionHandler handler) { - check(context, new String[]{permission}, rationale, null, handler); - } - - /** - * Check/Request a permission and call the callback methods of permission handler accordingly. - * - * @param context the android context. - * @param permission the permission to be requested. - * @param rationaleId The string resource id of the explanation to be shown to user if s/he has - * denied permission earlier. If resource is not found, permissions will be - * requested without showing the rationale dialog. - * @param handler The permission handler object for handling callbacks of various user - * actions such as permission granted, permission denied, etc. - */ - public static void check(Context context, String permission, int rationaleId, - PermissionHandler handler) { - String rationale = null; - try { - rationale = context.getString(rationaleId); - } catch (Exception ignored) { - } - check(context, new String[]{permission}, rationale, null, handler); - } - - /** - * Check/Request permissions and call the callback methods of permission handler accordingly. - * - * @param context Android context. - * @param permissions The array of one or more permission(s) to request. - * @param rationale Explanation to be shown to user if s/he has denied permission earlier. - * If this parameter is null, permissions will be requested without showing - * the rationale dialog. - * @param options The options for handling permissions. - * @param handler The permission handler object for handling callbacks of various user - * actions such as permission granted, permission denied, etc. - */ - public static void check(final Context context, String[] permissions, String rationale, - Options options, final PermissionHandler handler) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - handler.onGranted(); - log("Android version < 23"); - } else { - Set permissionsSet = new LinkedHashSet<>(); - Collections.addAll(permissionsSet, permissions); - boolean allPermissionProvided = true; - for (String aPermission : permissionsSet) { - if (context.checkSelfPermission(aPermission) != PackageManager.PERMISSION_GRANTED) { - allPermissionProvided = false; - break; - } - } - - if (allPermissionProvided) { - handler.onGranted(); - log("Permission(s) " + (PermissionsActivity.permissionHandler == null ? - "already granted." : "just granted from settings.")); - PermissionsActivity.permissionHandler = null; - - } else { - PermissionsActivity.permissionHandler = handler; - ArrayList permissionsList = new ArrayList<>(permissionsSet); - - Intent intent = new Intent(context, PermissionsActivity.class) - .putExtra(PermissionsActivity.EXTRA_PERMISSIONS, permissionsList) - .putExtra(PermissionsActivity.EXTRA_RATIONALE, rationale) - .putExtra(PermissionsActivity.EXTRA_OPTIONS, options); - if (options != null && options.createNewTask) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - context.startActivity(intent); - } - } - } - - /** - * Check/Request permissions and call the callback methods of permission handler accordingly. - * - * @param context Android context. - * @param permissions The array of one or more permission(s) to request. - * @param rationaleId The string resource id of the explanation to be shown to user if s/he has - * denied permission earlier. If resource is not found, permissions will be - * requested without showing the rationale dialog. - * @param options The options for handling permissions. - * @param handler The permission handler object for handling callbacks of various user - * actions such as permission granted, permission denied, etc. - */ - public static void check(final Context context, String[] permissions, int rationaleId, - Options options, final PermissionHandler handler) { - String rationale = null; - try { - rationale = context.getString(rationaleId); - } catch (Exception ignored) { - } - check(context, permissions, rationale, options, handler); - } - - /** - * Options to customize while requesting permissions. - */ - public static class Options implements Serializable { - - String settingsText = "Settings"; - String rationaleDialogTitle = "Permissions Required"; - String settingsDialogTitle = "Permissions Required"; - String settingsDialogMessage = "Required permission(s) have been set" + - " not to ask again! Please provide them from settings."; - boolean sendBlockedToSettings = true; - boolean createNewTask = false; - - /** - * Sets the button text for "settings" while asking user to go to settings. - * - * @param settingsText The text for "settings". - * @return same instance. - */ - public Options setSettingsText(String settingsText) { - this.settingsText = settingsText; - return this; - } - - /** - * Sets the "Create new Task" flag in Intent, for when we're - * calling this library from within a Service or other - * non-activity context. - * - * @param createNewTask true if we need the Intent.FLAG_ACTIVITY_NEW_TASK - * @return same instance. - */ - public Options setCreateNewTask(boolean createNewTask) { - this.createNewTask = createNewTask; - return this; - } - - /** - * Sets the title text for permission rationale dialog. - * - * @param rationaleDialogTitle the title text. - * @return same instance. - */ - public Options setRationaleDialogTitle(String rationaleDialogTitle) { - this.rationaleDialogTitle = rationaleDialogTitle; - return this; - } - - /** - * Sets the title text of the dialog which asks user to go to settings, in the case when - * permission(s) have been set not to ask again. - * - * @param settingsDialogTitle the title text. - * @return same instance. - */ - public Options setSettingsDialogTitle(String settingsDialogTitle) { - this.settingsDialogTitle = settingsDialogTitle; - return this; - } - - /** - * Sets the message of the dialog which asks user to go to settings, in the case when - * permission(s) have been set not to ask again. - * - * @param settingsDialogMessage the dialog message. - * @return same instance. - */ - public Options setSettingsDialogMessage(String settingsDialogMessage) { - this.settingsDialogMessage = settingsDialogMessage; - return this; - } - - /** - * In the case the user has previously set some permissions not to ask again, if this flag - * is true the user will be prompted to go to settings and provide the permissions otherwise - * the method {@link PermissionHandler#onDenied(Context, ArrayList)} will be invoked - * directly. The default state is true. - * - * @param send whether to ask user to go to settings or not. - * @return same instance. - */ - public Options sendDontAskAgainToSettings(boolean send) { - sendBlockedToSettings = send; - return this; - } - } - -} diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.kt b/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.kt new file mode 100644 index 0000000..7ef5795 --- /dev/null +++ b/permissions/src/main/java/com/nabinbhandari/android/permissions/Permissions.kt @@ -0,0 +1,236 @@ +package com.nabinbhandari.android.permissions + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.util.Log + +import java.io.Serializable +import java.util.ArrayList +import java.util.Collections +import java.util.LinkedHashSet + +/** + *
+ * Helper class for handling runtime permissions.
+ * Created on 6/11/2017 on 9:32 PM
+
* + * + * @author Nabin Bhandari + */ +object Permissions { + + internal var loggingEnabled = true + + /** + * Disable logs. + */ + fun disableLogging() { + loggingEnabled = false + } + + internal fun log(message: String) { + if (loggingEnabled) Log.d("Permissions", message) + } + + /** + * Check/Request a permission and call the callback methods of permission handler accordingly. + * + * @param context the android context. + * @param permission the permission to be requested. + * @param rationale Explanation to be shown to user if s/he has denied permission earlier. + * If this parameter is null, permissions will be requested without showing + * the rationale dialog. + * @param handler The permission handler object for handling callbacks of various user + * actions such as permission granted, permission denied, etc. + */ + fun check(context: Context, permission: String, rationale: String?, + handler: PermissionHandler) { + check(context, arrayOf(permission), rationale, null, handler) + } + + /** + * Check/Request a permission and call the callback methods of permission handler accordingly. + * + * @param context the android context. + * @param permission the permission to be requested. + * @param rationaleId The string resource id of the explanation to be shown to user if s/he has + * denied permission earlier. If resource is not found, permissions will be + * requested without showing the rationale dialog. + * @param handler The permission handler object for handling callbacks of various user + * actions such as permission granted, permission denied, etc. + */ + fun check(context: Context, permission: String, rationaleId: Int, + handler: PermissionHandler) { + var rationale: String? = null + try { + rationale = context.getString(rationaleId) + } catch (ignored: Exception) { + } + + check(context, arrayOf(permission), rationale, null, handler) + } + + /** + * Check/Request permissions and call the callback methods of permission handler accordingly. + * + * @param context Android context. + * @param permissions The array of one or more permission(s) to request. + * @param rationale Explanation to be shown to user if s/he has denied permission earlier. + * If this parameter is null, permissions will be requested without showing + * the rationale dialog. + * @param options The options for handling permissions. + * @param handler The permission handler object for handling callbacks of various user + * actions such as permission granted, permission denied, etc. + */ + fun check(context: Context, permissions: Array, rationale: String?, + options: Options?, handler: PermissionHandler) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + handler.onGranted() + log("Android version < 23") + } else { + val permissionsSet = LinkedHashSet() + Collections.addAll(permissionsSet, *permissions) + var allPermissionProvided = true + for (aPermission in permissionsSet) { + if (context.checkSelfPermission(aPermission) != PackageManager.PERMISSION_GRANTED) { + allPermissionProvided = false + break + } + } + + if (allPermissionProvided) { + handler.onGranted() + log("Permission(s) " + if (PermissionsActivity.permissionHandler == null) + "already granted." + else + "just granted from settings.") + PermissionsActivity.permissionHandler = null + + } else { + PermissionsActivity.permissionHandler = handler + val permissionsList = ArrayList(permissionsSet) + + val intent = Intent(context, PermissionsActivity::class.java) + .putExtra(PermissionsActivity.EXTRA_PERMISSIONS, permissionsList) + .putExtra(PermissionsActivity.EXTRA_RATIONALE, rationale) + .putExtra(PermissionsActivity.EXTRA_OPTIONS, options) + if (options != null && options.createNewTask) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + context.startActivity(intent) + } + } + } + + /** + * Check/Request permissions and call the callback methods of permission handler accordingly. + * + * @param context Android context. + * @param permissions The array of one or more permission(s) to request. + * @param rationaleId The string resource id of the explanation to be shown to user if s/he has + * denied permission earlier. If resource is not found, permissions will be + * requested without showing the rationale dialog. + * @param options The options for handling permissions. + * @param handler The permission handler object for handling callbacks of various user + * actions such as permission granted, permission denied, etc. + */ + fun check(context: Context, permissions: Array, rationaleId: Int, + options: Options, handler: PermissionHandler) { + var rationale: String? = null + try { + rationale = context.getString(rationaleId) + } catch (ignored: Exception) { + } + + check(context, permissions, rationale, options, handler) + } + + /** + * Options to customize while requesting permissions. + */ + class Options : Serializable { + + internal var settingsText = "Settings" + internal var rationaleDialogTitle = "Permissions Required" + internal var settingsDialogTitle = "Permissions Required" + internal var settingsDialogMessage = "Required permission(s) have been set" + " not to ask again! Please provide them from settings." + internal var sendBlockedToSettings = true + internal var createNewTask = false + + /** + * Sets the button text for "settings" while asking user to go to settings. + * + * @param settingsText The text for "settings". + * @return same instance. + */ + fun setSettingsText(settingsText: String): Options { + this.settingsText = settingsText + return this + } + + /** + * Sets the "Create new Task" flag in Intent, for when we're + * calling this library from within a Service or other + * non-activity context. + * + * @param createNewTask true if we need the Intent.FLAG_ACTIVITY_NEW_TASK + * @return same instance. + */ + fun setCreateNewTask(createNewTask: Boolean): Options { + this.createNewTask = createNewTask + return this + } + + /** + * Sets the title text for permission rationale dialog. + * + * @param rationaleDialogTitle the title text. + * @return same instance. + */ + fun setRationaleDialogTitle(rationaleDialogTitle: String): Options { + this.rationaleDialogTitle = rationaleDialogTitle + return this + } + + /** + * Sets the title text of the dialog which asks user to go to settings, in the case when + * permission(s) have been set not to ask again. + * + * @param settingsDialogTitle the title text. + * @return same instance. + */ + fun setSettingsDialogTitle(settingsDialogTitle: String): Options { + this.settingsDialogTitle = settingsDialogTitle + return this + } + + /** + * Sets the message of the dialog which asks user to go to settings, in the case when + * permission(s) have been set not to ask again. + * + * @param settingsDialogMessage the dialog message. + * @return same instance. + */ + fun setSettingsDialogMessage(settingsDialogMessage: String): Options { + this.settingsDialogMessage = settingsDialogMessage + return this + } + + /** + * In the case the user has previously set some permissions not to ask again, if this flag + * is true the user will be prompted to go to settings and provide the permissions otherwise + * the method [PermissionHandler.onDenied] will be invoked + * directly. The default state is true. + * + * @param send whether to ask user to go to settings or not. + * @return same instance. + */ + fun sendDontAskAgainToSettings(send: Boolean): Options { + sendBlockedToSettings = send + return this + } + } + +} diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.java b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.java deleted file mode 100644 index 7ecf972..0000000 --- a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.nabinbhandari.android.permissions; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.text.TextUtils; - -import java.util.ArrayList; - -/** - * Created by Nabin Bhandari on 7/21/2017 on 11:19 PM - */ - -@SuppressWarnings("unchecked") -@TargetApi(Build.VERSION_CODES.M) -public class PermissionsActivity extends Activity { - - private static final int RC_SETTINGS = 6739; - private static final int RC_PERMISSION = 6937; - - static final String EXTRA_PERMISSIONS = "permissions"; - static final String EXTRA_RATIONALE = "rationale"; - static final String EXTRA_OPTIONS = "options"; - - static PermissionHandler permissionHandler; - - private ArrayList allPermissions, deniedPermissions, noRationaleList; - private Permissions.Options options; - - @TargetApi(Build.VERSION_CODES.M) - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setFinishOnTouchOutside(false); - Intent intent = getIntent(); - if (intent == null || !intent.hasExtra(EXTRA_PERMISSIONS)) { - finish(); - return; - } - - getWindow().setStatusBarColor(0); - allPermissions = (ArrayList) intent.getSerializableExtra(EXTRA_PERMISSIONS); - options = (Permissions.Options) intent.getSerializableExtra(EXTRA_OPTIONS); - if (options == null) { - options = new Permissions.Options(); - } - deniedPermissions = new ArrayList<>(); - noRationaleList = new ArrayList<>(); - - boolean noRationale = true; - for (String permission : allPermissions) { - if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { - deniedPermissions.add(permission); - if (shouldShowRequestPermissionRationale(permission)) { - noRationale = false; - } else { - noRationaleList.add(permission); - } - } - } - - if (deniedPermissions.isEmpty()) { - grant(); - return; - } - - String rationale = intent.getStringExtra(EXTRA_RATIONALE); - if (noRationale || TextUtils.isEmpty(rationale)) { - Permissions.log("No rationale."); - requestPermissions(toArray(deniedPermissions), RC_PERMISSION); - } else { - Permissions.log("Show rationale."); - showRationale(rationale); - } - } - - private void showRationale(String rationale) { - DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - requestPermissions(toArray(deniedPermissions), RC_PERMISSION); - } else { - deny(); - } - } - }; - new AlertDialog.Builder(this).setTitle(options.rationaleDialogTitle) - .setMessage(rationale) - .setPositiveButton(android.R.string.ok, listener) - .setNegativeButton(android.R.string.cancel, listener) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - deny(); - } - }).create().show(); - } - - @SuppressWarnings("NullableProblems") - @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, - int[] grantResults) { - if (grantResults.length == 0) { - deny(); - } else { - deniedPermissions.clear(); - for (int i = 0; i < grantResults.length; i++) { - if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { - deniedPermissions.add(permissions[i]); - } - } - if (deniedPermissions.size() == 0) { - Permissions.log("Just allowed."); - grant(); - } else { - ArrayList blockedList = new ArrayList<>(); //set not to ask again. - ArrayList justBlockedList = new ArrayList<>(); //just set not to ask again. - ArrayList justDeniedList = new ArrayList<>(); - for (String permission : deniedPermissions) { - if (shouldShowRequestPermissionRationale(permission)) { - justDeniedList.add(permission); - } else { - blockedList.add(permission); - if (!noRationaleList.contains(permission)) { - justBlockedList.add(permission); - } - } - } - - if (justBlockedList.size() > 0) { //checked don't ask again for at least one. - PermissionHandler permissionHandler = PermissionsActivity.permissionHandler; - finish(); - if (permissionHandler != null) { - permissionHandler.onJustBlocked(getApplicationContext(), justBlockedList, - deniedPermissions); - } - - } else if (justDeniedList.size() > 0) { //clicked deny for at least one. - deny(); - - } else { //unavailable permissions were already set not to ask again. - if (permissionHandler != null && - !permissionHandler.onBlocked(getApplicationContext(), blockedList)) { - sendToSettings(); - - } else finish(); - } - } - } - } - - private void sendToSettings() { - if (!options.sendBlockedToSettings) { - deny(); - return; - } - Permissions.log("Ask to go to settings."); - new AlertDialog.Builder(this).setTitle(options.settingsDialogTitle) - .setMessage(options.settingsDialogMessage) - .setPositiveButton(options.settingsText, new DialogInterface.OnClickListener() { - @Override - @SuppressWarnings("InlinedAPI") - public void onClick(DialogInterface dialog, int which) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.fromParts("package", getPackageName(), null)); - startActivityForResult(intent, RC_SETTINGS); - } - }) - .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - deny(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - deny(); - } - }).create().show(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == RC_SETTINGS && permissionHandler != null) { - Permissions.check(this, toArray(allPermissions), null, options, - permissionHandler); - } - // super, because overridden method will make the handler null, and we don't want that. - super.finish(); - } - - private String[] toArray(ArrayList arrayList) { - int size = arrayList.size(); - String[] array = new String[size]; - for (int i = 0; i < size; i++) { - array[i] = arrayList.get(i); - } - return array; - } - - @Override - public void finish() { - permissionHandler = null; - super.finish(); - } - - private void deny() { - PermissionHandler permissionHandler = PermissionsActivity.permissionHandler; - finish(); - if (permissionHandler != null) { - permissionHandler.onDenied(getApplicationContext(), deniedPermissions); - } - } - - private void grant() { - PermissionHandler permissionHandler = PermissionsActivity.permissionHandler; - finish(); - if (permissionHandler != null) { - permissionHandler.onGranted(); - } - } - -} diff --git a/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.kt b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.kt new file mode 100644 index 0000000..d0a732d --- /dev/null +++ b/permissions/src/main/java/com/nabinbhandari/android/permissions/PermissionsActivity.kt @@ -0,0 +1,193 @@ +package com.nabinbhandari.android.permissions + +import android.annotation.TargetApi +import android.app.Activity +import android.app.AlertDialog +import android.content.DialogInterface +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import android.text.TextUtils +import java.util.* + +/** + * Created by Nabin Bhandari on 7/21/2017 on 11:19 PM + */ + +@TargetApi(Build.VERSION_CODES.M) +class PermissionsActivity : Activity() { + + private var allPermissions: ArrayList? = null + private var deniedPermissions: ArrayList? = null + private var noRationaleList: ArrayList? = null + private var options: Permissions.Options? = null + + @TargetApi(Build.VERSION_CODES.M) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setFinishOnTouchOutside(false) + val intent = intent + if (intent == null || !intent.hasExtra(EXTRA_PERMISSIONS)) { + finish() + return + } + + window.statusBarColor = 0 + allPermissions = intent.getSerializableExtra(EXTRA_PERMISSIONS) as ArrayList + options = intent.getSerializableExtra(EXTRA_OPTIONS) as Permissions.Options? + if (options == null) { + options = Permissions.Options() + } + deniedPermissions = ArrayList() + noRationaleList = ArrayList() + + var noRationale = true + for (permission in allPermissions!!) { + if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { + deniedPermissions!!.add(permission) + if (shouldShowRequestPermissionRationale(permission)) { + noRationale = false + } else { + noRationaleList!!.add(permission) + } + } + } + + if (deniedPermissions!!.isEmpty()) { + grant() + return + } + + val rationale = intent.getStringExtra(EXTRA_RATIONALE) + if (noRationale || TextUtils.isEmpty(rationale)) { + Permissions.log("No rationale.") + requestPermissions(deniedPermissions!!.toTypedArray(), RC_PERMISSION) + } else { + Permissions.log("Show rationale.") + showRationale(rationale) + } + } + + private fun showRationale(rationale: String?) { + val listener = DialogInterface.OnClickListener { dialog, which -> + if (which == DialogInterface.BUTTON_POSITIVE) { + requestPermissions(deniedPermissions!!.toTypedArray(), RC_PERMISSION) + } else { + deny() + } + } + AlertDialog.Builder(this).setTitle(options!!.rationaleDialogTitle) + .setMessage(rationale) + .setPositiveButton(android.R.string.ok, listener) + .setNegativeButton(android.R.string.cancel, listener) + .setOnCancelListener { deny() }.create().show() + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, + grantResults: IntArray) { + if (grantResults.isEmpty()) { + deny() + } else { + deniedPermissions!!.clear() + for (i in grantResults.indices) { + if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { + deniedPermissions!!.add(permissions[i]) + } + } + if (deniedPermissions!!.size == 0) { + Permissions.log("Just allowed.") + grant() + } else { + val blockedList = ArrayList() //set not to ask again. + val justBlockedList = ArrayList() //just set not to ask again. + val justDeniedList = ArrayList() + for (permission in deniedPermissions!!) { + if (shouldShowRequestPermissionRationale(permission)) { + justDeniedList.add(permission) + } else { + blockedList.add(permission) + if (!noRationaleList!!.contains(permission)) { + justBlockedList.add(permission) + } + } + } + + if (justBlockedList.size > 0) { //checked don't ask again for at least one. + val permissionHandler = permissionHandler + finish() + permissionHandler?.onJustBlocked(applicationContext, justBlockedList, + deniedPermissions!!) + + } else if (justDeniedList.size > 0) { //clicked deny for at least one. + deny() + + } else { //unavailable permissions were already set not to ask again. + if (permissionHandler != null && !permissionHandler!!.onBlocked(applicationContext, blockedList)) { + sendToSettings() + + } else + finish() + } + } + } + } + + private fun sendToSettings() { + if (!options!!.sendBlockedToSettings) { + deny() + return + } + Permissions.log("Ask to go to settings.") + AlertDialog.Builder(this).setTitle(options!!.settingsDialogTitle) + .setMessage(options!!.settingsDialogMessage) + .setPositiveButton(options!!.settingsText) { dialog, which -> + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", packageName, null)) + startActivityForResult(intent, RC_SETTINGS) + } + .setNegativeButton(android.R.string.cancel) { dialog, which -> deny() } + .setOnCancelListener { deny() }.create().show() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { + if (requestCode == RC_SETTINGS && permissionHandler != null) { + Permissions.check(this, allPermissions!!.toTypedArray(), null, options, + permissionHandler!!) + } + // super, because overridden method will make the handler null, and we don't want that. + super.finish() + } + + override fun finish() { + permissionHandler = null + super.finish() + } + + private fun deny() { + val permissionHandler = permissionHandler + finish() + permissionHandler?.onDenied(applicationContext, deniedPermissions!!) + } + + private fun grant() { + val permissionHandler = permissionHandler + finish() + permissionHandler?.onGranted() + } + + companion object { + + private val RC_SETTINGS = 6739 + private val RC_PERMISSION = 6937 + + internal val EXTRA_PERMISSIONS = "permissions" + internal val EXTRA_RATIONALE = "rationale" + internal val EXTRA_OPTIONS = "options" + + internal var permissionHandler: PermissionHandler? = null + } + +}