├── .gitignore
├── .idea
├── encodings.xml
├── gradle.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── Screenshot_2019-05-02-18-04-40-864_cn.bavelee.pok.png
├── Screenshot_2019-05-02-18-04-50-334_cn.bavelee.pok.png
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── ColorPickerPreference
│ │ ├── .classpath
│ │ ├── .gitignore
│ │ ├── .idea
│ │ ├── codeStyles
│ │ │ └── Project.xml
│ │ ├── gradle.xml
│ │ ├── misc.xml
│ │ ├── modules.xml
│ │ ├── runConfigurations.xml
│ │ └── workspace.xml
│ │ ├── .settings
│ │ └── org.eclipse.buildship.core.prefs
│ │ ├── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── local.properties
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── net
│ │ │ └── margaritov
│ │ │ └── colorpickerpreference
│ │ │ └── ApplicationTest.java
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── net
│ │ │ └── margaritov
│ │ │ └── preference
│ │ │ └── colorpicker
│ │ │ ├── AlphaPatternDrawable.java
│ │ │ ├── ColorPickerDialog.java
│ │ │ ├── ColorPickerPanelView.java
│ │ │ ├── ColorPickerPreference.java
│ │ │ └── ColorPickerView.java
│ │ └── res
│ │ ├── layout-land
│ │ └── dialog_color_picker.xml
│ │ ├── layout
│ │ └── dialog_color_picker.xml
│ │ └── values
│ │ └── strings.xml
├── proguard-rules.pro
├── release
│ ├── app-release.apk
│ └── output.json
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── bavelee
│ │ └── pokeinstaller
│ │ ├── BackgroundInstallActivity.java
│ │ ├── PokeInstallerActivity.java
│ │ ├── Prefs.java
│ │ ├── SettingsActivity.java
│ │ ├── ShellUtils.java
│ │ └── apk
│ │ ├── APKCommander.java
│ │ ├── ApkInfo.java
│ │ ├── ContentUriUtils.java
│ │ └── ICommanderCallback.java
│ └── res
│ ├── drawable
│ ├── bg_hover.xml
│ └── ic_settings.xml
│ ├── layout
│ ├── act_poke_installer.xml
│ ├── info_item.xml
│ └── info_item_permission.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-zh-rTW
│ └── strings.xml
│ ├── values-zh
│ └── strings.xml
│ ├── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── prefs.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── module_donatedialog
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── cn
│ │ └── bavelee
│ │ └── donatedialog
│ │ └── DonateToMe.java
│ └── res
│ ├── drawable
│ ├── alipay_money_revised.png
│ └── wechat_money_revised.png
│ ├── layout
│ └── layout_donate_dialog.xml
│ ├── values-zh
│ └── strings.xml
│ └── values
│ └── strings.xml
├── pokeinstaller.keystore
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PokeInstaller
2 | An android package installer alternatives under root
3 |
--------------------------------------------------------------------------------
/Screenshot_2019-05-02-18-04-40-864_cn.bavelee.pok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/Screenshot_2019-05-02-18-04-40-864_cn.bavelee.pok.png
--------------------------------------------------------------------------------
/Screenshot_2019-05-02-18-04-50-334_cn.bavelee.pok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/Screenshot_2019-05-02-18-04-50-334_cn.bavelee.pok.png
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "cn.bavelee.pokeinstaller"
7 | minSdkVersion 21
8 | targetSdkVersion 28
9 | versionCode 20
10 | versionName "2.9"
11 | }
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
16 | }
17 | }
18 | }
19 |
20 | dependencies {
21 | implementation fileTree(include: ['*.jar'], dir: 'libs')
22 | implementation project(':ColorPickerPreference')
23 | implementation project(':module_donatedialog')
24 | implementation 'com.github.florent37:runtime-permission:1.0.1'
25 | implementation 'com.android.support:support-fragment:28.0.0'
26 | }
27 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | 1556454767703
74 |
75 |
76 | 1556454767703
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | connection.project.dir=..
2 | eclipse.preferences.version=1
3 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | ext {
4 | bintrayRepo = 'android-ColorPickerPreference'
5 | bintrayName = 'android-colorpickerpreference'
6 |
7 | publishedGroupId = 'net.margaritov.preference.colorpicker.ColorPickerPreference'
8 | libraryName = 'ColorPickerPreference'
9 | artifact = 'ColorPickerPreference'
10 |
11 | libraryDescription = 'ColorPickerPreference for android to create color picker in preferences. Project created as Library'
12 |
13 | siteUrl = 'https://github.com/attenzione/android-ColorPickerPreference'
14 | gitUrl = 'https://github.com/attenzione/android-ColorPickerPreference.git'
15 |
16 | libraryVersion = '1.0.0'
17 |
18 | developerId = 'attenzione'
19 | developerName = 'Sergey Margaritov'
20 | developerEmail = 'github@semar.in'
21 |
22 | licenseName = 'The Apache Software License, Version 2.0'
23 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
24 | allLicenses = ["Apache-2.0"]
25 | }
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | defaultConfig {
31 | minSdkVersion 7
32 | targetSdkVersion 28
33 | versionCode 1
34 | versionName "1.0"
35 | }
36 | buildTypes {
37 | release {
38 | minifyEnabled false
39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40 | }
41 | }
42 | }
43 |
44 | dependencies {
45 | implementation fileTree(include: ['*.jar'], dir: 'libs')
46 | }
47 |
48 | // Place it at the end of the file
49 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
50 | //apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
51 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/libs/ColorPickerPreference/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Apr 28 20:32:56 CST 2019
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-4.10.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/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 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/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 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sun Apr 28 20:32:47 CST 2019
8 | sdk.dir=/Users/imbavelee/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class com.android.vending.licensing.ILicensingService
14 |
15 | -keepclasseswithmembernames class * {
16 | native ;
17 | }
18 |
19 | -keepclasseswithmembernames class * {
20 | public (android.content.Context, android.util.AttributeSet);
21 | }
22 |
23 | -keepclasseswithmembernames class * {
24 | public (android.content.Context, android.util.AttributeSet, int);
25 | }
26 |
27 | -keepclassmembers enum * {
28 | public static **[] values();
29 | public static ** valueOf(java.lang.String);
30 | }
31 |
32 | -keep class * implements android.os.Parcelable {
33 | public static final android.os.Parcelable$Creator *;
34 | }
35 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/androidTest/java/net/margaritov/colorpickerpreference/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package net.margaritov.colorpickerpreference;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/AlphaPatternDrawable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.graphics.Bitmap;
20 | import android.graphics.Bitmap.Config;
21 | import android.graphics.Canvas;
22 | import android.graphics.ColorFilter;
23 | import android.graphics.Paint;
24 | import android.graphics.Rect;
25 | import android.graphics.drawable.Drawable;
26 |
27 | /**
28 | * This drawable that draws a simple white and gray chessboard pattern.
29 | * It's pattern you will often see as a background behind a
30 | * partly transparent image in many applications.
31 | *
32 | * @author Daniel Nilsson
33 | */
34 | public class AlphaPatternDrawable extends Drawable {
35 |
36 | private int mRectangleSize = 10;
37 |
38 | private Paint mPaint = new Paint();
39 | private Paint mPaintWhite = new Paint();
40 | private Paint mPaintGray = new Paint();
41 |
42 | private int numRectanglesHorizontal;
43 | private int numRectanglesVertical;
44 |
45 | /**
46 | * Bitmap in which the pattern will be cahched.
47 | */
48 | private Bitmap mBitmap;
49 |
50 | public AlphaPatternDrawable(int rectangleSize) {
51 | mRectangleSize = rectangleSize;
52 | mPaintWhite.setColor(0xffffffff);
53 | mPaintGray.setColor(0xffcbcbcb);
54 | }
55 |
56 | @Override
57 | public void draw(Canvas canvas) {
58 | canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
59 | }
60 |
61 | @Override
62 | public int getOpacity() {
63 | return 0;
64 | }
65 |
66 | @Override
67 | public void setAlpha(int alpha) {
68 | throw new UnsupportedOperationException("Alpha is not supported by this drawwable.");
69 | }
70 |
71 | @Override
72 | public void setColorFilter(ColorFilter cf) {
73 | throw new UnsupportedOperationException("ColorFilter is not supported by this drawwable.");
74 | }
75 |
76 | @Override
77 | protected void onBoundsChange(Rect bounds) {
78 | super.onBoundsChange(bounds);
79 |
80 | int height = bounds.height();
81 | int width = bounds.width();
82 |
83 | numRectanglesHorizontal = (int) Math.ceil((width / mRectangleSize));
84 | numRectanglesVertical = (int) Math.ceil(height / mRectangleSize);
85 |
86 | generatePatternBitmap();
87 |
88 | }
89 |
90 | /**
91 | * This will generate a bitmap with the pattern
92 | * as big as the rectangle we were allow to draw on.
93 | * We do this to chache the bitmap so we don't need to
94 | * recreate it each time draw() is called since it
95 | * takes a few milliseconds.
96 | */
97 | private void generatePatternBitmap() {
98 |
99 | if (getBounds().width() <= 0 || getBounds().height() <= 0) {
100 | return;
101 | }
102 |
103 | mBitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);
104 | Canvas canvas = new Canvas(mBitmap);
105 |
106 | Rect r = new Rect();
107 | boolean verticalStartWhite = true;
108 | for (int i = 0; i <= numRectanglesVertical; i++) {
109 |
110 | boolean isWhite = verticalStartWhite;
111 | for (int j = 0; j <= numRectanglesHorizontal; j++) {
112 |
113 | r.top = i * mRectangleSize;
114 | r.left = j * mRectangleSize;
115 | r.bottom = r.top + mRectangleSize;
116 | r.right = r.left + mRectangleSize;
117 |
118 | canvas.drawRect(r, isWhite ? mPaintWhite : mPaintGray);
119 |
120 | isWhite = !isWhite;
121 | }
122 |
123 | verticalStartWhite = !verticalStartWhite;
124 |
125 | }
126 |
127 | }
128 |
129 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.app.Dialog;
20 | import android.content.Context;
21 | import android.content.res.ColorStateList;
22 | import android.graphics.Color;
23 | import android.graphics.PixelFormat;
24 | import android.os.Bundle;
25 | import android.text.InputFilter;
26 | import android.text.InputType;
27 | import android.view.KeyEvent;
28 | import android.view.LayoutInflater;
29 | import android.view.View;
30 | import android.view.ViewTreeObserver;
31 | import android.view.inputmethod.EditorInfo;
32 | import android.view.inputmethod.InputMethodManager;
33 | import android.widget.EditText;
34 | import android.widget.LinearLayout;
35 | import android.widget.TextView;
36 |
37 | import java.util.Locale;
38 |
39 | public class ColorPickerDialog
40 | extends
41 | Dialog
42 | implements
43 | ColorPickerView.OnColorChangedListener,
44 | View.OnClickListener, ViewTreeObserver.OnGlobalLayoutListener {
45 |
46 | private ColorPickerView mColorPicker;
47 |
48 | private ColorPickerPanelView mOldColor;
49 | private ColorPickerPanelView mNewColor;
50 |
51 | private EditText mHexVal;
52 | private boolean mHexValueEnabled = false;
53 | private ColorStateList mHexDefaultTextColor;
54 |
55 | private OnColorChangedListener mListener;
56 | private int mOrientation;
57 | private View mLayout;
58 |
59 | @Override
60 | public void onGlobalLayout() {
61 | if (getContext().getResources().getConfiguration().orientation != mOrientation) {
62 | final int oldcolor = mOldColor.getColor();
63 | final int newcolor = mNewColor.getColor();
64 | mLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
65 | setUp(oldcolor);
66 | mNewColor.setColor(newcolor);
67 | mColorPicker.setColor(newcolor);
68 | }
69 | }
70 |
71 | public interface OnColorChangedListener {
72 | public void onColorChanged(int color);
73 | }
74 |
75 | public ColorPickerDialog(Context context, int initialColor) {
76 | super(context);
77 |
78 | init(initialColor);
79 | }
80 |
81 | private void init(int color) {
82 | // To fight color banding.
83 | getWindow().setFormat(PixelFormat.RGBA_8888);
84 |
85 | setUp(color);
86 |
87 | }
88 |
89 | private void setUp(int color) {
90 |
91 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
92 |
93 | mLayout = inflater.inflate(R.layout.dialog_color_picker, null);
94 | mLayout.getViewTreeObserver().addOnGlobalLayoutListener(this);
95 |
96 | mOrientation = getContext().getResources().getConfiguration().orientation;
97 | setContentView(mLayout);
98 |
99 | setTitle(R.string.dialog_color_picker);
100 |
101 | mColorPicker = (ColorPickerView) mLayout.findViewById(R.id.color_picker_view);
102 | mOldColor = (ColorPickerPanelView) mLayout.findViewById(R.id.old_color_panel);
103 | mNewColor = (ColorPickerPanelView) mLayout.findViewById(R.id.new_color_panel);
104 |
105 | mHexVal = (EditText) mLayout.findViewById(R.id.hex_val);
106 | mHexVal.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
107 | mHexDefaultTextColor = mHexVal.getTextColors();
108 |
109 | mHexVal.setOnEditorActionListener(new TextView.OnEditorActionListener() {
110 |
111 | @Override
112 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
113 | if (actionId == EditorInfo.IME_ACTION_DONE) {
114 | InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
115 | imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
116 | String s = mHexVal.getText().toString();
117 | if (s.length() > 5 || s.length() < 10) {
118 | try {
119 | int c = ColorPickerPreference.convertToColorInt(s.toString());
120 | mColorPicker.setColor(c, true);
121 | mHexVal.setTextColor(mHexDefaultTextColor);
122 | } catch (IllegalArgumentException e) {
123 | mHexVal.setTextColor(Color.RED);
124 | }
125 | } else {
126 | mHexVal.setTextColor(Color.RED);
127 | }
128 | return true;
129 | }
130 | return false;
131 | }
132 | });
133 |
134 | ((LinearLayout) mOldColor.getParent()).setPadding(
135 | Math.round(mColorPicker.getDrawingOffset()),
136 | 0,
137 | Math.round(mColorPicker.getDrawingOffset()),
138 | 0
139 | );
140 |
141 | mOldColor.setOnClickListener(this);
142 | mNewColor.setOnClickListener(this);
143 | mColorPicker.setOnColorChangedListener(this);
144 | mOldColor.setColor(color);
145 | mColorPicker.setColor(color, true);
146 |
147 | }
148 |
149 | @Override
150 | public void onColorChanged(int color) {
151 |
152 | mNewColor.setColor(color);
153 |
154 | if (mHexValueEnabled)
155 | updateHexValue(color);
156 |
157 | /*
158 | if (mListener != null) {
159 | mListener.onColorChanged(color);
160 | }
161 | */
162 |
163 | }
164 |
165 | public void setHexValueEnabled(boolean enable) {
166 | mHexValueEnabled = enable;
167 | if (enable) {
168 | mHexVal.setVisibility(View.VISIBLE);
169 | updateHexLengthFilter();
170 | updateHexValue(getColor());
171 | } else
172 | mHexVal.setVisibility(View.GONE);
173 | }
174 |
175 | public boolean getHexValueEnabled() {
176 | return mHexValueEnabled;
177 | }
178 |
179 | private void updateHexLengthFilter() {
180 | if (getAlphaSliderVisible())
181 | mHexVal.setFilters(new InputFilter[]{new InputFilter.LengthFilter(9)});
182 | else
183 | mHexVal.setFilters(new InputFilter[]{new InputFilter.LengthFilter(7)});
184 | }
185 |
186 | private void updateHexValue(int color) {
187 | if (getAlphaSliderVisible()) {
188 | mHexVal.setText(ColorPickerPreference.convertToARGB(color).toUpperCase(Locale.getDefault()));
189 | } else {
190 | mHexVal.setText(ColorPickerPreference.convertToRGB(color).toUpperCase(Locale.getDefault()));
191 | }
192 | mHexVal.setTextColor(mHexDefaultTextColor);
193 | }
194 |
195 | public void setAlphaSliderVisible(boolean visible) {
196 | mColorPicker.setAlphaSliderVisible(visible);
197 | if (mHexValueEnabled) {
198 | updateHexLengthFilter();
199 | updateHexValue(getColor());
200 | }
201 | }
202 |
203 | public boolean getAlphaSliderVisible() {
204 | return mColorPicker.getAlphaSliderVisible();
205 | }
206 |
207 | /**
208 | * Set a OnColorChangedListener to get notified when the color
209 | * selected by the user has changed.
210 | *
211 | * @param listener
212 | */
213 | public void setOnColorChangedListener(OnColorChangedListener listener) {
214 | mListener = listener;
215 | }
216 |
217 | public int getColor() {
218 | return mColorPicker.getColor();
219 | }
220 |
221 | @Override
222 | public void onClick(View v) {
223 | if (v.getId() == R.id.new_color_panel) {
224 | if (mListener != null) {
225 | mListener.onColorChanged(mNewColor.getColor());
226 | }
227 | }
228 | dismiss();
229 | }
230 |
231 | @Override
232 | public Bundle onSaveInstanceState() {
233 | Bundle state = super.onSaveInstanceState();
234 | state.putInt("old_color", mOldColor.getColor());
235 | state.putInt("new_color", mNewColor.getColor());
236 | return state;
237 | }
238 |
239 | @Override
240 | public void onRestoreInstanceState(Bundle savedInstanceState) {
241 | super.onRestoreInstanceState(savedInstanceState);
242 | mOldColor.setColor(savedInstanceState.getInt("old_color"));
243 | mColorPicker.setColor(savedInstanceState.getInt("new_color"), true);
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPanelView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Paint;
22 | import android.graphics.RectF;
23 | import android.util.AttributeSet;
24 | import android.view.View;
25 |
26 | /**
27 | * This class draws a panel which which will be filled with a color which can be set.
28 | * It can be used to show the currently selected color which you will get from
29 | * the {@link ColorPickerView}.
30 | *
31 | * @author Daniel Nilsson
32 | */
33 | public class ColorPickerPanelView extends View {
34 |
35 | /**
36 | * The width in pixels of the border
37 | * surrounding the color panel.
38 | */
39 | private final static float BORDER_WIDTH_PX = 1;
40 |
41 | private float mDensity = 1f;
42 |
43 | private int mBorderColor = 0xff6E6E6E;
44 | private int mColor = 0xff000000;
45 |
46 | private Paint mBorderPaint;
47 | private Paint mColorPaint;
48 |
49 | private RectF mDrawingRect;
50 | private RectF mColorRect;
51 |
52 | private AlphaPatternDrawable mAlphaPattern;
53 |
54 |
55 | public ColorPickerPanelView(Context context) {
56 | this(context, null);
57 | }
58 |
59 | public ColorPickerPanelView(Context context, AttributeSet attrs) {
60 | this(context, attrs, 0);
61 | }
62 |
63 | public ColorPickerPanelView(Context context, AttributeSet attrs, int defStyle) {
64 | super(context, attrs, defStyle);
65 | init();
66 | }
67 |
68 | private void init() {
69 | mBorderPaint = new Paint();
70 | mColorPaint = new Paint();
71 | mDensity = getContext().getResources().getDisplayMetrics().density;
72 | }
73 |
74 |
75 | @Override
76 | protected void onDraw(Canvas canvas) {
77 |
78 | final RectF rect = mColorRect;
79 |
80 | if (BORDER_WIDTH_PX > 0) {
81 | mBorderPaint.setColor(mBorderColor);
82 | canvas.drawRect(mDrawingRect, mBorderPaint);
83 | }
84 |
85 | if (mAlphaPattern != null) {
86 | mAlphaPattern.draw(canvas);
87 | }
88 |
89 | mColorPaint.setColor(mColor);
90 |
91 | canvas.drawRect(rect, mColorPaint);
92 | }
93 |
94 | @Override
95 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96 |
97 | int width = MeasureSpec.getSize(widthMeasureSpec);
98 | int height = MeasureSpec.getSize(heightMeasureSpec);
99 |
100 | setMeasuredDimension(width, height);
101 | }
102 |
103 | @Override
104 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
105 | super.onSizeChanged(w, h, oldw, oldh);
106 |
107 | mDrawingRect = new RectF();
108 | mDrawingRect.left = getPaddingLeft();
109 | mDrawingRect.right = w - getPaddingRight();
110 | mDrawingRect.top = getPaddingTop();
111 | mDrawingRect.bottom = h - getPaddingBottom();
112 |
113 | setUpColorRect();
114 |
115 | }
116 |
117 | private void setUpColorRect() {
118 | final RectF dRect = mDrawingRect;
119 |
120 | float left = dRect.left + BORDER_WIDTH_PX;
121 | float top = dRect.top + BORDER_WIDTH_PX;
122 | float bottom = dRect.bottom - BORDER_WIDTH_PX;
123 | float right = dRect.right - BORDER_WIDTH_PX;
124 |
125 | mColorRect = new RectF(left, top, right, bottom);
126 |
127 | mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity));
128 |
129 | mAlphaPattern.setBounds(
130 | Math.round(mColorRect.left),
131 | Math.round(mColorRect.top),
132 | Math.round(mColorRect.right),
133 | Math.round(mColorRect.bottom)
134 | );
135 |
136 | }
137 |
138 | /**
139 | * Set the color that should be shown by this view.
140 | *
141 | * @param color
142 | */
143 | public void setColor(int color) {
144 | mColor = color;
145 | invalidate();
146 | }
147 |
148 | /**
149 | * Get the color currently show by this view.
150 | *
151 | * @return
152 | */
153 | public int getColor() {
154 | return mColor;
155 | }
156 |
157 | /**
158 | * Set the color of the border surrounding the panel.
159 | *
160 | * @param color
161 | */
162 | public void setBorderColor(int color) {
163 | mBorderColor = color;
164 | invalidate();
165 | }
166 |
167 | /**
168 | * Get the color of the border surrounding the panel.
169 | */
170 | public int getBorderColor() {
171 | return mBorderColor;
172 | }
173 |
174 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Sergey Margaritov
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Bitmap;
22 | import android.graphics.Bitmap.Config;
23 | import android.graphics.Color;
24 | import android.os.Bundle;
25 | import android.os.Parcel;
26 | import android.os.Parcelable;
27 | import android.preference.Preference;
28 | import android.util.AttributeSet;
29 | import android.view.View;
30 | import android.widget.ImageView;
31 | import android.widget.LinearLayout;
32 |
33 | /**
34 | * A preference type that allows a user to choose a time
35 | *
36 | * @author Sergey Margaritov
37 | */
38 | public class ColorPickerPreference
39 | extends
40 | Preference
41 | implements
42 | Preference.OnPreferenceClickListener,
43 | ColorPickerDialog.OnColorChangedListener {
44 |
45 | View mView;
46 | ColorPickerDialog mDialog;
47 | private int mValue = Color.BLACK;
48 | private float mDensity = 0;
49 | private boolean mAlphaSliderEnabled = false;
50 | private boolean mHexValueEnabled = false;
51 |
52 | public ColorPickerPreference(Context context) {
53 | super(context);
54 | init(context, null);
55 | }
56 |
57 | public ColorPickerPreference(Context context, AttributeSet attrs) {
58 | super(context, attrs);
59 | init(context, attrs);
60 | }
61 |
62 | public ColorPickerPreference(Context context, AttributeSet attrs, int defStyle) {
63 | super(context, attrs, defStyle);
64 | init(context, attrs);
65 | }
66 |
67 | /**Method edited by
68 | * @author Anna Berkovitch
69 | * added functionality to accept hex string as defaultValue
70 | * and to properly persist resources reference string, such as @color/someColor
71 | * previously persisted 0*/
72 | @Override
73 | protected Object onGetDefaultValue(TypedArray a, int index) {
74 | int colorInt;
75 | String mHexDefaultValue = a.getString(index);
76 | if (mHexDefaultValue != null && mHexDefaultValue.startsWith("#")) {
77 | colorInt = convertToColorInt(mHexDefaultValue);
78 | return colorInt;
79 |
80 | } else {
81 | return a.getColor(index, Color.BLACK);
82 | }
83 | }
84 |
85 | @Override
86 | protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
87 | onColorChanged(restoreValue ? getPersistedInt(mValue) : (Integer) defaultValue);
88 | }
89 |
90 | private void init(Context context, AttributeSet attrs) {
91 | mDensity = getContext().getResources().getDisplayMetrics().density;
92 | setOnPreferenceClickListener(this);
93 | if (attrs != null) {
94 | mAlphaSliderEnabled = attrs.getAttributeBooleanValue(null, "alphaSlider", false);
95 | mHexValueEnabled = attrs.getAttributeBooleanValue(null, "hexValue", false);
96 | }
97 | }
98 |
99 | @Override
100 | protected void onBindView(View view) {
101 | super.onBindView(view);
102 | mView = view;
103 | setPreviewColor();
104 | }
105 |
106 | private void setPreviewColor() {
107 | if (mView == null) return;
108 | ImageView iView = new ImageView(getContext());
109 | LinearLayout widgetFrameView = ((LinearLayout) mView.findViewById(android.R.id.widget_frame));
110 | if (widgetFrameView == null) return;
111 | widgetFrameView.setVisibility(View.VISIBLE);
112 | widgetFrameView.setPadding(
113 | widgetFrameView.getPaddingLeft(),
114 | widgetFrameView.getPaddingTop(),
115 | (int) (mDensity * 8),
116 | widgetFrameView.getPaddingBottom()
117 | );
118 | // remove already create preview image
119 | int count = widgetFrameView.getChildCount();
120 | if (count > 0) {
121 | widgetFrameView.removeViews(0, count);
122 | }
123 | widgetFrameView.addView(iView);
124 | widgetFrameView.setMinimumWidth(0);
125 | iView.setBackgroundDrawable(new AlphaPatternDrawable((int) (5 * mDensity)));
126 | iView.setImageBitmap(getPreviewBitmap());
127 | }
128 |
129 | private Bitmap getPreviewBitmap() {
130 | int d = (int) (mDensity * 31); //30dip
131 | int color = mValue;
132 | Bitmap bm = Bitmap.createBitmap(d, d, Config.ARGB_8888);
133 | int w = bm.getWidth();
134 | int h = bm.getHeight();
135 | int c = color;
136 | for (int i = 0; i < w; i++) {
137 | for (int j = i; j < h; j++) {
138 | c = (i <= 1 || j <= 1 || i >= w - 2 || j >= h - 2) ? Color.GRAY : color;
139 | bm.setPixel(i, j, c);
140 | if (i != j) {
141 | bm.setPixel(j, i, c);
142 | }
143 | }
144 | }
145 |
146 | return bm;
147 | }
148 |
149 | @Override
150 | public void onColorChanged(int color) {
151 | if (isPersistent()) {
152 | persistInt(color);
153 | }
154 | mValue = color;
155 | setPreviewColor();
156 | try {
157 | getOnPreferenceChangeListener().onPreferenceChange(this, color);
158 | } catch (NullPointerException e) {
159 |
160 | }
161 | }
162 |
163 | public boolean onPreferenceClick(Preference preference) {
164 | showDialog(null);
165 | return false;
166 | }
167 |
168 | protected void showDialog(Bundle state) {
169 | mDialog = new ColorPickerDialog(getContext(), mValue);
170 | mDialog.setOnColorChangedListener(this);
171 | if (mAlphaSliderEnabled) {
172 | mDialog.setAlphaSliderVisible(true);
173 | }
174 | if (mHexValueEnabled) {
175 | mDialog.setHexValueEnabled(true);
176 | }
177 | if (state != null) {
178 | mDialog.onRestoreInstanceState(state);
179 | }
180 | mDialog.show();
181 | }
182 |
183 | /**
184 | * Toggle Alpha Slider visibility (by default it's disabled)
185 | *
186 | * @param enable
187 | */
188 | public void setAlphaSliderEnabled(boolean enable) {
189 | mAlphaSliderEnabled = enable;
190 | }
191 |
192 | /**
193 | * Toggle Hex Value visibility (by default it's disabled)
194 | *
195 | * @param enable
196 | */
197 | public void setHexValueEnabled(boolean enable) {
198 | mHexValueEnabled = enable;
199 | }
200 |
201 | /**
202 | * For custom purposes. Not used by ColorPickerPreferrence
203 | *
204 | * @param color
205 | * @author Unknown
206 | */
207 | public static String convertToARGB(int color) {
208 | String alpha = Integer.toHexString(Color.alpha(color));
209 | String red = Integer.toHexString(Color.red(color));
210 | String green = Integer.toHexString(Color.green(color));
211 | String blue = Integer.toHexString(Color.blue(color));
212 |
213 | if (alpha.length() == 1) {
214 | alpha = "0" + alpha;
215 | }
216 |
217 | if (red.length() == 1) {
218 | red = "0" + red;
219 | }
220 |
221 | if (green.length() == 1) {
222 | green = "0" + green;
223 | }
224 |
225 | if (blue.length() == 1) {
226 | blue = "0" + blue;
227 | }
228 |
229 | return "#" + alpha + red + green + blue;
230 | }
231 |
232 | /**
233 | * Method currently used by onGetDefaultValue method to
234 | * convert hex string provided in android:defaultValue to color integer.
235 | *
236 | * @param color
237 | * @return A string representing the hex value of color,
238 | * without the alpha value
239 | * @author Charles Rosaaen
240 | */
241 | public static String convertToRGB(int color) {
242 | String red = Integer.toHexString(Color.red(color));
243 | String green = Integer.toHexString(Color.green(color));
244 | String blue = Integer.toHexString(Color.blue(color));
245 |
246 | if (red.length() == 1) {
247 | red = "0" + red;
248 | }
249 |
250 | if (green.length() == 1) {
251 | green = "0" + green;
252 | }
253 |
254 | if (blue.length() == 1) {
255 | blue = "0" + blue;
256 | }
257 |
258 | return "#" + red + green + blue;
259 | }
260 |
261 | /**
262 | * For custom purposes. Not used by ColorPickerPreferrence
263 | *
264 | * @param argb
265 | * @throws NumberFormatException
266 | * @author Unknown
267 | */
268 | public static int convertToColorInt(String argb) throws IllegalArgumentException {
269 |
270 | if (!argb.startsWith("#")) {
271 | argb = "#" + argb;
272 | }
273 |
274 | return Color.parseColor(argb);
275 | }
276 |
277 | @Override
278 | protected Parcelable onSaveInstanceState() {
279 | final Parcelable superState = super.onSaveInstanceState();
280 | if (mDialog == null || !mDialog.isShowing()) {
281 | return superState;
282 | }
283 |
284 | final SavedState myState = new SavedState(superState);
285 | myState.dialogBundle = mDialog.onSaveInstanceState();
286 | return myState;
287 | }
288 |
289 | @Override
290 | protected void onRestoreInstanceState(Parcelable state) {
291 | if (state == null || !(state instanceof SavedState)) {
292 | // Didn't save state for us in onSaveInstanceState
293 | super.onRestoreInstanceState(state);
294 | return;
295 | }
296 |
297 | SavedState myState = (SavedState) state;
298 | super.onRestoreInstanceState(myState.getSuperState());
299 | showDialog(myState.dialogBundle);
300 | }
301 |
302 | private static class SavedState extends BaseSavedState {
303 | Bundle dialogBundle;
304 |
305 | public SavedState(Parcel source) {
306 | super(source);
307 | dialogBundle = source.readBundle();
308 | }
309 |
310 | @Override
311 | public void writeToParcel(Parcel dest, int flags) {
312 | super.writeToParcel(dest, flags);
313 | dest.writeBundle(dialogBundle);
314 | }
315 |
316 | public SavedState(Parcelable superState) {
317 | super(superState);
318 | }
319 |
320 | @SuppressWarnings("unused")
321 | public static final Parcelable.Creator CREATOR =
322 | new Parcelable.Creator() {
323 | public SavedState createFromParcel(Parcel in) {
324 | return new SavedState(in);
325 | }
326 |
327 | public SavedState[] newArray(int size) {
328 | return new SavedState[size];
329 | }
330 | };
331 | }
332 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Color;
22 | import android.graphics.ComposeShader;
23 | import android.graphics.LinearGradient;
24 | import android.graphics.Paint;
25 | import android.graphics.Paint.Align;
26 | import android.graphics.Paint.Style;
27 | import android.graphics.Point;
28 | import android.graphics.PorterDuff;
29 | import android.graphics.RectF;
30 | import android.graphics.Shader;
31 | import android.graphics.Shader.TileMode;
32 | import android.util.AttributeSet;
33 | import android.view.MotionEvent;
34 | import android.view.View;
35 |
36 | /**
37 | * Displays a color picker to the user and allow them
38 | * to select a color. A slider for the alpha channel is
39 | * also available. Enable it by setting
40 | * setAlphaSliderVisible(boolean) to true.
41 | *
42 | * @author Daniel Nilsson
43 | */
44 | public class ColorPickerView extends View {
45 |
46 | private final static int PANEL_SAT_VAL = 0;
47 | private final static int PANEL_HUE = 1;
48 | private final static int PANEL_ALPHA = 2;
49 |
50 | /**
51 | * The width in pixels of the border
52 | * surrounding all color panels.
53 | */
54 | private final static float BORDER_WIDTH_PX = 1;
55 |
56 | /**
57 | * The width in dp of the hue panel.
58 | */
59 | private float HUE_PANEL_WIDTH = 30f;
60 | /**
61 | * The height in dp of the alpha panel
62 | */
63 | private float ALPHA_PANEL_HEIGHT = 20f;
64 | /**
65 | * The distance in dp between the different
66 | * color panels.
67 | */
68 | private float PANEL_SPACING = 10f;
69 | /**
70 | * The radius in dp of the color palette tracker circle.
71 | */
72 | private float PALETTE_CIRCLE_TRACKER_RADIUS = 5f;
73 | /**
74 | * The dp which the tracker of the hue or alpha panel
75 | * will extend outside of its bounds.
76 | */
77 | private float RECTANGLE_TRACKER_OFFSET = 2f;
78 |
79 |
80 | private float mDensity = 1f;
81 |
82 | private OnColorChangedListener mListener;
83 |
84 | private Paint mSatValPaint;
85 | private Paint mSatValTrackerPaint;
86 |
87 | private Paint mHuePaint;
88 | private Paint mHueTrackerPaint;
89 |
90 | private Paint mAlphaPaint;
91 | private Paint mAlphaTextPaint;
92 |
93 | private Paint mBorderPaint;
94 |
95 | private Shader mValShader;
96 | private Shader mSatShader;
97 | private Shader mHueShader;
98 | private Shader mAlphaShader;
99 |
100 | private int mAlpha = 0xff;
101 | private float mHue = 360f;
102 | private float mSat = 0f;
103 | private float mVal = 0f;
104 |
105 | private String mAlphaSliderText = "";
106 | private int mSliderTrackerColor = 0xff1c1c1c;
107 | private int mBorderColor = 0xff6E6E6E;
108 | private boolean mShowAlphaPanel = false;
109 |
110 | /*
111 | * To remember which panel that has the "focus" when
112 | * processing hardware button data.
113 | */
114 | private int mLastTouchedPanel = PANEL_SAT_VAL;
115 |
116 | /**
117 | * Offset from the edge we must have or else
118 | * the finger tracker will get clipped when
119 | * it is drawn outside of the view.
120 | */
121 | private float mDrawingOffset;
122 |
123 |
124 | /*
125 | * Distance form the edges of the view
126 | * of where we are allowed to draw.
127 | */
128 | private RectF mDrawingRect;
129 |
130 | private RectF mSatValRect;
131 | private RectF mHueRect;
132 | private RectF mAlphaRect;
133 |
134 | private AlphaPatternDrawable mAlphaPattern;
135 |
136 | private Point mStartTouchPoint = null;
137 |
138 | public interface OnColorChangedListener {
139 | public void onColorChanged(int color);
140 | }
141 |
142 | public ColorPickerView(Context context) {
143 | this(context, null);
144 | }
145 |
146 | public ColorPickerView(Context context, AttributeSet attrs) {
147 | this(context, attrs, 0);
148 | }
149 |
150 | public ColorPickerView(Context context, AttributeSet attrs, int defStyle) {
151 | super(context, attrs, defStyle);
152 | init();
153 | }
154 |
155 | private void init() {
156 | mDensity = getContext().getResources().getDisplayMetrics().density;
157 | PALETTE_CIRCLE_TRACKER_RADIUS *= mDensity;
158 | RECTANGLE_TRACKER_OFFSET *= mDensity;
159 | HUE_PANEL_WIDTH *= mDensity;
160 | ALPHA_PANEL_HEIGHT *= mDensity;
161 | PANEL_SPACING = PANEL_SPACING * mDensity;
162 |
163 | mDrawingOffset = calculateRequiredOffset();
164 |
165 | initPaintTools();
166 |
167 | //Needed for receiving trackball motion events.
168 | setFocusable(true);
169 | setFocusableInTouchMode(true);
170 | }
171 |
172 | private void initPaintTools() {
173 |
174 | mSatValPaint = new Paint();
175 | mSatValTrackerPaint = new Paint();
176 | mHuePaint = new Paint();
177 | mHueTrackerPaint = new Paint();
178 | mAlphaPaint = new Paint();
179 | mAlphaTextPaint = new Paint();
180 | mBorderPaint = new Paint();
181 |
182 |
183 | mSatValTrackerPaint.setStyle(Style.STROKE);
184 | mSatValTrackerPaint.setStrokeWidth(2f * mDensity);
185 | mSatValTrackerPaint.setAntiAlias(true);
186 |
187 | mHueTrackerPaint.setColor(mSliderTrackerColor);
188 | mHueTrackerPaint.setStyle(Style.STROKE);
189 | mHueTrackerPaint.setStrokeWidth(2f * mDensity);
190 | mHueTrackerPaint.setAntiAlias(true);
191 |
192 | mAlphaTextPaint.setColor(0xff1c1c1c);
193 | mAlphaTextPaint.setTextSize(14f * mDensity);
194 | mAlphaTextPaint.setAntiAlias(true);
195 | mAlphaTextPaint.setTextAlign(Align.CENTER);
196 | mAlphaTextPaint.setFakeBoldText(true);
197 |
198 |
199 | }
200 |
201 | private float calculateRequiredOffset() {
202 | float offset = Math.max(PALETTE_CIRCLE_TRACKER_RADIUS, RECTANGLE_TRACKER_OFFSET);
203 | offset = Math.max(offset, BORDER_WIDTH_PX * mDensity);
204 |
205 | return offset * 1.5f;
206 | }
207 |
208 | private int[] buildHueColorArray() {
209 |
210 | int[] hue = new int[361];
211 |
212 | int count = 0;
213 | for (int i = hue.length - 1; i >= 0; i--, count++) {
214 | hue[count] = Color.HSVToColor(new float[]{i, 1f, 1f});
215 | }
216 |
217 | return hue;
218 | }
219 |
220 |
221 | @Override
222 | protected void onDraw(Canvas canvas) {
223 |
224 | if (mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) return;
225 |
226 | drawSatValPanel(canvas);
227 | drawHuePanel(canvas);
228 | drawAlphaPanel(canvas);
229 |
230 | }
231 |
232 | private void drawSatValPanel(Canvas canvas) {
233 |
234 | final RectF rect = mSatValRect;
235 |
236 | if (BORDER_WIDTH_PX > 0) {
237 | mBorderPaint.setColor(mBorderColor);
238 | canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint);
239 | }
240 |
241 | if (mValShader == null) {
242 | mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom,
243 | 0xffffffff, 0xff000000, TileMode.CLAMP);
244 | }
245 |
246 | int rgb = Color.HSVToColor(new float[]{mHue, 1f, 1f});
247 |
248 | mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
249 | 0xffffffff, rgb, TileMode.CLAMP);
250 | ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY);
251 | mSatValPaint.setShader(mShader);
252 |
253 | canvas.drawRect(rect, mSatValPaint);
254 |
255 | Point p = satValToPoint(mSat, mVal);
256 |
257 | mSatValTrackerPaint.setColor(0xff000000);
258 | canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint);
259 |
260 | mSatValTrackerPaint.setColor(0xffdddddd);
261 | canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint);
262 |
263 | }
264 |
265 | private void drawHuePanel(Canvas canvas) {
266 |
267 | final RectF rect = mHueRect;
268 |
269 | if (BORDER_WIDTH_PX > 0) {
270 | mBorderPaint.setColor(mBorderColor);
271 | canvas.drawRect(rect.left - BORDER_WIDTH_PX,
272 | rect.top - BORDER_WIDTH_PX,
273 | rect.right + BORDER_WIDTH_PX,
274 | rect.bottom + BORDER_WIDTH_PX,
275 | mBorderPaint);
276 | }
277 |
278 | if (mHueShader == null) {
279 | mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, buildHueColorArray(), null, TileMode.CLAMP);
280 | mHuePaint.setShader(mHueShader);
281 | }
282 |
283 | canvas.drawRect(rect, mHuePaint);
284 |
285 | float rectHeight = 4 * mDensity / 2;
286 |
287 | Point p = hueToPoint(mHue);
288 |
289 | RectF r = new RectF();
290 | r.left = rect.left - RECTANGLE_TRACKER_OFFSET;
291 | r.right = rect.right + RECTANGLE_TRACKER_OFFSET;
292 | r.top = p.y - rectHeight;
293 | r.bottom = p.y + rectHeight;
294 |
295 |
296 | canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
297 |
298 | }
299 |
300 | private void drawAlphaPanel(Canvas canvas) {
301 |
302 | if (!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return;
303 |
304 | final RectF rect = mAlphaRect;
305 |
306 | if (BORDER_WIDTH_PX > 0) {
307 | mBorderPaint.setColor(mBorderColor);
308 | canvas.drawRect(rect.left - BORDER_WIDTH_PX,
309 | rect.top - BORDER_WIDTH_PX,
310 | rect.right + BORDER_WIDTH_PX,
311 | rect.bottom + BORDER_WIDTH_PX,
312 | mBorderPaint);
313 | }
314 |
315 |
316 | mAlphaPattern.draw(canvas);
317 |
318 | float[] hsv = new float[]{mHue, mSat, mVal};
319 | int color = Color.HSVToColor(hsv);
320 | int acolor = Color.HSVToColor(0, hsv);
321 |
322 | mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top,
323 | color, acolor, TileMode.CLAMP);
324 |
325 |
326 | mAlphaPaint.setShader(mAlphaShader);
327 |
328 | canvas.drawRect(rect, mAlphaPaint);
329 |
330 | if (mAlphaSliderText != null && mAlphaSliderText != "") {
331 | canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, mAlphaTextPaint);
332 | }
333 |
334 | float rectWidth = 4 * mDensity / 2;
335 |
336 | Point p = alphaToPoint(mAlpha);
337 |
338 | RectF r = new RectF();
339 | r.left = p.x - rectWidth;
340 | r.right = p.x + rectWidth;
341 | r.top = rect.top - RECTANGLE_TRACKER_OFFSET;
342 | r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET;
343 |
344 | canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint);
345 |
346 | }
347 |
348 |
349 | private Point hueToPoint(float hue) {
350 |
351 | final RectF rect = mHueRect;
352 | final float height = rect.height();
353 |
354 | Point p = new Point();
355 |
356 | p.y = (int) (height - (hue * height / 360f) + rect.top);
357 | p.x = (int) rect.left;
358 |
359 | return p;
360 | }
361 |
362 | private Point satValToPoint(float sat, float val) {
363 |
364 | final RectF rect = mSatValRect;
365 | final float height = rect.height();
366 | final float width = rect.width();
367 |
368 | Point p = new Point();
369 |
370 | p.x = (int) (sat * width + rect.left);
371 | p.y = (int) ((1f - val) * height + rect.top);
372 |
373 | return p;
374 | }
375 |
376 | private Point alphaToPoint(int alpha) {
377 |
378 | final RectF rect = mAlphaRect;
379 | final float width = rect.width();
380 |
381 | Point p = new Point();
382 |
383 | p.x = (int) (width - (alpha * width / 0xff) + rect.left);
384 | p.y = (int) rect.top;
385 |
386 | return p;
387 |
388 | }
389 |
390 | private float[] pointToSatVal(float x, float y) {
391 |
392 | final RectF rect = mSatValRect;
393 | float[] result = new float[2];
394 |
395 | float width = rect.width();
396 | float height = rect.height();
397 |
398 | if (x < rect.left) {
399 | x = 0f;
400 | } else if (x > rect.right) {
401 | x = width;
402 | } else {
403 | x = x - rect.left;
404 | }
405 |
406 | if (y < rect.top) {
407 | y = 0f;
408 | } else if (y > rect.bottom) {
409 | y = height;
410 | } else {
411 | y = y - rect.top;
412 | }
413 |
414 |
415 | result[0] = 1.f / width * x;
416 | result[1] = 1.f - (1.f / height * y);
417 |
418 | return result;
419 | }
420 |
421 | private float pointToHue(float y) {
422 |
423 | final RectF rect = mHueRect;
424 |
425 | float height = rect.height();
426 |
427 | if (y < rect.top) {
428 | y = 0f;
429 | } else if (y > rect.bottom) {
430 | y = height;
431 | } else {
432 | y = y - rect.top;
433 | }
434 |
435 | return 360f - (y * 360f / height);
436 | }
437 |
438 | private int pointToAlpha(int x) {
439 |
440 | final RectF rect = mAlphaRect;
441 | final int width = (int) rect.width();
442 |
443 | if (x < rect.left) {
444 | x = 0;
445 | } else if (x > rect.right) {
446 | x = width;
447 | } else {
448 | x = x - (int) rect.left;
449 | }
450 |
451 | return 0xff - (x * 0xff / width);
452 |
453 | }
454 |
455 |
456 | @Override
457 | public boolean onTrackballEvent(MotionEvent event) {
458 |
459 | float x = event.getX();
460 | float y = event.getY();
461 |
462 | boolean update = false;
463 |
464 |
465 | if (event.getAction() == MotionEvent.ACTION_MOVE) {
466 |
467 | switch (mLastTouchedPanel) {
468 |
469 | case PANEL_SAT_VAL:
470 |
471 | float sat, val;
472 |
473 | sat = mSat + x / 50f;
474 | val = mVal - y / 50f;
475 |
476 | if (sat < 0f) {
477 | sat = 0f;
478 | } else if (sat > 1f) {
479 | sat = 1f;
480 | }
481 |
482 | if (val < 0f) {
483 | val = 0f;
484 | } else if (val > 1f) {
485 | val = 1f;
486 | }
487 |
488 | mSat = sat;
489 | mVal = val;
490 |
491 | update = true;
492 |
493 | break;
494 |
495 | case PANEL_HUE:
496 |
497 | float hue = mHue - y * 10f;
498 |
499 | if (hue < 0f) {
500 | hue = 0f;
501 | } else if (hue > 360f) {
502 | hue = 360f;
503 | }
504 |
505 | mHue = hue;
506 |
507 | update = true;
508 |
509 | break;
510 |
511 | case PANEL_ALPHA:
512 |
513 | if (!mShowAlphaPanel || mAlphaRect == null) {
514 | update = false;
515 | } else {
516 |
517 | int alpha = (int) (mAlpha - x * 10);
518 |
519 | if (alpha < 0) {
520 | alpha = 0;
521 | } else if (alpha > 0xff) {
522 | alpha = 0xff;
523 | }
524 |
525 | mAlpha = alpha;
526 |
527 |
528 | update = true;
529 | }
530 |
531 | break;
532 | }
533 |
534 |
535 | }
536 |
537 |
538 | if (update) {
539 |
540 | if (mListener != null) {
541 | mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));
542 | }
543 |
544 | invalidate();
545 | return true;
546 | }
547 |
548 |
549 | return super.onTrackballEvent(event);
550 | }
551 |
552 | @Override
553 | public boolean onTouchEvent(MotionEvent event) {
554 |
555 | boolean update = false;
556 |
557 | switch (event.getAction()) {
558 |
559 | case MotionEvent.ACTION_DOWN:
560 |
561 | mStartTouchPoint = new Point((int) event.getX(), (int) event.getY());
562 |
563 | update = moveTrackersIfNeeded(event);
564 |
565 | break;
566 |
567 | case MotionEvent.ACTION_MOVE:
568 |
569 | update = moveTrackersIfNeeded(event);
570 |
571 | break;
572 |
573 | case MotionEvent.ACTION_UP:
574 |
575 | mStartTouchPoint = null;
576 |
577 | update = moveTrackersIfNeeded(event);
578 |
579 | break;
580 |
581 | }
582 |
583 | if (update) {
584 |
585 | if (mListener != null) {
586 | mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));
587 | }
588 |
589 | invalidate();
590 | return true;
591 | }
592 |
593 |
594 | return super.onTouchEvent(event);
595 | }
596 |
597 | private boolean moveTrackersIfNeeded(MotionEvent event) {
598 |
599 | if (mStartTouchPoint == null) return false;
600 |
601 | boolean update = false;
602 |
603 | int startX = mStartTouchPoint.x;
604 | int startY = mStartTouchPoint.y;
605 |
606 |
607 | if (mHueRect.contains(startX, startY)) {
608 | mLastTouchedPanel = PANEL_HUE;
609 |
610 | mHue = pointToHue(event.getY());
611 |
612 | update = true;
613 | } else if (mSatValRect.contains(startX, startY)) {
614 |
615 | mLastTouchedPanel = PANEL_SAT_VAL;
616 |
617 | float[] result = pointToSatVal(event.getX(), event.getY());
618 |
619 | mSat = result[0];
620 | mVal = result[1];
621 |
622 | update = true;
623 | } else if (mAlphaRect != null && mAlphaRect.contains(startX, startY)) {
624 |
625 | mLastTouchedPanel = PANEL_ALPHA;
626 |
627 | mAlpha = pointToAlpha((int) event.getX());
628 |
629 | update = true;
630 | }
631 |
632 |
633 | return update;
634 | }
635 |
636 | @Override
637 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
638 |
639 | int width = 0;
640 | int height = 0;
641 |
642 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
643 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
644 |
645 | int widthAllowed = MeasureSpec.getSize(widthMeasureSpec);
646 | int heightAllowed = MeasureSpec.getSize(heightMeasureSpec);
647 |
648 | widthAllowed = chooseWidth(widthMode, widthAllowed);
649 | heightAllowed = chooseHeight(heightMode, heightAllowed);
650 |
651 | if (!mShowAlphaPanel) {
652 |
653 | height = (int) (widthAllowed - PANEL_SPACING - HUE_PANEL_WIDTH);
654 |
655 | //If calculated height (based on the width) is more than the allowed height.
656 | if (height > heightAllowed || getTag().equals("landscape")) {
657 | height = heightAllowed;
658 | width = (int) (height + PANEL_SPACING + HUE_PANEL_WIDTH);
659 | } else {
660 | width = widthAllowed;
661 | }
662 | } else {
663 |
664 | width = (int) (heightAllowed - ALPHA_PANEL_HEIGHT + HUE_PANEL_WIDTH);
665 |
666 | if (width > widthAllowed) {
667 | width = widthAllowed;
668 | height = (int) (widthAllowed - HUE_PANEL_WIDTH + ALPHA_PANEL_HEIGHT);
669 | } else {
670 | height = heightAllowed;
671 | }
672 |
673 | }
674 |
675 | setMeasuredDimension(width, height);
676 | }
677 |
678 | private int chooseWidth(int mode, int size) {
679 | if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
680 | return size;
681 | } else { // (mode == MeasureSpec.UNSPECIFIED)
682 | return getPrefferedWidth();
683 | }
684 | }
685 |
686 | private int chooseHeight(int mode, int size) {
687 | if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) {
688 | return size;
689 | } else { // (mode == MeasureSpec.UNSPECIFIED)
690 | return getPrefferedHeight();
691 | }
692 | }
693 |
694 | private int getPrefferedWidth() {
695 |
696 | int width = getPrefferedHeight();
697 |
698 | if (mShowAlphaPanel) {
699 | width -= (PANEL_SPACING + ALPHA_PANEL_HEIGHT);
700 | }
701 |
702 |
703 | return (int) (width + HUE_PANEL_WIDTH + PANEL_SPACING);
704 |
705 | }
706 |
707 | private int getPrefferedHeight() {
708 |
709 | int height = (int) (200 * mDensity);
710 |
711 | if (mShowAlphaPanel) {
712 | height += PANEL_SPACING + ALPHA_PANEL_HEIGHT;
713 | }
714 |
715 | return height;
716 | }
717 |
718 |
719 | @Override
720 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
721 | super.onSizeChanged(w, h, oldw, oldh);
722 |
723 | mDrawingRect = new RectF();
724 | mDrawingRect.left = mDrawingOffset + getPaddingLeft();
725 | mDrawingRect.right = w - mDrawingOffset - getPaddingRight();
726 | mDrawingRect.top = mDrawingOffset + getPaddingTop();
727 | mDrawingRect.bottom = h - mDrawingOffset - getPaddingBottom();
728 |
729 | setUpSatValRect();
730 | setUpHueRect();
731 | setUpAlphaRect();
732 | }
733 |
734 | private void setUpSatValRect() {
735 |
736 | final RectF dRect = mDrawingRect;
737 | float panelSide = dRect.height() - BORDER_WIDTH_PX * 2;
738 |
739 | if (mShowAlphaPanel) {
740 | panelSide -= PANEL_SPACING + ALPHA_PANEL_HEIGHT;
741 | }
742 |
743 | float left = dRect.left + BORDER_WIDTH_PX;
744 | float top = dRect.top + BORDER_WIDTH_PX;
745 | float bottom = top + panelSide;
746 | float right = left + panelSide;
747 |
748 | mSatValRect = new RectF(left, top, right, bottom);
749 | }
750 |
751 | private void setUpHueRect() {
752 | final RectF dRect = mDrawingRect;
753 |
754 | float left = dRect.right - HUE_PANEL_WIDTH + BORDER_WIDTH_PX;
755 | float top = dRect.top + BORDER_WIDTH_PX;
756 | float bottom = dRect.bottom - BORDER_WIDTH_PX - (mShowAlphaPanel ? (PANEL_SPACING + ALPHA_PANEL_HEIGHT) : 0);
757 | float right = dRect.right - BORDER_WIDTH_PX;
758 |
759 | mHueRect = new RectF(left, top, right, bottom);
760 | }
761 |
762 | private void setUpAlphaRect() {
763 |
764 | if (!mShowAlphaPanel) return;
765 |
766 | final RectF dRect = mDrawingRect;
767 |
768 | float left = dRect.left + BORDER_WIDTH_PX;
769 | float top = dRect.bottom - ALPHA_PANEL_HEIGHT + BORDER_WIDTH_PX;
770 | float bottom = dRect.bottom - BORDER_WIDTH_PX;
771 | float right = dRect.right - BORDER_WIDTH_PX;
772 |
773 | mAlphaRect = new RectF(left, top, right, bottom);
774 |
775 | mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity));
776 | mAlphaPattern.setBounds(
777 | Math.round(mAlphaRect.left),
778 | Math.round(mAlphaRect.top),
779 | Math.round(mAlphaRect.right),
780 | Math.round(mAlphaRect.bottom)
781 | );
782 |
783 | }
784 |
785 |
786 | /**
787 | * Set a OnColorChangedListener to get notified when the color
788 | * selected by the user has changed.
789 | *
790 | * @param listener
791 | */
792 | public void setOnColorChangedListener(OnColorChangedListener listener) {
793 | mListener = listener;
794 | }
795 |
796 | /**
797 | * Set the color of the border surrounding all panels.
798 | *
799 | * @param color
800 | */
801 | public void setBorderColor(int color) {
802 | mBorderColor = color;
803 | invalidate();
804 | }
805 |
806 | /**
807 | * Get the color of the border surrounding all panels.
808 | */
809 | public int getBorderColor() {
810 | return mBorderColor;
811 | }
812 |
813 | /**
814 | * Get the current color this view is showing.
815 | *
816 | * @return the current color.
817 | */
818 | public int getColor() {
819 | return Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal});
820 | }
821 |
822 | /**
823 | * Set the color the view should show.
824 | *
825 | * @param color The color that should be selected.
826 | */
827 | public void setColor(int color) {
828 | setColor(color, false);
829 | }
830 |
831 | /**
832 | * Set the color this view should show.
833 | *
834 | * @param color The color that should be selected.
835 | * @param callback If you want to get a callback to
836 | * your OnColorChangedListener.
837 | */
838 | public void setColor(int color, boolean callback) {
839 |
840 | int alpha = Color.alpha(color);
841 |
842 | float[] hsv = new float[3];
843 |
844 | Color.colorToHSV(color, hsv);
845 |
846 | mAlpha = alpha;
847 | mHue = hsv[0];
848 | mSat = hsv[1];
849 | mVal = hsv[2];
850 |
851 | if (callback && mListener != null) {
852 | mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal}));
853 | }
854 |
855 | invalidate();
856 | }
857 |
858 | /**
859 | * Get the drawing offset of the color picker view.
860 | * The drawing offset is the distance from the side of
861 | * a panel to the side of the view minus the padding.
862 | * Useful if you want to have your own panel below showing
863 | * the currently selected color and want to align it perfectly.
864 | *
865 | * @return The offset in pixels.
866 | */
867 | public float getDrawingOffset() {
868 | return mDrawingOffset;
869 | }
870 |
871 | /**
872 | * Set if the user is allowed to adjust the alpha panel. Default is false.
873 | * If it is set to false no alpha will be set.
874 | *
875 | * @param visible
876 | */
877 | public void setAlphaSliderVisible(boolean visible) {
878 |
879 | if (mShowAlphaPanel != visible) {
880 | mShowAlphaPanel = visible;
881 |
882 | /*
883 | * Reset all shader to force a recreation.
884 | * Otherwise they will not look right after
885 | * the size of the view has changed.
886 | */
887 | mValShader = null;
888 | mSatShader = null;
889 | mHueShader = null;
890 | mAlphaShader = null;
891 |
892 | requestLayout();
893 | }
894 |
895 | }
896 |
897 | public boolean getAlphaSliderVisible() {
898 | return mShowAlphaPanel;
899 | }
900 |
901 | public void setSliderTrackerColor(int color) {
902 | mSliderTrackerColor = color;
903 |
904 | mHueTrackerPaint.setColor(mSliderTrackerColor);
905 |
906 | invalidate();
907 | }
908 |
909 | public int getSliderTrackerColor() {
910 | return mSliderTrackerColor;
911 | }
912 |
913 | /**
914 | * Set the text that should be shown in the
915 | * alpha slider. Set to null to disable text.
916 | *
917 | * @param res string resource id.
918 | */
919 | public void setAlphaSliderText(int res) {
920 | String text = getContext().getString(res);
921 | setAlphaSliderText(text);
922 | }
923 |
924 | /**
925 | * Set the text that should be shown in the
926 | * alpha slider. Set to null to disable text.
927 | *
928 | * @param text Text that should be shown.
929 | */
930 | public void setAlphaSliderText(String text) {
931 | mAlphaSliderText = text;
932 | invalidate();
933 | }
934 |
935 | /**
936 | * Get the current value of the text
937 | * that will be shown in the alpha
938 | * slider.
939 | *
940 | * @return
941 | */
942 | public String getAlphaSliderText() {
943 | return mAlphaSliderText;
944 | }
945 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/layout-land/dialog_color_picker.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
25 |
31 |
32 |
37 |
38 |
48 |
49 |
59 |
60 |
65 |
66 |
74 |
75 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/layout/dialog_color_picker.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
25 |
31 |
32 |
39 |
40 |
46 |
47 |
58 |
59 |
60 |
65 |
66 |
71 |
72 |
80 |
81 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Color Picker
5 | Press on Color to apply
6 |
7 |
--------------------------------------------------------------------------------
/app/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 |
--------------------------------------------------------------------------------
/app/release/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/release/app-release.apk
--------------------------------------------------------------------------------
/app/release/output.json:
--------------------------------------------------------------------------------
1 | [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":20,"versionName":"2.9","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/BackgroundInstallActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.widget.Toast;
7 |
8 | import cn.bavelee.pokeinstaller.apk.APKCommander;
9 | import cn.bavelee.pokeinstaller.apk.ApkInfo;
10 | import cn.bavelee.pokeinstaller.apk.ICommanderCallback;
11 |
12 | public class BackgroundInstallActivity extends Activity implements ICommanderCallback {
13 |
14 | private APKCommander apkCommander;
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | if (getIntent().getData() != null) {
20 | apkCommander = new APKCommander(this, getIntent().getData(), this);
21 | } else {
22 | showToast(getString(R.string.unable_to_install_apk));
23 | }
24 | }
25 |
26 | @Override
27 | protected void onResume() {
28 | super.onResume();
29 | finish();
30 | }
31 |
32 | private void showToast(String text) {
33 | Toast.makeText(BackgroundInstallActivity.this, text, Toast.LENGTH_SHORT).show();
34 | }
35 |
36 | @Override
37 | public void onStartParseApk(Uri uri) {
38 | showToast(getString(R.string.parsing));
39 | }
40 |
41 | @Override
42 | public void onApkParsed(ApkInfo apkInfo) {
43 | apkCommander.startInstall();
44 | }
45 |
46 | @Override
47 | public void onApkPreInstall(ApkInfo apkInfo) {
48 | showToast(getString(R.string.start_install, apkInfo.getApkFile().getPath()));
49 | }
50 |
51 | @Override
52 | public void onApkInstalled(ApkInfo apkInfo, int resultCode) {
53 | if (resultCode == 0) {
54 | showToast(getString(R.string.apk_installed, apkInfo.getAppName()));
55 | if (!apkInfo.isFakePath() && Prefs.getPreference(this).getBoolean("auto_delete", false)) {
56 | Toast.makeText(this, getString(R.string.apk_deleteed, apkInfo.getApkFile().getName()), Toast.LENGTH_SHORT).show();
57 | }
58 | } else {
59 | showToast(getString(R.string.install_failed, apkInfo.getAppName()));
60 | }
61 | finish();
62 | }
63 |
64 | @Override
65 | public void onInstallLog(ApkInfo apkInfo, String logText) {
66 |
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/PokeInstallerActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.graphics.Typeface;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.support.annotation.Nullable;
10 | import android.support.v4.app.FragmentActivity;
11 | import android.text.TextUtils;
12 | import android.view.Gravity;
13 | import android.view.View;
14 | import android.view.Window;
15 | import android.view.WindowManager;
16 | import android.widget.ImageView;
17 | import android.widget.LinearLayout;
18 | import android.widget.ProgressBar;
19 | import android.widget.TextView;
20 | import android.widget.Toast;
21 |
22 | import com.github.florent37.runtimepermission.RuntimePermission;
23 | import com.github.florent37.runtimepermission.callbacks.PermissionListener;
24 |
25 | import java.util.List;
26 |
27 | import cn.bavelee.pokeinstaller.apk.APKCommander;
28 | import cn.bavelee.pokeinstaller.apk.ApkInfo;
29 | import cn.bavelee.pokeinstaller.apk.ICommanderCallback;
30 |
31 | public class PokeInstallerActivity extends FragmentActivity implements ICommanderCallback, View.OnClickListener {
32 |
33 | private TextView tvAppName;
34 | private LinearLayout layoutAppDetails;
35 | private ImageView imgAppIcon;
36 |
37 | private ProgressBar progressBar;
38 | private LinearLayout layoutTitleContainer;
39 | private LinearLayout layoutPermissionList;
40 | private LinearLayout layoutButtons;
41 |
42 | private TextView btnInstall;
43 | private TextView btnSilently;
44 | private TextView btnCancel;
45 |
46 |
47 | private APKCommander apkCommander;
48 |
49 | private int[] settingsColors = new int[4];
50 |
51 |
52 | @Override
53 | protected void onCreate(Bundle savedInstanceState) {
54 | super.onCreate(savedInstanceState);
55 | setContentView(R.layout.act_poke_installer);
56 | layoutAppDetails = findViewById(R.id.layout_app_details);
57 | tvAppName = findViewById(R.id.tv_app_name);
58 | layoutTitleContainer = findViewById(R.id.titleBar);
59 | imgAppIcon = findViewById(R.id.img_app_icon);
60 | progressBar = findViewById(R.id.progressBar);
61 | progressBar.setVisibility(View.INVISIBLE);
62 |
63 | btnInstall = findViewById(R.id.btn_install);
64 | btnSilently = findViewById(R.id.btn_silently);
65 | btnCancel = findViewById(R.id.btn_cancel);
66 | layoutButtons = (LinearLayout) btnInstall.getParent();
67 | btnInstall.setEnabled(true);
68 | btnInstall.setOnClickListener(this);
69 | btnSilently.setOnClickListener(this);
70 | btnCancel.setOnClickListener(this);
71 |
72 | loadSettings();
73 | if (getIntent().getData() == null) {
74 | finish();
75 | } else
76 | checkPermission();
77 | }
78 |
79 | private void loadSettings() {
80 | findViewById(R.id.ic_settings).setAlpha(Prefs.getPreference(this).getBoolean("show_settings", true) ? 1 : 0);
81 | findViewById(R.id.ic_settings).setOnClickListener(new View.OnClickListener() {
82 | @Override
83 | public void onClick(View v) {
84 | Intent intent = new Intent(PokeInstallerActivity.this, SettingsActivity.class);
85 | startActivityForResult(intent, 100);
86 | }
87 | });
88 |
89 | settingsColors[0] = getColor("progress_normal_color");
90 | settingsColors[1] = getColor("progress_installing_color");
91 | settingsColors[2] = getColor("progress_success_color");
92 | settingsColors[3] = getColor("progress_failure_color");
93 | LinearLayout.LayoutParams marginParams = (LinearLayout.LayoutParams) btnInstall.getLayoutParams();
94 | marginParams.setMargins(Integer.parseInt(Prefs.getPreference(this).getString("btn_margins", "0")), 0, 0, 0);
95 | btnInstall.setLayoutParams(marginParams);
96 | btnSilently.setLayoutParams(marginParams);
97 | Window window = getWindow();
98 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
99 | window.setStatusBarColor(getColor("status_bar_color"));
100 | layoutTitleContainer.setBackgroundColor(settingsColors[0]);
101 | if (apkCommander != null && apkCommander.getApkInfo() != null && apkCommander.getApkInfo().getApkFile() != null) {
102 | initDetails(apkCommander.getApkInfo());
103 | }
104 | }
105 |
106 | @Override
107 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
108 | super.onActivityResult(requestCode, resultCode, data);
109 | loadSettings();
110 | }
111 |
112 | private void checkPermission() {
113 | RuntimePermission.askPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
114 | .ask(new PermissionListener() {
115 | @Override
116 | public void onAccepted(RuntimePermission runtimePermission, List accepted) {
117 | apkCommander = new APKCommander(PokeInstallerActivity.this, getIntent().getData(), PokeInstallerActivity.this);
118 | }
119 |
120 | @Override
121 | public void onDenied(RuntimePermission runtimePermission, List denied, List foreverDenied) {
122 | Toast.makeText(PokeInstallerActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT).show();
123 | finish();
124 | }
125 | });
126 | }
127 |
128 | private int getColor(String key) {
129 | return Prefs.getPreference(this).getInt(key, getResources().getColor(R.color.colorPrimary));
130 | }
131 |
132 | private void initDetails(ApkInfo apkInfo) {
133 | layoutAppDetails.removeAllViews();
134 | tvAppName.setText(apkInfo.getAppName());
135 | imgAppIcon.setImageDrawable(apkInfo.getIcon());
136 | layoutAppDetails.addView(createAppInfoView(getString(R.string.info_pkg_name), apkInfo.getPackageName()));
137 | layoutAppDetails.addView(createAppInfoView(getString(R.string.info_apk_path), apkInfo.getApkFile().getPath()));
138 | layoutAppDetails.addView(createAppInfoView(getString(R.string.info_version), apkInfo.getVersion()));
139 | if (apkInfo.hasInstalledApp())
140 | layoutAppDetails.addView(createAppInfoView(getString(R.string.info_installed_version), apkInfo.getInstalledVersion()));
141 | if (Prefs.getPreference(this).getBoolean("show_perm", true)) {
142 | if (apkInfo.getPermissions() != null && apkInfo.getPermissions().length > 0) {
143 | layoutPermissionList = new LinearLayout(this);
144 | layoutPermissionList.setOrientation(LinearLayout.VERTICAL);
145 | layoutPermissionList.addView(createAppInfoView(null, getString(R.string.app_permissions)));
146 | for (String perm : apkInfo.getPermissions()) {
147 | layoutPermissionList.addView(createAppPermissionView(perm));
148 | }
149 | layoutAppDetails.addView(layoutPermissionList);
150 | }
151 | }
152 | }
153 |
154 | private LinearLayout createAppPermissionView(String perm) {
155 | LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.info_item_permission, null, false);
156 | TextView tv1 = (TextView) layout.getChildAt(0);
157 | tv1.setText(perm);
158 | tv1.setTextColor(getColor("perm_color"));
159 | return layout;
160 | }
161 |
162 |
163 | private LinearLayout createAppInfoView(String key, String value) {
164 | LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.info_item, null, false);
165 | TextView tv1 = (TextView) layout.getChildAt(0);
166 | TextView tv2 = (TextView) layout.getChildAt(1);
167 | tv1.setText(key);
168 | tv2.setText(value);
169 | if (TextUtils.isEmpty(value)) {
170 | layout.removeView(tv2);
171 | tv1.setTypeface(Typeface.MONOSPACE);
172 | tv1.setGravity(Gravity.START);
173 | }
174 | if (TextUtils.isEmpty(key)) {
175 | layout.removeView(tv2);
176 | tv1.setText(value);
177 | }
178 | return layout;
179 | }
180 |
181 | @Override
182 | protected void onDestroy() {
183 | super.onDestroy();
184 | if (apkCommander.getApkInfo() != null && apkCommander.getApkInfo().isFakePath())
185 | apkCommander.getApkInfo().getApkFile().delete();
186 | }
187 |
188 |
189 | @Override
190 | public void onStartParseApk(Uri uri) {
191 | TextView textView = new TextView(this);
192 | textView.setTextColor(Color.RED);
193 | textView.setText(getString(R.string.parsing) + " : " + uri.toString());
194 | layoutAppDetails.addView(textView);
195 | btnInstall.setVisibility(View.GONE);
196 | }
197 |
198 | @Override
199 | public void onApkParsed(ApkInfo apkInfo) {
200 | if (apkInfo != null && !TextUtils.isEmpty(apkInfo.getPackageName())) {
201 | initDetails(apkInfo);
202 | btnInstall.setVisibility(View.VISIBLE);
203 | } else {
204 | Uri uri = getIntent().getData();
205 | String s = null;
206 | if (uri != null)
207 | s = uri.toString();
208 | TextView textView = new TextView(this);
209 | textView.setTextColor(Color.RED);
210 | textView.setText(getString(R.string.parse_apk_failed, s));
211 | layoutAppDetails.addView(textView);
212 | }
213 | }
214 |
215 | @Override
216 | public void onApkPreInstall(ApkInfo apkInfo) {
217 | if (layoutPermissionList != null)
218 | layoutAppDetails.removeView(layoutPermissionList);
219 | tvAppName.setText(R.string.installing);
220 | btnInstall.setEnabled(false);
221 | btnSilently.setEnabled(false);
222 | progressBar.setVisibility(
223 | Prefs.getPreference(this).getBoolean("show_progress_bar", true) ?
224 | View.VISIBLE : View.INVISIBLE);
225 | layoutTitleContainer.setBackgroundColor(settingsColors[1]);
226 | layoutButtons.setVisibility(View.INVISIBLE);
227 | }
228 |
229 | @Override
230 | public void onApkInstalled(ApkInfo apkInfo, int resultCode) {
231 | getString(R.string.install_finished_with_result_code, resultCode);
232 | btnInstall.setEnabled(false);
233 | btnSilently.setEnabled(false);
234 | layoutTitleContainer.setBackgroundColor(settingsColors[0]);
235 | if (resultCode == 0) {
236 | Toast.makeText(getApplicationContext(), getString(R.string.apk_installed, apkInfo.getAppName()), Toast.LENGTH_SHORT).show();
237 | tvAppName.setText(R.string.successful);
238 | btnInstall.setEnabled(true);
239 | btnInstall.setText(R.string.open_app);
240 | layoutTitleContainer.setBackgroundColor(settingsColors[2]);
241 | if (!apkInfo.isFakePath() && Prefs.getPreference(this).getBoolean("auto_delete", false)) {
242 | Toast.makeText(this, getString(R.string.apk_deleteed, apkInfo.getApkFile().getName()), Toast.LENGTH_SHORT).show();
243 | }
244 | } else {
245 | tvAppName.setText(R.string.failed);
246 | layoutTitleContainer.setBackgroundColor(settingsColors[3]);
247 | }
248 | progressBar.setVisibility(View.INVISIBLE);
249 | layoutButtons.setVisibility(View.VISIBLE);
250 | }
251 |
252 | @Override
253 | public void onInstallLog(ApkInfo apkInfo, String logText) {
254 | layoutAppDetails.addView(createAppInfoView(logText, null));
255 | }
256 |
257 | @Override
258 | public void onClick(View v) {
259 | switch (v.getId()) {
260 | case R.id.btn_install:
261 | if (btnInstall.getText().toString().equalsIgnoreCase(getString(R.string.open_app))) {
262 | Intent intent = getPackageManager().getLaunchIntentForPackage(apkCommander.getApkInfo().getPackageName());
263 | startActivity(intent);
264 | finish();
265 | } else {
266 | apkCommander.startInstall();
267 | }
268 | break;
269 | case R.id.btn_silently:
270 | Intent intent = new Intent(this, BackgroundInstallActivity.class);
271 | intent.setData(getIntent().getData());
272 | startActivity(intent);
273 | finish();
274 | break;
275 | case R.id.btn_cancel:
276 | finish();
277 | break;
278 | }
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/Prefs.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 |
7 | public class Prefs {
8 | public static SharedPreferences getPreference(Context context) {
9 | return PreferenceManager.getDefaultSharedPreferences(context);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller;
2 |
3 | import android.os.Bundle;
4 | import android.preference.Preference;
5 | import android.preference.PreferenceActivity;
6 |
7 | import cn.bavelee.donatedialog.DonateToMe;
8 |
9 | public class SettingsActivity extends PreferenceActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | addPreferencesFromResource(R.xml.prefs);
15 | findPreference("donate").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
16 | @Override
17 | public boolean onPreferenceClick(Preference preference) {
18 | DonateToMe.show(SettingsActivity.this);
19 | return false;
20 | }
21 | });
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/ShellUtils.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller;
2 | // Copyright (C) 2018 Bave Lee
3 | // This file is part of Quick-Android.
4 | // https://github.com/Crixec/Quick-Android
5 | //
6 | // Quick-Android is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // Quick-Android is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 |
18 | import java.io.BufferedReader;
19 | import java.io.Closeable;
20 | import java.io.DataOutputStream;
21 | import java.io.IOException;
22 | import java.io.InputStreamReader;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | public class ShellUtils {
27 |
28 | private static int exec(final String sh, final List cmds, final Result result) {
29 | Process process;
30 | DataOutputStream stdin = null;
31 | OutputReader stdout = null;
32 | OutputReader stderr = null;
33 | int resultCode = -1;
34 | try {
35 | process = Runtime.getRuntime().exec(sh);
36 | stdin = new DataOutputStream(process.getOutputStream());
37 | if (result != null) {
38 | stdout = new OutputReader(new BufferedReader(new InputStreamReader(process.getInputStream())),
39 | new Output() {
40 | @Override
41 | public void output(String text) {
42 | result.onStdout(text);
43 | }
44 | });
45 | stderr = new OutputReader(new BufferedReader(new InputStreamReader(process.getErrorStream())),
46 | new Output() {
47 | @Override
48 | public void output(String text) {
49 | result.onStderr(text);
50 | }
51 | });
52 | stdout.start();
53 | stderr.start();
54 | }
55 | for (String cmd : cmds) {
56 | if (result != null) {
57 | result.onCommand(cmd);
58 | }
59 | stdin.write(cmd.getBytes());
60 | stdin.writeBytes("\n");
61 | stdin.flush();
62 | }
63 | stdin.writeBytes("exit $?\n");
64 | stdin.flush();
65 | resultCode = process.waitFor();
66 | if (result != null) {
67 | result.onFinish(resultCode);
68 | }
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | } finally {
72 | safeCancel(stderr);
73 | safeCancel(stdout);
74 | safeClose(stdout);
75 | safeClose(stderr);
76 | safeClose(stdin);
77 | }
78 | return resultCode;
79 | }
80 |
81 | private static void safeCancel(OutputReader reader) {
82 | try {
83 | if (reader != null) reader.cancel();
84 | } catch (Exception ignored) {
85 |
86 | }
87 | }
88 |
89 | private static void safeClose(Closeable closeable) {
90 | try {
91 | if (closeable != null) closeable.close();
92 | } catch (Exception ignored) {
93 |
94 | }
95 | }
96 |
97 | public static int exec(final List cmds, final Result result, final boolean isRoot) {
98 | String sh = isRoot ? "su" : "sh";
99 | return exec(sh, cmds, result);
100 | }
101 |
102 | public static int exec(final List cmds, final boolean isRoot) {
103 | return exec(cmds, null, isRoot);
104 | }
105 |
106 | public static int exec(final String cmd, boolean isRoot) {
107 | return exec(cmd, null, isRoot);
108 | }
109 |
110 | public static int exec(final String cmd, final Result result, boolean isRoot) {
111 | List cmds = new ArrayList();
112 | cmds.add(cmd);
113 | return exec(cmds, result, isRoot);
114 | }
115 |
116 | public static int exec(final String cmd) {
117 | return exec(cmd, null, false);
118 | }
119 |
120 | public static int execWithRoot(final String cmd) {
121 | return exec(cmd, null, true);
122 | }
123 |
124 | public static int execWithRoot(final String cmd, final Result result) {
125 | return exec(cmd, result, true);
126 | }
127 |
128 | public interface Result {
129 | void onStdout(String text);
130 |
131 | void onStderr(String text);
132 |
133 | void onCommand(String command);
134 |
135 | void onFinish(int resultCode);
136 | }
137 |
138 | private interface Output {
139 | void output(String text);
140 | }
141 |
142 | public static class OutputReader extends Thread implements Closeable {
143 | private Output output = null;
144 | private BufferedReader reader = null;
145 | private boolean isRunning = false;
146 |
147 | private OutputReader(BufferedReader reader, Output output) {
148 | this.output = output;
149 | this.reader = reader;
150 | this.isRunning = true;
151 | }
152 |
153 | @Override
154 | public void close() {
155 | try {
156 | reader.close();
157 | } catch (IOException ignored) {
158 | }
159 | }
160 |
161 | @Override
162 | public void run() {
163 | super.run();
164 | String line;
165 | while (isRunning) {
166 | try {
167 | line = reader.readLine();
168 | if (line != null)
169 | output.output(line);
170 | } catch (IOException ignored) {
171 | }
172 | }
173 | }
174 |
175 | private void cancel() {
176 | synchronized (this) {
177 | isRunning = false;
178 | this.notifyAll();
179 | }
180 | }
181 | }
182 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/apk/APKCommander.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller.apk;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.net.Uri;
7 | import android.os.Handler;
8 | import android.os.Looper;
9 | import android.util.AndroidRuntimeException;
10 |
11 | import java.io.File;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.io.OutputStream;
16 |
17 | import cn.bavelee.pokeinstaller.ShellUtils;
18 |
19 | public class APKCommander {
20 |
21 | private Context context;
22 | private Uri uri;
23 | private ApkInfo mApkInfo;
24 | private ICommanderCallback callback;
25 | private Handler handler;
26 |
27 | public APKCommander(Context context, Uri uri, ICommanderCallback commanderCallback) {
28 | this.context = context;
29 | this.uri = uri;
30 | this.callback = commanderCallback;
31 | handler = new Handler(Looper.getMainLooper());
32 | new ParseApkTask().start();
33 | }
34 |
35 | public void startInstall() {
36 | new InstallApkTask().start();
37 | }
38 |
39 | public ApkInfo getApkInfo() {
40 | return mApkInfo;
41 | }
42 |
43 | private class InstallApkTask extends Thread {
44 | @Override
45 | public void run() {
46 | super.run();
47 | handler.post(new Runnable() {
48 | @Override
49 | public void run() {
50 | callback.onApkPreInstall(mApkInfo);
51 | }
52 | });
53 | final int retCode = ShellUtils.execWithRoot("setenforce 0 && pm install -r --user 0 \"" + mApkInfo.getApkFile().getPath() + "\"" + "\n", new ShellUtils.Result() {
54 | @Override
55 | public void onStdout(final String text) {
56 | handler.post(new Runnable() {
57 | @Override
58 | public void run() {
59 | callback.onInstallLog(mApkInfo, text);
60 | }
61 | });
62 | }
63 |
64 | @Override
65 | public void onStderr(final String text) {
66 | handler.post(new Runnable() {
67 | @Override
68 | public void run() {
69 | callback.onInstallLog(mApkInfo, text);
70 | }
71 | });
72 | }
73 |
74 | @Override
75 | public void onCommand(String command) {
76 |
77 | }
78 |
79 | @Override
80 | public void onFinish(int resultCode) {
81 |
82 | }
83 | });
84 | if (retCode == 0 && mApkInfo.isFakePath())
85 | mApkInfo.getApkFile().delete();
86 | handler.post(new Runnable() {
87 | @Override
88 | public void run() {
89 | callback.onApkInstalled(mApkInfo, retCode);
90 | }
91 | });
92 | }
93 | }
94 |
95 | private class ParseApkTask extends Thread {
96 | @Override
97 | public void run() {
98 | super.run();
99 | try {
100 | handler.post(new Runnable() {
101 | @Override
102 | public void run() {
103 | callback.onStartParseApk(uri);
104 | }
105 | });
106 | mApkInfo = new ApkInfo();
107 | String apkSourcePath = ContentUriUtils.getPath(context, uri);
108 | if (apkSourcePath == null) {
109 | mApkInfo.setFakePath(true);
110 | File tempFile = new File(context.getExternalCacheDir(), System.currentTimeMillis() + ".apk");
111 | try {
112 | InputStream is = context.getContentResolver().openInputStream(uri);
113 | if (is != null) {
114 | OutputStream fos = new FileOutputStream(tempFile);
115 | byte[] buf = new byte[4096 * 1024];
116 | int ret;
117 | while ((ret = is.read(buf)) != -1) {
118 | fos.write(buf, 0, ret);
119 | fos.flush();
120 | }
121 | fos.close();
122 | is.close();
123 | }
124 | } catch (IOException e) {
125 | e.printStackTrace();
126 | }
127 | mApkInfo.setApkFile(tempFile);
128 | } else {
129 | mApkInfo.setApkFile(new File(apkSourcePath));
130 | }
131 | //读取apk的信息
132 | PackageManager pm = context.getPackageManager();
133 | PackageInfo pkgInfo = pm.getPackageArchiveInfo(mApkInfo.getApkFile().getPath(), PackageManager.GET_PERMISSIONS);
134 | if (pkgInfo != null) {
135 | pkgInfo.applicationInfo.sourceDir = mApkInfo.getApkFile().getPath();
136 | pkgInfo.applicationInfo.publicSourceDir = mApkInfo.getApkFile().getPath();
137 | mApkInfo.setAppName(pm.getApplicationLabel(pkgInfo.applicationInfo).toString());
138 | mApkInfo.setPackageName(pkgInfo.applicationInfo.packageName);
139 | mApkInfo.setVersionName(pkgInfo.versionName);
140 | mApkInfo.setVersionCode(pkgInfo.versionCode);
141 | mApkInfo.setIcon(pkgInfo.applicationInfo.loadIcon(pm));
142 | try {
143 | PackageInfo installedPkgInfo = pm.getPackageInfo(mApkInfo.getPackageName(), 0);
144 | mApkInfo.setInstalledVersionName(installedPkgInfo.versionName);
145 | mApkInfo.setInstalledVersionCode(installedPkgInfo.versionCode);
146 | mApkInfo.setHasInstalledApp(true);
147 | } catch (PackageManager.NameNotFoundException e) {
148 | e.printStackTrace();
149 | mApkInfo.setHasInstalledApp(false);
150 | }
151 | mApkInfo.setPermissions(pkgInfo.requestedPermissions);
152 | }
153 | handler.post(new Runnable() {
154 | @Override
155 | public void run() {
156 | callback.onApkParsed(mApkInfo);
157 | }
158 | });
159 | } catch (Exception e) {
160 | handler.post(new Runnable() {
161 | @Override
162 | public void run() {
163 | callback.onApkParsed(null);
164 | }
165 | });
166 | e.printStackTrace();
167 | throw new AndroidRuntimeException(e);
168 |
169 | }
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/apk/ApkInfo.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller.apk;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | import java.io.File;
6 |
7 | /**
8 | * Created by Bave on 2018/2/2.
9 | */
10 |
11 | public class ApkInfo {
12 | private File apkFile;
13 | private String appName;
14 | private Drawable icon;
15 | private String versionName;
16 | private int versionCode;
17 | private String packageName;
18 | private boolean hasInstalledApp;
19 | private String installedVersionName;
20 | private int installedVersionCode;
21 | private boolean isFakePath;
22 | private String[] permissions;
23 |
24 | public boolean isHasInstalledApp() {
25 | return hasInstalledApp;
26 | }
27 |
28 | public String[] getPermissions() {
29 | return permissions;
30 | }
31 |
32 | public void setPermissions(String[] permissions) {
33 | this.permissions = permissions;
34 | }
35 |
36 | public void setApkFile(File apkFile) {
37 | this.apkFile = apkFile;
38 | }
39 |
40 | public boolean isFakePath() {
41 | return isFakePath;
42 | }
43 |
44 | public void setFakePath(boolean fakePath) {
45 | isFakePath = fakePath;
46 | }
47 |
48 | public String getVersionName() {
49 | return versionName;
50 | }
51 |
52 | public void setVersionName(String versionName) {
53 | this.versionName = versionName;
54 | }
55 |
56 | public int getVersionCode() {
57 | return versionCode;
58 | }
59 |
60 | public void setVersionCode(int versionCode) {
61 | this.versionCode = versionCode;
62 | }
63 |
64 | public String getPackageName() {
65 | return packageName;
66 | }
67 |
68 | public String getVersion() {
69 | return versionName + "(" + versionCode + ")";
70 | }
71 |
72 | public String getInstalledVersion() {
73 | return hasInstalledApp ? installedVersionName + "(" + installedVersionCode + ")" : "NO";
74 | }
75 |
76 | public void setPackageName(String packageName) {
77 | this.packageName = packageName;
78 | }
79 |
80 | public boolean hasInstalledApp() {
81 | return hasInstalledApp;
82 | }
83 |
84 | public void setHasInstalledApp(boolean hasInstalledApp) {
85 | this.hasInstalledApp = hasInstalledApp;
86 | }
87 |
88 | public String getInstalledVersionName() {
89 | return installedVersionName;
90 | }
91 |
92 | public void setInstalledVersionName(String installedVersionName) {
93 | this.installedVersionName = installedVersionName;
94 | }
95 |
96 | public int getInstalledVersionCode() {
97 | return installedVersionCode;
98 | }
99 |
100 | public void setInstalledVersionCode(int installedVersionCode) {
101 | this.installedVersionCode = installedVersionCode;
102 | }
103 |
104 | public String getAppName() {
105 | return appName;
106 | }
107 |
108 | public Drawable getIcon() {
109 | return icon;
110 | }
111 |
112 | public void setIcon(Drawable icon) {
113 | this.icon = icon;
114 | }
115 |
116 | public void setAppName(String appName) {
117 | this.appName = appName;
118 | }
119 |
120 | public File getApkFile() {
121 | return apkFile;
122 | }
123 |
124 | public String getFileName() {
125 | return apkFile == null ? null : apkFile.getName();
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/apk/ContentUriUtils.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller.apk;
2 |
3 |
4 | import android.content.ContentUris;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.database.DatabaseUtils;
8 | import android.net.Uri;
9 | import android.os.Environment;
10 | import android.provider.DocumentsContract;
11 | import android.provider.MediaStore;
12 |
13 | public class ContentUriUtils {
14 | //修改自https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
15 | //原帖:https://stackoverflow.com/questions/19985286/convert-content-uri-to-actual-path-in-android-4-4
16 |
17 | /**
18 | * Get a file path from a Uri. This will get the the path for Storage Access
19 | * Framework Documents, as well as the _data field for the MediaStore and
20 | * other file-based ContentProviders.
21 | *
22 | * Callers should check whether the path is local before assuming it
23 | * represents a local file.
24 | *
25 | * @param context The context.
26 | * @param uri The Uri to query.
27 | * @author paulburke
28 | */
29 | public static String getPath(final Context context, final Uri uri) {
30 |
31 | // DocumentProvider
32 | if (DocumentsContract.isDocumentUri(context, uri)) {
33 | // ExternalStorageProvider
34 | if (isExternalStorageDocument(uri)) {
35 | final String docId = DocumentsContract.getDocumentId(uri);
36 | final String[] split = docId.split(":");
37 | final String type = split[0];
38 |
39 | if ("primary".equalsIgnoreCase(type)) {
40 | return Environment.getExternalStorageDirectory() + "/" + split[1];
41 | }
42 |
43 | }
44 | // DownloadsProvider
45 | else if (isDownloadsDocument(uri)) {
46 |
47 | final String id = DocumentsContract.getDocumentId(uri);
48 | final Uri contentUri = ContentUris.withAppendedId(
49 | Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
50 |
51 | return getDataColumn(context, contentUri, null, null);
52 | }
53 | // MediaProvider
54 | else if (isMediaDocument(uri)) {
55 | final String docId = DocumentsContract.getDocumentId(uri);
56 | final String[] split = docId.split(":");
57 | final String type = split[0];
58 |
59 | Uri contentUri = null;
60 | if ("image".equals(type)) {
61 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
62 | } else if ("video".equals(type)) {
63 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
64 | } else if ("audio".equals(type)) {
65 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
66 | }
67 |
68 | final String selection = "_id=?";
69 | final String[] selectionArgs = new String[]{
70 | split[1]
71 | };
72 |
73 | return getDataColumn(context, contentUri, selection, selectionArgs);
74 | }
75 | }
76 | // MediaStore (and general)
77 | else if ("content".equalsIgnoreCase(uri.getScheme())) {
78 |
79 | // Return the remote address
80 | if (isGooglePhotosUri(uri))
81 | return uri.getLastPathSegment();
82 |
83 | return getDataColumn(context, uri, null, null);
84 | }
85 | // File
86 | else if ("file".equalsIgnoreCase(uri.getScheme())) {
87 | return uri.getPath();
88 | }
89 |
90 | return null;
91 | }
92 |
93 | /**
94 | * @param uri The Uri to check.
95 | * @return Whether the Uri authority is ExternalStorageProvider.
96 | * @author paulburke
97 | */
98 | private static boolean isExternalStorageDocument(Uri uri) {
99 | return "com.android.externalstorage.documents".equals(uri.getAuthority());
100 | }
101 |
102 | /**
103 | * @param uri The Uri to check.
104 | * @return Whether the Uri authority is DownloadsProvider.
105 | * @author paulburke
106 | */
107 | private static boolean isDownloadsDocument(Uri uri) {
108 | return "com.android.providers.downloads.documents".equals(uri.getAuthority());
109 | }
110 |
111 | /**
112 | * @param uri The Uri to check.
113 | * @return Whether the Uri authority is MediaProvider.
114 | * @author paulburke
115 | */
116 | private static boolean isMediaDocument(Uri uri) {
117 | return "com.android.providers.media.documents".equals(uri.getAuthority());
118 | }
119 |
120 | /**
121 | * @param uri The Uri to check.
122 | * @return Whether the Uri authority is Google Photos.
123 | */
124 | private static boolean isGooglePhotosUri(Uri uri) {
125 | return "com.google.android.apps.photos.content".equals(uri.getAuthority());
126 | }
127 |
128 |
129 | /**
130 | * Get the value of the data column for this Uri. This is useful for
131 | * MediaStore Uris, and other file-based ContentProviders.
132 | *
133 | * @param context The context.
134 | * @param uri The Uri to query.
135 | * @param selection (Optional) Filter used in the query.
136 | * @param selectionArgs (Optional) Selection arguments used in the query.
137 | * @return The value of the _data column, which is typically a file path.
138 | * @author paulburke
139 | */
140 | private static String getDataColumn(Context context, Uri uri, String selection,
141 | String[] selectionArgs) {
142 |
143 | Cursor cursor = null;
144 | final String column = MediaStore.MediaColumns.DATA;
145 | final String[] projection = {
146 | column
147 | };
148 |
149 | try {
150 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
151 | null);
152 | if (cursor != null && cursor.moveToFirst()) {
153 | DatabaseUtils.dumpCursor(cursor);
154 | final int column_index = cursor.getColumnIndexOrThrow(column);
155 | return cursor.getString(column_index);
156 | }
157 | } catch (Exception e) {
158 | e.printStackTrace();
159 | } finally {
160 | if (cursor != null)
161 | cursor.close();
162 | }
163 | return null;
164 | }
165 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/bavelee/pokeinstaller/apk/ICommanderCallback.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.pokeinstaller.apk;
2 |
3 | import android.net.Uri;
4 |
5 | import cn.bavelee.pokeinstaller.apk.ApkInfo;
6 |
7 | public interface ICommanderCallback {
8 | void onStartParseApk(Uri uri);
9 |
10 | void onApkParsed(ApkInfo apkInfo);
11 |
12 | void onApkPreInstall(ApkInfo apkInfo);
13 |
14 | void onApkInstalled(ApkInfo apkInfo, int resultCode);
15 |
16 | void onInstallLog(ApkInfo apkInfo, String logText);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_hover.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/act_poke_installer.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
22 |
23 |
28 |
29 |
30 |
35 |
36 |
45 |
46 |
47 |
48 |
56 |
57 |
63 |
64 |
71 |
72 |
77 |
78 |
79 |
80 |
81 |
87 |
88 |
97 |
98 |
107 |
108 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/info_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/info_item_permission.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Poke 安裝器
4 | 安裝中…
5 | 安裝
6 | 無法解析 %s
7 | 背景安裝
8 | 解析中…
9 | %s 安裝失敗
10 | %s 已安裝
11 | 開始安裝 %s
12 | 安裝返回值 : %d
13 | 檔案位置 :
14 | 應用名稱 :
15 | 套件名稱 :
16 | 版本訊息 :
17 | 目前版本 :
18 | 安裝成功
19 | 安裝失败
20 | 返回
21 | 是
22 | 否
23 | 背景安裝
24 | 無法安裝應用
25 | 打開
26 | 顯示設置按鈕
27 | 是否在安裝界面顯示設置按鈕(不可見但是可以點擊)
28 | 安裝時顯示進度條
29 | 進度條
30 | 顏色設置
31 | 頂部顏色
32 | 安裝時的頂部背景色
33 | 安裝時的背景色
34 | 安裝失敗後的頂部背景顏色
35 | 失敗
36 | 安裝成功後的頂部背景色
37 | 成功
38 | 狀態欄的顏色
39 | 狀態欄
40 | 強迫症設置
41 | 頂部默認顏色
42 | 捐贈
43 | 捐贈,可以讓我把軟件做的更好
44 | 未授予讀寫權限,退出
45 | 成功安裝後自動刪除安裝包
46 | 自動刪除
47 | %s 已刪除
48 | 應用權限 :
49 | 應用權限
50 | 顯示權限列表
51 | 權限列表的文字顏色
52 | 權限文字
53 | 邊距
54 | 底部按鈕邊距
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Poke 安装器
4 | 安装中…
5 | 安装
6 | 无法解析 %s
7 | 静默安装
8 | 解析中…
9 | %s 安装失败
10 | %s 已安装
11 | 开始安装 %s
12 | 安装完成返回 : %d
13 | 应用路径 :
14 | 应用名称 :
15 | 应用包名 :
16 | 版本信息 :
17 | 当前版本 :
18 | 安装成功
19 | 安装失败
20 | 返回
21 | 是
22 | 否
23 | 静默安装
24 | 无法安装应用
25 | 打开
26 | 显示设置按钮
27 | 是否在安装界面显示设置按钮(不可见但是可以点击)
28 | 安装时显示进度条
29 | 进度条
30 | 颜色设置
31 | 顶部颜色
32 | 安装时的顶部背景色
33 | 安装时的背景色
34 | 安装失败后的顶部背景色
35 | 失败
36 | 安装成功后的顶部背景色
37 | 成功
38 | 状态栏的颜色
39 | 状态栏
40 | 强迫症设置
41 | 顶部默认颜色
42 | 捐赠
43 | 捐赠,可以让我把软件做的更好
44 | 没权限,不干!!!
45 | 安装成功后自动删除安装包
46 | 自动删除
47 | %s 已删除
48 | "应用权限 : "
49 | 应用权限
50 | 显示权限列表
51 | 权限列表的文字颜色
52 | 权限文字
53 | 边距
54 | 底部按钮边距
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 0
5 | - 16
6 | - 32
7 | - 48
8 | - 64
9 | - 80
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #B6B6B6
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 120dp
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Poke Installer
3 | Installing…
4 | Install
5 | Cannot parse apk file :%s
6 | Silently Install Under ROOT
7 | Parsing …
8 | %s install failed
9 | %s has been installed
10 | Start install %s
11 | Installation finished with result code %d
12 | APK PATH :
13 | APP NAME :
14 | PKG NAME :
15 | VERSION :
16 | CUR VER :
17 | Successful
18 | Failed
19 | Back
20 | YES
21 | NO
22 | Silently
23 | Unable to install apk
24 | OPEN
25 | Display Settings Button
26 | Display settings button on install screen(invisible but can be click)
27 | Display progress bar while installing
28 | Display progress bar
29 | OCD Settings
30 | Color Settings
31 | Default background color of top
32 | Default
33 | Background color while installing
34 | Installing
35 | Background color after install failure
36 | Failure
37 | Background color of success
38 | Success
39 | Color of status bar
40 | Status Bar
41 | Donate
42 | Donation can makes this app do better
43 | Did not grant read and write permissions, exit
44 | Automatically remove the installation package after successful installation
45 | Auto Delete
46 | %s has been delete
47 | APP PERM :
48 | App Permissions
49 | Display app permissions list
50 | Text color of permission list
51 | Permission Text
52 | Margins
53 | Margins of bottom buttons
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/prefs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
15 |
20 |
25 |
30 |
38 |
39 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/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 | google()
6 | jcenter()
7 |
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.4.1'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 |
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/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 |
15 |
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 01 16:10:53 CST 2019
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-5.1.1-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 |
--------------------------------------------------------------------------------
/module_donatedialog/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/module_donatedialog/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | targetSdkVersion 28
7 | minSdkVersion 21
8 | versionCode 1
9 | versionName "1.0"
10 | }
11 | buildTypes {
12 | release {
13 | minifyEnabled false
14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15 | }
16 | }
17 | }
18 |
19 | dependencies {
20 | implementation fileTree(include: ['*.jar'], dir: 'libs')
21 | }
22 |
--------------------------------------------------------------------------------
/module_donatedialog/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 |
--------------------------------------------------------------------------------
/module_donatedialog/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/module_donatedialog/src/main/java/cn/bavelee/donatedialog/DonateToMe.java:
--------------------------------------------------------------------------------
1 | package cn.bavelee.donatedialog;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.Intent;
9 | import android.content.pm.PackageManager;
10 | import android.graphics.Bitmap;
11 | import android.net.Uri;
12 | import android.provider.MediaStore;
13 | import android.widget.ImageView;
14 | import android.widget.Toast;
15 |
16 | import java.io.File;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 | import java.net.URLEncoder;
20 |
21 | /**
22 | * Created by Bave on 2018/1/5.
23 | */
24 |
25 | public class DonateToMe {
26 | public static void show(final Context context) {
27 | if (context == null) return;
28 | DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
29 | @Override
30 | public void onClick(DialogInterface dialogInterface, int i) {
31 | switch (i) {
32 | case DialogInterface.BUTTON_NEGATIVE:
33 | // wechat
34 | showSaveQRCodeDialog(context, R.drawable.wechat_money_revised);
35 | break;
36 | case DialogInterface.BUTTON_POSITIVE:
37 | // alipay
38 | if (haveInstalledAlipay(context)) {
39 | jumpToAlipyScreen(context);
40 | } else {
41 | showSaveQRCodeDialog(context, R.drawable.alipay_money_revised);
42 | }
43 | break;
44 | case DialogInterface.BUTTON_NEUTRAL:
45 | break;
46 | }
47 | }
48 | };
49 | new AlertDialog.Builder(context).setView(R.layout.layout_donate_dialog)
50 | .setTitle(R.string.title_donate_dialog_donate_methods)
51 | .setNeutralButton(android.R.string.no, onClickListener)
52 | .setPositiveButton(R.string.title_donate_dialog_alipay, onClickListener)
53 | .setNegativeButton(R.string.title_donate_dialog_wechat, onClickListener)
54 | .show();
55 |
56 | }
57 |
58 | private static void showSaveQRCodeDialog(Context context, int resId) {
59 | final ImageView imageView = new ImageView(context);
60 | imageView.setImageResource(resId);
61 | imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
62 | new AlertDialog.Builder(context).setView(imageView)
63 | .setNeutralButton(android.R.string.cancel, null)
64 | .setPositiveButton(R.string.title_donate_dialog_save_qr_code, new DialogInterface.OnClickListener() {
65 | @Override
66 | public void onClick(DialogInterface dialogInterface, int i) {
67 | saveImage(imageView);
68 | }
69 | })
70 | .show();
71 | }
72 |
73 | private static void saveBitmap(Bitmap mBitmap, File file) {
74 | try {
75 | FileOutputStream fos = new FileOutputStream(file);
76 | mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
77 | fos.flush();
78 | fos.close();
79 | } catch (IOException e) {
80 | e.printStackTrace();
81 | }
82 | }
83 |
84 | private static void saveImage(ImageView imageView) {
85 | imageView.setDrawingCacheEnabled(true);
86 | Bitmap bitmap = imageView.getDrawingCache();
87 | File qrCode = new File(imageView.getContext().getExternalCacheDir(), "qrcode.jpg");
88 | saveBitmap(bitmap, qrCode);
89 | imageView.setDrawingCacheEnabled(false);
90 | imageView.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + qrCode.getAbsolutePath())));
91 | Toast.makeText(imageView.getContext(), R.string.text_donate_dialog_qr_code_saved, Toast.LENGTH_SHORT).show();
92 | }
93 |
94 | public static boolean haveInstalledAlipay(Context context) {
95 | try {
96 | return context.getPackageManager().getPackageInfo("com.eg.android.AlipayGphone", PackageManager.GET_ACTIVITIES) != null;
97 | } catch (PackageManager.NameNotFoundException e) {
98 | e.printStackTrace();
99 | return false;
100 | }
101 | }
102 |
103 | public static void jumpToAlipyScreen(Context context) {
104 | String qrcode = URLEncoder.encode("HTTPS://QR.ALIPAY.COM/FKX05494PUYB5GFV1VNXAD");
105 | String url = "alipayqr://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=" + qrcode + "%3F_s%3Dweb-other&_t=" + System.currentTimeMillis();
106 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
107 | context.startActivity(intent);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/module_donatedialog/src/main/res/drawable/alipay_money_revised.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/module_donatedialog/src/main/res/drawable/alipay_money_revised.png
--------------------------------------------------------------------------------
/module_donatedialog/src/main/res/drawable/wechat_money_revised.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/module_donatedialog/src/main/res/drawable/wechat_money_revised.png
--------------------------------------------------------------------------------
/module_donatedialog/src/main/res/layout/layout_donate_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
24 |
--------------------------------------------------------------------------------
/module_donatedialog/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 捐赠
4 | 嗨,你好,欢迎使用我的app,我是一个独立的个人开发者,独立的个人开发者收入有限。如果你觉得这个程序很有用,可以给我买我一杯咖啡作为鼓励吗,谢谢你的支持。\n
5 | 有任何问题,请联系我 : \n\nbavelee@foxmail.com\n
6 | 支付宝
7 | 微信
8 | 捐赠方式
9 | 二维码已保存
10 | 保存二维码
11 |
--------------------------------------------------------------------------------
/module_donatedialog/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DONATE
3 | Hey, guy, welcome to my app.I am a young personal developer, I learning programming by myself, I enjoy writing codes.If you think this app is useful, may you can donate me for a coffee as a encouragement, thanks for your support.\n
4 | If you have any problems, please contact me : \n\nbavelee@foxmail.com\n
5 | Alipay
6 | Wechat
7 | Methods of donation
8 | QR Code saved
9 | Save QR code
10 |
11 |
--------------------------------------------------------------------------------
/pokeinstaller.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rayae/PokeInstaller/501f0e286189aaa145e50e7fcc46d834c70487c8/pokeinstaller.keystore
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':ColorPickerPreference', 'module_donatedialog'
2 | project(':ColorPickerPreference').projectDir = new File('app/libs/ColorPickerPreference')
--------------------------------------------------------------------------------