├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── 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
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ └── layout
│ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── gun0912
│ │ └── tedpermissiondemo
│ │ ├── CoroutineActivity.kt
│ │ ├── RxJava2Activity.java
│ │ ├── NormalActivity.java
│ │ ├── WindowPermissionActivity.java
│ │ ├── RxJava3Activity.java
│ │ └── MainActivity.java
├── proguard-rules.pro
└── build.gradle
├── tedpermission
├── .gitignore
├── gradle.properties
├── src
│ └── main
│ │ ├── res
│ │ ├── values-ko
│ │ │ └── strings.xml
│ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── java
│ │ └── com
│ │ │ └── gun0912
│ │ │ └── tedpermission
│ │ │ ├── PermissionListener.java
│ │ │ ├── TedPermissionResult.java
│ │ │ ├── util
│ │ │ └── ObjectUtils.java
│ │ │ ├── provider
│ │ │ └── TedPermissionProvider.java
│ │ │ ├── TedPermissionUtil.java
│ │ │ ├── PermissionBuilder.java
│ │ │ └── TedPermissionActivity.java
│ │ └── AndroidManifest.xml
├── build.gradle
└── proguard-rules.pro
├── tedpermission-normal
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── gun0912
│ │ └── tedpermission
│ │ └── normal
│ │ └── TedPermission.java
├── build.gradle
└── proguard-rules.pro
├── tedpermission-rx2
├── .gitignore
├── gradle.properties
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── gun0912
│ │ └── tedpermission
│ │ └── rx2
│ │ └── TedPermission.java
├── build.gradle
└── proguard-rules.pro
├── tedpermission-rx3
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── gun0912
│ │ └── tedpermission
│ │ └── rx3
│ │ └── TedPermission.java
├── build.gradle
└── proguard-rules.pro
├── tedpermission-coroutine
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── gun0912
│ │ └── tedpermission
│ │ └── coroutine
│ │ └── TedPermission.kt
├── build.gradle
└── proguard-rules.pro
├── Screenshot.png
├── Screenshot_1.png
├── Screenshot_2.png
├── denied_dialog.png
├── request_dialog.png
├── Screenshot_cases.png
├── google_play_150.png
├── setting_activity.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle
├── .gitignore
├── .travis.yml
├── dependencies.gradle
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission-normal/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission-rx2/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission-rx3/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission-coroutine/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/tedpermission/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=tedpermission
2 | POM_NAME=TedPermission
--------------------------------------------------------------------------------
/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/Screenshot.png
--------------------------------------------------------------------------------
/Screenshot_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/Screenshot_1.png
--------------------------------------------------------------------------------
/Screenshot_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/Screenshot_2.png
--------------------------------------------------------------------------------
/denied_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/denied_dialog.png
--------------------------------------------------------------------------------
/request_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/request_dialog.png
--------------------------------------------------------------------------------
/tedpermission-rx3/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Screenshot_cases.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/Screenshot_cases.png
--------------------------------------------------------------------------------
/google_play_150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/google_play_150.png
--------------------------------------------------------------------------------
/setting_activity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/setting_activity.png
--------------------------------------------------------------------------------
/tedpermission-rx2/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=tedpermission-rx2
2 | POM_NAME=TedPermission-Rx2
--------------------------------------------------------------------------------
/tedpermission-rx2/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tedpermission-normal/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tedpermission-coroutine/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':tedpermission', ':tedpermission-normal', ':tedpermission-rx2', ':tedpermission-rx3', ':tedpermission-coroutine'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ParkSangGwon/TedPermission/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
10 | /.idea
11 | *.properties
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/tedpermission/src/main/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 설정
6 | 닫기
7 | 확인
8 |
9 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/PermissionListener.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission;
2 |
3 | import java.util.List;
4 |
5 | public interface PermissionListener {
6 |
7 | void onPermissionGranted();
8 |
9 | void onPermissionDenied(List deniedPermissions);
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/tedpermission/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TedPermission
3 |
4 |
5 | Setting
6 | Close
7 | Confirm
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | android:
4 | components:
5 | - tools
6 | - platform-tools
7 | - tools
8 | - build-tools-29.0.3
9 | - build-tools-25.0.0
10 | - build-tools-23.0.2
11 | - android-29
12 | - android-25
13 | - android-23
14 | - extra-android-m2repository
15 | - extra-google-m2repository
16 | script:
17 | - ./gradlew build
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TedPermissionDemo
3 |
4 |
5 | Custom Close
6 |
7 | Permission required
8 | we need permission for write storage and find your location
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tedpermission-normal/src/main/java/com/gun0912/tedpermission/normal/TedPermission.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.normal;
2 |
3 | import com.gun0912.tedpermission.PermissionBuilder;
4 |
5 | public class TedPermission {
6 | public static final String TAG = TedPermission.class.getSimpleName();
7 |
8 | public static Builder create() {
9 | return new Builder();
10 | }
11 |
12 | public static class Builder extends PermissionBuilder {
13 |
14 | public void check() {
15 | checkPermissions();
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/dependencies.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | versions = [
3 | 'minSdkVersion' : 14,
4 | 'compileSdkVersion': 34,
5 | 'targetSdkVersion' : 34,
6 | 'kotlin' : '1.9.10',
7 | ]
8 |
9 | deps = [
10 | 'rx' : [
11 | 'rxJava2': 'io.reactivex.rxjava2:rxjava:2.2.19',
12 | 'rxJava3': 'io.reactivex.rxjava3:rxjava:3.1.0',
13 | ],
14 |
15 |
16 | 'androidx': [
17 | 'appcompat': "androidx.appcompat:appcompat:1.3.1",
18 | ],
19 |
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/tedpermission/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion versions.minSdkVersion
8 | targetSdkVersion versions.targetSdkVersion
9 | }
10 | buildTypes {
11 | release {
12 | minifyEnabled false
13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
14 | }
15 | }
16 |
17 | lintOptions {
18 | abortOnError false
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation deps.androidx.appcompat
24 | }
25 |
26 | apply plugin: "com.vanniktech.maven.publish"
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/TedPermissionResult.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission;
2 |
3 | import com.gun0912.tedpermission.util.ObjectUtils;
4 | import java.util.List;
5 |
6 | public class TedPermissionResult {
7 |
8 | private boolean granted;
9 | private List deniedPermissions;
10 |
11 | public TedPermissionResult(List deniedPermissions) {
12 | this.granted = ObjectUtils.isEmpty(deniedPermissions);
13 | this.deniedPermissions = deniedPermissions;
14 | }
15 |
16 | public boolean isGranted() {
17 | return granted;
18 | }
19 |
20 | public List getDeniedPermissions() {
21 | return deniedPermissions;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tedpermission-normal/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion versions.minSdkVersion
8 | targetSdkVersion versions.targetSdkVersion
9 | }
10 | buildTypes {
11 | release {
12 | minifyEnabled false
13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
14 | }
15 | }
16 |
17 |
18 | lintOptions {
19 | abortOnError false
20 | }
21 | }
22 |
23 | dependencies {
24 | api project(':tedpermission')
25 | implementation deps.androidx.appcompat
26 | }
27 |
28 | apply plugin: "com.vanniktech.maven.publish"
29 |
--------------------------------------------------------------------------------
/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/TedPark/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 |
--------------------------------------------------------------------------------
/tedpermission/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/TedPark/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 |
--------------------------------------------------------------------------------
/tedpermission-rx2/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion versions.minSdkVersion
8 | targetSdkVersion versions.targetSdkVersion
9 | }
10 | buildTypes {
11 | release {
12 | minifyEnabled false
13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
14 | }
15 | }
16 |
17 |
18 | lintOptions {
19 | abortOnError false
20 | }
21 | }
22 |
23 | dependencies {
24 | api project(':tedpermission')
25 | implementation deps.androidx.appcompat
26 | implementation deps.rx.rxJava2
27 | }
28 |
29 | apply plugin: "com.vanniktech.maven.publish"
30 |
--------------------------------------------------------------------------------
/tedpermission-rx3/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion versions.minSdkVersion
8 | targetSdkVersion versions.targetSdkVersion
9 | }
10 | buildTypes {
11 | release {
12 | minifyEnabled false
13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
14 | }
15 | }
16 |
17 |
18 | lintOptions {
19 | abortOnError false
20 | }
21 |
22 | }
23 |
24 | dependencies {
25 | api project(':tedpermission')
26 | implementation deps.androidx.appcompat
27 | implementation deps.rx.rxJava3
28 | }
29 |
30 | apply plugin: "com.vanniktech.maven.publish"
31 |
--------------------------------------------------------------------------------
/tedpermission/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tedpermission/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/util/ObjectUtils.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.util;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | public class ObjectUtils {
7 |
8 | public static boolean isEmpty(Object s) {
9 | if (s == null) {
10 | return true;
11 | }
12 | if ((s instanceof String) && (((String)s).trim().length() == 0)) {
13 | return true;
14 | }
15 | if (s instanceof Map) {
16 | return ((Map, ?>)s).isEmpty();
17 | }
18 | if (s instanceof List) {
19 | return ((List>)s).isEmpty();
20 | }
21 | if (s instanceof Object[]) {
22 | return (((Object[])s).length == 0);
23 | }
24 | return false;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tedpermission-coroutine/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion versions.compileSdkVersion
6 |
7 | defaultConfig {
8 | minSdkVersion versions.minSdkVersion
9 | targetSdkVersion versions.targetSdkVersion
10 | }
11 | buildTypes {
12 | release {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15 | }
16 | }
17 |
18 |
19 | lintOptions {
20 | abortOnError false
21 | }
22 | }
23 |
24 | dependencies {
25 | api project(':tedpermission')
26 | implementation deps.androidx.appcompat
27 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
28 | }
29 |
30 | apply plugin: "com.vanniktech.maven.publish"
--------------------------------------------------------------------------------
/tedpermission-rx2/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/tedpark/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/tedpermission-rx3/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/tedpark/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/tedpermission-normal/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/tedpark/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/tedpermission-coroutine/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/tedpark/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
20 |
21 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/CoroutineActivity.kt:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo
2 |
3 | import android.Manifest
4 | import android.os.Bundle
5 | import android.util.Log
6 | import androidx.appcompat.app.AppCompatActivity
7 | import androidx.lifecycle.lifecycleScope
8 | import com.gun0912.tedpermission.coroutine.TedPermission
9 | import kotlinx.coroutines.launch
10 |
11 |
12 | class CoroutineActivity : AppCompatActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 |
17 | lifecycleScope.launch {
18 |
19 | val permissionResult = TedPermission.create()
20 | .setRationaleTitle(R.string.rationale_title)
21 | .setRationaleMessage(R.string.rationale_message)
22 | .setDeniedTitle("Permission denied")
23 | .setDeniedMessage(
24 | "If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]"
25 | )
26 | .setGotoSettingButtonText("bla bla")
27 | .setPermissions(
28 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
29 | Manifest.permission.ACCESS_FINE_LOCATION
30 | )
31 | .check()
32 |
33 | Log.d("ted", "permissionResult: $permissionResult")
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/tedpermission-coroutine/src/main/java/com/gun0912/tedpermission/coroutine/TedPermission.kt:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.coroutine
2 |
3 | import android.annotation.SuppressLint
4 | import com.gun0912.tedpermission.PermissionBuilder
5 | import com.gun0912.tedpermission.PermissionListener
6 | import com.gun0912.tedpermission.TedPermissionResult
7 | import kotlin.coroutines.resume
8 | import kotlin.coroutines.suspendCoroutine
9 |
10 | @SuppressLint("StaticFieldLeak")
11 | object TedPermission {
12 |
13 | fun create(): Builder = Builder()
14 |
15 |
16 | class Builder : PermissionBuilder() {
17 |
18 | override fun setPermissionListener(listener: PermissionListener): Builder {
19 | throw UnsupportedOperationException("Use check() function")
20 | }
21 |
22 | suspend fun check(): TedPermissionResult = suspendCoroutine {
23 | super.setPermissionListener(object : PermissionListener {
24 | override fun onPermissionGranted() {
25 | it.resume(TedPermissionResult(null))
26 | }
27 |
28 | override fun onPermissionDenied(deniedPermissions: MutableList?) {
29 | it.resume(TedPermissionResult(deniedPermissions))
30 | }
31 | })
32 | checkPermissions()
33 | }
34 |
35 | suspend fun checkGranted(): Boolean = check().isGranted
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-parcelize'
4 |
5 | android {
6 | compileSdkVersion versions.compileSdkVersion
7 |
8 | defaultConfig {
9 | applicationId "com.gun0912.tedpermissiondemo"
10 | minSdkVersion versions.minSdkVersion
11 | targetSdkVersion versions.targetSdkVersion
12 | versionCode 1
13 | versionName "1.0"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | packagingOptions {
24 | exclude 'META-INF/rxjava.properties'
25 | }
26 |
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 |
32 | lintOptions {
33 | abortOnError false
34 | }
35 | }
36 |
37 | dependencies {
38 | implementation project(':tedpermission')
39 | implementation project(':tedpermission-normal')
40 | implementation project(':tedpermission-rx2')
41 | implementation project(':tedpermission-rx3')
42 | implementation project(':tedpermission-coroutine')
43 |
44 | implementation deps.androidx.appcompat
45 | implementation deps.rx.rxJava2
46 | implementation deps.rx.rxJava3
47 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
48 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/RxJava2Activity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo;
2 |
3 | import android.Manifest;
4 | import android.os.Bundle;
5 | import android.widget.Toast;
6 |
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.gun0912.tedpermission.rx2.TedPermission;
11 |
12 |
13 | /**
14 | * Created by TedPark on 16. 2. 21..
15 | */
16 | public class RxJava2Activity extends AppCompatActivity {
17 |
18 | @Override
19 | protected void onCreate(@Nullable Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 |
22 | TedPermission.create()
23 | .setRationaleTitle(R.string.rationale_title)
24 | .setRationaleMessage(R.string.rationale_message) // "we need permission for read contact and find your location"
25 | .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
26 | .request()
27 | .subscribe(tedPermissionResult -> {
28 | if (tedPermissionResult.isGranted()) {
29 | Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
30 | } else {
31 | Toast.makeText(this,
32 | "Permission Denied\n" + tedPermissionResult.getDeniedPermissions().toString(), Toast.LENGTH_SHORT)
33 | .show();
34 | }
35 | }, throwable -> {
36 | });
37 |
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/provider/TedPermissionProvider.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.provider;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.ContentProvider;
5 | import android.content.ContentValues;
6 | import android.content.Context;
7 | import android.database.Cursor;
8 | import android.net.Uri;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 |
13 | public class TedPermissionProvider extends ContentProvider {
14 |
15 | @SuppressLint("StaticFieldLeak")
16 | public static Context context = null;
17 |
18 | @Override
19 | public boolean onCreate() {
20 | TedPermissionProvider.context = getContext();
21 | return false;
22 | }
23 |
24 | @Nullable
25 | @Override
26 | public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
27 | return null;
28 | }
29 |
30 | @Nullable
31 | @Override
32 | public String getType(@NonNull Uri uri) {
33 | return null;
34 | }
35 |
36 | @Nullable
37 | @Override
38 | public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
39 | return null;
40 | }
41 |
42 | @Override
43 | public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
44 | return 0;
45 | }
46 |
47 | @Override
48 | public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
49 | return 0;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 | org.gradle.jvmargs=--add-opens java.base/java.io=ALL-UNNAMED
15 |
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
20 |
21 | GROUP=io.github.ParkSangGwon
22 | VERSION_NAME=3.4.2
23 |
24 | POM_PACKAGING=aar
25 |
26 | POM_DESCRIPTION=Easy check permission library for Android Marshmallow
27 | POM_INCEPTION_YEAR=2021
28 |
29 | POM_URL=https://github.com/ParkSangGwon/TedPermission
30 | POM_SCM_URL=https://github.com/ParkSangGwon/TedPermission
31 | POM_SCM_CONNECTION=scm:git:git://github.com/ParkSangGwon/TedPermission.git
32 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/ParkSangGwon/TedPermission.git
33 |
34 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
35 | POM_LICENCE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
36 | POM_LICENCE_DIST=repo
37 |
38 | POM_DEVELOPER_ID=ParkSangGwon
39 | POM_DEVELOPER_NAME=ParkSangGwon
40 | POM_DEVELOPER_URL=https://github.com/ParkSangGwon
41 |
42 | android.useAndroidX=true
43 | android.enableJetifier=true
44 |
--------------------------------------------------------------------------------
/tedpermission-rx2/src/main/java/com/gun0912/tedpermission/rx2/TedPermission.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.rx2;
2 |
3 | import com.gun0912.tedpermission.PermissionBuilder;
4 | import com.gun0912.tedpermission.PermissionListener;
5 | import com.gun0912.tedpermission.TedPermissionResult;
6 |
7 | import java.util.List;
8 |
9 | import io.reactivex.Single;
10 | import io.reactivex.SingleEmitter;
11 | import io.reactivex.SingleOnSubscribe;
12 |
13 | public class TedPermission {
14 |
15 | public static Builder create() {
16 | return new Builder();
17 | }
18 |
19 | public static class Builder extends PermissionBuilder {
20 |
21 | public Single request() {
22 | return Single.create(new SingleOnSubscribe() {
23 | @Override
24 | public void subscribe(final SingleEmitter emitter) throws Exception {
25 | PermissionListener listener = new PermissionListener() {
26 | @Override
27 | public void onPermissionGranted() {
28 | emitter.onSuccess(new TedPermissionResult(null));
29 | }
30 |
31 | @Override
32 | public void onPermissionDenied(List deniedPermissions) {
33 | emitter.onSuccess(new TedPermissionResult(deniedPermissions));
34 | }
35 | };
36 |
37 | try {
38 | setPermissionListener(listener);
39 | checkPermissions();
40 | } catch (Exception exception) {
41 | emitter.onError(exception);
42 | }
43 | }
44 | });
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/tedpermission-rx3/src/main/java/com/gun0912/tedpermission/rx3/TedPermission.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission.rx3;
2 |
3 | import com.gun0912.tedpermission.PermissionBuilder;
4 | import com.gun0912.tedpermission.PermissionListener;
5 | import com.gun0912.tedpermission.TedPermissionResult;
6 |
7 | import java.util.List;
8 |
9 | import io.reactivex.rxjava3.annotations.NonNull;
10 | import io.reactivex.rxjava3.core.Single;
11 | import io.reactivex.rxjava3.core.SingleEmitter;
12 | import io.reactivex.rxjava3.core.SingleOnSubscribe;
13 |
14 |
15 | public class TedPermission {
16 |
17 | public static Builder create() {
18 | return new Builder();
19 | }
20 |
21 | public static class Builder extends PermissionBuilder {
22 |
23 | public Single request() {
24 | return Single.create(new SingleOnSubscribe() {
25 | @Override
26 | public void subscribe(@NonNull final SingleEmitter emitter) {
27 | PermissionListener listener = new PermissionListener() {
28 | @Override
29 | public void onPermissionGranted() {
30 | emitter.onSuccess(new TedPermissionResult(null));
31 | }
32 |
33 | @Override
34 | public void onPermissionDenied(List deniedPermissions) {
35 | emitter.onSuccess(new TedPermissionResult(deniedPermissions));
36 | }
37 | };
38 |
39 | try {
40 | setPermissionListener(listener);
41 | checkPermissions();
42 | } catch (Exception exception) {
43 | emitter.onError(exception);
44 | }
45 | }
46 | });
47 | }
48 | }
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/NormalActivity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo;
2 |
3 | import android.Manifest;
4 | import android.os.Bundle;
5 | import android.widget.Toast;
6 |
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.gun0912.tedpermission.PermissionListener;
11 | import com.gun0912.tedpermission.normal.TedPermission;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Created by TedPark on 16. 2. 21..
17 | */
18 | public class NormalActivity extends AppCompatActivity {
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 |
24 | PermissionListener permissionlistener = new PermissionListener() {
25 | @Override
26 | public void onPermissionGranted() {
27 | Toast.makeText(NormalActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
28 | }
29 |
30 | @Override
31 | public void onPermissionDenied(List deniedPermissions) {
32 | Toast.makeText(NormalActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT)
33 | .show();
34 | }
35 |
36 |
37 | };
38 |
39 |
40 | TedPermission.create()
41 | .setPermissionListener(permissionlistener)
42 | .setRationaleTitle(R.string.rationale_title)
43 | .setRationaleMessage(R.string.rationale_message)
44 | .setDeniedTitle("Permission denied")
45 | .setDeniedMessage(
46 | "If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
47 | .setGotoSettingButtonText("bla bla")
48 | .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
49 | .check();
50 |
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/WindowPermissionActivity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo;
2 |
3 | import android.Manifest;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.widget.Toast;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 |
11 | import com.gun0912.tedpermission.PermissionListener;
12 | import com.gun0912.tedpermission.TedPermissionUtil;
13 | import com.gun0912.tedpermission.normal.TedPermission;
14 |
15 | import java.util.List;
16 |
17 | /**
18 | * Created by babosamo on 16. 10. 4..
19 | */
20 | public class WindowPermissionActivity extends AppCompatActivity {
21 |
22 | @Override
23 | protected void onCreate(@Nullable Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 |
26 | boolean isAlertWindowPermissionGranted = TedPermissionUtil.isGranted(Manifest.permission.SYSTEM_ALERT_WINDOW);
27 | Log.d("ted", "isAlertWindowPermissionGranted: " + isAlertWindowPermissionGranted);
28 |
29 |
30 | PermissionListener permissionlistener = new PermissionListener() {
31 | @Override
32 | public void onPermissionGranted() {
33 | Toast.makeText(WindowPermissionActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
34 | }
35 |
36 | @Override
37 | public void onPermissionDenied(List deniedPermissions) {
38 | Toast.makeText(WindowPermissionActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
39 | }
40 |
41 |
42 | };
43 |
44 |
45 | TedPermission.create()
46 | .setPermissionListener(permissionlistener)
47 | .setRationaleMessage("we need permission for read contact, find your location and system alert window")
48 | .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
49 | .setGotoSettingButtonText("setting")
50 | .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.SYSTEM_ALERT_WINDOW)
51 | .check();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/RxJava3Activity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo;
2 |
3 | import android.Manifest;
4 | import android.os.Bundle;
5 | import android.widget.Toast;
6 |
7 | import androidx.annotation.Nullable;
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | import com.gun0912.tedpermission.PermissionListener;
11 | import com.gun0912.tedpermission.rx3.TedPermission;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Created by TedPark on 16. 2. 21..
17 | */
18 | public class RxJava3Activity extends AppCompatActivity {
19 |
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 |
24 | PermissionListener permissionlistener = new PermissionListener() {
25 | @Override
26 | public void onPermissionGranted() {
27 | Toast.makeText(RxJava3Activity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
28 | }
29 |
30 | @Override
31 | public void onPermissionDenied(List deniedPermissions) {
32 | Toast.makeText(RxJava3Activity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT)
33 | .show();
34 | }
35 |
36 |
37 | };
38 |
39 | TedPermission.create()
40 | .setDeniedMessage(
41 | "If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
42 | .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
43 | .request()
44 | .subscribe(tedPermissionResult -> {
45 | if (tedPermissionResult.isGranted()) {
46 | Toast.makeText(RxJava3Activity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
47 | } else {
48 | Toast.makeText(RxJava3Activity.this,
49 | "Permission Denied\n" + tedPermissionResult.getDeniedPermissions().toString(), Toast.LENGTH_SHORT)
50 | .show();
51 | }
52 | }, throwable -> {
53 | });
54 |
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gun0912/tedpermissiondemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermissiondemo;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.view.View.OnClickListener;
9 |
10 | import androidx.appcompat.app.AppCompatActivity;
11 |
12 | import com.gun0912.tedpermission.TedPermissionUtil;
13 | import com.gun0912.tedpermission.normal.TedPermission;
14 |
15 | import java.util.List;
16 |
17 | public class MainActivity extends AppCompatActivity implements OnClickListener {
18 |
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 |
24 | setContentView(R.layout.activity_main);
25 | findViewById(R.id.btn_normal).setOnClickListener(this);
26 | findViewById(R.id.btn_rxjava2).setOnClickListener(this);
27 | findViewById(R.id.btn_rxjava3).setOnClickListener(this);
28 | findViewById(R.id.btn_coroutine).setOnClickListener(this);
29 | findViewById(R.id.btn_windowPermission).setOnClickListener(this);
30 |
31 | boolean isGranted = TedPermissionUtil.isGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION);
32 | Log.d("ted", "isGranted: " + isGranted);
33 | List deniedPermissions = TedPermissionUtil.getDeniedPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION);
34 | Log.d("ted", "deniedPermissions: " + deniedPermissions);
35 | }
36 |
37 | @Override
38 | public void onClick(View view) {
39 | int id = view.getId();
40 |
41 | Intent intent = null;
42 |
43 | switch (id) {
44 | case R.id.btn_normal:
45 | intent = new Intent(this, NormalActivity.class);
46 | break;
47 |
48 | case R.id.btn_rxjava2:
49 | intent = new Intent(this, RxJava2Activity.class);
50 | break;
51 |
52 | case R.id.btn_rxjava3:
53 | intent = new Intent(this, RxJava3Activity.class);
54 | break;
55 |
56 | case R.id.btn_coroutine:
57 | intent = new Intent(this, CoroutineActivity.class);
58 | break;
59 |
60 | case R.id.btn_windowPermission:
61 | intent = new Intent(this, WindowPermissionActivity.class);
62 | break;
63 |
64 | }
65 |
66 | if (intent != null) {
67 | startActivity(intent);
68 | }
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/TedPermissionUtil.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission;
2 |
3 | import android.Manifest;
4 | import android.annotation.SuppressLint;
5 | import android.app.Activity;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.pm.PackageManager;
10 | import android.net.Uri;
11 | import android.os.Build;
12 | import android.provider.Settings;
13 |
14 | import androidx.annotation.NonNull;
15 | import androidx.core.app.ActivityCompat;
16 | import androidx.core.content.ContextCompat;
17 | import androidx.fragment.app.Fragment;
18 |
19 | import com.gun0912.tedpermission.provider.TedPermissionProvider;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Created by TedPark on 2017. 9. 26..
26 | */
27 |
28 | public class TedPermissionUtil {
29 | public static final int REQ_CODE_REQUEST_SETTING = 2000;
30 | private static final String PREFS_NAME_PERMISSION = "PREFS_NAME_PERMISSION";
31 | private static final String PREFS_IS_FIRST_REQUEST = "IS_FIRST_REQUEST";
32 |
33 | @SuppressLint("StaticFieldLeak")
34 | private static final Context context = TedPermissionProvider.context;
35 |
36 | public static boolean isGranted(@NonNull String... permissions) {
37 | for (String permission : permissions) {
38 | if (isDenied(permission)) {
39 | return false;
40 | }
41 | }
42 | return true;
43 | }
44 |
45 | public static boolean isDenied(@NonNull String permission) {
46 | return !isGranted(permission);
47 | }
48 |
49 | private static boolean isGranted(@NonNull String permission) {
50 | if (permission.equals(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
52 | return Settings.canDrawOverlays(context);
53 | } else {
54 | return true;
55 | }
56 | } else {
57 | return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
58 | }
59 | }
60 |
61 | public static boolean isMediaFullOrPartialGranted(@NonNull String permission) {
62 | boolean isPartialAccessGranted =
63 | Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
64 | && isGranted(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED);
65 |
66 | return isGranted(permission) || isPartialAccessGranted;
67 | }
68 |
69 | public static List getDeniedPermissions(@NonNull String... permissions) {
70 | List deniedPermissions = new ArrayList<>();
71 | for (String permission : permissions) {
72 | if (isDenied(permission)) {
73 | deniedPermissions.add(permission);
74 | }
75 | }
76 | return deniedPermissions;
77 | }
78 |
79 | public static boolean canRequestPermission(Activity activity, @NonNull String... permissions) {
80 |
81 | if (isFirstRequest(permissions)) {
82 | return true;
83 | }
84 |
85 | for (String permission : permissions) {
86 | boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
87 | if (isDenied(permission) && !showRationale) {
88 | return false;
89 | }
90 | }
91 | return true;
92 | }
93 |
94 | private static boolean isFirstRequest(@NonNull String[] permissions) {
95 | for (String permission : permissions) {
96 | if (!isFirstRequest(permission)) {
97 | return false;
98 | }
99 | }
100 | return true;
101 | }
102 |
103 | private static boolean isFirstRequest(String permission) {
104 | return getSharedPreferences().getBoolean(getPrefsNamePermission(permission), true);
105 | }
106 |
107 | private static String getPrefsNamePermission(String permission) {
108 | return PREFS_IS_FIRST_REQUEST + "_" + permission;
109 | }
110 |
111 | private static SharedPreferences getSharedPreferences() {
112 | return context.getSharedPreferences(PREFS_NAME_PERMISSION, Context.MODE_PRIVATE);
113 | }
114 |
115 | public static void startSettingActivityForResult(Activity activity) {
116 | startSettingActivityForResult(activity, REQ_CODE_REQUEST_SETTING);
117 | }
118 |
119 | public static void startSettingActivityForResult(Activity activity, int requestCode) {
120 | activity.startActivityForResult(getSettingIntent(), requestCode);
121 | }
122 |
123 | public static Intent getSettingIntent() {
124 | return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:" + context.getPackageName()));
125 | }
126 |
127 | public static void startSettingActivityForResult(Fragment fragment) {
128 | startSettingActivityForResult(fragment, REQ_CODE_REQUEST_SETTING);
129 | }
130 |
131 | public static void startSettingActivityForResult(Fragment fragment, int requestCode) {
132 | fragment.startActivityForResult(getSettingIntent(), requestCode);
133 | }
134 |
135 | static void setFirstRequest(@NonNull String[] permissions) {
136 | for (String permission : permissions) {
137 | setFirstRequest(permission);
138 | }
139 | }
140 |
141 | private static void setFirstRequest(String permission) {
142 | getSharedPreferences().edit().putBoolean(getPrefsNamePermission(permission), false).apply();
143 | }
144 |
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/PermissionBuilder.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.pm.ActivityInfo;
6 | import android.os.Build;
7 |
8 | import androidx.annotation.StringRes;
9 |
10 | import com.gun0912.tedpermission.provider.TedPermissionProvider;
11 | import com.gun0912.tedpermission.util.ObjectUtils;
12 |
13 |
14 | public abstract class PermissionBuilder {
15 |
16 | private static final String PREFS_NAME_PERMISSION = "PREFS_NAME_PERMISSION";
17 | private static final String PREFS_IS_FIRST_REQUEST = "PREFS_IS_FIRST_REQUEST";
18 |
19 | private final Context context = TedPermissionProvider.context;
20 | private PermissionListener listener;
21 | private String[] permissions;
22 | private CharSequence rationaleTitle;
23 | private CharSequence rationaleMessage;
24 | private CharSequence denyTitle;
25 | private CharSequence denyMessage;
26 | private CharSequence settingButtonText;
27 | private boolean hasSettingBtn = true;
28 | private CharSequence deniedCloseButtonText = context.getString(R.string.tedpermission_close);
29 | private CharSequence rationaleConfirmText = context.getString(R.string.tedpermission_confirm);
30 | private int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
31 |
32 | protected void checkPermissions() {
33 | if (listener == null) {
34 | throw new IllegalArgumentException("You must setPermissionListener() on TedPermission");
35 | } else if (ObjectUtils.isEmpty(permissions)) {
36 | throw new IllegalArgumentException("You must setPermissions() on TedPermission");
37 | }
38 |
39 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
40 | listener.onPermissionGranted();
41 | return;
42 | }
43 |
44 | Intent intent = new Intent(context, TedPermissionActivity.class);
45 | intent.putExtra(TedPermissionActivity.EXTRA_PERMISSIONS, permissions);
46 |
47 | intent.putExtra(TedPermissionActivity.EXTRA_RATIONALE_TITLE, rationaleTitle);
48 | intent.putExtra(TedPermissionActivity.EXTRA_RATIONALE_MESSAGE, rationaleMessage);
49 | intent.putExtra(TedPermissionActivity.EXTRA_DENY_TITLE, denyTitle);
50 | intent.putExtra(TedPermissionActivity.EXTRA_DENY_MESSAGE, denyMessage);
51 | intent.putExtra(TedPermissionActivity.EXTRA_PACKAGE_NAME, context.getPackageName());
52 | intent.putExtra(TedPermissionActivity.EXTRA_SETTING_BUTTON, hasSettingBtn);
53 | intent.putExtra(TedPermissionActivity.EXTRA_DENIED_DIALOG_CLOSE_TEXT, deniedCloseButtonText);
54 | intent.putExtra(TedPermissionActivity.EXTRA_RATIONALE_CONFIRM_TEXT, rationaleConfirmText);
55 | intent.putExtra(TedPermissionActivity.EXTRA_SETTING_BUTTON_TEXT, settingButtonText);
56 | intent.putExtra(TedPermissionActivity.EXTRA_SCREEN_ORIENTATION, requestedOrientation);
57 |
58 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
59 | intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
60 | TedPermissionActivity.startActivity(context, intent, listener);
61 | TedPermissionUtil.setFirstRequest(permissions);
62 | }
63 |
64 | public T setPermissionListener(PermissionListener listener) {
65 | this.listener = listener;
66 | return (T) this;
67 | }
68 |
69 | public T setPermissions(String... permissions) {
70 | this.permissions = permissions;
71 | return (T) this;
72 | }
73 |
74 | public T setRationaleMessage(@StringRes int stringRes) {
75 | return setRationaleMessage(getText(stringRes));
76 | }
77 |
78 | private CharSequence getText(@StringRes int stringRes) {
79 | return context.getText(stringRes);
80 | }
81 |
82 | public T setRationaleMessage(CharSequence rationaleMessage) {
83 | this.rationaleMessage = rationaleMessage;
84 | return (T) this;
85 | }
86 |
87 |
88 | public T setRationaleTitle(@StringRes int stringRes) {
89 | return setRationaleTitle(getText(stringRes));
90 | }
91 |
92 | public T setRationaleTitle(CharSequence rationaleMessage) {
93 | this.rationaleTitle = rationaleMessage;
94 | return (T) this;
95 | }
96 |
97 | public T setDeniedMessage(@StringRes int stringRes) {
98 | return setDeniedMessage(getText(stringRes));
99 | }
100 |
101 | public T setDeniedMessage(CharSequence denyMessage) {
102 | this.denyMessage = denyMessage;
103 | return (T) this;
104 | }
105 |
106 | public T setDeniedTitle(@StringRes int stringRes) {
107 | return setDeniedTitle(getText(stringRes));
108 | }
109 |
110 | public T setDeniedTitle(CharSequence denyTitle) {
111 | this.denyTitle = denyTitle;
112 | return (T) this;
113 | }
114 |
115 | public T setGotoSettingButton(boolean hasSettingBtn) {
116 | this.hasSettingBtn = hasSettingBtn;
117 | return (T) this;
118 | }
119 |
120 | public T setGotoSettingButtonText(@StringRes int stringRes) {
121 | return setGotoSettingButtonText(getText(stringRes));
122 | }
123 |
124 | public T setGotoSettingButtonText(CharSequence rationaleConfirmText) {
125 | this.settingButtonText = rationaleConfirmText;
126 | return (T) this;
127 | }
128 |
129 | public T setRationaleConfirmText(@StringRes int stringRes) {
130 | return setRationaleConfirmText(getText(stringRes));
131 | }
132 |
133 | public T setRationaleConfirmText(CharSequence rationaleConfirmText) {
134 | this.rationaleConfirmText = rationaleConfirmText;
135 | return (T) this;
136 | }
137 |
138 | public T setDeniedCloseButtonText(CharSequence deniedCloseButtonText) {
139 | this.deniedCloseButtonText = deniedCloseButtonText;
140 | return (T) this;
141 | }
142 |
143 | public T setDeniedCloseButtonText(@StringRes int stringRes) {
144 | return setDeniedCloseButtonText(getText(stringRes));
145 | }
146 |
147 | public T setScreenOrientation(int requestedOrientation) {
148 | this.requestedOrientation = requestedOrientation;
149 | return (T) this;
150 | }
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://android-arsenal.com/details/1/3238)
2 |
3 | # What is TedPermission?
4 |
5 | After the update to Android 6.0 Marshmallow, we have to not only declare permissions in `AndroidManifest.xml`, but also request them at runtime. Furthermore, the user can turn permissions on/off anytime in application settings.
6 | When you use **dangerous permissons**(ex. `CAMERA`, `READ_CONTACTS`, `READ_PHONE_STATE`, ...), you must check and request them at runtime.
7 | (https://developer.android.com/guide/topics/permissions/overview?hl=en#normal-dangerous)
8 |
9 | You can make your own permission check logic [like this](http://developer.android.com/intl/ko/training/permissions/requesting.html), but it's very complex, mainly because functions Google offer are very hard to use: `checkSelfPermission()`, `requestPermissions()`, `onRequestPermissionsResult()`, `onActivityResult()`.
10 |
11 | TedPermission makes it easy to check and request android permissions.
12 |
13 |
14 | (For Korean)
15 | 아래 블로그를 통해 마시멜로우 권한 관련된 사항을 알아보세요
16 | http://gun0912.tistory.com/55
17 |
18 |
19 |
20 |
21 | ## Demo
22 |
23 |
24 |
25 |
26 | 
27 |
28 |
29 | 1. Request permissions.
30 | 2. If user denied permissions, a message dialog with a button to go to Settings will appear.
31 |
32 |
33 | ## Setup
34 | - Edit `root/app/build.gradle` like below.
35 | - You can choose only one library depend on your code style `normal`/`coroutine`/`rxJava2`/`rxJava3`
36 | - Replace `x.y.z` with the version shown in the 'Maven Central' button below, or the specific version you want (e.g. replace `x.y.z` with `3.4.2` if you want 3.4.2).
37 |
38 | [](https://search.maven.org/search?q=g:%22io.github.ParkSangGwon%22%20AND%20a:%tedpermission-normal%22)
39 |
40 | ```gradle
41 | repositories {
42 | google()
43 | mavenCentral()
44 | }
45 |
46 | dependencies {
47 | // Normal
48 | implementation("io.github.ParkSangGwon:tedpermission-normal:3.4.2")
49 |
50 | // Coroutine
51 | implementation("io.github.ParkSangGwon:tedpermission-coroutine:3.4.2")
52 |
53 | // RxJava2
54 | implementation("io.github.ParkSangGwon:tedpermission-rx2:3.4.2")
55 | // RxJava3
56 | implementation("io.github.ParkSangGwon:tedpermission-rx3:3.4.2")
57 | }
58 | ```
59 |
60 |
61 | If you think this library is useful, please press the star button at the top.
62 |
63 |
64 |
65 |
66 |
67 | ## How to use
68 |
69 | ### Normal
70 | #### -Make PermissionListener
71 | We will use `PermissionListener` for handling permission check result.
72 | You will get the result to `onPermissionGranted()` or `onPermissionDenied()` depending on approved permissions.
73 |
74 | ```java
75 |
76 | PermissionListener permissionlistener = new PermissionListener() {
77 | @Override
78 | public void onPermissionGranted() {
79 | Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
80 | }
81 |
82 | @Override
83 | public void onPermissionDenied(List deniedPermissions) {
84 | Toast.makeText(MainActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
85 | }
86 |
87 |
88 | };
89 | ```
90 |
91 | #### -Start TedPermission
92 | TedPermission class requires `setPermissionListener()`, `setPermissions()`, and `check()` methods.
93 | Call `check()` to start checking for permissions.
94 |
95 | `setRationaleMessage()` and `setDeniedMessage()` are optional methods for displaying messages.
96 |
97 | ```java
98 | TedPermission.create()
99 | .setPermissionListener(permissionlistener)
100 | .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
101 | .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
102 | .check();
103 | ```
104 |
105 |
106 |
107 | ### Coroutine
108 | If you use kotlin and coroutine, You can use `check()`function.
109 | `TedPermissionResult` instance has `isGranted()`, `getDeniedPermissions()` methods for checking permission check result.
110 | ```kotlin
111 | val permissionResult =
112 | TedPermission.create()
113 | .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
114 | .check()
115 | ```
116 | Also if you want know only granted result, you can use `checkGranted(): boolean`
117 |
118 |
119 |
120 | ### RxJava
121 | If you use RxJava, You can use `request()` method instead `check()`.
122 | When permission check has finished, you will receive `TedPermissionResult` instance.
123 | `TedPermissionResult` instance has `isGranted()`, `getDeniedPermissions()` methods for checking permission check result.
124 |
125 | ```java
126 | TedPermission.create()
127 | .setRationaleTitle(R.string.rationale_title)
128 | .setRationaleMessage(R.string.rationale_message) // "we need permission for read contact and find your location"
129 | .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
130 | .request()
131 | .subscribe(tedPermissionResult -> {
132 | if (tedPermissionResult.isGranted()) {
133 | Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
134 | } else {
135 | Toast.makeText(this,
136 | "Permission Denied\n" + tedPermissionResult.getDeniedPermissions().toString(), Toast.LENGTH_SHORT)
137 | .show();
138 | }
139 | }, throwable -> {
140 | });
141 | ```
142 |
143 |
144 |
145 |
146 |
147 | ## Customize
148 | TedPermission supports the following methods.
149 |
150 | * `setGotoSettingButton(boolean) (default: true)`
151 | * `setRationaleTitle(R.string.xxx or String)`
152 | * `setRationaleMessage(R.string.xxx or String)`
153 | * `setRationaleConfirmText(R.string.xxx or String) (default: confirm / 확인)`
154 | * `setDeniedTitle(R.string.xxx or String)`
155 | * `setDeniedMessage(R.string.xxx or String)`
156 | * `setDeniedCloseButtonText(R.string.xxx or String) (default: close / 닫기)`
157 | * `setGotoSettingButtonText(R.string.xxx or String) (default: setting / 설정)`
158 |
159 | Also you can use the following utility functions.
160 | * `isGranted(String... permissions)`: Check if all permissions are granted
161 | * `isDenied(String... permissions)`: Check if all permissions are denied
162 | * `getDeniedPermissions(String... permissions)`
163 | * `canRequestPermission(Activity activity, String... permissions)`: If `true` you can request a system popup, `false` means user checked `Never ask again`.
164 | * `startSettingActivityForResult()`
165 | * `startSettingActivityForResult(int requestCode)`
166 |
167 |
168 |
169 |
170 |
171 |
172 | ## Number of Cases
173 | 1. Check permissions -> Already have permissions
174 | : `onPermissionGranted()` is called.
175 |
176 | 2. Check permissions -> Don't have permissions
177 | : Request dialog is shown.
178 | 
179 |
180 |
181 | 3. Show request dialog -> User granted permissions
182 | : `onPermissionGranted()` is called.
183 |
184 | 4. Show request dialog -> User denied one or more permissions
185 | : Denied dialog is shown.
186 | 
187 |
188 | 5. Show denied dialog -> Close the dialog
189 | : `onPermissionDenied()` called
190 |
191 | 6. Show denied dialog -> Setting button clicked
192 | : `startActivityForResult()` to application Setting Activity.
193 | 
194 |
195 |
196 | 7. Setting Activity -> `onActivityResult()`
197 | : Check permissions again
198 |
199 | 8. Check permission -> Permissions are granted
200 | : `onPermissionGranted()` is called.
201 |
202 | 9. Check permission -> There are denied permissions
203 | : `onPermissionDenied()` is called.
204 |
205 |
206 |
207 |
208 | 
209 |
210 |
211 |
212 |
213 |
214 | ## License
215 | ```code
216 | Copyright 2021 Ted Park
217 |
218 | Licensed under the Apache License, Version 2.0 (the "License");
219 | you may not use this file except in compliance with the License.
220 | You may obtain a copy of the License at
221 |
222 | http://www.apache.org/licenses/LICENSE-2.0
223 |
224 | Unless required by applicable law or agreed to in writing, software
225 | distributed under the License is distributed on an "AS IS" BASIS,
226 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
227 | See the License for the specific language governing permissions and
228 | limitations under the License.
229 | ```
230 |
--------------------------------------------------------------------------------
/tedpermission/src/main/java/com/gun0912/tedpermission/TedPermissionActivity.java:
--------------------------------------------------------------------------------
1 | package com.gun0912.tedpermission;
2 |
3 | import android.Manifest;
4 | import android.annotation.TargetApi;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.content.pm.ActivityInfo;
9 | import android.net.Uri;
10 | import android.os.Build.VERSION_CODES;
11 | import android.os.Bundle;
12 | import android.provider.Settings;
13 | import android.text.TextUtils;
14 | import android.view.WindowManager;
15 |
16 | import androidx.annotation.NonNull;
17 | import androidx.appcompat.app.AlertDialog;
18 | import androidx.appcompat.app.AppCompatActivity;
19 | import androidx.core.app.ActivityCompat;
20 |
21 | import com.gun0912.tedpermission.util.ObjectUtils;
22 |
23 | import java.util.ArrayDeque;
24 | import java.util.ArrayList;
25 | import java.util.Deque;
26 | import java.util.List;
27 |
28 | public class TedPermissionActivity extends AppCompatActivity {
29 |
30 |
31 | public static final int REQ_CODE_PERMISSION_REQUEST = 10;
32 |
33 | public static final int REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST = 30;
34 | public static final int REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST_SETTING = 31;
35 |
36 |
37 | public static final String EXTRA_PERMISSIONS = "permissions";
38 | public static final String EXTRA_RATIONALE_TITLE = "rationale_title";
39 | public static final String EXTRA_RATIONALE_MESSAGE = "rationale_message";
40 | public static final String EXTRA_DENY_TITLE = "deny_title";
41 | public static final String EXTRA_DENY_MESSAGE = "deny_message";
42 | public static final String EXTRA_PACKAGE_NAME = "package_name";
43 | public static final String EXTRA_SETTING_BUTTON = "setting_button";
44 | public static final String EXTRA_SETTING_BUTTON_TEXT = "setting_button_text";
45 | public static final String EXTRA_RATIONALE_CONFIRM_TEXT = "rationale_confirm_text";
46 | public static final String EXTRA_DENIED_DIALOG_CLOSE_TEXT = "denied_dialog_close_text";
47 | public static final String EXTRA_SCREEN_ORIENTATION = "screen_orientation";
48 | private static Deque permissionListenerStack;
49 | CharSequence rationaleTitle;
50 | CharSequence rationale_message;
51 | CharSequence denyTitle;
52 | CharSequence denyMessage;
53 | String[] permissions;
54 | String packageName;
55 | boolean hasSettingButton;
56 | String settingButtonText;
57 | String deniedCloseButtonText;
58 | String rationaleConfirmText;
59 | boolean isShownRationaleDialog;
60 | int requestedOrientation;
61 |
62 | public static void startActivity(Context context, Intent intent, PermissionListener listener) {
63 | if (permissionListenerStack == null) {
64 | permissionListenerStack = new ArrayDeque<>();
65 | }
66 | permissionListenerStack.push(listener);
67 | context.startActivity(intent);
68 | }
69 |
70 | @Override
71 | protected void onCreate(Bundle savedInstanceState) {
72 | overridePendingTransition(0, 0);
73 | super.onCreate(savedInstanceState);
74 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
75 | setupFromSavedInstanceState(savedInstanceState);
76 | // check windows
77 | if (needWindowPermission()) {
78 | requestWindowPermission();
79 | } else {
80 | checkPermissions(false);
81 | }
82 |
83 | setRequestedOrientation(requestedOrientation);
84 | }
85 |
86 |
87 | private void setupFromSavedInstanceState(Bundle savedInstanceState) {
88 | if (savedInstanceState != null) {
89 | permissions = savedInstanceState.getStringArray(EXTRA_PERMISSIONS);
90 | rationaleTitle = savedInstanceState.getCharSequence(EXTRA_RATIONALE_TITLE);
91 | rationale_message = savedInstanceState.getCharSequence(EXTRA_RATIONALE_MESSAGE);
92 | denyTitle = savedInstanceState.getCharSequence(EXTRA_DENY_TITLE);
93 | denyMessage = savedInstanceState.getCharSequence(EXTRA_DENY_MESSAGE);
94 | packageName = savedInstanceState.getString(EXTRA_PACKAGE_NAME);
95 |
96 | hasSettingButton = savedInstanceState.getBoolean(EXTRA_SETTING_BUTTON, true);
97 |
98 | rationaleConfirmText = savedInstanceState.getString(EXTRA_RATIONALE_CONFIRM_TEXT);
99 | deniedCloseButtonText = savedInstanceState.getString(EXTRA_DENIED_DIALOG_CLOSE_TEXT);
100 |
101 | settingButtonText = savedInstanceState.getString(EXTRA_SETTING_BUTTON_TEXT);
102 | requestedOrientation = savedInstanceState.getInt(EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
103 | } else {
104 |
105 | Intent intent = getIntent();
106 | permissions = intent.getStringArrayExtra(EXTRA_PERMISSIONS);
107 | rationaleTitle = intent.getCharSequenceExtra(EXTRA_RATIONALE_TITLE);
108 | rationale_message = intent.getCharSequenceExtra(EXTRA_RATIONALE_MESSAGE);
109 | denyTitle = intent.getCharSequenceExtra(EXTRA_DENY_TITLE);
110 | denyMessage = intent.getCharSequenceExtra(EXTRA_DENY_MESSAGE);
111 | packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
112 | hasSettingButton = intent.getBooleanExtra(EXTRA_SETTING_BUTTON, true);
113 | rationaleConfirmText = intent.getStringExtra(EXTRA_RATIONALE_CONFIRM_TEXT);
114 | deniedCloseButtonText = intent.getStringExtra(EXTRA_DENIED_DIALOG_CLOSE_TEXT);
115 | settingButtonText = intent.getStringExtra(EXTRA_SETTING_BUTTON_TEXT);
116 | requestedOrientation = intent.getIntExtra(EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
117 |
118 | }
119 |
120 |
121 | }
122 |
123 | private boolean needWindowPermission() {
124 | for (String permission : permissions) {
125 | if (permission.equals(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
126 | return !hasWindowPermission();
127 | }
128 | }
129 | return false;
130 | }
131 |
132 | @TargetApi(VERSION_CODES.M)
133 | private boolean hasWindowPermission() {
134 | return Settings.canDrawOverlays(getApplicationContext());
135 | }
136 |
137 | @TargetApi(VERSION_CODES.M)
138 | private void requestWindowPermission() {
139 | Uri uri = Uri.fromParts("package", packageName, null);
140 | final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, uri);
141 |
142 | if (!TextUtils.isEmpty(rationale_message)) {
143 | new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert)
144 | .setMessage(rationale_message)
145 | .setCancelable(false)
146 |
147 | .setNegativeButton(rationaleConfirmText, new DialogInterface.OnClickListener() {
148 | @Override
149 | public void onClick(DialogInterface dialogInterface, int i) {
150 | startActivityForResult(intent, REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST);
151 | }
152 | })
153 | .show();
154 | isShownRationaleDialog = true;
155 | } else {
156 | startActivityForResult(intent, REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST);
157 | }
158 | }
159 |
160 | private void checkPermissions(boolean fromOnActivityResult) {
161 |
162 | List needPermissions = new ArrayList<>();
163 |
164 | for (String permission : permissions) {
165 | if (permission.equals(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
166 | if (!hasWindowPermission()) {
167 | needPermissions.add(permission);
168 | }
169 | } else {
170 | if (TedPermissionUtil.isDenied(permission)) {
171 | needPermissions.add(permission);
172 | }
173 | }
174 | }
175 |
176 | if (needPermissions.isEmpty()) {
177 | permissionResult(null);
178 | } else if (fromOnActivityResult) { //From Setting Activity
179 | permissionResult(needPermissions);
180 | } else if (needPermissions.size() == 1 && needPermissions
181 | .contains(Manifest.permission.SYSTEM_ALERT_WINDOW)) { // window permission deny
182 | permissionResult(needPermissions);
183 | } else if (!isShownRationaleDialog && !TextUtils.isEmpty(rationale_message)) { // //Need Show Rationale
184 | showRationaleDialog(needPermissions);
185 | } else { // //Need Request Permissions
186 | requestPermissions(needPermissions);
187 | }
188 | }
189 |
190 | private void permissionResult(List deniedPermissions) {
191 | finish();
192 | overridePendingTransition(0, 0);
193 |
194 | if (permissionListenerStack != null) {
195 | PermissionListener listener = permissionListenerStack.pop();
196 |
197 | if (ObjectUtils.isEmpty(deniedPermissions)) {
198 | listener.onPermissionGranted();
199 | } else {
200 | listener.onPermissionDenied(deniedPermissions);
201 | }
202 | if (permissionListenerStack.size() == 0) {
203 | permissionListenerStack = null;
204 | }
205 | }
206 |
207 | }
208 |
209 | @Override
210 | public void finish() {
211 | super.finish();
212 | overridePendingTransition(0, 0);
213 | }
214 |
215 | private void showRationaleDialog(final List needPermissions) {
216 |
217 | new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert)
218 | .setTitle(rationaleTitle)
219 | .setMessage(rationale_message)
220 | .setCancelable(false)
221 |
222 | .setNegativeButton(rationaleConfirmText, new DialogInterface.OnClickListener() {
223 | @Override
224 | public void onClick(DialogInterface dialogInterface, int i) {
225 | requestPermissions(needPermissions);
226 |
227 | }
228 | })
229 | .show();
230 | isShownRationaleDialog = true;
231 |
232 |
233 | }
234 |
235 | public void requestPermissions(List needPermissions) {
236 | ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]),
237 | REQ_CODE_PERMISSION_REQUEST);
238 | }
239 |
240 | @Override
241 | public void onSaveInstanceState(Bundle outState) {
242 | outState.putStringArray(EXTRA_PERMISSIONS, permissions);
243 | outState.putCharSequence(EXTRA_RATIONALE_TITLE, rationaleTitle);
244 | outState.putCharSequence(EXTRA_RATIONALE_MESSAGE, rationale_message);
245 | outState.putCharSequence(EXTRA_DENY_TITLE, denyTitle);
246 | outState.putCharSequence(EXTRA_DENY_MESSAGE, denyMessage);
247 | outState.putString(EXTRA_PACKAGE_NAME, packageName);
248 | outState.putBoolean(EXTRA_SETTING_BUTTON, hasSettingButton);
249 | outState.putString(EXTRA_DENIED_DIALOG_CLOSE_TEXT, deniedCloseButtonText);
250 | outState.putString(EXTRA_RATIONALE_CONFIRM_TEXT, rationaleConfirmText);
251 | outState.putString(EXTRA_SETTING_BUTTON_TEXT, settingButtonText);
252 |
253 | super.onSaveInstanceState(outState);
254 | }
255 |
256 | @Override
257 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
258 | @NonNull int[] grantResults) {
259 |
260 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
261 | List deniedPermissions = TedPermissionUtil.getDeniedPermissions(permissions);
262 | for (String permission : deniedPermissions) {
263 | if (isMediaPartialAccessGranted(permission)) {
264 | deniedPermissions.remove(permission);
265 | break;
266 | }
267 | }
268 | if (deniedPermissions.isEmpty()) {
269 | permissionResult(null);
270 | } else {
271 | showPermissionDenyDialog(deniedPermissions);
272 | }
273 | }
274 |
275 | private boolean isMediaPartialAccessGranted(@NonNull String permission) {
276 | if (!permission.equals(Manifest.permission.READ_MEDIA_IMAGES) && !permission.equals(Manifest.permission.READ_MEDIA_VIDEO)) {
277 | return false;
278 | }
279 | return TedPermissionUtil.isMediaFullOrPartialGranted(permission);
280 | }
281 |
282 | public void showPermissionDenyDialog(final List deniedPermissions) {
283 |
284 | if (TextUtils.isEmpty(denyMessage)) {
285 | // denyMessage 설정 안함
286 | permissionResult(deniedPermissions);
287 | return;
288 | }
289 |
290 | AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert);
291 |
292 | builder.setTitle(denyTitle)
293 | .setMessage(denyMessage)
294 | .setCancelable(false)
295 | .setNegativeButton(deniedCloseButtonText, new DialogInterface.OnClickListener() {
296 | @Override
297 | public void onClick(DialogInterface dialogInterface, int i) {
298 | permissionResult(deniedPermissions);
299 | }
300 | });
301 |
302 | if (hasSettingButton) {
303 |
304 | if (TextUtils.isEmpty(settingButtonText)) {
305 | settingButtonText = getString(R.string.tedpermission_setting);
306 | }
307 |
308 | builder.setPositiveButton(settingButtonText, new DialogInterface.OnClickListener() {
309 | @Override
310 | public void onClick(DialogInterface dialog, int which) {
311 | TedPermissionUtil.startSettingActivityForResult(TedPermissionActivity.this);
312 |
313 | }
314 | });
315 |
316 | }
317 | builder.show();
318 | }
319 |
320 | public boolean shouldShowRequestPermissionRationale(List needPermissions) {
321 |
322 | if (needPermissions == null) {
323 | return false;
324 | }
325 |
326 | for (String permission : needPermissions) {
327 | if (!ActivityCompat.shouldShowRequestPermissionRationale(TedPermissionActivity.this, permission)) {
328 | return false;
329 | }
330 | }
331 |
332 | return true;
333 |
334 | }
335 |
336 | public void showWindowPermissionDenyDialog() {
337 |
338 | AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Light_Dialog_Alert);
339 | builder.setMessage(denyMessage)
340 | .setCancelable(false)
341 | .setNegativeButton(deniedCloseButtonText, new DialogInterface.OnClickListener() {
342 | @Override
343 | public void onClick(DialogInterface dialogInterface, int i) {
344 | checkPermissions(false);
345 | }
346 | });
347 |
348 | if (hasSettingButton) {
349 | if (TextUtils.isEmpty(settingButtonText)) {
350 | settingButtonText = getString(R.string.tedpermission_setting);
351 | }
352 |
353 | builder.setPositiveButton(settingButtonText, new DialogInterface.OnClickListener() {
354 | @TargetApi(VERSION_CODES.M)
355 | @Override
356 | public void onClick(DialogInterface dialog, int which) {
357 | Uri uri = Uri.fromParts("package", packageName, null);
358 | final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, uri);
359 | startActivityForResult(intent, REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST_SETTING);
360 | }
361 | });
362 |
363 | }
364 | builder.show();
365 | }
366 |
367 | @Override
368 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
369 | switch (requestCode) {
370 | case TedPermissionUtil.REQ_CODE_REQUEST_SETTING:
371 | checkPermissions(true);
372 | break;
373 | case REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST: // 최초 ALERT WINDOW 요청에 대한 결과
374 | if (!hasWindowPermission() && !TextUtils.isEmpty(denyMessage)) { // 권한이 거부되고 denyMessage 가 있는 경우
375 | showWindowPermissionDenyDialog();
376 | } else { // 권한있거나 또는 denyMessage가 없는 경우는 일반 permission 을 확인한다.
377 | checkPermissions(false);
378 | }
379 | break;
380 | case REQ_CODE_SYSTEM_ALERT_WINDOW_PERMISSION_REQUEST_SETTING: // ALERT WINDOW 권한 설정 실패후 재 요청에 대한 결과
381 | checkPermissions(false);
382 | break;
383 | default:
384 | super.onActivityResult(requestCode, resultCode, data);
385 | }
386 |
387 | }
388 | }
389 |
--------------------------------------------------------------------------------