├── .gitignore ├── README.md ├── _config.yml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── qw │ │ └── sample │ │ ├── AfterActivity.java │ │ ├── BeforeActivity.java │ │ ├── MainActivity.java │ │ ├── SimpleApplication.java │ │ ├── adapter │ │ ├── CheckPermissionAdapter.java │ │ └── CheckPermissionWithRationaleAdapter.java │ │ ├── guide │ │ ├── ApiGuideActivity.java │ │ ├── ApiGuideAppComponentActivity.java │ │ ├── WithPagerFragmentActivity.java │ │ └── fragment │ │ │ ├── ApiGuideFragment.java │ │ │ ├── ApiGuideSupportFragment.java │ │ │ ├── ContainerActivity.java │ │ │ └── PagerItemFragment.java │ │ └── utils │ │ ├── ApiGuideUtils.java │ │ ├── Utils.java │ │ └── UtilsWithPermission.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_example.xml │ ├── activity_main.xml │ ├── activity_with_fragment.xml │ └── layout_api_guide.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── soulpermission ├── .gitignore ├── build.gradle └── src └── main ├── AndroidManifest.xml ├── java └── com │ └── qw │ └── soul │ └── permission │ ├── Constants.java │ ├── InitProvider.java │ ├── PermissionActivityLifecycle.java │ ├── PermissionTools.java │ ├── SoulPermission.java │ ├── adapter │ ├── SimplePermissionAdapter.java │ ├── SimplePermissionsAdapter.java │ └── SimpleSpecialPermissionAdapter.java │ ├── bean │ ├── Permission.java │ ├── Permissions.java │ └── Special.java │ ├── callbcak │ ├── CheckRequestPermissionListener.java │ ├── CheckRequestPermissionsListener.java │ ├── CheckStatusCallBack.java │ ├── GoAppDetailCallBack.java │ ├── RequestPermissionListener.java │ └── SpecialPermissionListener.java │ ├── checker │ ├── AppOpsChecker.java │ ├── CheckerFactory.java │ ├── PermissionChecker.java │ ├── RunTimePermissionChecker.java │ └── SpecialChecker.java │ ├── debug │ └── PermissionDebug.java │ ├── exception │ ├── ContainerStatusException.java │ └── InitException.java │ └── request │ ├── IPermissionActions.java │ ├── PermissionConfig.java │ ├── PermissionFragmentFactory.java │ ├── PermissionRequester.java │ └── fragment │ ├── FragmentProxy.java │ ├── PermissionFragment.java │ └── PermissionSupportFragment.java └── res ├── values-en └── strings.xml └── values └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | # Built application files 4 | *.apk 5 | *.ap_ 6 | 7 | # Files for the Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Windows thumbnail db 37 | Thumbs.db 38 | 39 | # OSX files 40 | .DS_Store 41 | 42 | # Eclipse project files 43 | .classpath 44 | .project 45 | 46 | # Android Studio 47 | *.iml 48 | .idea 49 | 50 | #NDK 51 | obj/ 52 | 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SoulPermission 2 | [![Hex.pm](https://img.shields.io/badge/download-1.4.0-green)](https://bintray.com/beta/#/soulqw/maven/soulpermission?tab=overview) 3 | [![Hex.pm](https://img.shields.io/badge/Jetpack-AndroidX-orange)]() 4 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://www.apache.org/licenses/LICENSE-2.0) 5 | #### Android权限适配的更优解决方案: 6 | - 方法级权限适配、解耦Activity和Fragment、不再需要Context、不再需要onPermissionResult 7 | - 内部涵盖版本判断,一行代码解决权限相关操作,无需在调用业务方写权限适配代码,继而实现真正调用时请求的“真运行时权限” 8 | - 接入成本低,代码改动极小,零入侵,仅需要在gradle配置一行代码 9 | - 支持多项权限同时请求 10 | - 支持特殊权限(Notification[通知]、SystemAlert[应用悬浮窗]、UNKNOW_SOURCE[未知来源应用安装]、WRITE_SYS_SETTINGS[写入系统设置])的检查与请求 11 | - 支持系统权限页面跳转 12 | - 支持debug模式 13 | ## Installation: 14 | 15 | ```gradle 16 | dependencies { 17 | implementation 'com.github.soulqw:SoulPermission:1.4.0' 18 | } 19 | 20 | ``` 21 | 如果你的应用还没有适配Android X: 22 | 23 | ```gradle 24 | dependencies { 25 | implementation 'com.qw:soulpermission:1.2.2' 26 | } 27 | ``` 28 | - 1.2.2即为支持support28的最后版本,后续不再维护,新功能只会在1.3.0基础上迭代(代码分支 master_old) 29 | - 后期Jcenter 库将无法正常下载,建议尽快迁移到AndroidX,可享受最新的更新 30 | 31 | ## Usage: 32 | 33 | #### 基本用法: 34 | - 一句话版本完成自动判断、权限检查、请求、后续操作: 35 | ```java 36 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.ACCESS_FINE_LOCATION, 37 | //if you want do noting or no need all the callbacks you may use SimplePermissionAdapter instead 38 | new CheckRequestPermissionListener() { 39 | @Override 40 | public void onPermissionOk(Permission permission) { 41 | Toast.makeText(ApiGuideActivity.this, permission.toString() + 42 | "\n is ok , you can do your operations", Toast.LENGTH_SHORT).show(); 43 | } 44 | 45 | @Override 46 | public void onPermissionDenied(Permission permission) { 47 | Toast.makeText(ApiGuideActivity.this, permission.toString() + 48 | " \n is refused you can not do next things", Toast.LENGTH_SHORT).show(); 49 | } 50 | }); 51 | 52 | ``` 53 | - 也可以一次请求多项权限 54 | 55 | ```java 56 | SoulPermission.getInstance().checkAndRequestPermissions( 57 | Permissions.build(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), 58 | //if you want do noting or no need all the callbacks you may use SimplePermissionsAdapter instead 59 | new CheckRequestPermissionsListener() { 60 | @Override 61 | public void onAllPermissionOk(Permission[] allPermissions) { 62 | Toast.makeText(ApiGuideActivity.this, allPermissions.length + "permissions is ok" + 63 | " \n you can do your operations", Toast.LENGTH_SHORT).show(); 64 | } 65 | 66 | @Override 67 | public void onPermissionDenied(Permission[] refusedPermissions) { 68 | Toast.makeText(ApiGuideActivity.this, refusedPermissions[0].toString() + 69 | " \n is refused you can not do next things", Toast.LENGTH_SHORT).show(); 70 | } 71 | }); 72 | 73 | ``` 74 | - 包含shouldShowRequestPermissionRationale的情形 75 | 76 | ```java 77 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.READ_CONTACTS, 78 | new CheckRequestPermissionListener() { 79 | @Override 80 | public void onPermissionOk(Permission permission) { 81 | Toast.makeText(ApiGuideActivity.this, permission.toString() + 82 | "\n is ok , you can do your operations", Toast.LENGTH_SHORT).show(); 83 | } 84 | 85 | @Override 86 | public void onPermissionDenied(Permission permission) { 87 | // see CheckPermissionWithRationaleAdapter 88 | if (permission.shouldRationale()) { 89 | Toast.makeText(ApiGuideActivity.this, permission.toString() + 90 | " \n you should show a explain for user then retry ", Toast.LENGTH_SHORT).show(); 91 | } else { 92 | Toast.makeText(ApiGuideActivity.this, permission.toString() + 93 | " \n is refused you can not do next things", Toast.LENGTH_SHORT).show(); 94 | } 95 | } 96 | }); 97 | 98 | ``` 99 | - 检查某项权限 100 | 101 | ```java 102 | //you can also use checkPermissions() for a series of permissions 103 | Permission checkResult = SoulPermission.getInstance().checkSinglePermission(Manifest.permission.ACCESS_FINE_LOCATION); 104 | ``` 105 | - 检查特殊权限[通知权限] 106 | 107 | ```java 108 | boolean checkResult = SoulPermission.getInstance().checkSpecialPermission(Special.NOTIFICATION); 109 | ``` 110 | - 检查并请求特殊权限[未知应用安装] 111 | 112 | ```java 113 | //if you want do noting or no need all the callbacks you may use SimpleSpecialPermissionAdapter instead 114 | SoulPermission.getInstance().checkAndRequestPermission(Special.UNKNOWN_APP_SOURCES, new SpecialPermissionListener() { 115 | @Override 116 | public void onGranted(Special permission) { 117 | Toast.makeText(ApiGuideActivity.this, "install unKnown app is enable now", Toast.LENGTH_SHORT).show(); 118 | } 119 | 120 | @Override 121 | public void onDenied(Special permission) { 122 | Toast.makeText(ApiGuideActivity.this, "install unKnown app is disable yet", Toast.LENGTH_SHORT).show(); 123 | } 124 | }); 125 | ``` 126 | 127 | - 跳转到应用设置页 128 | 129 | 130 | ```java 131 | SoulPermission.getInstance().goApplicationSettings(new GoAppDetailCallBack() { 132 | @Override 133 | public void onBackFromAppDetail(Intent data) { 134 | //if you need to know when back from app detail 135 | Utils.showMessage(view, "back from go appDetail"); 136 | } 137 | }); 138 | ``` 139 | - 设置跳过老的权限系统(老的系统默认权限直接授予) 140 | ```java 141 | SoulPermission.skipOldRom(true); 142 | ``` 143 | 144 | - 设置debug模式(看日志打印) 145 | 146 | ```java 147 | SoulPermission.setDebug(true); 148 | ``` 149 | 150 | #### 注意事项: 151 | - 最低支持Android 4.0(Api level 14) 152 | - SoulPermission内部使用contentProvider自动初始化,如果你项目中使用了通过替换Application方式从而可能会导致SoulPermission内部初始化失败的框架(如Tinker,腾讯乐固等),请手动在你的Application类中调用init即可(通过设置debug,可以看到错误日志打印和相关Toast)。 153 | 154 | ```java 155 | //invoke init in your application when auto init failed 156 | public class SimpleApplication extends Application { 157 | @Override 158 | public void onCreate() { 159 | super.onCreate(); 160 | //no necessary 161 | SoulPermission.init(this); 162 | } 163 | } 164 | 165 | ``` 166 | - 如果需要在某个页面创建时候请求权限,请在onCreate()中使用、请不要在onResume()调用,否则权限未被动态授予前会陷入死循环。 167 | ### Screenshot: 168 | ![image](https://img-blog.csdnimg.cn/20190612212049718.png) 169 | 170 | ![image](https://img-blog.csdnimg.cn/20190530192140891.png) 171 | - for common Permission 172 | 173 | ![image](https://img-blog.csdnimg.cn/20190530192219180.gif) 174 | 175 | - for Special Permission 176 | 177 | ![image](https://img-blog.csdnimg.cn/2019053019225180.gif) 178 | 179 | ### MoreDetail: 180 | #### [工作原理和最佳示例](https://blog.csdn.net/u014626094/article/details/89438614) 181 | 182 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | maven { 8 | url 'https://maven.google.com/' 9 | name 'Google' 10 | } 11 | maven { url 'https://jitpack.io' } 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:7.1.2' 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | jcenter() 21 | google() 22 | maven { 23 | url 'https://maven.google.com/' 24 | name 'Google' 25 | } 26 | maven { url 'https://jitpack.io' } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # Kotlin code style for this project: "official" or "obsolete": 15 | kotlin.code.style=official 16 | android.useAndroidX=true 17 | android.enableJetifier=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulqw/SoulPermission/c3eb4f5d661f5963b899c31f38462953ad0d3bf7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Nov 15 10:47:14 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | # Built application files 4 | *.apk 5 | *.ap_ 6 | 7 | # Files for the Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | 17 | # Gradle files 18 | .gradle/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Windows thumbnail db 37 | Thumbs.db 38 | 39 | # OSX files 40 | .DS_Store 41 | 42 | # Eclipse project files 43 | .classpath 44 | .project 45 | 46 | # Android Studio 47 | *.iml 48 | .idea 49 | 50 | #NDK 51 | obj/ 52 | 53 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 34 5 | defaultConfig { 6 | applicationId "com.qw.sample" 7 | minSdkVersion 14 8 | targetSdkVersion 34 9 | versionCode 13 10 | versionName "1.3.2" 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | } 18 | 19 | namespace 'com.qw.sample' 20 | } 21 | 22 | 23 | dependencies { 24 | // implementation project(':soulpermission') 25 | implementation 'com.github.soulqw:SoulPermission:1.4.0' 26 | implementation 'androidx.appcompat:appcompat:1.6.1' 27 | implementation 'com.google.android.material:material:1.9.0' 28 | 29 | } 30 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/AfterActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.annotation.Nullable; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.Toast; 9 | import com.qw.sample.utils.Utils; 10 | import com.qw.sample.utils.UtilsWithPermission; 11 | 12 | public class AfterActivity extends AppCompatActivity { 13 | private static final int REQUEST_CODE_CONTACT = 1; 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_example); 19 | findViewById(R.id.bt_call).setOnClickListener(new View.OnClickListener() { 20 | @Override 21 | public void onClick(View view) { 22 | UtilsWithPermission.makeCall(AfterActivity.this, "10086"); 23 | // makeCall(); 24 | } 25 | }); 26 | findViewById(R.id.bt_choose_contact).setOnClickListener(new View.OnClickListener() { 27 | @Override 28 | public void onClick(View view) { 29 | chooseContact(); 30 | } 31 | }); 32 | findViewById(R.id.bt_read_phone_status).setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View v) { 35 | UtilsWithPermission.readPhoneStatus(); 36 | } 37 | }); 38 | } 39 | 40 | // public void makeCall() { 41 | // SoulPermission.getInstance() 42 | // .checkAndRequestPermission(Manifest.permission.CALL_PHONE, new CheckRequestPermissionListener() { 43 | // @Override 44 | // public void onPermissionOk(Permission permission) { 45 | // Utils.makeCall(AfterActivity.this, "10086"); 46 | // } 47 | // 48 | // @Override 49 | // public void onPermissionDenied(Permission permission) { 50 | // //绿色框中的流程 51 | // //用户第一次拒绝了权限,没有勾选"不再提示。"这个值为true,此时告诉用户为什么需要这个权限。 52 | // if (permission.shouldRationale) { 53 | // new AlertDialog.Builder(AfterActivity.this) 54 | // .setTitle("提示") 55 | // .setMessage("如果你拒绝了权限,你将无法拨打电话,请点击授予权限") 56 | // .setPositiveButton("授予", new DialogInterface.OnClickListener() { 57 | // @Override 58 | // public void onClick(DialogInterface dialogInterface, int i) { 59 | // //用户确定以后,重新执行请求原始流程 60 | // makeCall(); 61 | // } 62 | // }).create().show(); 63 | // } else { 64 | // Toast.makeText(AfterActivity.this, "本次拨打电话授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show(); 65 | // } 66 | // } 67 | // }); 68 | // } 69 | 70 | public void chooseContact() { 71 | UtilsWithPermission.chooseContact(AfterActivity.this, REQUEST_CODE_CONTACT); 72 | } 73 | 74 | @Override 75 | protected void onActivityResult(int requestCode, int resultCode, @Nullable final Intent data) { 76 | super.onActivityResult(requestCode, resultCode, data); 77 | if (resultCode == RESULT_OK) { 78 | switch (requestCode) { 79 | case REQUEST_CODE_CONTACT: 80 | Utils.onGetChooseContactData(AfterActivity.this, data, new Utils.ReadContactListener() { 81 | @Override 82 | public void onSuccess(Utils.ContactInfo contactInfo) { 83 | Toast.makeText(AfterActivity.this, contactInfo.toString(), Toast.LENGTH_SHORT).show(); 84 | } 85 | 86 | @Override 87 | public void onFailed() { 88 | 89 | } 90 | }); 91 | break; 92 | default: 93 | break; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/BeforeActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.os.Bundle; 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.core.app.ActivityCompat; 10 | import androidx.core.content.ContextCompat; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | import android.view.View; 13 | import android.widget.Toast; 14 | import com.qw.sample.utils.Utils; 15 | 16 | import static android.os.Build.VERSION_CODES.M; 17 | 18 | public class BeforeActivity extends AppCompatActivity { 19 | 20 | private static final int PERMISSION_CODE_CALL = 100; 21 | 22 | private static final int PERMISSION_CODE_CONTACT = 101; 23 | 24 | private static final int PERMISSION_CODE_READ_PHONE_STATE = 102; 25 | 26 | private static final int REQUEST_CODE_CONTACT = 1; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_example); 32 | findViewById(R.id.bt_call).setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View view) { 35 | makeCall(); 36 | } 37 | }); 38 | findViewById(R.id.bt_choose_contact).setOnClickListener(new View.OnClickListener() { 39 | @Override 40 | public void onClick(View view) { 41 | chooseContact(); 42 | } 43 | }); 44 | findViewById(R.id.bt_read_phone_status).setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | readPhoneStatus(); 48 | } 49 | }); 50 | } 51 | 52 | public void makeCall() { 53 | //6.0以下 直接即可拨打 54 | if (android.os.Build.VERSION.SDK_INT < M) { 55 | Utils.makeCall(BeforeActivity.this, "10086"); 56 | } else { 57 | //6.0以上 58 | if (ContextCompat.checkSelfPermission(BeforeActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { 59 | ActivityCompat.requestPermissions(BeforeActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 60 | PERMISSION_CODE_CALL); 61 | } else { 62 | Utils.makeCall(BeforeActivity.this, "10086"); 63 | } 64 | } 65 | } 66 | 67 | public void chooseContact() { 68 | //6.0以下 直接即可直接选择 69 | if (android.os.Build.VERSION.SDK_INT < M) { 70 | Utils.chooseContact(BeforeActivity.this, REQUEST_CODE_CONTACT); 71 | } else { 72 | //6.0以上 73 | if (ContextCompat.checkSelfPermission(BeforeActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { 74 | ActivityCompat.requestPermissions(BeforeActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 75 | PERMISSION_CODE_CONTACT); 76 | } else { 77 | Utils.chooseContact(BeforeActivity.this, REQUEST_CODE_CONTACT); 78 | } 79 | } 80 | } 81 | 82 | /** 83 | * 读取联系人权限和打电话是一组,只要一个授予即可无需重复请求 84 | */ 85 | public void readPhoneStatus() { 86 | //6.0以下 直接即可直接读取 87 | if (android.os.Build.VERSION.SDK_INT < M) { 88 | Utils.readPhoneStatus(BeforeActivity.this); 89 | } else { 90 | //6.0以上 91 | if (ContextCompat.checkSelfPermission(BeforeActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { 92 | ActivityCompat.requestPermissions(BeforeActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, 93 | PERMISSION_CODE_READ_PHONE_STATE); 94 | } else { 95 | Utils.readPhoneStatus(BeforeActivity.this); 96 | } 97 | } 98 | } 99 | 100 | @Override 101 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 102 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 103 | switch (requestCode) { 104 | case PERMISSION_CODE_CALL: 105 | if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { 106 | Toast.makeText(BeforeActivity.this, "本次拨打电话授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show(); 107 | } else { 108 | Utils.makeCall(BeforeActivity.this, "10086"); 109 | } 110 | break; 111 | case PERMISSION_CODE_CONTACT: 112 | if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { 113 | Toast.makeText(BeforeActivity.this, "本次选择联系人授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show(); 114 | } else { 115 | Utils.chooseContact(BeforeActivity.this, REQUEST_CODE_CONTACT); 116 | } 117 | break; 118 | case PERMISSION_CODE_READ_PHONE_STATE: 119 | if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { 120 | Toast.makeText(BeforeActivity.this, "本次读取联系人失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show(); 121 | } else { 122 | Utils.readPhoneStatus(BeforeActivity.this); 123 | } 124 | break; 125 | default: 126 | break; 127 | } 128 | } 129 | 130 | @Override 131 | protected void onActivityResult(int requestCode, int resultCode, @Nullable final Intent data) { 132 | super.onActivityResult(requestCode, resultCode, data); 133 | if (resultCode == RESULT_OK) { 134 | switch (requestCode) { 135 | case REQUEST_CODE_CONTACT: 136 | Utils.onGetChooseContactData(BeforeActivity.this, data, new Utils.ReadContactListener() { 137 | @Override 138 | public void onSuccess(Utils.ContactInfo contactInfo) { 139 | Toast.makeText(BeforeActivity.this, contactInfo.toString(), Toast.LENGTH_SHORT).show(); 140 | } 141 | 142 | @Override 143 | public void onFailed() { 144 | 145 | } 146 | }); 147 | break; 148 | default: 149 | break; 150 | } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import android.view.View; 7 | import com.qw.sample.guide.ApiGuideActivity; 8 | import com.qw.sample.guide.ApiGuideAppComponentActivity; 9 | import com.qw.sample.guide.WithPagerFragmentActivity; 10 | import com.qw.sample.guide.fragment.ContainerActivity; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | } 19 | 20 | public void before(View view) { 21 | startActivity(new Intent(MainActivity.this, BeforeActivity.class)); 22 | } 23 | 24 | public void after(View view) { 25 | startActivity(new Intent(MainActivity.this, AfterActivity.class)); 26 | } 27 | 28 | public void apiGuideActivity(View view) { 29 | startActivity(new Intent(MainActivity.this, ApiGuideActivity.class)); 30 | } 31 | 32 | public void apiGuideAppComponentActivity(View view) { 33 | startActivity(new Intent(MainActivity.this, ApiGuideAppComponentActivity.class)); 34 | } 35 | 36 | public void fragment(View view) { 37 | ContainerActivity.start(this, false); 38 | } 39 | 40 | public void supportFragment(View view) { 41 | ContainerActivity.start(this, true); 42 | } 43 | 44 | public void fragmentWithViewPager(View view) { 45 | startActivity(new Intent(MainActivity.this, WithPagerFragmentActivity.class)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/SimpleApplication.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | import com.qw.soul.permission.SoulPermission; 6 | 7 | /** 8 | * @author cd5160866 9 | */ 10 | public class SimpleApplication extends Application { 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | Log.d(SimpleApplication.class.getSimpleName(), "appInit"); 15 | SoulPermission.setDebug(true); 16 | // SoulPermission.skipOldRom(true); 17 | //no necessary 18 | // SoulPermission.init(this); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/adapter/CheckPermissionAdapter.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.DialogInterface; 5 | import androidx.appcompat.app.AlertDialog; 6 | import com.qw.soul.permission.SoulPermission; 7 | import com.qw.soul.permission.bean.Permission; 8 | import com.qw.soul.permission.callbcak.CheckRequestPermissionListener; 9 | 10 | /** 11 | * @author cd5160866 12 | */ 13 | public abstract class CheckPermissionAdapter implements CheckRequestPermissionListener { 14 | 15 | @Override 16 | public void onPermissionDenied(Permission permission) { 17 | //SoulPermission提供栈顶Activity 18 | Activity activity = SoulPermission.getInstance().getTopActivity(); 19 | if (null == activity) { 20 | return; 21 | } 22 | String permissionDesc = permission.getPermissionNameDesc(); 23 | new AlertDialog.Builder(activity) 24 | .setTitle("提示") 25 | .setMessage(permissionDesc + "异常,请前往设置->权限管理,打开" + permissionDesc + "。") 26 | .setPositiveButton("去设置", new DialogInterface.OnClickListener() { 27 | @Override 28 | public void onClick(DialogInterface dialogInterface, int i) { 29 | //去设置页 30 | SoulPermission.getInstance().goPermissionSettings(); 31 | } 32 | }).create().show(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/adapter/CheckPermissionWithRationaleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.adapter; 2 | 3 | import android.app.Activity; 4 | import android.content.DialogInterface; 5 | import androidx.appcompat.app.AlertDialog; 6 | import com.qw.soul.permission.SoulPermission; 7 | import com.qw.soul.permission.bean.Permission; 8 | import com.qw.soul.permission.callbcak.CheckRequestPermissionListener; 9 | 10 | /** 11 | * @author cd5160866 12 | */ 13 | public abstract class CheckPermissionWithRationaleAdapter implements CheckRequestPermissionListener { 14 | 15 | private String rationaleMessage; 16 | 17 | private Runnable retryRunnable; 18 | 19 | /** 20 | * @param rationaleMessage 当用户首次拒绝弹框时候,根据权限不同给用户不同的文案解释 21 | * @param retryRunnable 用户点重新授权的runnable 即重新执行原方法 22 | */ 23 | public CheckPermissionWithRationaleAdapter(String rationaleMessage, Runnable retryRunnable) { 24 | this.rationaleMessage = rationaleMessage; 25 | this.retryRunnable = retryRunnable; 26 | } 27 | 28 | @Override 29 | public void onPermissionDenied(Permission permission) { 30 | Activity activity = SoulPermission.getInstance().getTopActivity(); 31 | if (null == activity) { 32 | return; 33 | } 34 | //绿色框中的流程 35 | //用户第一次拒绝了权限、并且没有勾选"不再提示"这个值为true,此时告诉用户为什么需要这个权限。 36 | if (permission.shouldRationale()) { 37 | new AlertDialog.Builder(activity) 38 | .setTitle("提示") 39 | .setMessage(rationaleMessage) 40 | .setPositiveButton("授予", new DialogInterface.OnClickListener() { 41 | @Override 42 | public void onClick(DialogInterface dialogInterface, int i) { 43 | //用户确定以后,重新执行请求原始流程 44 | retryRunnable.run(); 45 | } 46 | }).create().show(); 47 | } else { 48 | //此时请求权限会直接报未授予,需要用户手动去权限设置页,所以弹框引导用户跳转去设置页 49 | String permissionDesc = permission.getPermissionNameDesc(); 50 | new AlertDialog.Builder(activity) 51 | .setTitle("提示") 52 | .setMessage(permissionDesc + "异常,请前往设置->权限管理,打开" + permissionDesc + "。") 53 | .setPositiveButton("去设置", new DialogInterface.OnClickListener() { 54 | @Override 55 | public void onClick(DialogInterface dialogInterface, int i) { 56 | //去设置页 57 | SoulPermission.getInstance().goApplicationSettings(); 58 | } 59 | }).create().show(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/ApiGuideActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide; 2 | 3 | 4 | import android.app.Activity; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import com.qw.sample.R; 10 | import com.qw.sample.utils.ApiGuideUtils; 11 | 12 | /** 13 | * if your project based on Activity 14 | */ 15 | public class ApiGuideActivity extends Activity { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.layout_api_guide); 21 | Toast.makeText(this, "use permission Based on Activity", Toast.LENGTH_SHORT).show(); 22 | findViewById(R.id.checkSinglePermission) 23 | .setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | ApiGuideUtils.checkSinglePermission(v); 27 | } 28 | }); 29 | findViewById(R.id.requestSinglePermission) 30 | .setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | ApiGuideUtils.requestSinglePermission(v); 34 | } 35 | }); 36 | findViewById(R.id.requestPermissions) 37 | .setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | ApiGuideUtils.requestPermissions(v); 41 | } 42 | }); 43 | findViewById(R.id.requestSinglePermissionWithRationale) 44 | .setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | ApiGuideUtils.requestSinglePermissionWithRationale(v); 48 | } 49 | }); 50 | findViewById(R.id.checkNotification) 51 | .setOnClickListener(new View.OnClickListener() { 52 | @Override 53 | public void onClick(View v) { 54 | ApiGuideUtils.checkNotification(v); 55 | } 56 | }); 57 | findViewById(R.id.checkAndRequestNotification) 58 | .setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | ApiGuideUtils.checkAndRequestNotification(v); 62 | } 63 | }); 64 | findViewById(R.id.checkAndRequestSystemAlert) 65 | .setOnClickListener(new View.OnClickListener() { 66 | @Override 67 | public void onClick(View v) { 68 | ApiGuideUtils.checkAndRequestSystemAlert(v); 69 | } 70 | }); 71 | findViewById(R.id.checkAndRequestUnKnownSource) 72 | .setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | ApiGuideUtils.checkAndRequestUnKnownSource(v); 76 | } 77 | }); 78 | findViewById(R.id.checkAndRequestWriteSystemSettings) 79 | .setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | ApiGuideUtils.checkAndRequestWriteSystemSettings(v); 83 | } 84 | }); 85 | findViewById(R.id.goApplicationSettings) 86 | .setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | ApiGuideUtils.goApplicationSettings(v); 90 | } 91 | }); 92 | findViewById(R.id.getTopActivity) 93 | .setOnClickListener(new View.OnClickListener() { 94 | @Override 95 | public void onClick(View v) { 96 | ApiGuideUtils.getTopActivity(v); 97 | } 98 | }); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/ApiGuideAppComponentActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide; 2 | 3 | 4 | import android.os.Bundle; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.Toast; 8 | 9 | import com.qw.sample.R; 10 | import com.qw.sample.utils.ApiGuideUtils; 11 | 12 | /** 13 | * if your project based on AppComponentActivity or FragmentActivity 14 | */ 15 | public class ApiGuideAppComponentActivity extends AppCompatActivity { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.layout_api_guide); 21 | Toast.makeText(this, "use permission Based on AppCompatActivity", Toast.LENGTH_SHORT).show(); 22 | findViewById(R.id.checkSinglePermission) 23 | .setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | ApiGuideUtils.checkSinglePermission(v); 27 | } 28 | }); 29 | findViewById(R.id.requestSinglePermission) 30 | .setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | ApiGuideUtils.requestSinglePermission(v); 34 | } 35 | }); 36 | findViewById(R.id.requestPermissions) 37 | .setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | ApiGuideUtils.requestPermissions(v); 41 | } 42 | }); 43 | findViewById(R.id.requestSinglePermissionWithRationale) 44 | .setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | ApiGuideUtils.requestSinglePermissionWithRationale(v); 48 | } 49 | }); 50 | findViewById(R.id.checkNotification) 51 | .setOnClickListener(new View.OnClickListener() { 52 | @Override 53 | public void onClick(View v) { 54 | ApiGuideUtils.checkNotification(v); 55 | } 56 | }); 57 | findViewById(R.id.checkAndRequestNotification) 58 | .setOnClickListener(new View.OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | ApiGuideUtils.checkAndRequestNotification(v); 62 | } 63 | }); 64 | findViewById(R.id.checkAndRequestSystemAlert) 65 | .setOnClickListener(new View.OnClickListener() { 66 | @Override 67 | public void onClick(View v) { 68 | ApiGuideUtils.checkAndRequestSystemAlert(v); 69 | } 70 | }); 71 | findViewById(R.id.checkAndRequestUnKnownSource) 72 | .setOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | ApiGuideUtils.checkAndRequestUnKnownSource(v); 76 | } 77 | }); 78 | findViewById(R.id.checkAndRequestWriteSystemSettings) 79 | .setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | ApiGuideUtils.checkAndRequestWriteSystemSettings(v); 83 | } 84 | }); 85 | findViewById(R.id.goApplicationSettings) 86 | .setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | ApiGuideUtils.goApplicationSettings(v); 90 | } 91 | }); 92 | findViewById(R.id.getTopActivity) 93 | .setOnClickListener(new View.OnClickListener() { 94 | @Override 95 | public void onClick(View v) { 96 | ApiGuideUtils.getTopActivity(v); 97 | } 98 | }); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/WithPagerFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import androidx.fragment.app.FragmentManager; 6 | import androidx.fragment.app.FragmentPagerAdapter; 7 | import androidx.fragment.app.FragmentStatePagerAdapter; 8 | import androidx.viewpager.widget.ViewPager; 9 | import androidx.appcompat.app.AppCompatActivity; 10 | import android.view.View; 11 | import com.qw.sample.R; 12 | import com.qw.sample.guide.fragment.PagerItemFragment; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class WithPagerFragmentActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_with_fragment); 23 | findViewById(R.id.FragmentPagerAdapter).setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | ViewPager viewPager = findViewById(R.id.vp); 27 | viewPager.setAdapter(new MyFragmentAdapter(getSupportFragmentManager())); 28 | } 29 | }); 30 | findViewById(R.id.FragmentStatePagerAdapter).setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | ViewPager viewPager = findViewById(R.id.vp); 34 | viewPager.setAdapter(new MyFragmentStateAdapter(getSupportFragmentManager())); 35 | } 36 | }); 37 | } 38 | 39 | class MyFragmentStateAdapter extends FragmentStatePagerAdapter { 40 | private final static int TAB_COUNT = 3; 41 | 42 | private List listData = Arrays.asList(Color.RED, Color.GREEN, Color.BLUE); 43 | 44 | MyFragmentStateAdapter(FragmentManager fm) { 45 | super(fm); 46 | } 47 | 48 | @Override 49 | public PagerItemFragment getItem(int position) { 50 | return PagerItemFragment.get(listData.get(position)); 51 | } 52 | 53 | @Override 54 | public int getCount() { 55 | return TAB_COUNT; 56 | } 57 | } 58 | 59 | class MyFragmentAdapter extends FragmentPagerAdapter { 60 | private final static int TAB_COUNT = 3; 61 | 62 | private List listData = Arrays.asList(Color.RED, Color.GREEN, Color.BLUE); 63 | 64 | MyFragmentAdapter(FragmentManager fm) { 65 | super(fm); 66 | } 67 | 68 | @Override 69 | public PagerItemFragment getItem(int position) { 70 | return PagerItemFragment.get(listData.get(position)); 71 | } 72 | 73 | @Override 74 | public int getCount() { 75 | return TAB_COUNT; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/fragment/ApiGuideFragment.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide.fragment; 2 | 3 | 4 | import android.app.Fragment; 5 | import android.os.Bundle; 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Toast; 12 | import com.qw.sample.R; 13 | import com.qw.sample.utils.ApiGuideUtils; 14 | 15 | public class ApiGuideFragment extends Fragment { 16 | 17 | private View root; 18 | 19 | @Nullable 20 | @Override 21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) { 22 | Toast.makeText(getActivity(), "use permission Based on Fragment", Toast.LENGTH_SHORT).show(); 23 | root = LayoutInflater.from(container.getContext()).inflate(R.layout.layout_api_guide, container, false); 24 | findViewById(R.id.checkSinglePermission) 25 | .setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View v) { 28 | ApiGuideUtils.checkSinglePermission(v); 29 | } 30 | }); 31 | findViewById(R.id.requestSinglePermission) 32 | .setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View v) { 35 | ApiGuideUtils.requestSinglePermission(v); 36 | } 37 | }); 38 | findViewById(R.id.requestPermissions) 39 | .setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | ApiGuideUtils.requestPermissions(v); 43 | } 44 | }); 45 | findViewById(R.id.requestSinglePermissionWithRationale) 46 | .setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | ApiGuideUtils.requestSinglePermissionWithRationale(v); 50 | } 51 | }); 52 | findViewById(R.id.checkNotification) 53 | .setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | ApiGuideUtils.checkNotification(v); 57 | } 58 | }); 59 | findViewById(R.id.checkAndRequestNotification) 60 | .setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | ApiGuideUtils.checkAndRequestNotification(v); 64 | } 65 | }); 66 | findViewById(R.id.checkAndRequestSystemAlert) 67 | .setOnClickListener(new View.OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | ApiGuideUtils.checkAndRequestSystemAlert(v); 71 | } 72 | }); 73 | findViewById(R.id.checkAndRequestUnKnownSource) 74 | .setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | ApiGuideUtils.checkAndRequestUnKnownSource(v); 78 | } 79 | }); 80 | findViewById(R.id.checkAndRequestWriteSystemSettings) 81 | .setOnClickListener(new View.OnClickListener() { 82 | @Override 83 | public void onClick(View v) { 84 | ApiGuideUtils.checkAndRequestWriteSystemSettings(v); 85 | } 86 | }); 87 | findViewById(R.id.goApplicationSettings) 88 | .setOnClickListener(new View.OnClickListener() { 89 | @Override 90 | public void onClick(View v) { 91 | ApiGuideUtils.goApplicationSettings(v); 92 | } 93 | }); 94 | findViewById(R.id.getTopActivity) 95 | .setOnClickListener(new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | ApiGuideUtils.getTopActivity(v); 99 | } 100 | }); 101 | 102 | return root; 103 | } 104 | 105 | private T findViewById(int id) { 106 | return root.findViewById(id); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/fragment/ApiGuideSupportFragment.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide.fragment; 2 | 3 | 4 | import android.os.Bundle; 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | import androidx.fragment.app.Fragment; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Toast; 12 | import com.qw.sample.R; 13 | import com.qw.sample.utils.ApiGuideUtils; 14 | 15 | public class ApiGuideSupportFragment extends Fragment { 16 | 17 | private View root; 18 | 19 | @Nullable 20 | @Override 21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) { 22 | Toast.makeText(getActivity(), "use permission Based on SupportFragment", Toast.LENGTH_SHORT).show(); 23 | root = LayoutInflater.from(container.getContext()).inflate(R.layout.layout_api_guide, container, false); 24 | findViewById(R.id.checkSinglePermission) 25 | .setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View v) { 28 | ApiGuideUtils.checkSinglePermission(v); 29 | } 30 | }); 31 | findViewById(R.id.requestSinglePermission) 32 | .setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View v) { 35 | ApiGuideUtils.requestSinglePermission(v); 36 | } 37 | }); 38 | findViewById(R.id.requestPermissions) 39 | .setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | ApiGuideUtils.requestPermissions(v); 43 | } 44 | }); 45 | findViewById(R.id.requestSinglePermissionWithRationale) 46 | .setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | ApiGuideUtils.requestSinglePermissionWithRationale(v); 50 | } 51 | }); 52 | findViewById(R.id.checkNotification) 53 | .setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | ApiGuideUtils.checkNotification(v); 57 | } 58 | }); 59 | findViewById(R.id.checkAndRequestNotification) 60 | .setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | ApiGuideUtils.checkAndRequestNotification(v); 64 | } 65 | }); 66 | findViewById(R.id.checkAndRequestSystemAlert) 67 | .setOnClickListener(new View.OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | ApiGuideUtils.checkAndRequestSystemAlert(v); 71 | } 72 | }); 73 | findViewById(R.id.checkAndRequestUnKnownSource) 74 | .setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | ApiGuideUtils.checkAndRequestUnKnownSource(v); 78 | } 79 | }); 80 | findViewById(R.id.checkAndRequestWriteSystemSettings) 81 | .setOnClickListener(new View.OnClickListener() { 82 | @Override 83 | public void onClick(View v) { 84 | ApiGuideUtils.checkAndRequestWriteSystemSettings(v); 85 | } 86 | }); 87 | findViewById(R.id.goApplicationSettings) 88 | .setOnClickListener(new View.OnClickListener() { 89 | @Override 90 | public void onClick(View v) { 91 | ApiGuideUtils.goApplicationSettings(v); 92 | } 93 | }); 94 | findViewById(R.id.getTopActivity) 95 | .setOnClickListener(new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | ApiGuideUtils.getTopActivity(v); 99 | } 100 | }); 101 | 102 | return root; 103 | } 104 | 105 | private T findViewById(int id) { 106 | return root.findViewById(id); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/fragment/ContainerActivity.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide.fragment; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | import android.widget.FrameLayout; 8 | 9 | 10 | /** 11 | * @author cd5160866 12 | * @date 2019-06-11 13 | */ 14 | public class ContainerActivity extends AppCompatActivity { 15 | 16 | public static void start(Activity activity, boolean isSupport) { 17 | Intent intent = new Intent(activity, ContainerActivity.class); 18 | intent.putExtra("isSupport", isSupport); 19 | activity.startActivity(intent); 20 | } 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | int contentViewId = 1000; 26 | FrameLayout frameLayout = new FrameLayout(this); 27 | frameLayout.setId(contentViewId); 28 | setContentView(frameLayout); 29 | if (getIntent().getExtras() == null) { 30 | return; 31 | } 32 | boolean isSupport = getIntent().getExtras().getBoolean("isSupport", false); 33 | if (isSupport) { 34 | getSupportFragmentManager() 35 | .beginTransaction() 36 | .replace(contentViewId, new ApiGuideSupportFragment()) 37 | .commitNowAllowingStateLoss(); 38 | } else { 39 | getFragmentManager().beginTransaction() 40 | .replace(contentViewId, new ApiGuideFragment()) 41 | .commitAllowingStateLoss(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/guide/fragment/PagerItemFragment.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.guide.fragment; 2 | 3 | 4 | import android.Manifest; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.fragment.app.Fragment; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Toast; 14 | import com.qw.soul.permission.SoulPermission; 15 | import com.qw.soul.permission.adapter.SimplePermissionAdapter; 16 | import com.qw.soul.permission.bean.Permission; 17 | 18 | public class PagerItemFragment extends Fragment { 19 | 20 | public static PagerItemFragment get(int color) { 21 | PagerItemFragment fragment = new PagerItemFragment(); 22 | Bundle bundle = new Bundle(); 23 | bundle.putInt("Color", color); 24 | fragment.setArguments(bundle); 25 | return fragment; 26 | } 27 | 28 | @Nullable 29 | @Override 30 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) { 31 | View view = new View(container.getContext()); 32 | int color = getArguments().getInt("Color"); 33 | view.setBackgroundColor(color); 34 | if (color == Color.RED) { 35 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.BODY_SENSORS, new SimplePermissionAdapter() { 36 | @Override 37 | public void onPermissionOk(Permission permission) { 38 | Toast.makeText(container.getContext(), "sensor permission ok", Toast.LENGTH_SHORT).show(); 39 | } 40 | 41 | @Override 42 | public void onPermissionDenied(Permission permission) { 43 | Toast.makeText(container.getContext(), "sensor permission denied", Toast.LENGTH_SHORT).show(); 44 | } 45 | }); 46 | } 47 | return view; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/utils/ApiGuideUtils.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.utils; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import com.google.android.material.snackbar.Snackbar; 7 | import android.view.View; 8 | import com.qw.soul.permission.SoulPermission; 9 | import com.qw.soul.permission.bean.Permission; 10 | import com.qw.soul.permission.bean.Permissions; 11 | import com.qw.soul.permission.bean.Special; 12 | import com.qw.soul.permission.callbcak.CheckRequestPermissionListener; 13 | import com.qw.soul.permission.callbcak.CheckRequestPermissionsListener; 14 | import com.qw.soul.permission.callbcak.GoAppDetailCallBack; 15 | import com.qw.soul.permission.callbcak.SpecialPermissionListener; 16 | 17 | /** 18 | * @author cd5160866 19 | */ 20 | public class ApiGuideUtils { 21 | 22 | public static void checkSinglePermission(View view) { 23 | //you can also use checkPermissions() for a series of permissions 24 | Permission checkResult = SoulPermission.getInstance().checkSinglePermission(Manifest.permission.ACCESS_FINE_LOCATION); 25 | Utils.showMessage(view, checkResult.toString()); 26 | } 27 | 28 | public static void requestSinglePermission(final View view) { 29 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.ACCESS_FINE_LOCATION, 30 | //if you want do noting or no need all the callbacks you may use SimplePermissionAdapter instead 31 | new CheckRequestPermissionListener() { 32 | @Override 33 | public void onPermissionOk(Permission permission) { 34 | Utils.showMessage(view, permission.toString() + "\n is ok , you can do your operations"); 35 | } 36 | 37 | @Override 38 | public void onPermissionDenied(Permission permission) { 39 | Utils.showMessage(view, permission.toString() + " \n is refused you can not do next things"); 40 | } 41 | }); 42 | } 43 | 44 | public static void requestPermissions(final View view) { 45 | SoulPermission.getInstance().checkAndRequestPermissions( 46 | Permissions.build(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), 47 | //if you want do noting or no need all the callbacks you may use SimplePermissionsAdapter instead 48 | new CheckRequestPermissionsListener() { 49 | @Override 50 | public void onAllPermissionOk(Permission[] allPermissions) { 51 | Utils.showMessage(view, allPermissions.length + "permissions is ok" + " \n you can do your operations"); 52 | } 53 | 54 | @Override 55 | public void onPermissionDenied(Permission[] refusedPermissions) { 56 | Utils.showMessage(view, refusedPermissions[0].toString() + " \n is refused you can not do next things"); 57 | } 58 | }); 59 | } 60 | 61 | public static void requestSinglePermissionWithRationale(final View view) { 62 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.READ_CONTACTS, 63 | new CheckRequestPermissionListener() { 64 | @Override 65 | public void onPermissionOk(Permission permission) { 66 | Utils.showMessage(view, permission.toString() + "\n is ok , you can do your operations"); 67 | } 68 | 69 | @Override 70 | public void onPermissionDenied(Permission permission) { 71 | // see CheckPermissionWithRationaleAdapter 72 | if (permission.shouldRationale()) { 73 | Utils.showMessage(view, permission.toString() + " \n you should show a explain for user then retry "); 74 | } else { 75 | Utils.showMessage(view, permission.toString() + " \n is refused you can not do next things"); 76 | } 77 | } 78 | }); 79 | } 80 | 81 | public static void checkNotification(View view) { 82 | boolean checkResult = SoulPermission.getInstance().checkSpecialPermission(Special.NOTIFICATION); 83 | Utils.showMessage(view, checkResult ? "Notification is enable" : 84 | "Notification is disable \n you may invoke checkAndRequestPermission and enable notification"); 85 | } 86 | 87 | public static void checkAndRequestNotification(final View view) { 88 | //if you want do noting or no need all the callbacks you may use SimpleSpecialPermissionAdapter instead 89 | SoulPermission.getInstance().checkAndRequestPermission(Special.NOTIFICATION, new SpecialPermissionListener() { 90 | @Override 91 | public void onGranted(Special permission) { 92 | Utils.showMessage(view, "Notification is enable now "); 93 | } 94 | 95 | @Override 96 | public void onDenied(Special permission) { 97 | Snackbar.make(view, "Notification is disable yet ", Snackbar.LENGTH_LONG) 98 | .setAction("retry", new View.OnClickListener() { 99 | @Override 100 | public void onClick(View v) { 101 | checkAndRequestNotification(v); 102 | } 103 | }).show(); 104 | } 105 | }); 106 | } 107 | 108 | public static void checkAndRequestSystemAlert(final View view) { 109 | //if you want do noting or no need all the callbacks you may use SimpleSpecialPermissionAdapter instead 110 | SoulPermission.getInstance().checkAndRequestPermission(Special.SYSTEM_ALERT, new SpecialPermissionListener() { 111 | @Override 112 | public void onGranted(Special permission) { 113 | Utils.showMessage(view, "System Alert is enable now "); 114 | } 115 | 116 | @Override 117 | public void onDenied(Special permission) { 118 | Utils.showMessage(view, "System Alert is disable yet "); 119 | } 120 | }); 121 | } 122 | 123 | public static void checkAndRequestUnKnownSource(final View view) { 124 | //if you want do noting or no need all the callbacks you may use SimpleSpecialPermissionAdapter instead 125 | SoulPermission.getInstance().checkAndRequestPermission(Special.UNKNOWN_APP_SOURCES, new SpecialPermissionListener() { 126 | @Override 127 | public void onGranted(Special permission) { 128 | Utils.showMessage(view, "install unKnown app is enable now "); 129 | } 130 | 131 | @Override 132 | public void onDenied(Special permission) { 133 | Utils.showMessage(view, "install unKnown app is disable yet"); 134 | } 135 | }); 136 | } 137 | 138 | public static void checkAndRequestWriteSystemSettings(final View view) { 139 | //if you want do noting or no need all the callbacks you may use SimpleSpecialPermissionAdapter instead 140 | SoulPermission.getInstance().checkAndRequestPermission(Special.WRITE_SETTINGS, new SpecialPermissionListener() { 141 | @Override 142 | public void onGranted(Special permission) { 143 | Utils.showMessage(view, "install unKnown app is enable now "); 144 | } 145 | 146 | @Override 147 | public void onDenied(Special permission) { 148 | Utils.showMessage(view, "install unKnown app is disable yet"); 149 | } 150 | }); 151 | } 152 | 153 | public static void goApplicationSettings(final View view) { 154 | SoulPermission.getInstance().goApplicationSettings(new GoAppDetailCallBack() { 155 | @Override 156 | public void onBackFromAppDetail(Intent data) { 157 | //if you need to know when back from app detail 158 | Utils.showMessage(view, "back from go appDetail"); 159 | } 160 | }); 161 | } 162 | 163 | public static void getTopActivity(View view) { 164 | Activity activity = SoulPermission.getInstance().getTopActivity(); 165 | if (null != activity) { 166 | Utils.showMessage(view, activity.getClass().getSimpleName() + " " + activity.hashCode()); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | import android.provider.ContactsContract; 9 | import androidx.annotation.NonNull; 10 | import androidx.appcompat.app.AlertDialog; 11 | import android.telephony.TelephonyManager; 12 | import android.view.View; 13 | import android.widget.Toast; 14 | import com.qw.soul.permission.SoulPermission; 15 | import com.qw.soul.permission.bean.Special; 16 | import org.json.JSONException; 17 | import org.json.JSONObject; 18 | 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | /** 23 | * @author cd5160866 24 | */ 25 | public class Utils { 26 | 27 | public static void showMessage(View view, final String message) { 28 | boolean isNotificationCanShow = SoulPermission.getInstance().checkSpecialPermission(Special.NOTIFICATION); 29 | //通知权限可用Toast才能展示出来 30 | if (isNotificationCanShow) { 31 | Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show(); 32 | } else { 33 | new AlertDialog.Builder(view.getContext()) 34 | .setMessage(message) 35 | .setPositiveButton("OK", null) 36 | .create().show(); 37 | } 38 | } 39 | 40 | /** 41 | * 拨打指定电话 42 | */ 43 | public static void makeCall(Context context, String phoneNumber) { 44 | Intent intent = new Intent(Intent.ACTION_CALL); 45 | Uri data = Uri.parse("tel:" + phoneNumber); 46 | intent.setData(data); 47 | if (!(context instanceof Activity)) { 48 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 49 | } 50 | context.startActivity(intent); 51 | } 52 | 53 | /** 54 | * 读取手机状态 55 | */ 56 | public static void readPhoneStatus(Context context) { 57 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 58 | if (tm == null) { 59 | return; 60 | } 61 | Toast.makeText(context, "phone " + tm.getLine1Number() + "\nime " + tm.getDeviceId() + "\nsimSerialNumber " + tm.getSimSerialNumber(), Toast.LENGTH_SHORT) 62 | .show(); 63 | } 64 | 65 | /** 66 | * 选择联系人 67 | */ 68 | public static void chooseContact(Activity activity, int requestCode) { 69 | activity.startActivityForResult(new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI), requestCode); 70 | } 71 | 72 | 73 | public static void onGetChooseContactData(Context context, Intent data, @NonNull ReadContactListener listener) { 74 | Uri contactUri = data.getData(); 75 | if (null == contactUri) { 76 | listener.onFailed(); 77 | return; 78 | } 79 | 80 | Cursor cursor; 81 | try { 82 | cursor = context.getContentResolver().query(contactUri, null, null, null, null); 83 | } catch (SecurityException e) { 84 | listener.onFailed(); 85 | e.printStackTrace(); 86 | return; 87 | } 88 | if (cursor == null || !cursor.moveToFirst()) { 89 | closeCursor(cursor); 90 | listener.onFailed(); 91 | return; 92 | } 93 | String contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 94 | ContactInfo contactInfo = new ContactInfo(contactName); 95 | final String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); 96 | closeCursor(cursor); 97 | 98 | Cursor phoneCursor = context.getContentResolver().query( 99 | ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 100 | ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null); 101 | if (null == phoneCursor) { 102 | listener.onFailed(); 103 | return; 104 | } 105 | 106 | while (phoneCursor.moveToNext()) { 107 | String phone = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 108 | contactInfo.addPhone(phone); 109 | } 110 | closeCursor(phoneCursor); 111 | listener.onSuccess(contactInfo); 112 | } 113 | 114 | public interface ReadContactListener { 115 | 116 | /** 117 | * 选择成功 118 | * 119 | * @param contactInfo 联系人实体类 120 | */ 121 | void onSuccess(ContactInfo contactInfo); 122 | 123 | /** 124 | * 选择失败 125 | */ 126 | void onFailed(); 127 | } 128 | 129 | private static void closeCursor(Cursor c) { 130 | if (null != c && !c.isClosed()) { 131 | c.close(); 132 | } 133 | } 134 | 135 | public static class ContactInfo { 136 | private String name; 137 | private List phones; 138 | 139 | public ContactInfo(String name) { 140 | this.name = name; 141 | this.phones = new LinkedList<>(); 142 | } 143 | 144 | public void addPhone(String phone) { 145 | phones.add(phone); 146 | } 147 | 148 | public String getName() { 149 | return name; 150 | } 151 | 152 | public List getPhones() { 153 | return phones; 154 | } 155 | 156 | @Override 157 | public String toString() { 158 | JSONObject object = new JSONObject(); 159 | //name 160 | try { 161 | object.put("name", name); 162 | } catch (JSONException e) { 163 | e.printStackTrace(); 164 | } 165 | //phones 166 | for (int i = 0; i < phones.size(); i++) { 167 | String phone = phones.get(i); 168 | StringBuilder builder = new StringBuilder("phone"); 169 | if (i > 0) { 170 | builder.append(i); 171 | } 172 | try { 173 | object.put(builder.toString(), phone); 174 | } catch (JSONException e) { 175 | e.printStackTrace(); 176 | } 177 | } 178 | return object.toString(); 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /sample/src/main/java/com/qw/sample/utils/UtilsWithPermission.java: -------------------------------------------------------------------------------- 1 | package com.qw.sample.utils; 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.net.Uri; 9 | import android.provider.ContactsContract; 10 | import android.telephony.TelephonyManager; 11 | import android.widget.Toast; 12 | import com.qw.sample.adapter.CheckPermissionAdapter; 13 | import com.qw.sample.adapter.CheckPermissionWithRationaleAdapter; 14 | import com.qw.soul.permission.SoulPermission; 15 | import com.qw.soul.permission.bean.Permission; 16 | 17 | /** 18 | * @author cd5160866 19 | */ 20 | public class UtilsWithPermission { 21 | 22 | /** 23 | * 拨打指定电话 24 | */ 25 | public static void makeCall(final Context context, final String phoneNumber) { 26 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.CALL_PHONE, 27 | new CheckPermissionWithRationaleAdapter("如果你拒绝了权限,你将无法拨打电话,请点击授予权限", 28 | new Runnable() { 29 | @Override 30 | public void run() { 31 | //retry 32 | makeCall(context, phoneNumber); 33 | } 34 | }) { 35 | @SuppressLint("MissingPermission") 36 | @Override 37 | public void onPermissionOk(Permission permission) { 38 | Intent intent = new Intent(Intent.ACTION_CALL); 39 | Uri data = Uri.parse("tel:" + phoneNumber); 40 | intent.setData(data); 41 | if (!(context instanceof Activity)) { 42 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 43 | } 44 | context.startActivity(intent); 45 | } 46 | }); 47 | } 48 | 49 | /** 50 | * 选择联系人 51 | */ 52 | public static void chooseContact(final Activity activity, final int requestCode) { 53 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.READ_CONTACTS, 54 | new CheckPermissionAdapter() { 55 | @SuppressLint("MissingPermission") 56 | @Override 57 | public void onPermissionOk(Permission permission) { 58 | activity.startActivityForResult(new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI), requestCode); 59 | } 60 | }); 61 | } 62 | 63 | /** 64 | * 读取手机状态 65 | * 读取联系人权限和打电话是一组,只要一个授予即可无需重复请求 66 | */ 67 | public static void readPhoneStatus() { 68 | SoulPermission.getInstance().checkAndRequestPermission(Manifest.permission.READ_PHONE_STATE, new CheckPermissionAdapter() { 69 | @SuppressLint("MissingPermission") 70 | @Override 71 | public void onPermissionOk(Permission permission) { 72 | Context context = SoulPermission.getInstance().getContext(); 73 | TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 74 | if (tm == null) { 75 | return; 76 | } 77 | Toast.makeText(context, "phone " + tm.getLine1Number() + "\nime " + tm.getDeviceId() + "\nsimSerialNumber " + tm.getSimSerialNumber(), Toast.LENGTH_SHORT) 78 | .show(); 79 | } 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |