├── .gitignore ├── LICENSE ├── README.md └── TurkcellUpdaterSampleApp ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── settings.gradle ├── turkcellUpdater ├── build.gradle ├── proguard-project.txt └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── tr │ │ └── com │ │ └── turkcellteknoloji │ │ └── turkcellupdater │ │ ├── Configuration.java │ │ ├── DownloadHandler.java │ │ ├── DownloadRequest.java │ │ ├── Filter.java │ │ ├── FilteredEntry.java │ │ ├── LocalizedStringMap.java │ │ ├── Log.java │ │ ├── Message.java │ │ ├── MessageDescription.java │ │ ├── MessageDisplayRecords.java │ │ ├── MessageEntry.java │ │ ├── Properties.java │ │ ├── RestFailureHandler.java │ │ ├── RestJsonObjectResultHandler.java │ │ ├── RestNoValueResultHandler.java │ │ ├── RestRequest.java │ │ ├── TurkcellUpdater.java │ │ ├── Update.java │ │ ├── UpdateDescription.java │ │ ├── UpdateDisplayRecords.java │ │ ├── UpdateEntry.java │ │ ├── UpdateManager.java │ │ ├── UpdaterDialogManager.java │ │ ├── UpdaterException.java │ │ ├── Utilities.java │ │ ├── VersionsMap.java │ │ └── package-info.java │ ├── res │ ├── drawable-hdpi │ │ └── updater_warning.png │ ├── drawable-mdpi │ │ └── updater_warning.png │ ├── drawable-xhdpi │ │ └── updater_warning.png │ ├── layout │ │ ├── updater_dialog_message.xml │ │ └── updater_dialog_update_found.xml │ ├── values-tr │ │ └── updater_strings.xml │ └── values │ │ └── updater_strings.xml │ └── resources │ └── tr │ └── com │ └── turkcellteknoloji │ └── turkcellupdater │ └── doc-files │ └── configuration-reference.html └── turkcellUpdaterSampleApp ├── build.gradle └── src └── main ├── AndroidManifest.xml ├── java └── tr │ └── com │ └── turkcellteknoloji │ └── turkcellupdatersampleapp │ ├── LoginActivity.java │ └── SplashActivity.java └── res ├── drawable-hdpi └── ic_launcher.png ├── drawable-ldpi └── ic_launcher.png ├── drawable-mdpi └── ic_launcher.png ├── drawable-xhdpi └── ic_launcher.png ├── drawable └── splash.png ├── layout ├── activity_login.xml ├── activity_splash.xml └── intro.xml ├── menu ├── activity_login.xml └── activity_splash.xml ├── values-large └── styles.xml ├── values-v11 └── styles.xml ├── values-v14 └── styles.xml └── values ├── strings.xml ├── strings_activity_login.xml └── styles.xml /.gitignore: -------------------------------------------------------------------------------- 1 | TurkcellUpdaterTest/ 2 | TurkcellUpdaterTestWebContents/ 3 | 4 | build/ 5 | .gradle/ 6 | .idea/ 7 | .settings/ 8 | .svn/ 9 | # built application files 10 | *.apk 11 | *.ap_ 12 | 13 | # files for the dex VM 14 | *.dex 15 | 16 | # Java class files 17 | *.class 18 | 19 | # generated files 20 | bin/ 21 | gen/ 22 | 23 | # Local configuration file (sdk path, etc) 24 | local.properties 25 | 26 | # Android Studio 27 | .idea/ 28 | .gradle/ 29 | /*/local.properties 30 | /*/out 31 | /*/*/build/ 32 | /*/*/production/ 33 | *.iml 34 | *.iws 35 | *.ipr 36 | *~ 37 | *.swp 38 | build 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2013 Turkcell İletişim Hizmetleri A.Ş 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.2.3' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Wed Jun 03 09:45:52 EEST 2015 16 | systemProp.http.proxyHost=127.0.0.1 17 | systemProp.http.proxyPort=3128 18 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 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-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/import-summary.txt: -------------------------------------------------------------------------------- 1 | ECLIPSE ANDROID PROJECT IMPORT SUMMARY 2 | ====================================== 3 | 4 | Manifest Merging: 5 | ----------------- 6 | Your project uses libraries that provide manifests, and your Eclipse 7 | project did not explicitly turn on manifest merging. In Android Gradle 8 | projects, manifests are always merged (meaning that contents from your 9 | libraries' manifests will be merged into the app manifest. If you had 10 | manually copied contents from library manifests into your app manifest 11 | you may need to remove these for the app to build correctly. 12 | 13 | Ignored Files: 14 | -------------- 15 | The following files were *not* copied into the new Gradle project; you 16 | should evaluate whether these are still needed in your project and if 17 | so manually move them: 18 | 19 | From TurkcellUpdater: 20 | * .gitignore 21 | * build.gradle 22 | * build.xml 23 | * gradle\ 24 | * gradle\wrapper\ 25 | * gradle\wrapper\gradle-wrapper.jar 26 | * gradle\wrapper\gradle-wrapper.properties 27 | * gradlew 28 | * gradlew.bat 29 | From TurkcellUpdaterSampleApp: 30 | * .gitignore 31 | * ic_launcher-web.png 32 | * proguard-project.txt 33 | 34 | Replaced Jars with Dependencies: 35 | -------------------------------- 36 | The importer recognized the following .jar files as third party 37 | libraries and replaced them with Gradle dependencies instead. This has 38 | the advantage that more explicit version information is known, and the 39 | libraries can be updated automatically. However, it is possible that 40 | the .jar file in your project was of an older version than the 41 | dependency we picked, which could render the project not compileable. 42 | You can disable the jar replacement in the import wizard and try again: 43 | 44 | android-support-v4.jar => com.android.support:support-v4:18.0.0 45 | 46 | Moved Files: 47 | ------------ 48 | Android Gradle projects use a different directory structure than ADT 49 | Eclipse projects. Here's how the projects were restructured: 50 | 51 | In TurkcellUpdater: 52 | * AndroidManifest.xml => turkcellUpdater\src\main\AndroidManifest.xml 53 | * proguard-project.txt => turkcellUpdater\proguard-project.txt 54 | * res\ => turkcellUpdater\src\main\res\ 55 | * src\ => turkcellUpdater\src\main\java\ 56 | * src\tr\com\turkcellteknoloji\turkcellupdater\doc-files\configuration-reference.html => turkcellUpdater\src\main\resources\tr\com\turkcellteknoloji\turkcellupdater\doc-files\configuration-reference.html 57 | In TurkcellUpdaterSampleApp: 58 | * AndroidManifest.xml => turkcellUpdaterSampleApp\src\main\AndroidManifest.xml 59 | * res\ => turkcellUpdaterSampleApp\src\main\res\ 60 | * src\ => turkcellUpdaterSampleApp\src\main\java\ 61 | 62 | Next Steps: 63 | ----------- 64 | You can now build the project. The Gradle project needs network 65 | connectivity to download dependencies. 66 | 67 | Bugs: 68 | ----- 69 | If for some reason your project does not build, and you determine that 70 | it is due to a bug or limitation of the Eclipse to Gradle importer, 71 | please file a bug at http://b.android.com with category 72 | Component-Tools. 73 | 74 | (This import summary is for your information only, and can be deleted 75 | after import once you are satisfied with the results.) 76 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':turkcellUpdater' 2 | include ':turkcellUpdaterSampleApp' 3 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | 7 | defaultConfig { 8 | minSdkVersion 9 9 | targetSdkVersion 25 10 | useLibrary 'org.apache.http.legacy' 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled true 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/proguard-project.txt: -------------------------------------------------------------------------------- 1 | -keep public class !**.R$*,!**.R,!**.BuildConfig,!android.**, !tr.com.turkcellteknoloji.turkcellupdater.Utilities, tr.com.turkcellteknoloji.turkcellupdater.*,tr.com.turkcellteknoloji.turkcellupdater.*$* { 2 | public protected *; 3 | } 4 | 5 | -keepparameternames 6 | -keepattributes Exceptions,InnerClasses,Signature,Deprecated, 7 | SourceFile,LineNumberTable,*Annotation*,EnclosingMethod 8 | 9 | -keepclassmembernames class * { 10 | java.lang.Class class$(java.lang.String); 11 | java.lang.Class class$(java.lang.String, boolean); 12 | } 13 | 14 | -keepclasseswithmembernames class * { 15 | native ; 16 | } 17 | 18 | -keepclassmembers enum * { 19 | public static **[] values(); 20 | public static ** valueOf(java.lang.String); 21 | } 22 | 23 | -keepclassmembers class * implements java.io.Serializable { 24 | static final long serialVersionUID; 25 | private static final java.io.ObjectStreamField[] serialPersistentFields; 26 | private void writeObject(java.io.ObjectOutputStream); 27 | private void readObject(java.io.ObjectInputStream); 28 | java.lang.Object writeReplace(); 29 | java.lang.Object readResolve(); 30 | } -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Configuration.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | /** 21 | * Static runtime configuration for this library. 22 | * @author Ugur Ozmen 23 | */ 24 | class Configuration { 25 | 26 | public final static String VERSION_NAME = "1.0"; 27 | public final static String PRODUCT_NAME = "TurkcellUpdater"; 28 | 29 | /** 30 | * Library compliance level. This value should be increased after non-backward-compatible changes are introduced to this library. 31 | */ 32 | final static int UPDATER_LEVEL = 3; 33 | 34 | /** 35 | * Setting this value true activates debug behavior. This value always should be false in production versions. 36 | */ 37 | final static boolean DEBUG = false; 38 | 39 | /** 40 | * Setting this value to null disables MIME type checking for JSON files. 41 | */ 42 | final static String EXPECTED_JSON_MIME_TYPE = null; //DEBUG ? null : "application/json"; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/DownloadHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | interface DownloadHandler { 21 | void onFail(Exception ex); 22 | void onCancelled(); 23 | void onProgress(Integer percent); 24 | void onSuccess(byte[] result); 25 | } 26 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/DownloadRequest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.net.URI; 24 | 25 | import org.apache.http.Header; 26 | import org.apache.http.HttpEntity; 27 | import org.apache.http.HttpResponse; 28 | import org.apache.http.StatusLine; 29 | import org.apache.http.client.HttpClient; 30 | import org.apache.http.client.methods.HttpGet; 31 | import org.apache.http.client.methods.HttpUriRequest; 32 | 33 | import android.os.AsyncTask; 34 | 35 | class DownloadRequest { 36 | 37 | private URI uri; 38 | 39 | URI getUri() { 40 | return uri; 41 | } 42 | 43 | void setUri(URI uri) { 44 | this.uri = uri; 45 | } 46 | 47 | private int[] expectedHttpStatusCodes = { 200, 201, 202, 204 }; 48 | private String expectedContentType; 49 | private DownloadHandler downloadHandler; 50 | 51 | String getExpectedContentType() { 52 | return expectedContentType; 53 | } 54 | 55 | void setExpectedContentType(String expectedContentType) { 56 | this.expectedContentType = expectedContentType; 57 | } 58 | 59 | DownloadHandler getDownloadHandler() { 60 | return downloadHandler; 61 | } 62 | 63 | void setDownloadHandler(DownloadHandler downloadHandler) { 64 | this.downloadHandler = downloadHandler; 65 | } 66 | 67 | final int[] getExpectedHttpStatusCodes() { 68 | return expectedHttpStatusCodes; 69 | } 70 | 71 | final void setExpectedHttpStatusCodes( 72 | int... expectedHttpStatusCodes) { 73 | this.expectedHttpStatusCodes = expectedHttpStatusCodes; 74 | } 75 | 76 | HttpUriRequest createHttpRequest() throws Exception { 77 | return createHttpGetRequest(); 78 | } 79 | 80 | protected void appendHeaders(HttpUriRequest request) { 81 | } 82 | 83 | private HttpGet createHttpGetRequest() { 84 | final HttpGet result = new HttpGet(); 85 | result.setURI(getUri()); 86 | appendHeaders(result); 87 | return result; 88 | } 89 | 90 | protected byte[] getByteArrayFromResponse(HttpResponse response) 91 | throws IOException { 92 | final HttpEntity entity = response.getEntity(); 93 | if (entity == null) { 94 | return null; 95 | } 96 | 97 | final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 98 | try { 99 | entity.writeTo(byteArrayOutputStream); 100 | return byteArrayOutputStream.toByteArray(); 101 | } finally { 102 | try { 103 | entity.consumeContent(); 104 | } catch (Exception e) { 105 | // Omit 106 | } 107 | try { 108 | byteArrayOutputStream.close(); 109 | } catch (Exception e) { 110 | } 111 | } 112 | } 113 | 114 | AsyncTask executeAsync(final HttpClient client) 115 | throws Exception { 116 | final Worker worker = new Worker(client); 117 | worker.execute(); 118 | return worker; 119 | } 120 | 121 | protected void checkResponse(HttpResponse response) throws Exception { 122 | if (response == null) { 123 | throw new Exception("Response is null."); 124 | } 125 | checkResponseStatus(response); 126 | checkResponseContentType(response); 127 | } 128 | 129 | private void checkResponseStatus(HttpResponse response) 130 | throws Exception { 131 | final StatusLine statusLine = response.getStatusLine(); 132 | 133 | if (statusLine == null) { 134 | throw new Exception("Status line is null."); 135 | } 136 | 137 | final int statusCode = statusLine.getStatusCode(); 138 | final int[] expectedHttpStatusCodes = getExpectedHttpStatusCodes(); 139 | if (expectedHttpStatusCodes != null) { 140 | if (!Utilities.isElementFound(expectedHttpStatusCodes, statusCode)) { 141 | throw new Exception("Unexpected status http code: " + statusCode); 142 | } 143 | } 144 | } 145 | 146 | private void checkResponseContentType(HttpResponse response) 147 | throws Exception { 148 | if (expectedContentType != null) { 149 | final Header contentTypeHeader = response 150 | .getFirstHeader("Content-Type"); 151 | if (contentTypeHeader == null) { 152 | throw new Exception("Missing content-type header. '" 153 | + expectedContentType + "' is expected"); 154 | } 155 | 156 | final String contentType = contentTypeHeader.getValue(); 157 | if (Utilities.isNullOrEmpty(contentType)) { 158 | throw new Exception("Missing content-type header value. '" 159 | + expectedContentType + "' is expected"); 160 | } 161 | 162 | if (!contentType.startsWith(expectedContentType)) { 163 | throw new Exception( 164 | "Unexpected content-type header value: '" + contentType 165 | + "'. '" + expectedContentType 166 | + "' is expected"); 167 | } 168 | 169 | } 170 | } 171 | 172 | class Worker extends AsyncTask { 173 | final HttpClient client; 174 | private HttpUriRequest request; 175 | 176 | private Worker(HttpClient client) { 177 | super(); 178 | this.client = client; 179 | } 180 | 181 | private volatile Exception exception; 182 | 183 | @Override 184 | protected void onPreExecute() { 185 | super.onPreExecute(); 186 | try { 187 | request = createHttpRequest(); 188 | } catch (Exception e) { 189 | exception = e; 190 | } 191 | } 192 | 193 | @Override 194 | protected byte[] doInBackground(Void... params) { 195 | if (exception != null) { 196 | return null; 197 | } 198 | 199 | HttpResponse response = null; 200 | try { 201 | response = client.execute(request); 202 | 203 | checkResponse(response); 204 | 205 | final HttpEntity entity = response.getEntity(); 206 | if (entity == null) { 207 | return null; 208 | } 209 | long totalLength = entity.getContentLength(); 210 | long completedLenght = 0; 211 | 212 | if (totalLength > 0) { 213 | publishProgress(0); 214 | } else { 215 | publishProgress((Integer) null); 216 | } 217 | 218 | final InputStream is = entity.getContent(); 219 | final ByteArrayOutputStream os = new ByteArrayOutputStream(); 220 | try { 221 | 222 | final byte[] buffer = new byte[5120]; 223 | int i = 0; 224 | while ((i = is.read(buffer)) > -1) { 225 | os.write(buffer, 0, i); 226 | 227 | completedLenght += i; 228 | 229 | if (totalLength > 0) { 230 | int percent = (int) ((100 * completedLenght) / totalLength); 231 | if (percent > -1 && percent < 101) { 232 | publishProgress(percent); 233 | } else { 234 | publishProgress((Integer) null); 235 | } 236 | } 237 | } 238 | publishProgress(100); 239 | 240 | return os.toByteArray(); 241 | 242 | } finally { 243 | try { 244 | is.close(); 245 | } catch (Exception e) { 246 | // Omit 247 | } 248 | 249 | try { 250 | os.close(); 251 | } catch (Exception e) { 252 | // Omit 253 | } 254 | } 255 | 256 | } catch (Exception e) { 257 | 258 | exception = e; 259 | return null; 260 | 261 | } finally { 262 | // ensure that connection is released 263 | if (response != null) { 264 | final HttpEntity entity = response.getEntity(); 265 | if (entity != null) { 266 | try { 267 | entity.consumeContent(); 268 | } catch (IOException e1) { 269 | // Omit 270 | } 271 | } 272 | } 273 | } 274 | } 275 | 276 | @Override 277 | protected void onCancelled() { 278 | try { 279 | if (request != null) { 280 | request.abort(); 281 | } 282 | } catch (Exception e) { 283 | // omitted 284 | } 285 | super.onCancelled(); 286 | } 287 | 288 | @Override 289 | protected void onPostExecute(byte[] result) { 290 | if (exception == null) { 291 | try { 292 | if (downloadHandler != null) { 293 | downloadHandler.onSuccess(result); 294 | } 295 | return; 296 | } catch (Exception e) { 297 | exception = e; 298 | } 299 | } 300 | 301 | if (downloadHandler == null) { 302 | exception.printStackTrace(); 303 | } else { 304 | try { 305 | downloadHandler.onFail(exception); 306 | } catch (Exception e1) { 307 | e1.printStackTrace(); 308 | } 309 | } 310 | 311 | } 312 | 313 | @Override 314 | protected void onProgressUpdate(Integer... values) { 315 | super.onProgressUpdate(values); 316 | try { 317 | if (downloadHandler != null) { 318 | if (!Utilities.isNullOrEmpty(values)) { 319 | downloadHandler.onProgress(values[values.length - 1]); 320 | } 321 | } 322 | } catch (Exception e) { 323 | e.printStackTrace(); 324 | } 325 | } 326 | 327 | } 328 | 329 | } 330 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Filter.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | 21 | 22 | /** 23 | * Checks if given value matches with filtering rule.
24 | *
  • Rules are sequences of rule parts joined with ","
  • 25 | *
  • Both rule parts and values are converted to lower case and trimmed before 26 | * comparison
  • 27 | *
  • Order of rule parts doesn't change the result, example: "!b,a" is same with "a,!b"
  • 28 | *
  • "*", null or empty string matches with any value including 29 | * null
  • 30 | *
  • "''" matches with null or empty string
  • 31 | *
  • "!''" matches with any value except null or empty string
  • 32 | *
  • "![rule part]" excludes any value matches with [rule].
  • 33 | *
  • "[value]" matches with any value equals to [value]
  • 34 | *
  • "[prefix]*" matches with any value starting with [prefix]
  • 35 | *
  • "*[suffix]" matches with any value ending with [suffix]
  • 36 | *
  • "[prefix]*[suffix]" matches with any value starting with [prefix] and 37 | * ending with [suffix]
  • 38 | *
  • ">[integer]" matches with any value greater than [integer]
  • 39 | *
  • ">=[integer]" matches with any value greater than or equals to [integer]
  • 40 | *
  • "<[integer]" matches with any value lesser than [integer]
  • 41 | *
  • "<=[integer]" matches with any value lesser than or equals to [integer]
  • 42 | *
  • "<>[integer]" matches with any value not equals to [integer]
  • 43 | * 44 | * @author Ugur Ozmen 45 | * 46 | */ 47 | class Filter { 48 | final String name; 49 | final String rule; 50 | 51 | Filter(String name, String rule) { 52 | this.name = name; 53 | this.rule = rule; 54 | } 55 | 56 | boolean isMatchesWith(String value) { 57 | return isMatchesWith(value, rule); 58 | } 59 | 60 | private static boolean isMatchesWith(String value, final String rule) { 61 | value = Utilities.normalize(value); 62 | if (rule == null) { 63 | return true; 64 | } 65 | 66 | // should match with any value excluding filtered ones if rule has no include filters 67 | // example: "a" should match with "!b,!c" rule 68 | boolean onlyExcludeFiltersFound = true; 69 | 70 | // since exclude filters has higher priority over include filters, 71 | // we should not immediately return true when value matches with an include filter. 72 | // example: "abc" should not match with "a*c,!*b*" rule 73 | boolean matchedWithAnIncludeFilter = false; 74 | 75 | String[] ruleParts = rule.split(","); 76 | for (int i = 0; i < ruleParts.length; i++) { 77 | final String part = Utilities.normalize(ruleParts[i]); 78 | if (part.length()<1) { 79 | // omit empty rules 80 | continue; 81 | } 82 | 83 | if(part.startsWith("!")) { 84 | // Exclude rule 85 | if(part.length()>1) { 86 | // omit empty rules 87 | if(isFilterPartMatches(part.substring(1), value)) { 88 | return false; 89 | } 90 | } 91 | } else { 92 | // Include rule 93 | onlyExcludeFiltersFound = false; 94 | if(!matchedWithAnIncludeFilter) { 95 | if (isFilterPartMatches(part, value)) { 96 | matchedWithAnIncludeFilter = true; 97 | } 98 | } 99 | } 100 | 101 | } 102 | 103 | return onlyExcludeFiltersFound || matchedWithAnIncludeFilter; 104 | } 105 | 106 | private static boolean isFilterPartMatches(String rulePart, String value) { 107 | if (rulePart.equals("''")) { 108 | return value.equals(""); 109 | } 110 | if (rulePart.startsWith("<>")) { 111 | Integer valueAsInteger = Utilities.tryParseInteger(value); 112 | Integer ref = Utilities.tryParseInteger(rulePart.substring(2).trim()); 113 | if(valueAsInteger == null || ref == null) { 114 | return false; 115 | } 116 | return valueAsInteger.intValue() != ref.intValue(); 117 | } 118 | if (rulePart.startsWith("<=")) { 119 | Integer valueAsInteger = Utilities.tryParseInteger(value); 120 | Integer ref = Utilities.tryParseInteger(rulePart.substring(2).trim()); 121 | if(valueAsInteger == null || ref == null) { 122 | return false; 123 | } 124 | return valueAsInteger <= ref; 125 | } 126 | if (rulePart.startsWith(">=")) { 127 | Integer valueAsInteger = Utilities.tryParseInteger(value); 128 | Integer ref = Utilities.tryParseInteger(rulePart.substring(2).trim()); 129 | if(valueAsInteger == null || ref == null) { 130 | return false; 131 | } 132 | return valueAsInteger >= ref; 133 | } 134 | if (rulePart.startsWith("<")) { 135 | Integer valueAsInteger = Utilities.tryParseInteger(value); 136 | Integer ref = Utilities.tryParseInteger(rulePart.substring(1).trim()); 137 | if(valueAsInteger == null || ref == null) { 138 | return false; 139 | } 140 | return valueAsInteger < ref; 141 | } 142 | if (rulePart.startsWith(">")) { 143 | Integer valueAsInteger = Utilities.tryParseInteger(value); 144 | Integer ref = Utilities.tryParseInteger(rulePart.substring(1).trim()); 145 | if(valueAsInteger == null || ref == null) { 146 | return false; 147 | } 148 | return valueAsInteger > ref; 149 | } 150 | 151 | if (rulePart.indexOf("*") > -1) { 152 | final String regex = rulePart.replace("?", ".").replace("*", ".*"); 153 | return value.matches(regex); 154 | } 155 | 156 | return rulePart.equals(value); 157 | } 158 | 159 | 160 | 161 | 162 | } -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/FilteredEntry.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.util.Iterator; 21 | import java.util.List; 22 | import java.util.Vector; 23 | 24 | import org.json.JSONObject; 25 | 26 | /** 27 | * Base class for information that can be filtered by a list of {@link Filter}s 28 | * @author Ugur Ozmen 29 | */ 30 | class FilteredEntry { 31 | 32 | final List filters; 33 | 34 | FilteredEntry(List filters) 35 | throws UpdaterException { 36 | super(); 37 | this.filters = filters; 38 | } 39 | 40 | FilteredEntry(JSONObject jsonObject) throws UpdaterException { 41 | this.filters = createFilters(jsonObject); 42 | } 43 | 44 | private static List createFilters(JSONObject jsonObject) { 45 | final List result = new Vector(); 46 | final JSONObject filtersObject = jsonObject.optJSONObject("filters"); 47 | 48 | if (filtersObject != null) { 49 | Iterator names = filtersObject.keys(); 50 | while (names.hasNext()) { 51 | String name = names.next().toString(); 52 | String rule = filtersObject.optString(name); 53 | Filter filter = new Filter(name, rule); 54 | result.add(filter); 55 | } 56 | } 57 | 58 | return result; 59 | } 60 | 61 | boolean isMatches(Properties properties) { 62 | if (filters != null) { 63 | 64 | for (Filter filter : filters) { 65 | if (filter != null) { 66 | if(properties==null) { 67 | return false; 68 | } 69 | 70 | final String value = properties.getValue(filter.name); 71 | 72 | if (!filter.isMatchesWith(value)) { 73 | return false; 74 | } 75 | } 76 | } 77 | } 78 | 79 | return true; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/LocalizedStringMap.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.io.Serializable; 21 | import java.util.HashSet; 22 | import java.util.Hashtable; 23 | import java.util.Iterator; 24 | import java.util.List; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | import org.json.JSONObject; 29 | 30 | 31 | /** 32 | * Provides base class for language specific set of Strings. Every String value has its own key. 33 | * @author Ugur Ozmen 34 | * 35 | */ 36 | abstract class LocalizedStringMap implements Serializable { 37 | /** 38 | * 39 | */ 40 | private static final long serialVersionUID = 1L; 41 | 42 | /** 43 | * Two letter language code defining language of contents. null means no language is specified. 44 | */ 45 | public final String languageCode; 46 | final Hashtable map ; 47 | 48 | LocalizedStringMap(String languageCode, Map map) { 49 | super(); 50 | this.languageCode = formatLanguageCode(languageCode); 51 | 52 | this.map = new Hashtable(map); 53 | } 54 | 55 | LocalizedStringMap(String languageCode, JSONObject jsonObject) { 56 | super(); 57 | this.languageCode = formatLanguageCode(languageCode); 58 | this.map = new Hashtable(); 59 | if(jsonObject!=null) { 60 | @SuppressWarnings("unchecked") 61 | final Iterator keys = jsonObject.keys(); 62 | while (keys.hasNext()) { 63 | String key = keys.next(); 64 | if(key!=null) { 65 | String value = jsonObject.optString(key, null); 66 | map.put(key, value); 67 | } 68 | } 69 | } 70 | 71 | } 72 | 73 | public String get(String key) { 74 | if(key==null) { 75 | return null; 76 | } 77 | return map.get(key); 78 | } 79 | 80 | public Set getKeys() { 81 | return new HashSet(map.keySet()); 82 | } 83 | 84 | private static String formatLanguageCode(String languageCode) { 85 | languageCode = Utilities.normalize(languageCode); 86 | if (languageCode == null || languageCode.length() < 1 87 | || languageCode.equals("*")) { 88 | return null; 89 | } 90 | return languageCode; 91 | } 92 | 93 | @Override 94 | public int hashCode() { 95 | final int prime = 31; 96 | int result = 1; 97 | result = prime * result 98 | + ((languageCode == null) ? 0 : languageCode.hashCode()); 99 | result = prime * result + ((map == null) ? 0 : map.hashCode()); 100 | return result; 101 | } 102 | 103 | @Override 104 | public boolean equals(Object obj) { 105 | if (this == obj) 106 | return true; 107 | if (obj == null) 108 | return false; 109 | if (getClass() != obj.getClass()) 110 | return false; 111 | LocalizedStringMap other = (LocalizedStringMap) obj; 112 | if (languageCode == null) { 113 | if (other.languageCode != null) 114 | return false; 115 | } else if (!languageCode.equals(other.languageCode)) 116 | return false; 117 | if (map == null) { 118 | if (other.map != null) 119 | return false; 120 | } else if (!map.equals(other.map)) 121 | return false; 122 | return true; 123 | } 124 | 125 | static T select(List list, String languageCode) { 126 | final String normalizedLanguageCode = Utilities.normalize(languageCode); 127 | T result = null; 128 | for (T t : list) { 129 | if (t != null) { 130 | final String normalizedLanguageCode2 = Utilities 131 | .normalize(t.languageCode); 132 | 133 | if (normalizedLanguageCode2.equals(normalizedLanguageCode)) { 134 | result = t; 135 | break; 136 | } 137 | 138 | if (normalizedLanguageCode2.equals("*") 139 | || normalizedLanguageCode2.equals("") 140 | || normalizedLanguageCode2 141 | .equals(normalizedLanguageCode)) { 142 | result = t; 143 | } 144 | } 145 | } 146 | 147 | return result; 148 | } 149 | 150 | @Override 151 | public String toString() { 152 | 153 | String mapAsString; 154 | 155 | if(map == null) { 156 | mapAsString = null; 157 | } else { 158 | StringBuilder sb = new StringBuilder(); 159 | sb.append('['); 160 | boolean first = true; 161 | for (String key:map.keySet()) { 162 | if(first) { 163 | first = false; 164 | } else { 165 | sb.append(','); 166 | } 167 | sb.append(key); 168 | sb.append("="); 169 | sb.append(map.get(key)); 170 | } 171 | sb.append(']'); 172 | mapAsString = sb.toString(); 173 | } 174 | 175 | return "LocalizedStringMap [languageCode=" + languageCode + ", map=" 176 | + mapAsString + "]"; 177 | } 178 | 179 | 180 | 181 | } 182 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Log.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import android.annotation.SuppressLint; 21 | import android.os.Build; 22 | 23 | /** 24 | * Provides a logging interface that can filter message debug messages when {@link Configuration#DEBUG} is false. 25 | *
    26 | * All log messages sent using this class will be tagged with {@value #TAG} string. 27 | * @author Ugur Ozmen 28 | */ 29 | class Log { 30 | final static String TAG = Configuration.PRODUCT_NAME; 31 | 32 | 33 | static void printProductInfo() { 34 | if(Configuration.DEBUG) { 35 | e("Debug version of " + Configuration.PRODUCT_NAME + " should not be used in production environment."); 36 | } 37 | 38 | i("version: " + Configuration.VERSION_NAME); 39 | } 40 | 41 | static void d(String msg) { 42 | if(Configuration.DEBUG) { 43 | android.util.Log.d(TAG, msg); 44 | } 45 | } 46 | static void d(String msg, Throwable tr) { 47 | if(Configuration.DEBUG) { 48 | android.util.Log.d(TAG, msg, tr); 49 | } 50 | } 51 | static void e(String msg) { 52 | android.util.Log.e(TAG, msg); 53 | } 54 | static void e(String msg, Throwable tr) { 55 | android.util.Log.e(TAG, msg, tr); 56 | } 57 | static void i(String msg) { 58 | if(Configuration.DEBUG) { 59 | android.util.Log.i(TAG, msg); 60 | } 61 | } 62 | static void i(String msg, Throwable tr) { 63 | if(Configuration.DEBUG) { 64 | android.util.Log.i(TAG, msg, tr); 65 | } 66 | } 67 | static void v(String msg) { 68 | if(Configuration.DEBUG) { 69 | android.util.Log.v(TAG, msg); 70 | } 71 | } 72 | static void v(String msg, Throwable tr) { 73 | if(Configuration.DEBUG) { 74 | android.util.Log.v(TAG, msg, tr); 75 | } 76 | } 77 | static void w(String msg) { 78 | if(Configuration.DEBUG) { 79 | android.util.Log.w(TAG, msg); 80 | } 81 | } 82 | static void w(String msg, Throwable tr) { 83 | if(Configuration.DEBUG) { 84 | android.util.Log.w(TAG, msg, tr); 85 | } 86 | } 87 | static void w(Throwable tr) { 88 | if(Configuration.DEBUG) { 89 | android.util.Log.w(TAG, tr); 90 | } 91 | } 92 | 93 | @SuppressLint("NewApi") 94 | static void wtf(String msg) { 95 | if(Build.VERSION.SDK_INT>8) { 96 | android.util.Log.wtf(TAG, msg); 97 | } else { 98 | android.util.Log.e(TAG, msg); 99 | } 100 | } 101 | 102 | @SuppressLint("NewApi") 103 | static void wtf(String msg, Throwable tr) { 104 | if(Build.VERSION.SDK_INT>8) { 105 | android.util.Log.wtf(TAG, msg, tr); 106 | } else { 107 | android.util.Log.e(TAG, msg, tr); 108 | } 109 | } 110 | 111 | @SuppressLint("NewApi") 112 | static void wtf(Throwable tr) { 113 | if(Build.VERSION.SDK_INT>8) { 114 | android.util.Log.wtf(TAG, tr); 115 | } else { 116 | android.util.Log.e(TAG, "wtf", tr); 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Message.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import java.io.Serializable; 19 | import java.net.URL; 20 | 21 | /** 22 | * Provides information about an deployable application package 23 | * @author Ugur Ozmen 24 | * 25 | */ 26 | public class Message implements Serializable { 27 | 28 | /** 29 | * 30 | */ 31 | private static final long serialVersionUID = 1L; 32 | 33 | /** 34 | * User representable message contents. 35 | */ 36 | public final MessageDescription description; 37 | 38 | /** 39 | * URL of web page to display user. null if undefined. 40 | */ 41 | public final URL targetWebsiteUrl; 42 | 43 | /** 44 | * true if user should directed to Google Play product page. 45 | */ 46 | public final boolean targetGooglePlay; 47 | 48 | /** 49 | * Package name of referred package 50 | */ 51 | public final String targetPackageName; 52 | 53 | Message(MessageDescription description, URL targetWebsiteUrl, boolean targetGooglePlay, String targetPackageName) { 54 | super(); 55 | this.description = description; 56 | this.targetGooglePlay = targetGooglePlay; 57 | this.targetWebsiteUrl = targetWebsiteUrl; 58 | this.targetPackageName = targetPackageName; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "Message [description=" + description + ", targetWebsiteUrl=" + targetWebsiteUrl + ", targetGooglePlay=" + targetGooglePlay + ", targetPackageName=" + targetPackageName + "]"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/MessageDescription.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import org.json.JSONObject; 19 | 20 | import java.io.Serializable; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * Container for texts that are displayed on message dialog. 26 | * 27 | * @author Ugur Ozmen 28 | * @see #get(String) 29 | * @see #KEY_TITLE 30 | * @see #KEY_MESSAGE 31 | * @see #KEY_IMAGE_URL 32 | */ 33 | public class MessageDescription extends LocalizedStringMap implements Serializable { 34 | 35 | /** 36 | * 37 | */ 38 | private static final long serialVersionUID = 1L; 39 | 40 | /** 41 | * Key for dialog title 42 | * 43 | * @see #get(String) 44 | */ 45 | public final static String KEY_TITLE = "title"; 46 | 47 | /** 48 | * Key for text displayed inside dialog 49 | * 50 | * @see #get(String) 51 | */ 52 | public final static String KEY_MESSAGE = "message"; 53 | 54 | /** 55 | * Key for url of image that displayed in dialog 56 | * 57 | * @see #get(String) 58 | */ 59 | public final static String KEY_IMAGE_URL = "imageUrl"; 60 | 61 | /** 62 | * Key for positive button text of update dialog 63 | * 64 | * @see #get(String) 65 | */ 66 | public final static String KEY_POSITIVE_BUTTON = "positive_button"; 67 | 68 | /** 69 | * Key for negative button text of update dialog 70 | * 71 | * @see #get(String) 72 | */ 73 | public final static String KEY_NEGATIVE_BUTTON = "negative_button"; 74 | 75 | MessageDescription(String languageCode, String title, String message, String imageUrl, String positiveButton, String negativeButton) { 76 | super(languageCode, createMap(title, message, imageUrl, positiveButton, negativeButton)); 77 | } 78 | 79 | MessageDescription(String languageCode, JSONObject jsonObject) { 80 | super(languageCode, jsonObject); 81 | } 82 | 83 | MessageDescription(String languageCode, String message) { 84 | super(languageCode, createMap(message)); 85 | } 86 | 87 | private static Map createMap(String title, String message, String imageUrl, String positiveButton, String negativeButton) { 88 | Map result = createMap(message); 89 | result.put(KEY_TITLE, title); 90 | result.put(KEY_IMAGE_URL, imageUrl); 91 | result.put(KEY_POSITIVE_BUTTON, positiveButton); 92 | result.put(KEY_NEGATIVE_BUTTON, negativeButton); 93 | return result; 94 | } 95 | 96 | private static Map createMap(String message) { 97 | Map result = new HashMap(); 98 | result.put(KEY_MESSAGE, message); 99 | return result; 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/MessageDisplayRecords.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.util.Date; 21 | import java.util.HashSet; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | import android.annotation.SuppressLint; 26 | import android.content.Context; 27 | import android.content.SharedPreferences; 28 | import android.content.SharedPreferences.Editor; 29 | 30 | /** 31 | * Keeps information about displayed messages like last display date and display count. 32 | *
    33 | * Data kept by this class is backed by an {@link SharedPreferences} object named {@value #SHARED_PREFERENCES_NAME} 34 | * @author Ugur Ozmen 35 | * 36 | */ 37 | class MessageDisplayRecords { 38 | static final String SHARED_PREFERENCES_NAME = "turkcell-updater-message-display-records"; 39 | 40 | private final SharedPreferences sharedPreferences; 41 | 42 | /** 43 | * Creates a new instance 44 | * @param context 45 | */ 46 | MessageDisplayRecords(Context context) { 47 | sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); 48 | } 49 | 50 | /** 51 | * Returns display count of message with given id 52 | * @param id ID of queried message 53 | * @return total display count. 54 | */ 55 | int getMessageDisplayCount(int id) { 56 | return sharedPreferences.getInt(id + "-display-count", 0); 57 | } 58 | 59 | /** 60 | * Returns last display time of message with given id 61 | * @param id ID of queried message 62 | * @return last display date or null if message is not displayed yet. 63 | */ 64 | Date getMessageLastDisplayDate(int id) { 65 | final long millis = sharedPreferences.getLong(id + "-last-display-date", 0); 66 | if(millis == 0) { 67 | return null; 68 | } else { 69 | return new Date(millis); 70 | } 71 | } 72 | 73 | /** 74 | * Increases display count of message with given id by one and stores current time as last display date for the message. 75 | * @param id ID of queried message 76 | */ 77 | @SuppressLint("NewApi") 78 | void onMessageDisplayed(int id) { 79 | onMessageDisplayed(id, new Date()); 80 | } 81 | 82 | /** 83 | * Test friendly version of {@link #onMessageDisplayed(int)}. 84 | *
    85 | * Note: This method is should only be used for testing purposes. 86 | * @param id 87 | * @param date 88 | */ 89 | @SuppressLint("NewApi") 90 | @Deprecated 91 | void onMessageDisplayed(int id, Date now) { 92 | final int messageDisplayCount = getMessageDisplayCount(id); 93 | final Editor edit = sharedPreferences.edit(); 94 | edit.putInt(id + "-display-count", messageDisplayCount + 1); 95 | edit.putLong(id + "-last-display-date", now.getTime()); 96 | if(android.os.Build.VERSION.SDK_INT>8) { 97 | edit.apply(); 98 | } else { 99 | edit.commit(); 100 | } 101 | } 102 | 103 | /** 104 | * Deletes record for given id. 105 | *
    106 | * Note: This method is should only be used for testing purposes. 107 | * @param id 108 | */ 109 | @Deprecated 110 | void deleteMessageRecords(int id) { 111 | final Editor edit = sharedPreferences.edit(); 112 | edit.remove(id + "-display-count"); 113 | edit.remove(id + "-last-display-date"); 114 | edit.commit(); 115 | } 116 | 117 | /** 118 | * Deletes all records. 119 | *
    120 | * Note: This method is should only be used for testing purposes. 121 | */ 122 | @Deprecated 123 | void deleteAllRecords() { 124 | final Map all = sharedPreferences.getAll(); 125 | Set keys = new HashSet(all.keySet()); 126 | final Editor edit = sharedPreferences.edit(); 127 | for (String key : keys) { 128 | edit.remove(key); 129 | } 130 | edit.commit(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/MessageEntry.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import android.content.Context; 19 | 20 | import org.json.JSONObject; 21 | 22 | import java.net.MalformedURLException; 23 | import java.net.URL; 24 | import java.util.Date; 25 | import java.util.Iterator; 26 | import java.util.List; 27 | import java.util.Vector; 28 | 29 | class MessageEntry extends FilteredEntry { 30 | 31 | final List messageDescriptions; 32 | 33 | final int id; 34 | 35 | final String targetPackageName; 36 | final URL targetWebsiteUrl; 37 | final boolean targetGooglePlay; 38 | 39 | final int displayPeriodInHours; 40 | final Date displayAfterDate; 41 | final Date displayBeforeDate; 42 | final int maxDisplayCount; 43 | 44 | MessageEntry(List filters, int id, List messageDescriptions, int displayPeriodInHours, Date displayAfterDate, Date displayBeforeDate, int maxDisplayCount, String targetPackageName, URL targetWebsiteUrl, boolean targetGooglePlay) throws UpdaterException { 45 | super(filters); 46 | this.messageDescriptions = messageDescriptions; 47 | this.displayPeriodInHours = displayPeriodInHours; 48 | this.displayAfterDate = displayAfterDate; 49 | this.displayBeforeDate = displayBeforeDate; 50 | this.maxDisplayCount = maxDisplayCount; 51 | this.targetPackageName = targetPackageName; 52 | this.targetGooglePlay = targetGooglePlay; 53 | this.targetWebsiteUrl = targetWebsiteUrl; 54 | this.id = id == 0 ? generateId() : id; 55 | validate(); 56 | } 57 | 58 | MessageEntry(JSONObject jsonObject) throws UpdaterException { 59 | super(jsonObject); 60 | this.messageDescriptions = createMessageDescriptions(jsonObject); 61 | this.displayPeriodInHours = jsonObject.optInt("displayPeriodInHours", 0); 62 | this.displayAfterDate = getDate(jsonObject, "displayAfterDate"); 63 | this.displayBeforeDate = getDate(jsonObject, "displayBeforeDate"); 64 | this.maxDisplayCount = jsonObject.optInt("maxDisplayCount", Integer.MAX_VALUE); 65 | this.targetWebsiteUrl = getUrl(jsonObject, "targetWebsiteUrl"); 66 | this.targetPackageName = Utilities.removeWhiteSpaces(jsonObject.optString("targetPackageName")); 67 | this.targetGooglePlay = jsonObject.optBoolean("targetGooglePlay"); 68 | int i = jsonObject.optInt("id", 0); 69 | this.id = i == 0 ? generateId() : i; 70 | validate(); 71 | } 72 | 73 | private int generateId() { 74 | final int prime = 31; 75 | int result = 1; 76 | result = prime * result + (targetGooglePlay ? 1231 : 1237); 77 | result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); 78 | result = prime * result + ((targetWebsiteUrl == null) ? 0 : targetWebsiteUrl.hashCode()); 79 | result = prime * result + ((messageDescriptions == null) ? 0 : messageDescriptions.hashCode()); 80 | return result; 81 | } 82 | 83 | private static URL getUrl(JSONObject jsonObject, String key) throws UpdaterException { 84 | String spec = Utilities.removeWhiteSpaces(jsonObject.optString(key)); 85 | if ("".equals(spec)) { 86 | return null; 87 | } 88 | try { 89 | return new URL(spec); 90 | } catch (MalformedURLException e) { 91 | throw new UpdaterException("'" + key + "' url is malformatted", e); 92 | } 93 | } 94 | 95 | private static Date getDate(JSONObject jsonObject, String name) { 96 | if (jsonObject == null || name == null) { 97 | return null; 98 | } 99 | final String s = jsonObject.optString(name, null); 100 | if (s == null) { 101 | return null; 102 | } 103 | return Utilities.parseIsoDate(s); 104 | } 105 | 106 | private static List createMessageDescriptions(JSONObject jsonObject) { 107 | final List result = new Vector(); 108 | final JSONObject udsObject = jsonObject.optJSONObject("descriptions"); 109 | if (udsObject != null) { 110 | Iterator languages = udsObject.keys(); 111 | while (languages.hasNext()) { 112 | String languageCode = languages.next().toString(); 113 | final JSONObject o = udsObject.optJSONObject(languageCode); 114 | if (o != null) { 115 | MessageDescription ud = new MessageDescription(languageCode, o); 116 | result.add(ud); 117 | } else { 118 | final String s = udsObject.optString(languageCode, null); 119 | if (s != null) { 120 | MessageDescription ud = new MessageDescription(languageCode, s); 121 | result.add(ud); 122 | } 123 | } 124 | } 125 | } 126 | return result; 127 | } 128 | 129 | boolean shouldDisplay(Properties properties, MessageDisplayRecords records, Context context) { 130 | final Date now = new Date(); 131 | return shouldDisplay(properties, records, context, now); 132 | } 133 | 134 | /** 135 | * Test friendly version of {@link #shouldDisplay(Properties, MessageDisplayRecords, Context)}
    136 | * Note: This method is should only be used for testing purposes. 137 | * @param properties 138 | * @param records 139 | * @param context 140 | * @param now 141 | * @return 142 | */ 143 | @Deprecated 144 | boolean shouldDisplay(Properties properties, MessageDisplayRecords records, Context context, final Date now) { 145 | // check filters 146 | if (!isMatches(properties)) { 147 | return false; 148 | } 149 | // check if it is early to display message 150 | if (displayAfterDate != null) { 151 | if (displayAfterDate.after(now)) { 152 | return false; 153 | } 154 | } 155 | // check if it is late to display message 156 | if (displayBeforeDate != null) { 157 | if (displayBeforeDate.before(now)) { 158 | return false; 159 | } 160 | } 161 | // check if it is displayed more than specified count 162 | if (maxDisplayCount < Integer.MAX_VALUE) { 163 | final int count = records.getMessageDisplayCount(id); 164 | if (count >= maxDisplayCount) { 165 | return false; 166 | } 167 | } 168 | // check if it is displayed earlier than specified period 169 | if (displayPeriodInHours > 0) { 170 | final Date messageLastDisplayDate = records.getMessageLastDisplayDate(id); 171 | // check if message displayed before 172 | if (messageLastDisplayDate != null) { 173 | final Date date = Utilities.addHours(now, -displayPeriodInHours); 174 | if (messageLastDisplayDate.after(date)) { 175 | return false; 176 | } 177 | } 178 | } 179 | // check if target application is already installed 180 | if (!Utilities.isNull(targetPackageName)) { 181 | if (Utilities.isPackageInstalled(context, targetPackageName)) { 182 | return false; 183 | } 184 | } 185 | return true; 186 | } 187 | 188 | Message getMessageToDisplay(Properties properties, MessageDisplayRecords records) { 189 | return getMessageToDisplay(properties, records, new Date()); 190 | } 191 | 192 | /** 193 | * Test friendly version of {@link #getMessageToDisplay(Properties, MessageDisplayRecords)}. 194 | *
    195 | * Note: This method is should only be used for testing purposes. 196 | * @param properties 197 | * @param records 198 | * @param now 199 | * @return 200 | */ 201 | @Deprecated 202 | Message getMessageToDisplay(Properties properties, MessageDisplayRecords records, Date now) { 203 | String languageCode = null; 204 | if (properties != null) { 205 | final String s = properties.getValue(Properties.KEY_DEVICE_LANGUAGE); 206 | if (!Utilities.isNullOrEmpty(s)) { 207 | languageCode = s; 208 | } 209 | } 210 | final MessageDescription description = LocalizedStringMap.select(messageDescriptions, languageCode); 211 | records.onMessageDisplayed(id, now); 212 | return new Message(description, targetWebsiteUrl, targetGooglePlay, targetPackageName); 213 | } 214 | 215 | private void validate() throws UpdaterException { 216 | if (targetGooglePlay && Utilities.isNullOrEmpty(targetPackageName)) { 217 | throw new UpdaterException("'targetPackageName' shoud be not be empty if target is Google Play"); 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Properties.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.security.MessageDigest; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | import android.content.Context; 25 | import android.content.pm.PackageInfo; 26 | import android.content.pm.PackageManager.NameNotFoundException; 27 | import android.os.Build.VERSION_CODES; 28 | import android.provider.Settings.Secure; 29 | import android.util.Base64; 30 | 31 | /** 32 | * Represents Device and application properties. 33 | * Following property values are automatically retrieved: 34 | *

      35 | *
    • {@link #KEY_APP_INSTALLER_PACKAGE_NAME}
    • 36 | *
    • {@link #KEY_APP_PACKAGE_NAME}
    • 37 | *
    • {@link #KEY_APP_VERSION_CODE}
    • 38 | *
    • {@link #KEY_APP_VERSION_NAME}
    • 39 | *
    • {@link #KEY_DEVICE_API_LEVEL}
    • 40 | *
    • {@link #KEY_DEVICE_BRAND}
    • 41 | *
    • {@link #KEY_DEVICE_IS_TABLET}
    • 42 | *
    • {@link #KEY_DEVICE_LANGUAGE}
    • 43 | *
    • {@link #KEY_DEVICE_MCC}
    • 44 | *
    • {@link #KEY_DEVICE_MNC}
    • 45 | *
    • {@link #KEY_DEVICE_MODEL}
    • 46 | *
    • {@link #KEY_DEVICE_PRODUCT}
    • 47 | *

    48 | * These values can be overrided by calling {@link #setValue(String, String)} method. 49 | * Also it is possible to introduce new key-value pairs using {@link #KEY_COSTUM_PREFIX}. 50 | * @author Ugur Ozmen 51 | */ 52 | public class Properties { 53 | private final Map map; 54 | 55 | /** 56 | * Package name of application.
    57 | * Example value: "com.sample.app" 58 | *
    59 | * Overriding value of this key is not recommended. 60 | */ 61 | public static final String KEY_APP_PACKAGE_NAME = "appPackageName"; 62 | 63 | /** 64 | * Version name of application which is defined in AndroidManifest.xml typically in Major.Minor.Revision or Major.Minor format.
    65 | * Example value: "1.0.0". 66 | */ 67 | public static final String KEY_APP_VERSION_NAME = "appVersionName"; 68 | 69 | /** 70 | * An integer version code of application which is defined in AndroidManifest.xml.
    71 | * Example value: "10". 72 | */ 73 | public static final String KEY_APP_VERSION_CODE = "appVersionCode"; 74 | 75 | /** 76 | * Package name of application installed current application. Maybe null if not specified.
    77 | * Example value: "com.android.vending" of Google play. 78 | */ 79 | public static final String KEY_APP_INSTALLER_PACKAGE_NAME = "appInstallerPackageName"; 80 | 81 | /** 82 | * Version code of Android OS. See {@link VERSION_CODES}.
    83 | * Example value: "10" for Android 2.3.3. 84 | */ 85 | public static final String KEY_DEVICE_API_LEVEL = "deviceApiLevel"; 86 | 87 | /** 88 | * Name of operating system of device.
    89 | * Value: "Android". 90 | *
    91 | * Overriding value of this key is not recommended. 92 | */ 93 | public static final String KEY_DEVICE_OS_NAME = "deviceOsName"; 94 | 95 | /** 96 | * Version name of operating system of device.
    97 | * Example value: "2.3.3". 98 | */ 99 | public static final String KEY_DEVICE_OS_VERSION = "deviceOsVersion"; 100 | 101 | /** 102 | * Brand name of device.
    103 | * Example value: "htc_europe" for HTC Wildfire S. 104 | */ 105 | public static final String KEY_DEVICE_BRAND = "deviceBrand"; 106 | 107 | /** 108 | * Model name of device.
    109 | * Example value: "HTC Wildfire S A510e" for HTC Wildfire S. 110 | */ 111 | public static final String KEY_DEVICE_MODEL = "deviceModel"; 112 | 113 | /** 114 | * Product name of the device.
    115 | * Example value: "htc_marvel" for HTC Wildfire S. 116 | */ 117 | public static final String KEY_DEVICE_PRODUCT = "deviceProduct"; 118 | 119 | /** 120 | * "true" if devices is a tablet, otherwise "false". Since there is no clear evidence to determine if an Android device 121 | * is tablet or not, devices with minimum screen size wider than 600 dpi are considered as tablets.
    122 | * Example values: "true", "false". 123 | */ 124 | public static final String KEY_DEVICE_IS_TABLET = "deviceIsTablet"; 125 | 126 | /** 127 | * Two letter language code of device 128 | * (see: ISO 639-1).
    129 | * Example values: "en", "tr", "fr". 130 | */ 131 | public static final String KEY_DEVICE_LANGUAGE = "deviceLanguage"; 132 | 133 | /** 134 | * "x-" is prefix for application defined keys of arbitrary properties.
    135 | * Applications may define and add own custom property key-value pairs for application specific filters.
    136 | * Example values: "x-foo", "x-bar". 137 | */ 138 | public static final String KEY_COSTUM_PREFIX = "x-"; 139 | 140 | /** 141 | * Mobile country code of device. See Mobile country code
    142 | * Example value: "286" for Turkey. 143 | */ 144 | public static final String KEY_DEVICE_MCC = "deviceMcc"; 145 | 146 | /** 147 | * Mobile network code of device. See Mobile country code
    148 | * Example value: "1" for Turkcell. 149 | */ 150 | public static final String KEY_DEVICE_MNC = "deviceMnc"; 151 | 152 | /** 153 | * A unique alphanumeric identifier for device.
    154 | * Example value: "5e5aC2coeO0UuPY/nH/C3DdelqE4MuTkywh2aB9PT84" 155 | */ 156 | public static final String KEY_DEVICE_ID = "deviceId"; 157 | 158 | /** 159 | * An integer number that is used to define updater version used by application.
    160 | * Example value: "1" for initial version of updater sdk. 161 | *
    162 | * Overriding value of this key is not recommended. 163 | */ 164 | public static final String KEY_UPDATER_LEVEL = "updaterLevel"; 165 | 166 | /** 167 | * Creates an instance and automatically retrives current device and application properties. 168 | * To override property values, use {@link #setValue(String, String)} method. 169 | * @param context current context. 170 | */ 171 | public Properties(Context context) { 172 | this(new HashMap()); 173 | autoFetch(context); 174 | } 175 | 176 | Properties(Map map) { 177 | this.map = map; 178 | } 179 | 180 | void autoFetch(Context context) { 181 | final PackageInfo packageInfo; 182 | try { 183 | packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 184 | } catch (NameNotFoundException e) { 185 | return; 186 | } 187 | String packageName = packageInfo.packageName; 188 | 189 | setValue(KEY_APP_PACKAGE_NAME, packageName); 190 | setValue(KEY_APP_VERSION_CODE, Integer.toString(packageInfo.versionCode)); 191 | setValue(KEY_APP_VERSION_NAME, packageInfo.versionName); 192 | setValue(KEY_APP_INSTALLER_PACKAGE_NAME, context.getPackageManager().getInstallerPackageName(packageName)); 193 | setValue(KEY_DEVICE_BRAND, android.os.Build.BRAND); 194 | setValue(KEY_DEVICE_PRODUCT, android.os.Build.PRODUCT); 195 | setValue(KEY_DEVICE_MODEL, android.os.Build.MODEL); 196 | setValue(KEY_DEVICE_API_LEVEL, Integer.toString(android.os.Build.VERSION.SDK_INT)); 197 | setValue(KEY_DEVICE_IS_TABLET, Boolean.toString(Utilities.isTablet(context))); 198 | setValue(KEY_DEVICE_LANGUAGE, context.getResources().getConfiguration().locale.getLanguage()); 199 | setValue(KEY_DEVICE_MCC, Integer.toString(context.getResources().getConfiguration().mcc)); 200 | setValue(KEY_DEVICE_MNC, Integer.toString(context.getResources().getConfiguration().mnc)); 201 | setValue(KEY_UPDATER_LEVEL, Integer.toString(Configuration.UPDATER_LEVEL)); 202 | setValue(KEY_DEVICE_OS_NAME, "android"); 203 | setValue(KEY_DEVICE_OS_VERSION, android.os.Build.VERSION.RELEASE); 204 | 205 | String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID); 206 | if(!Utilities.isNullOrEmpty(androidId)) { 207 | try { 208 | final MessageDigest digest = MessageDigest.getInstance("SHA-256"); 209 | digest.reset(); 210 | androidId = "7c1094d7ea9c4da11d17" + androidId; 211 | final byte[] ba = digest.digest(androidId.getBytes("UTF-8")); 212 | androidId = Base64.encodeToString(ba, Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); 213 | setValue(KEY_DEVICE_ID, androidId); 214 | } catch (Exception e) { 215 | Log.e("couldn't calculate device id hash", e); 216 | } 217 | } 218 | 219 | 220 | 221 | } 222 | 223 | /** 224 | * Returns value of given key 225 | * @param key 226 | * @return value if key is found, otherwise null 227 | */ 228 | public String getValue(String key) { 229 | return map.get(key); 230 | } 231 | 232 | /** 233 | * Adds or overrides settings 234 | * 235 | * @param key 236 | * @param value 237 | */ 238 | public void setValue(String key, String value) { 239 | map.put(key, value); 240 | } 241 | 242 | /** 243 | * Returns a {@link Map} containing property keys and values. 244 | * @return map containing property keys and values. 245 | */ 246 | public Map toMap() { 247 | return new HashMap(map); 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/RestFailureHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | interface RestFailureHandler { 21 | void onFail(Exception ex); 22 | } 23 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/RestJsonObjectResultHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import org.json.JSONObject; 21 | 22 | interface RestJsonObjectResultHandler extends RestFailureHandler { 23 | void onSuccess(JSONObject jsonObject); 24 | } 25 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/RestNoValueResultHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | interface RestNoValueResultHandler extends RestFailureHandler { 21 | void onSuccess(); 22 | } 23 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/RestRequest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.IOException; 22 | import java.io.UnsupportedEncodingException; 23 | import java.net.URI; 24 | 25 | import org.apache.http.Header; 26 | import org.apache.http.HttpEntity; 27 | import org.apache.http.HttpResponse; 28 | import org.apache.http.StatusLine; 29 | import org.apache.http.client.ClientProtocolException; 30 | import org.apache.http.client.HttpClient; 31 | import org.apache.http.client.methods.HttpDelete; 32 | import org.apache.http.client.methods.HttpGet; 33 | import org.apache.http.client.methods.HttpPost; 34 | import org.apache.http.client.methods.HttpPut; 35 | import org.apache.http.client.methods.HttpUriRequest; 36 | import org.apache.http.entity.ByteArrayEntity; 37 | import org.json.JSONException; 38 | import org.json.JSONObject; 39 | 40 | import android.os.AsyncTask; 41 | 42 | class RestRequest { 43 | 44 | enum HttpMethod { 45 | GET, 46 | PUT, 47 | POST, 48 | DELETE 49 | } 50 | 51 | private HttpMethod httpMethod = HttpMethod.GET; 52 | private URI uri; 53 | protected URI getUri() { 54 | return uri; 55 | } 56 | 57 | protected void setUri(URI uri) { 58 | this.uri = uri; 59 | } 60 | 61 | private JSONObject inputJsonObject; 62 | 63 | private RestNoValueResultHandler noValueResultHandler; 64 | private RestJsonObjectResultHandler jsonObjectResultHandler; 65 | 66 | private int[] expectedHttpStatusCodes = {200, 201, 202, 204}; 67 | 68 | private void setResultHandlerNone() { 69 | this.noValueResultHandler = null; 70 | this.jsonObjectResultHandler = null; 71 | } 72 | 73 | 74 | protected final void setResultHandler(RestNoValueResultHandler noValueResultHandler) { 75 | Utilities.checkArgumentNotNull("noValueResultHandler", noValueResultHandler); 76 | 77 | setResultHandlerNone(); 78 | 79 | this.noValueResultHandler = noValueResultHandler; 80 | } 81 | 82 | protected final void setResultHandler(RestJsonObjectResultHandler jsonObjectResultHandler) { 83 | Utilities.checkArgumentNotNull("jsonObjectResultHandler", jsonObjectResultHandler); 84 | 85 | setResultHandlerNone(); 86 | 87 | this.jsonObjectResultHandler = jsonObjectResultHandler; 88 | } 89 | 90 | private RestFailureHandler getFailureHandler() { 91 | if(noValueResultHandler != null) { 92 | return noValueResultHandler; 93 | } 94 | 95 | return jsonObjectResultHandler; 96 | } 97 | 98 | protected final void setInputNone() { 99 | this.inputJsonObject = null; 100 | } 101 | 102 | protected final void setInput(JSONObject inputJsonObject) { 103 | Utilities.checkArgumentNotNull("inputJsonObject", inputJsonObject); 104 | 105 | setInputNone(); 106 | 107 | this.inputJsonObject = inputJsonObject; 108 | } 109 | 110 | protected final RestNoValueResultHandler getNoValueResultHandler() { 111 | return noValueResultHandler; 112 | } 113 | 114 | protected final RestJsonObjectResultHandler getJsonObjectResultHandler() { 115 | return jsonObjectResultHandler; 116 | } 117 | 118 | protected final JSONObject getInputJsonObject() { 119 | return inputJsonObject; 120 | } 121 | 122 | protected final int[] getExpectedHttpStatusCodes() { 123 | return expectedHttpStatusCodes; 124 | } 125 | 126 | protected final void setExpectedHttpStatusCodes(int expectedHttpStatusCode) { 127 | this.expectedHttpStatusCodes = new int[]{expectedHttpStatusCode}; 128 | } 129 | 130 | protected final void setExpectedHttpStatusCodes(int... expectedHttpStatusCodes) { 131 | this.expectedHttpStatusCodes = expectedHttpStatusCodes; 132 | } 133 | 134 | protected final HttpMethod getHttpMethod() { 135 | return httpMethod; 136 | } 137 | 138 | protected final void setHttpMethod(HttpMethod httpMethod) { 139 | this.httpMethod = httpMethod; 140 | } 141 | 142 | protected HttpUriRequest createHttpRequest() throws Exception { 143 | final HttpMethod method = getHttpMethod(); 144 | if(method==null) { 145 | throw new Exception("HTTP method should not be null"); 146 | } 147 | 148 | final HttpUriRequest result; 149 | 150 | switch (method) { 151 | case GET: 152 | result = createHttpGetRequest(); 153 | break; 154 | case POST: 155 | result = createHttpPostRequest(); 156 | break; 157 | case PUT: 158 | result = createHttpPutRequest(); 159 | break; 160 | case DELETE: 161 | result = createHttpDeleteRequest(); 162 | break; 163 | default: 164 | throw new Exception("Unknown HTTP method:" + httpMethod.toString()); 165 | } 166 | 167 | return result; 168 | } 169 | 170 | protected void appendHeaders(HttpUriRequest request) { 171 | } 172 | 173 | private HttpGet createHttpGetRequest() { 174 | final HttpGet result = new HttpGet(); 175 | result.setURI(getUri()); 176 | appendHeaders(result); 177 | return result; 178 | } 179 | 180 | private HttpPost createHttpPostRequest() throws Exception { 181 | final HttpPost result = new HttpPost(); 182 | result.setURI(getUri()); 183 | appendHeaders(result); 184 | result.setEntity(getRequestContents()); 185 | return result; 186 | } 187 | 188 | private HttpPut createHttpPutRequest() throws Exception { 189 | final HttpPut result = new HttpPut(); 190 | result.setURI(getUri()); 191 | appendHeaders(result); 192 | result.setEntity(getRequestContents()); 193 | return result; 194 | } 195 | 196 | private HttpDelete createHttpDeleteRequest() { 197 | final HttpDelete result = new HttpDelete(); 198 | result.setURI(getUri()); 199 | appendHeaders(result); 200 | return result; 201 | } 202 | 203 | 204 | /** 205 | * Subclasses may override this method to place different object types to request body 206 | * @return contents of request. 207 | * @throws JsonConversionException 208 | * @throws JSONException 209 | */ 210 | protected HttpEntity getRequestContents() throws Exception { 211 | try { 212 | final JSONObject jsonObject; 213 | if(inputJsonObject==null) { 214 | jsonObject = new JSONObject(); 215 | } else { 216 | jsonObject = inputJsonObject; 217 | } 218 | 219 | final String string = jsonObject.toString(); 220 | 221 | final byte[] bytes; 222 | bytes = string.getBytes("UTF-8"); 223 | 224 | final ByteArrayEntity result = new ByteArrayEntity(bytes); 225 | result.setContentType("application/json; charset=UTF-8"); 226 | 227 | return result; 228 | 229 | } catch (Exception e) { 230 | throw new Exception("Couldn't create request contents", e); 231 | } 232 | } 233 | 234 | protected String getExpectedResponseContentType() { 235 | return "application/json"; 236 | } 237 | 238 | protected byte[] getByteArrayFromResponse(HttpResponse response) throws IOException { 239 | final HttpEntity entity = response.getEntity(); 240 | if(entity==null) { 241 | return null; 242 | } 243 | 244 | final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 245 | try { 246 | entity.writeTo(byteArrayOutputStream); 247 | return byteArrayOutputStream.toByteArray(); 248 | } finally { 249 | try { 250 | entity.consumeContent(); 251 | } catch (Exception e) { 252 | // Omit 253 | } 254 | try { 255 | byteArrayOutputStream.close(); 256 | } catch (Exception e) { 257 | } 258 | } 259 | } 260 | 261 | protected String getStringFromResponse(HttpResponse response) throws IOException, UnsupportedEncodingException { 262 | final byte[] byteArray = getByteArrayFromResponse(response); 263 | if(byteArray==null) { 264 | return null; 265 | } 266 | return new String(byteArray, "UTF-8"); 267 | } 268 | 269 | protected JSONObject getJsonObjectFromResponse(HttpResponse response) 270 | throws IOException, UnsupportedEncodingException, Exception { 271 | 272 | String json = getStringFromResponse(response); 273 | 274 | // see http://code.google.com/p/android/issues/detail?id=18508 275 | json = Utilities.removeUTF8BOM(json); 276 | 277 | JSONObject jsonObject = null; 278 | if(json!=null) { 279 | try { 280 | jsonObject = new JSONObject(json); 281 | } catch (JSONException e) { 282 | throw new Exception("Json result couldn't be parsed", e); 283 | } 284 | } 285 | return jsonObject; 286 | } 287 | 288 | protected void proccessJsonResponseContents(JSONObject jsonObject) throws Exception { 289 | if(jsonObjectResultHandler != null) { 290 | if(jsonObject==null) { 291 | throw new Exception("Json object is null"); 292 | } 293 | jsonObjectResultHandler.onSuccess(jsonObject); 294 | 295 | } else if(noValueResultHandler!=null){ 296 | noValueResultHandler.onSuccess(); 297 | 298 | } else { 299 | throw new Exception("No result handlers found"); 300 | 301 | } 302 | } 303 | 304 | void execute(final HttpClient client) throws Exception { 305 | try { 306 | final HttpResponse response; 307 | try { 308 | response = client.execute(createHttpRequest()); 309 | } catch (ClientProtocolException e) { 310 | throw new Exception(e); 311 | } 312 | checkResponse(response); 313 | final JSONObject jsonObject = getJsonObjectFromResponse(response); 314 | proccessJsonResponseContents(jsonObject); 315 | 316 | } catch (Exception e) { 317 | final RestFailureHandler failureHandler = getFailureHandler(); 318 | if(failureHandler==null) { 319 | e.printStackTrace(); 320 | } else { 321 | try { 322 | failureHandler.onFail(e); 323 | } catch (Exception e1) { 324 | e1.printStackTrace(); 325 | } 326 | } 327 | } 328 | } 329 | 330 | AsyncTask executeAsync(final HttpClient client) throws Exception { 331 | final Worker worker = new Worker(client); 332 | worker.execute(); 333 | return worker; 334 | } 335 | 336 | protected void checkResponse(HttpResponse response) throws Exception { 337 | if(response == null) { 338 | throw new Exception("Response is null."); 339 | } 340 | checkResponseStatus(response); 341 | checkResponseContentType(response); 342 | } 343 | 344 | private void checkResponseStatus(HttpResponse response) throws Exception { 345 | final StatusLine statusLine = response.getStatusLine(); 346 | 347 | if(statusLine == null) { 348 | throw new Exception("Status line is null."); 349 | } 350 | 351 | final int statusCode = statusLine.getStatusCode(); 352 | final int[] expectedHttpStatusCodes = getExpectedHttpStatusCodes(); 353 | if(expectedHttpStatusCodes!=null) { 354 | if(!Utilities.isElementFound(expectedHttpStatusCodes, statusCode)) { 355 | throw new Exception("Unexpected status code: " + statusCode); 356 | } 357 | } 358 | } 359 | 360 | private void checkResponseContentType(HttpResponse response) throws Exception { 361 | final String expectedResponseContentType = getExpectedResponseContentType(); 362 | if(expectedResponseContentType!=null) { 363 | final Header contentTypeHeader = response.getFirstHeader("Content-Type"); 364 | if(contentTypeHeader==null) { 365 | throw new Exception("Missing content-type header. '" + expectedResponseContentType + "' is expected"); 366 | } 367 | 368 | final String contentType = contentTypeHeader.getValue(); 369 | if(Utilities.isNullOrEmpty(contentType)) { 370 | throw new Exception("Missing content-type header value. '" + expectedResponseContentType + "' is expected"); 371 | } 372 | 373 | if(!contentType.startsWith(expectedResponseContentType)) { 374 | throw new Exception("Unexpected content-type header value: '" + contentType + "'. '" + expectedResponseContentType + "' is expected"); 375 | } 376 | 377 | } 378 | } 379 | 380 | class Worker extends AsyncTask { 381 | final HttpClient client; 382 | private HttpUriRequest request; 383 | 384 | private Worker(HttpClient client) { 385 | super(); 386 | this.client = client; 387 | } 388 | 389 | private volatile Exception exception; 390 | 391 | @Override 392 | protected void onPreExecute() { 393 | super.onPreExecute(); 394 | try { 395 | request = createHttpRequest(); 396 | } catch (Exception e) { 397 | exception = e; 398 | } 399 | } 400 | 401 | @Override 402 | protected JSONObject doInBackground(Void... params) { 403 | if(exception!=null) { 404 | return null; 405 | } 406 | 407 | 408 | HttpResponse response = null; 409 | try { 410 | try { 411 | response = client.execute(request); 412 | } catch (ClientProtocolException e) { 413 | throw new Exception(e); 414 | } 415 | 416 | 417 | checkResponse(response); 418 | 419 | return getJsonObjectFromResponse(response); 420 | } catch (Exception e) { 421 | 422 | // ensure that connection is released 423 | if(response != null) { 424 | final HttpEntity entity = response.getEntity(); 425 | if(entity != null) { 426 | try { 427 | entity.consumeContent(); 428 | } catch (IOException e1) { 429 | // omitted 430 | } 431 | } 432 | } 433 | 434 | exception = e; 435 | return null; 436 | } 437 | } 438 | 439 | @Override 440 | protected void onCancelled() { 441 | try { 442 | if(request!=null) { 443 | request.abort(); 444 | } 445 | } catch (Exception e) { 446 | // omitted 447 | } 448 | super.onCancelled(); 449 | } 450 | 451 | 452 | @Override 453 | protected void onPostExecute(JSONObject result) { 454 | if(exception==null) { 455 | try { 456 | proccessJsonResponseContents(result); 457 | return; 458 | } catch (Exception e) { 459 | exception = e; 460 | } 461 | } 462 | 463 | final RestFailureHandler failureHandler = getFailureHandler(); 464 | if(failureHandler==null) { 465 | exception.printStackTrace(); 466 | } else { 467 | try { 468 | failureHandler.onFail(exception); 469 | } catch (Exception e1) { 470 | e1.printStackTrace(); 471 | } 472 | } 473 | 474 | 475 | } 476 | 477 | 478 | 479 | } 480 | 481 | } 482 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/TurkcellUpdater.java: -------------------------------------------------------------------------------- 1 | package tr.com.turkcellteknoloji.turkcellupdater; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | 6 | import java.net.URI; 7 | 8 | import tr.com.turkcellteknoloji.turkcellupdater.UpdateManager.UpdateCheckListener; 9 | import tr.com.turkcellteknoloji.turkcellupdater.UpdaterDialogManager.UpdaterUiListener; 10 | 11 | /** 12 | * Turkcell Android uygulamalarinin guncelleme durumlarini kontrol eder ve otomatik yonlendirmeler saglar. 13 | * 14 | * @author Ibrahim Menekse 15 | */ 16 | public final class TurkcellUpdater { 17 | 18 | /** 19 | * Guncelleme kontrolu yapildiktan sonra tetiklenen metodlari barindirir. 20 | * Bu callback, SDK'nin varsayilan dialog'u gosterilmeyip guncelleme durumlari manual islenecegi durumda TurkcellUpdater instance'ina set'lenir. 21 | */ 22 | public interface TurkcellUpdaterCallback { 23 | 24 | /** 25 | * Zorunlu guncelleme oldugunda tetiklenir. 26 | * 27 | * @param message 28 | * @param warnings 29 | * @param whatIsNew 30 | */ 31 | void onForceUpdateReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton); 32 | 33 | /** 34 | * Hizmet kullanilamadigi durumda tetiklenir. 35 | * 36 | * @param message 37 | * @param warnings 38 | * @param whatIsNew 39 | */ 40 | void onForceExitReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton); 41 | 42 | /** 43 | * Zorunlu olmayan guncelleme durumunda tetiklenir. 44 | * 45 | * @param message 46 | * @param warnings 47 | * @param whatIsNew 48 | */ 49 | void onNonForceUpdateReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton); 50 | 51 | /** 52 | * Kullaniciya gosterilmesi gereken mesaj geldiginde tetiklenir. 53 | * 54 | * @param title 55 | * @param message 56 | * @param imageUrl 57 | * @param redirectionUri 58 | */ 59 | void onMessageReceive(String title, String message, String positiveButton, String negativeButton, String imageUrl, Uri redirectionUri); 60 | 61 | /** 62 | * Hicbir guncelleme ve mesaj olmadigi durumda tetiklenir. 63 | */ 64 | void onUpdateNotFoundReceive(); 65 | 66 | /** 67 | * Guncelleme sunucusuna baglanilamadiginda yada bir hata ile karsilasildiginda tetiklenir. 68 | * 69 | * @param e 70 | */ 71 | void onUpdaterErrorReceive(Exception e); 72 | } 73 | 74 | private static final String GOOGLE_PLAY_BASE_URL = "http://play.google.com/store/apps/details?id="; 75 | 76 | private Activity mActivity; 77 | private Properties mProperties; 78 | private UpdateManager mUpdateManager; 79 | private String mUpdateServerUrl; 80 | private TurkcellUpdaterCallback mTurkcellUpdaterCallback; 81 | private UpdaterUiListener mDefaultDialogCallback; 82 | 83 | public TurkcellUpdater(Activity activity, String updaterServerUrl) { 84 | mActivity = activity; 85 | mUpdateServerUrl = updaterServerUrl; 86 | mProperties = new Properties(mActivity); 87 | mUpdateManager = new UpdateManager(); 88 | } 89 | 90 | /** 91 | * Kontrol sonrasi islemler manual yapilacaksa bu metod ile {@link TurkcellUpdaterCallback) callback'i set'lenir. 92 | * 93 | * @param callback 94 | */ 95 | public void setTurkcellUpdaterCallback(TurkcellUpdaterCallback callback) { 96 | mTurkcellUpdaterCallback = callback; 97 | } 98 | 99 | /** 100 | * SDK'nin varsayilan dialog'u gosterilerek otomatik yonlendirme yapilacaksa bu metod ile {@link UpdaterUiListener} callback'i set'lenir. 101 | * 102 | * @param listener 103 | */ 104 | public void setDefaultDialogCallback(UpdaterUiListener listener) { 105 | mDefaultDialogCallback = listener; 106 | } 107 | 108 | /** 109 | * Guncelleme kontrolunu baslatir. Bu metod cagrilmadan once callback set'lenmelidir. 110 | * 111 | * @param showDefaultDialog SDK'nin varsayilan dialog'u gosterilerek otomatik yonlendirme yapilacaksa true, 112 | * kontrol sonrasi islemler manual yapilacaksa false gonderilmesi gerekli. 113 | */ 114 | public void check(boolean showDefaultDialog) { 115 | if (showDefaultDialog) { 116 | if (mDefaultDialogCallback == null) { 117 | throw new RuntimeException("You should set UpdaterUiListener (default dialog callback) before check"); 118 | } 119 | UpdaterDialogManager updaterUI = new UpdaterDialogManager(mUpdateServerUrl); 120 | updaterUI.startUpdateCheck(mActivity, mDefaultDialogCallback); 121 | } else { 122 | if (mTurkcellUpdaterCallback == null) { 123 | throw new RuntimeException("You should set TurkcellUpdaterCallback before check"); 124 | } 125 | try { 126 | URI versionServerUri = new URI(mUpdateServerUrl); 127 | mUpdateManager.checkUpdates(mActivity, versionServerUri, mProperties, true, mUpdateCheckListener); 128 | } catch (Exception e) { 129 | if (mTurkcellUpdaterCallback != null) { 130 | mTurkcellUpdaterCallback.onUpdaterErrorReceive(e); 131 | } 132 | } 133 | } 134 | } 135 | 136 | private UpdateCheckListener mUpdateCheckListener = new UpdateCheckListener() { 137 | @Override 138 | public void onUpdateCheckCompleted(UpdateManager manager, Update update) { 139 | UpdateDescription description = update.description; 140 | String warnings = null; 141 | String message = null; 142 | String whatIsNew = null; 143 | String positiveButton = null; 144 | String negativeButton = null; 145 | if (description != null) { 146 | warnings = update.description.get(UpdateDescription.KEY_WARNINGS); 147 | message = update.description.get(UpdateDescription.KEY_MESSAGE); 148 | whatIsNew = update.description.get(UpdateDescription.KEY_WHAT_IS_NEW); 149 | positiveButton = update.description.get(UpdateDescription.KEY_POSITIVE_BUTTON); 150 | negativeButton = update.description.get(UpdateDescription.KEY_NEGATIVE_BUTTON); 151 | } 152 | if (update.forceExit) { 153 | if (mTurkcellUpdaterCallback != null) { 154 | mTurkcellUpdaterCallback.onForceExitReceive(message, warnings, whatIsNew, positiveButton, negativeButton); 155 | } 156 | } else if (update.forceUpdate) { 157 | if (mTurkcellUpdaterCallback != null) { 158 | mTurkcellUpdaterCallback.onForceUpdateReceive(message, warnings, whatIsNew, positiveButton, negativeButton); 159 | } 160 | } else { 161 | if (mTurkcellUpdaterCallback != null) { 162 | mTurkcellUpdaterCallback.onNonForceUpdateReceive(message, warnings, whatIsNew, positiveButton, negativeButton); 163 | } 164 | } 165 | } 166 | 167 | @Override 168 | public void onUpdateCheckCompleted(UpdateManager manager, Message message) { 169 | MessageDescription description = message.description; 170 | String title = null; 171 | String messageText = null; 172 | String positiveButton = null; 173 | String negativeButton = null; 174 | String imageUrl = null; 175 | Uri redirectionUri = null; 176 | if (description != null) { 177 | title = description.get(MessageDescription.KEY_TITLE); 178 | messageText = description.get(MessageDescription.KEY_MESSAGE); 179 | imageUrl = description.get(MessageDescription.KEY_IMAGE_URL); 180 | positiveButton = description.get(MessageDescription.KEY_POSITIVE_BUTTON); 181 | negativeButton = description.get(MessageDescription.KEY_NEGATIVE_BUTTON); 182 | } 183 | if (message.targetGooglePlay && message.targetPackageName != null) { 184 | String packageName = message.targetPackageName; 185 | redirectionUri = Uri.parse(GOOGLE_PLAY_BASE_URL + packageName); 186 | } else if (message.targetWebsiteUrl != null) { 187 | redirectionUri = Uri.parse(message.targetWebsiteUrl.toExternalForm()); 188 | } 189 | if (mTurkcellUpdaterCallback != null) { 190 | mTurkcellUpdaterCallback.onMessageReceive(title, messageText, positiveButton, negativeButton, imageUrl, redirectionUri); 191 | } 192 | } 193 | 194 | @Override 195 | public void onUpdateCheckCompleted(UpdateManager manager) { 196 | if (mTurkcellUpdaterCallback != null) { 197 | mTurkcellUpdaterCallback.onUpdateNotFoundReceive(); 198 | } 199 | } 200 | 201 | @Override 202 | public void onUpdateCheckFailed(UpdateManager manager, Exception exception) { 203 | if (mTurkcellUpdaterCallback != null) { 204 | mTurkcellUpdaterCallback.onUpdaterErrorReceive(exception); 205 | } 206 | } 207 | }; 208 | } 209 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Update.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.io.Serializable; 21 | import java.net.URL; 22 | 23 | /** 24 | * Provides information about an deployable application package 25 | * @author Ugur Ozmen 26 | * 27 | */ 28 | public class Update implements Serializable { 29 | /** 30 | * 31 | */ 32 | private static final long serialVersionUID = 1L; 33 | 34 | /** 35 | * User representable information about version. 36 | */ 37 | public final UpdateDescription description; 38 | 39 | /** 40 | * URL of .apk file. null if undefined. 41 | */ 42 | public final URL targetPackageUrl; 43 | 44 | /** 45 | * URL of web page to display user to download this version. null if undefined. 46 | */ 47 | public final URL targetWebsiteUrl; 48 | 49 | /** 50 | * true if update should be performed through Google Play product page. 51 | */ 52 | public final boolean targetGooglePlay; 53 | 54 | 55 | /** 56 | * Version code of referred package. 57 | */ 58 | public final int targetVersionCode; 59 | 60 | /** 61 | * Package name of referred package 62 | */ 63 | public final String targetPackageName; 64 | 65 | /** 66 | * true if current application should not resume without installing this package 67 | */ 68 | public final boolean forceUpdate; 69 | 70 | /** 71 | * Exits application after displaying message. 72 | */ 73 | public final boolean forceExit; 74 | 75 | 76 | Update(UpdateDescription description, URL targetPackageUrl, 77 | URL targetWebsiteUrl, boolean targetGooglePlay, int targetVersionCode, 78 | String targetPackageName, boolean forceUpdate, 79 | boolean forceExit) { 80 | super(); 81 | this.description = description; 82 | this.targetGooglePlay = targetGooglePlay; 83 | this.targetPackageUrl = targetPackageUrl; 84 | this.targetWebsiteUrl = targetWebsiteUrl; 85 | this.targetVersionCode = targetVersionCode; 86 | this.targetPackageName = targetPackageName; 87 | this.forceUpdate = forceUpdate; 88 | this.forceExit = forceExit; 89 | } 90 | 91 | 92 | @Override 93 | public String toString() { 94 | return "Update [description=" + description + ", targetPackageUrl=" 95 | + targetPackageUrl + ", targetWebsiteUrl=" + targetWebsiteUrl 96 | + ", targetGooglePlay=" + targetGooglePlay 97 | + ", targetVersionCode=" + targetVersionCode 98 | + ", targetPackageName=" + targetPackageName + ", forceUpdate=" 99 | + forceUpdate + ", forceExit=" + forceExit + "]"; 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/UpdateDescription.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import org.json.JSONObject; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * Container for update message strings that are displayed in a update notification dialog. 25 | * 26 | * @author Ugur Ozmen 27 | * @see #get(String) 28 | * @see #KEY_WHAT_IS_NEW 29 | * @see #KEY_MESSAGE 30 | * @see #KEY_WARNINGS 31 | * @see #KEY_POSITIVE_BUTTON 32 | * @see #KEY_NEGATIVE_BUTTON 33 | */ 34 | public class UpdateDescription extends LocalizedStringMap { 35 | 36 | /** 37 | * 38 | */ 39 | private static final long serialVersionUID = 1L; 40 | 41 | /** 42 | * Key for summary information describing update contents. 43 | * 44 | * @see #get(String) 45 | */ 46 | public final static String KEY_MESSAGE = "message"; 47 | /** 48 | * Key for text describing changes and new features of new version. 49 | * 50 | * @see #get(String) 51 | */ 52 | public final static String KEY_WHAT_IS_NEW = "whatIsNew"; 53 | 54 | /** 55 | * Key for warning text about the update. Any important issues that user should know before updating should be described here. 56 | * 57 | * @see #get(String) 58 | */ 59 | public final static String KEY_WARNINGS = "warnings"; 60 | 61 | /** 62 | * Key for positive button text of update dialog 63 | * 64 | * @see #get(String) 65 | */ 66 | public final static String KEY_POSITIVE_BUTTON = "positive_button"; 67 | 68 | /** 69 | * Key for negative button text of update dialog 70 | * 71 | * @see #get(String) 72 | */ 73 | public final static String KEY_NEGATIVE_BUTTON = "negative_button"; 74 | 75 | UpdateDescription(String languageCode, String message) { 76 | this(languageCode, message, null, null, null, null); 77 | } 78 | 79 | UpdateDescription(String languageCode, String message, String whatIsNew, String warnings, String positiveButton, String negativeButton) { 80 | super(languageCode, createMap(message, whatIsNew, warnings, positiveButton, negativeButton)); 81 | } 82 | 83 | UpdateDescription(String languageCode, JSONObject jsonObject) { 84 | super(languageCode, jsonObject); 85 | } 86 | 87 | private static Map createMap(String message, String whatIsNew, String warnings, String positiveButton, String negativeButton) { 88 | Map result = new HashMap(); 89 | result.put(KEY_MESSAGE, message); 90 | result.put(KEY_WARNINGS, warnings); 91 | result.put(KEY_WHAT_IS_NEW, whatIsNew); 92 | result.put(KEY_POSITIVE_BUTTON, positiveButton); 93 | result.put(KEY_NEGATIVE_BUTTON, negativeButton); 94 | return result; 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/UpdateDisplayRecords.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import android.annotation.SuppressLint; 19 | import android.content.Context; 20 | import android.content.SharedPreferences; 21 | import android.content.SharedPreferences.Editor; 22 | 23 | import java.util.Date; 24 | import java.util.HashSet; 25 | import java.util.Map; 26 | import java.util.Set; 27 | 28 | /** 29 | * Keeps information about displayed updates like last display date and display count. 30 | *
    31 | * Data kept by this class is backed by an {@link SharedPreferences} object named {@value #SHARED_PREFERENCES_NAME} 32 | * @author Ugur Ozmen 33 | * 34 | */ 35 | class UpdateDisplayRecords { 36 | 37 | static final String SHARED_PREFERENCES_NAME = "turkcell-updater-update-display-records"; 38 | 39 | private final SharedPreferences sharedPreferences; 40 | 41 | /** 42 | * Creates a new instance 43 | * @param context 44 | */ 45 | UpdateDisplayRecords(Context context) { 46 | sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); 47 | } 48 | 49 | /** 50 | * Returns display count of update with given id 51 | * @param id ID of queried update 52 | * @return total display count. 53 | */ 54 | int getUpdateDisplayCount(int id) { 55 | return sharedPreferences.getInt(id + "-display-count", 0); 56 | } 57 | 58 | /** 59 | * Returns last display time of update with given id 60 | * @param id ID of queried update 61 | * @return last display date or null if update is not displayed yet. 62 | */ 63 | Date getUpdateLastDisplayDate(int id) { 64 | final long millis = sharedPreferences.getLong(id + "-last-display-date", 0); 65 | if (millis == 0) { 66 | return null; 67 | } else { 68 | return new Date(millis); 69 | } 70 | } 71 | 72 | /** 73 | * Increases display count of update with given id by one and stores current time as last display date for the update. 74 | * @param id ID of queried update 75 | */ 76 | @SuppressLint("NewApi") 77 | void onUpdateDisplayed(int id) { 78 | onUpdateDisplayed(id, new Date()); 79 | } 80 | 81 | /** 82 | * Test friendly version of {@link #onUpdateDisplayed(int)}. 83 | *
    84 | * Note: This method is should only be used for testing purposes. 85 | * @param id 86 | * @param now 87 | */ 88 | @SuppressLint("NewApi") 89 | @Deprecated 90 | void onUpdateDisplayed(int id, Date now) { 91 | final int updateDisplayCount = getUpdateDisplayCount(id); 92 | final Editor edit = sharedPreferences.edit(); 93 | edit.putInt(id + "-display-count", updateDisplayCount + 1); 94 | edit.putLong(id + "-last-display-date", now.getTime()); 95 | if (android.os.Build.VERSION.SDK_INT > 8) { 96 | edit.apply(); 97 | } else { 98 | edit.commit(); 99 | } 100 | } 101 | 102 | /** 103 | * Deletes record for given id. 104 | *
    105 | * Note: This method is should only be used for testing purposes. 106 | * @param id 107 | */ 108 | @Deprecated 109 | void deleteUpdateRecords(int id) { 110 | final Editor edit = sharedPreferences.edit(); 111 | edit.remove(id + "-display-count"); 112 | edit.remove(id + "-last-display-date"); 113 | edit.commit(); 114 | } 115 | 116 | /** 117 | * Deletes all records. 118 | *
    119 | * Note: This method is should only be used for testing purposes. 120 | */ 121 | @Deprecated 122 | void deleteAllRecords() { 123 | final Map all = sharedPreferences.getAll(); 124 | Set keys = new HashSet(all.keySet()); 125 | final Editor edit = sharedPreferences.edit(); 126 | for (String key : keys) { 127 | edit.remove(key); 128 | } 129 | edit.commit(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/UpdateEntry.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import android.content.Context; 19 | 20 | import org.json.JSONObject; 21 | 22 | import java.net.MalformedURLException; 23 | import java.net.URL; 24 | import java.util.Date; 25 | import java.util.Iterator; 26 | import java.util.List; 27 | import java.util.Vector; 28 | 29 | class UpdateEntry extends FilteredEntry { 30 | 31 | final List updateDescriptions; 32 | 33 | final int id; 34 | 35 | final int targetVersionCode; 36 | final String targetPackageName; 37 | 38 | final URL targetPackageUrl; 39 | final URL targetWebsiteUrl; 40 | final boolean targetGooglePlay; 41 | final int displayPeriodInHours; 42 | final int maxDisplayCount; 43 | final boolean forceUpdate; 44 | final boolean forceExit; 45 | 46 | UpdateEntry(List filters, int id, List updateDescriptions, int displayPeriodInHours, int maxDisplayCount, int targetVersionCode, String targetPackageName, URL targetPackageUrl, URL targetWebsiteUrl, boolean targetGooglePlay, boolean forceUpdate, boolean forceExit) throws UpdaterException { 47 | super(filters); 48 | this.updateDescriptions = updateDescriptions; 49 | this.targetVersionCode = targetVersionCode; 50 | this.targetPackageName = targetPackageName; 51 | this.targetPackageUrl = targetPackageUrl; 52 | this.targetWebsiteUrl = targetWebsiteUrl; 53 | this.targetGooglePlay = targetGooglePlay; 54 | this.forceUpdate = forceUpdate; 55 | this.forceExit = forceExit; 56 | this.displayPeriodInHours = displayPeriodInHours; 57 | this.maxDisplayCount = maxDisplayCount; 58 | this.id = id == 0 ? generateId() : id; 59 | validate(); 60 | } 61 | 62 | UpdateEntry(JSONObject jsonObject) throws UpdaterException { 63 | super(jsonObject); 64 | this.targetVersionCode = jsonObject.optInt("targetVersionCode", -1); 65 | this.forceUpdate = jsonObject.optBoolean("forceUpdate"); 66 | this.forceExit = jsonObject.optBoolean("forceExit"); 67 | this.updateDescriptions = createUpdateDescritions(jsonObject); 68 | this.targetPackageUrl = getUrl(jsonObject, "targetPackageUrl"); 69 | this.targetWebsiteUrl = getUrl(jsonObject, "targetWebsiteUrl"); 70 | this.targetPackageName = Utilities.removeWhiteSpaces(jsonObject.optString("targetPackageName")); 71 | this.targetGooglePlay = jsonObject.optBoolean("targetGooglePlay"); 72 | this.displayPeriodInHours = jsonObject.optInt("displayPeriodInHours", 0); 73 | this.maxDisplayCount = jsonObject.optInt("maxDisplayCount", Integer.MAX_VALUE); 74 | int i = jsonObject.optInt("id", 0); 75 | this.id = i == 0 ? generateId() : i; 76 | validate(); 77 | } 78 | 79 | private int generateId() { 80 | final int prime = 31; 81 | int result = 1; 82 | result = prime * result + (targetGooglePlay ? 1231 : 1237); 83 | result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); 84 | result = prime * result + ((targetWebsiteUrl == null) ? 0 : targetWebsiteUrl.hashCode()); 85 | result = prime * result + ((updateDescriptions == null) ? 0 : updateDescriptions.hashCode()); 86 | return result; 87 | } 88 | 89 | private static URL getUrl(JSONObject jsonObject, String key) throws UpdaterException { 90 | String spec = Utilities.removeWhiteSpaces(jsonObject.optString(key)); 91 | if ("".equals(spec)) { 92 | return null; 93 | } 94 | try { 95 | return new URL(spec); 96 | } catch (MalformedURLException e) { 97 | throw new UpdaterException("'" + key + "' url is malformatted", e); 98 | } 99 | } 100 | 101 | private static List createUpdateDescritions(JSONObject jsonObject) { 102 | final List result = new Vector(); 103 | final JSONObject udsObject = jsonObject.optJSONObject("descriptions"); 104 | if (udsObject != null) { 105 | Iterator languages = udsObject.keys(); 106 | while (languages.hasNext()) { 107 | String languageCode = languages.next().toString(); 108 | final JSONObject o = udsObject.optJSONObject(languageCode); 109 | if (o != null) { 110 | UpdateDescription ud = new UpdateDescription(languageCode, o); 111 | result.add(ud); 112 | } else { 113 | final String s = udsObject.optString(languageCode, null); 114 | if (s != null) { 115 | UpdateDescription ud = new UpdateDescription(languageCode, s); 116 | result.add(ud); 117 | } 118 | } 119 | } 120 | } 121 | return result; 122 | } 123 | 124 | Update getUpdate(Properties properties, UpdateDisplayRecords records) throws UpdaterException { 125 | Date now = new Date(); 126 | String languageCode = null; 127 | if (properties != null) { 128 | final String s = properties.getValue(Properties.KEY_DEVICE_LANGUAGE); 129 | if (!Utilities.isNullOrEmpty(s)) { 130 | languageCode = s; 131 | } 132 | } 133 | String packageName = this.targetPackageName; 134 | if (Utilities.isNullOrEmpty(packageName) && properties != null) { 135 | packageName = properties.getValue(Properties.KEY_APP_PACKAGE_NAME); 136 | } 137 | if (Utilities.isNullOrEmpty(packageName)) { 138 | throw new UpdaterException("'packageName' property should not be null or empty."); 139 | } 140 | if (!forceUpdate && !forceExit) { 141 | if (maxDisplayCount < Integer.MAX_VALUE) { 142 | final int count = records.getUpdateDisplayCount(id); 143 | if (count >= maxDisplayCount) { 144 | return null; 145 | } 146 | } 147 | // check if it is displayed earlier than specified period 148 | if (displayPeriodInHours > 0) { 149 | final Date updateLastDisplayDate = records.getUpdateLastDisplayDate(id); 150 | // check if message displayed before 151 | if (updateLastDisplayDate != null) { 152 | final Date date = Utilities.addHours(now, -displayPeriodInHours); 153 | if (updateLastDisplayDate.after(date)) { 154 | return null; 155 | } 156 | } 157 | } 158 | } 159 | final UpdateDescription updateDescription = LocalizedStringMap.select(updateDescriptions, languageCode); 160 | records.onUpdateDisplayed(id, now); 161 | return new Update(updateDescription, targetPackageUrl, targetWebsiteUrl, targetGooglePlay, targetVersionCode, packageName, forceUpdate, forceExit); 162 | } 163 | 164 | private void validate() throws UpdaterException { 165 | if (forceExit) { 166 | return; 167 | } 168 | if (targetVersionCode < 0) { 169 | throw new UpdaterException("'targetVersionCode' shoud be a positive number. Current value: " + targetVersionCode); 170 | } 171 | if (targetPackageUrl == null && targetWebsiteUrl == null && !targetGooglePlay) { 172 | throw new UpdaterException("At least one of 'targetWebsiteUrl' and 'targetPackageUrl' shoud not be a null or 'targetGooglePlay' should be true."); 173 | } 174 | } 175 | 176 | boolean shouldDisplay(Properties properties, UpdateDisplayRecords records, Context context) { 177 | if (isMatches(properties)) { 178 | final Integer currentVersionCode = Utilities.tryParseInteger(properties.getValue(Properties.KEY_APP_VERSION_CODE)); 179 | if (currentVersionCode != null && targetVersionCode > currentVersionCode.intValue()) { 180 | if (forceUpdate || forceExit) { 181 | return true; 182 | } else { 183 | boolean rtn = true; 184 | // check if it is displayed more than specified count 185 | if (maxDisplayCount < Integer.MAX_VALUE) { 186 | final int count = records.getUpdateDisplayCount(id); 187 | if (count >= maxDisplayCount) { 188 | rtn = false; 189 | } 190 | } 191 | // check if it is displayed earlier than specified period 192 | if (displayPeriodInHours > 0) { 193 | final Date updateLastDisplayDate = records.getUpdateLastDisplayDate(id); 194 | // check if update displayed before 195 | if (updateLastDisplayDate != null) { 196 | Date now = new Date(); 197 | final Date date = Utilities.addHours(now, -displayPeriodInHours); 198 | if (updateLastDisplayDate.after(date)) { 199 | rtn = false; 200 | } 201 | } 202 | } 203 | return rtn; 204 | } 205 | } 206 | } 207 | return false; 208 | } 209 | } -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/UpdateManager.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import android.annotation.SuppressLint; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.net.Uri; 22 | import android.os.AsyncTask; 23 | 24 | import org.apache.http.client.HttpClient; 25 | import org.apache.http.impl.client.DefaultHttpClient; 26 | import org.json.JSONObject; 27 | 28 | import java.io.File; 29 | import java.io.FileOutputStream; 30 | import java.net.URI; 31 | import java.net.URL; 32 | 33 | /** 34 | * Provides a auto update mechanism for Android applications 35 | * 36 | * @author Ugur Ozmen 37 | */ 38 | public class UpdateManager { 39 | 40 | private final static int DOWNLOAD_PROGRESS_PERCENT = 95; 41 | 42 | /** 43 | * Provides callback methods for update check results.
    44 | * Conditionally one of 4 methods will be called at the end of a update check: 45 | *

      46 | *
    • A new version is found, {@link UpdateCheckListener#onUpdateCheckCompleted(UpdateManager, Update)}
    • 47 | *
    • A message should be displayed to user, {@link UpdateCheckListener#onUpdateCheckCompleted(UpdateManager, Message)}
    • 48 | *
    • Completed successfully and no messages and no new versions found, {@link UpdateCheckListener#onUpdateCheckCompleted(UpdateManager)}
    • 49 | *
    • Update check is fail due to an error
    • 50 | *
    51 | * 52 | * @author Ugur Ozmen 53 | * @see UpdateManager#checkUpdates(Context, URI, Properties, UpdateCheckListener) 54 | */ 55 | public interface UpdateCheckListener { 56 | 57 | /** 58 | * This method is called when update check is completed successfully and a newer version is found. Implementations should display {@link Update#description} to users. 59 | * Implementations should not provide an option to cancel and continue to application if {@link Update#forceUpdate} is true. 60 | * 61 | * @param manager Update manager that has performed update check. 62 | * @param update Information about next version found. 63 | */ 64 | void onUpdateCheckCompleted(UpdateManager manager, Update update); 65 | 66 | /** 67 | * This method is called when update check is completed successfully and a message should be displayed to user. 68 | * Implementations should not continue normal operation after this message is dismissed. 69 | * 70 | * @param manager Update manager that has performed update check. 71 | * @param message Information delivered from server that should be displayed to user. 72 | */ 73 | void onUpdateCheckCompleted(UpdateManager manager, Message message); 74 | 75 | /** 76 | * This method is called when update check is completed successfully and current version is the latest version. 77 | * 78 | * @param manager Update manager that has performed update check. 79 | */ 80 | void onUpdateCheckCompleted(UpdateManager manager); 81 | 82 | /** 83 | * This method is called when update check is failed. 84 | * 85 | * @param manager Update manager that has performed update check. 86 | * @param exception Failure reason. 87 | */ 88 | void onUpdateCheckFailed(UpdateManager manager, Exception exception); 89 | } 90 | 91 | /** 92 | * Provides callback methods for update process events. 93 | * 94 | * @author Ugur Ozmen 95 | * @see UpdateManager#applyUpdate(Context, Update, UpdateListener) 96 | */ 97 | public interface UpdateListener { 98 | 99 | /** 100 | * Returns a percent value indicating update progress 101 | * 102 | * @param percent null if current state is interminable otherwise percent of completed progress 103 | */ 104 | void onUpdateProgress(Integer percent); 105 | 106 | /** 107 | * Called when update is cancelled. Implementations should close application if {@link Update#forceUpdate} is true. 108 | */ 109 | void onUpdateCancelled(); 110 | 111 | /** 112 | * Called when update is successfully completed. Implementations should close application if {@link Update#forceUpdate} is true. 113 | */ 114 | void onUpdateCompleted(); 115 | 116 | /** 117 | * Indicates that update is failed due to a reason. 118 | * 119 | * @param exception Failure reason. 120 | */ 121 | void onUpdateFailed(Exception exception); 122 | } 123 | 124 | /** 125 | * Creates an instance of {@link UpdateManager}. 126 | */ 127 | public UpdateManager() { 128 | Log.printProductInfo(); 129 | } 130 | 131 | /** 132 | * Starts an asynchronous operation for checking if a newer version of current application is available. 133 | * 134 | * @param context Current context. 135 | * @param versionServerUri Location of update definitions. 136 | * @param currentProperties properties of current application and device. 137 | * @param postProperties true if current properties should post to server for server side processing. 138 | * @param listener Callback listener. 139 | * @throws UpdaterException if operation couldn't be started. 140 | */ 141 | public void checkUpdates(Context context, final URI versionServerUri, Properties currentProperties, boolean postProperties, UpdateCheckListener listener) throws UpdaterException { 142 | final DefaultHttpClient client = Utilities.createClient("TurkcellUpdater/1.0", false); 143 | final VersionMapRequest request = new VersionMapRequest(context, versionServerUri, currentProperties, postProperties, listener); 144 | try { 145 | request.executeAsync(client); 146 | } catch (Exception e) { 147 | throw new UpdaterException(e); 148 | } 149 | } 150 | 151 | /** 152 | * Starts an asynchronous operation for installing newer version of application. 153 | * 154 | * @param context Current context. 155 | * @param update Information about next version. 156 | * @param listener Callback listener. 157 | */ 158 | public void applyUpdate(Context context, Update update, final UpdateListener listener) { 159 | if (update.targetGooglePlay) { 160 | openGooglePlayPage(context, update.targetPackageName, listener); 161 | } else if (update.targetWebsiteUrl != null) { 162 | openWebPage(context, update.targetWebsiteUrl, listener); 163 | } else if (update.targetPackageUrl != null) { 164 | try { 165 | final DownloadRequest dr = new DownloadRequest(); 166 | dr.setUri(update.targetPackageUrl.toURI()); 167 | dr.setExpectedContentType("application/vnd.android.package-archive"); 168 | dr.setDownloadHandler(new DownloadHandlerAdapter(context, listener)); 169 | HttpClient client = Utilities.createClient("Turkcell Updater/1.0 ", false); 170 | dr.executeAsync(client); 171 | } catch (Exception e) { 172 | if (listener == null) { 173 | Log.e("Update failed", e); 174 | } else { 175 | listener.onUpdateFailed(e); 176 | } 177 | } 178 | } 179 | } 180 | 181 | private final class DownloadHandlerAdapter implements DownloadHandler { 182 | 183 | private final UpdateListener listener; 184 | private final Context context; 185 | 186 | private DownloadHandlerAdapter(Context context, UpdateListener listener) { 187 | this.listener = listener; 188 | this.context = context; 189 | } 190 | 191 | @Override 192 | public void onSuccess(byte[] result) { 193 | try { 194 | installPackage(context, result, listener); 195 | } catch (Exception e) { 196 | if (listener != null) { 197 | listener.onUpdateFailed(e); 198 | } 199 | } 200 | } 201 | 202 | @Override 203 | public void onProgress(Integer percent) { 204 | if (listener != null) { 205 | if (percent != null) { 206 | percent *= DOWNLOAD_PROGRESS_PERCENT; 207 | percent /= 100; 208 | } 209 | listener.onUpdateProgress(percent); 210 | } 211 | } 212 | 213 | @Override 214 | public void onFail(Exception ex) { 215 | if (listener == null) { 216 | Log.e("Update failed", ex); 217 | } else { 218 | listener.onUpdateFailed(ex); 219 | } 220 | } 221 | 222 | @Override 223 | public void onCancelled() { 224 | if (listener != null) { 225 | listener.onUpdateCancelled(); 226 | } 227 | } 228 | } 229 | 230 | private void installPackage(final Context context, final byte[] apkContents, final UpdateListener listener) { 231 | final AsyncTask task = new AsyncTask() { 232 | volatile Exception exception; 233 | 234 | @SuppressLint("WorldReadableFiles") 235 | @Override 236 | protected File doInBackground(Void... params) { 237 | try { 238 | if (Utilities.isNullOrEmpty(apkContents)) { 239 | throw new NullPointerException("apkContents"); 240 | } 241 | String tempFileName = "nextversion.apk"; 242 | File tempFile = context.getFileStreamPath(tempFileName); 243 | if (tempFile.exists()) { 244 | tempFile.delete(); 245 | } 246 | FileOutputStream fout = context.openFileOutput(tempFileName, Context.MODE_WORLD_READABLE); 247 | try { 248 | fout.write(apkContents); 249 | fout.flush(); 250 | } finally { 251 | try { 252 | fout.close(); 253 | } catch (Exception e) { 254 | // omit 255 | } 256 | } 257 | return tempFile; 258 | } catch (Exception e) { 259 | exception = e; 260 | Log.e("Couldn't save apk", e); 261 | return null; 262 | } 263 | } 264 | 265 | @Override 266 | protected void onPostExecute(File result) { 267 | if (exception == null) { 268 | try { 269 | Uri data = Uri.fromFile(result); 270 | String type = "application/vnd.android.package-archive"; 271 | Intent promptInstall = new Intent(Intent.ACTION_VIEW); 272 | promptInstall.setDataAndType(data, type); 273 | context.startActivity(promptInstall); 274 | if (listener != null) { 275 | listener.onUpdateCompleted(); 276 | } 277 | return; 278 | } catch (Exception e) { 279 | exception = e; 280 | } 281 | } 282 | if (listener == null) { 283 | Log.e("Update failed", exception); 284 | } else { 285 | listener.onUpdateFailed(exception); 286 | } 287 | } 288 | }; 289 | task.execute(); 290 | } 291 | 292 | private void openGooglePlayPage(Context context, String packageName, final UpdateListener listener) { 293 | if (listener != null) { 294 | listener.onUpdateProgress(null); 295 | } 296 | try { 297 | try { 298 | context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName))); 299 | } catch (android.content.ActivityNotFoundException anfe) { 300 | context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + packageName))); 301 | } 302 | } catch (Exception e) { 303 | if (listener == null) { 304 | Log.e("open google play page failed", e); 305 | } else { 306 | listener.onUpdateFailed(e); 307 | } 308 | } 309 | if (listener != null) { 310 | listener.onUpdateProgress(100); 311 | listener.onUpdateCompleted(); 312 | } 313 | } 314 | 315 | private void openWebPage(Context context, URL url, final UpdateListener listener) { 316 | if (listener != null) { 317 | listener.onUpdateProgress(null); 318 | } 319 | try { 320 | context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url.toExternalForm()))); 321 | } catch (Exception e) { 322 | if (listener == null) { 323 | Log.e("open web page failed", e); 324 | } else { 325 | listener.onUpdateFailed(e); 326 | } 327 | } 328 | if (listener != null) { 329 | listener.onUpdateProgress(100); 330 | listener.onUpdateCompleted(); 331 | } 332 | } 333 | 334 | private class VersionMapRequest extends RestRequest { 335 | 336 | @Override 337 | protected String getExpectedResponseContentType() { 338 | return Configuration.EXPECTED_JSON_MIME_TYPE; 339 | } 340 | 341 | public VersionMapRequest(final Context context, final URI versionServerUri, final Properties currentProperties, boolean postProperties, final UpdateCheckListener listener) { 342 | if (postProperties && currentProperties != null) { 343 | setHttpMethod(HttpMethod.POST); 344 | setInput(new JSONObject(currentProperties.toMap())); 345 | } else { 346 | setHttpMethod(HttpMethod.GET); 347 | setInputNone(); 348 | } 349 | setUri(versionServerUri); 350 | setResultHandler(new RestJsonObjectResultHandler() { 351 | @Override 352 | public void onFail(Exception e) { 353 | Log.d("Couldn't read update configuration file", e); 354 | listener.onUpdateCheckFailed(UpdateManager.this, e); 355 | } 356 | 357 | @Override 358 | public void onSuccess(JSONObject jsonObject) { 359 | try { 360 | final String packageName = currentProperties.getValue(Properties.KEY_APP_PACKAGE_NAME); 361 | if (jsonObject != null && jsonObject.has("errorMessage")) { 362 | Log.e("Remote error: " + jsonObject.optString("errorMessage")); 363 | } 364 | if (VersionsMap.isVersionMapOfPackageId(packageName, jsonObject)) { 365 | VersionsMap map = new VersionsMap(jsonObject); 366 | UpdateDisplayRecords updateRecords = new UpdateDisplayRecords(context); 367 | final Update update = map.getUpdate(currentProperties, updateRecords, context); 368 | if (update != null) { 369 | Log.i("Update found: " + update); 370 | listener.onUpdateCheckCompleted(UpdateManager.this, update); 371 | } else { 372 | final MessageDisplayRecords records = new MessageDisplayRecords(context); 373 | final Message message = map.getMessage(currentProperties, records, context); 374 | if (message == null) { 375 | Log.i("No update or message found."); 376 | listener.onUpdateCheckCompleted(UpdateManager.this); 377 | } else { 378 | Log.i("Message found: " + message); 379 | listener.onUpdateCheckCompleted(UpdateManager.this, message); 380 | } 381 | } 382 | } else { 383 | throw new UpdaterException("Configuration file packagename should be: " + packageName); 384 | } 385 | } catch (Exception e) { 386 | Log.d("Couldn't process update configuration file", e); 387 | listener.onUpdateCheckFailed(UpdateManager.this, e); 388 | } 389 | } 390 | }); 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/UpdaterException.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | public class UpdaterException extends Exception { 21 | 22 | /** 23 | * 24 | */ 25 | private static final long serialVersionUID = 1L; 26 | 27 | public UpdaterException() { 28 | } 29 | 30 | public UpdaterException(String detailMessage) { 31 | super(detailMessage); 32 | } 33 | 34 | public UpdaterException(Throwable throwable) { 35 | super(throwable); 36 | } 37 | 38 | public UpdaterException(String detailMessage, Throwable throwable) { 39 | super(detailMessage, throwable); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/Utilities.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | package tr.com.turkcellteknoloji.turkcellupdater; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.OutputStream; 24 | import java.net.Socket; 25 | import java.net.UnknownHostException; 26 | import java.security.KeyManagementException; 27 | import java.security.KeyStore; 28 | import java.security.KeyStoreException; 29 | import java.security.NoSuchAlgorithmException; 30 | import java.security.UnrecoverableKeyException; 31 | import java.security.cert.CertificateException; 32 | import java.security.cert.X509Certificate; 33 | import java.text.ParseException; 34 | import java.text.SimpleDateFormat; 35 | import java.util.Arrays; 36 | import java.util.Calendar; 37 | import java.util.Date; 38 | import java.util.Locale; 39 | import java.util.zip.GZIPOutputStream; 40 | 41 | import javax.net.ssl.SSLContext; 42 | import javax.net.ssl.TrustManager; 43 | import javax.net.ssl.X509TrustManager; 44 | 45 | import org.apache.http.client.params.HttpClientParams; 46 | import org.apache.http.conn.params.ConnManagerParams; 47 | import org.apache.http.conn.params.ConnPerRoute; 48 | import org.apache.http.conn.routing.HttpRoute; 49 | import org.apache.http.conn.scheme.PlainSocketFactory; 50 | import org.apache.http.conn.scheme.Scheme; 51 | import org.apache.http.conn.scheme.SchemeRegistry; 52 | import org.apache.http.conn.ssl.SSLSocketFactory; 53 | import org.apache.http.impl.client.DefaultHttpClient; 54 | import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 55 | import org.apache.http.params.BasicHttpParams; 56 | import org.apache.http.params.HttpConnectionParams; 57 | import org.apache.http.params.HttpParams; 58 | import org.apache.http.params.HttpProtocolParams; 59 | 60 | import android.annotation.SuppressLint; 61 | import android.app.Activity; 62 | import android.content.Context; 63 | import android.content.pm.ActivityInfo; 64 | import android.content.pm.ApplicationInfo; 65 | import android.content.pm.PackageInfo; 66 | import android.content.pm.PackageManager; 67 | import android.content.pm.PackageManager.NameNotFoundException; 68 | import android.content.res.Configuration; 69 | import android.content.res.Resources; 70 | import android.graphics.drawable.Drawable; 71 | import android.os.Build; 72 | import android.util.DisplayMetrics; 73 | import android.util.Log; 74 | import android.util.TypedValue; 75 | import android.view.LayoutInflater; 76 | import android.view.Surface; 77 | import android.view.View; 78 | 79 | /** 80 | * Static utility methods 81 | * 82 | * @author Ugur Ozmen 83 | */ 84 | class Utilities { 85 | static boolean isNull(Object o) { 86 | return o == null; 87 | } 88 | 89 | static boolean isNullOrEmpty(String s) { 90 | return isNull(s) || s.length() < 1; 91 | } 92 | 93 | static boolean isNullOrEmpty(int[] array) { 94 | return isNull(array) || array.length < 1; 95 | } 96 | 97 | static boolean isNullOrEmpty(byte[] array) { 98 | return isNull(array) || array.length < 1; 99 | } 100 | 101 | static boolean isNullOrEmpty(short[] array) { 102 | return isNull(array) || array.length < 1; 103 | } 104 | 105 | static boolean isNullOrEmpty(float[] array) { 106 | return isNull(array) || array.length < 1; 107 | } 108 | 109 | static boolean isNullOrEmpty(double[] array) { 110 | return isNull(array) || array.length < 1; 111 | } 112 | 113 | static boolean isNullOrEmpty(long[] array) { 114 | return isNull(array) || array.length < 1; 115 | } 116 | 117 | static boolean isNullOrEmpty(Object[] array) { 118 | return isNull(array) || array.length < 1; 119 | } 120 | 121 | static boolean isEmpty(String s) { 122 | return (!isNull(s)) && s.length() < 1; 123 | } 124 | 125 | static boolean isEmpty(int[] array) { 126 | return (!isNull(array)) && array.length < 1; 127 | } 128 | 129 | static boolean isEmpty(byte[] array) { 130 | return (!isNull(array)) && array.length < 1; 131 | } 132 | 133 | static boolean isEmpty(short[] array) { 134 | return (!isNull(array)) && array.length < 1; 135 | } 136 | 137 | static boolean isEmpty(float[] array) { 138 | return (!isNull(array)) && array.length < 1; 139 | } 140 | 141 | static boolean isEmpty(double[] array) { 142 | return (!isNull(array)) && array.length < 1; 143 | } 144 | 145 | static boolean isEmpty(long[] array) { 146 | return (!isNull(array)) && array.length < 1; 147 | } 148 | 149 | static boolean isEmpty(Object[] array) { 150 | return (!isNull(array)) && array.length < 1; 151 | } 152 | 153 | static void checkArgumentNotNull(String argumentName, Object argument) { 154 | if (isNull(argument)) { 155 | throw new IllegalArgumentException("'" + argumentName 156 | + "' should not be null."); 157 | } 158 | } 159 | 160 | static int getIndexOfElement(int[] array, int element) { 161 | if (array != null) { 162 | for (int i = 0; i < array.length; i++) { 163 | if (array[i] == element) { 164 | return i; 165 | } 166 | } 167 | 168 | } 169 | return -1; 170 | } 171 | 172 | static boolean isElementFound(int[] array, int element) { 173 | return getIndexOfElement(array, element) > -1; 174 | } 175 | 176 | static String getDigits(String s) { 177 | StringBuffer buffer = new StringBuffer(); 178 | for (int i = 0; i < s.length(); i++) { 179 | if (Character.isDigit(s.charAt(i))) { 180 | buffer.append(s.charAt(i)); 181 | } 182 | } 183 | return buffer.toString(); 184 | } 185 | 186 | static Date getStartOfToday() { 187 | return getStartOfDate(new Date()); 188 | } 189 | 190 | static Date getStartOfDate(Date date) { 191 | final Calendar calendar = Calendar.getInstance(); 192 | calendar.setTime(date); 193 | calendar.set(Calendar.HOUR_OF_DAY, 0); 194 | calendar.set(Calendar.MINUTE, 0); 195 | calendar.set(Calendar.SECOND, 0); 196 | calendar.set(Calendar.MILLISECOND, 0); 197 | return calendar.getTime(); 198 | } 199 | 200 | static Date addDays(Date date, int numberOfDays) { 201 | final Calendar calendar = Calendar.getInstance(); 202 | calendar.setTime(date); 203 | calendar.add(Calendar.DAY_OF_YEAR, numberOfDays); 204 | return calendar.getTime(); 205 | } 206 | 207 | static Date addHours(Date date, int numberOfHours) { 208 | final Calendar calendar = Calendar.getInstance(); 209 | calendar.setTime(date); 210 | calendar.add(Calendar.HOUR_OF_DAY, numberOfHours); 211 | return calendar.getTime(); 212 | } 213 | 214 | static float convertPixelsToDp(float px, Context context) { 215 | Resources resources = context.getResources(); 216 | DisplayMetrics metrics = resources.getDisplayMetrics(); 217 | float dp = px / (metrics.densityDpi / 160f); 218 | return dp; 219 | } 220 | 221 | @SuppressLint("NewApi") 222 | static boolean isTablet(Context context) { 223 | if (android.os.Build.VERSION.SDK_INT > 12) { 224 | return context.getResources().getConfiguration().smallestScreenWidthDp > 600; 225 | } else if (android.os.Build.VERSION.SDK_INT > 10) { 226 | int size = context.getResources().getConfiguration().screenLayout 227 | & Configuration.SCREENLAYOUT_SIZE_MASK; 228 | return (size == Configuration.SCREENLAYOUT_SIZE_LARGE) 229 | || (size == Configuration.SCREENLAYOUT_SIZE_XLARGE); 230 | } else { 231 | return false; 232 | } 233 | } 234 | 235 | static String normalize(String string) { 236 | if (string == null) { 237 | return ""; 238 | } 239 | 240 | return removeWhiteSpaces(string.toLowerCase(Locale.ENGLISH)); 241 | } 242 | 243 | static String removeWhiteSpaces(String string) { 244 | if (string == null) { 245 | return ""; 246 | } 247 | 248 | final int length = string.length(); 249 | if (length < 1) { 250 | return string; 251 | } 252 | 253 | StringBuilder sb = new StringBuilder(length); 254 | for (int i = 0; i < length; i++) { 255 | final char c = string.charAt(i); 256 | if (!Character.isWhitespace(c)) { 257 | sb.append(c); 258 | } 259 | } 260 | 261 | return sb.toString(); 262 | } 263 | 264 | static Integer tryParseInteger(String value) { 265 | try { 266 | return Integer.parseInt(value); 267 | } catch (NumberFormatException nfe) { 268 | return null; 269 | } 270 | } 271 | 272 | static Drawable getDrawableByName(Context context, String name) { 273 | final Resources resources = context.getResources(); 274 | final int id = getResourceIdByName(context, "drawable", name); 275 | if (id == 0) { 276 | return null; 277 | } 278 | return resources.getDrawable(id); 279 | } 280 | 281 | static View inflateLayoutByName(Context context, String name) { 282 | final int id = getResourceIdByName(context, "layout", name); 283 | if (id == 0) { 284 | return null; 285 | } 286 | 287 | final View view = LayoutInflater.from(context).inflate(id, null); 288 | return view; 289 | } 290 | 291 | static int getResourceIdByName(Context context, String type, String name) { 292 | final Resources resources = context.getResources(); 293 | final int id = resources.getIdentifier(name, type, 294 | context.getPackageName()); 295 | return id; 296 | } 297 | 298 | static DefaultHttpClient createClient(String userAgent, 299 | boolean acceptAllSslCertificates) { 300 | 301 | HttpParams params = new BasicHttpParams(); 302 | HttpConnectionParams.setStaleCheckingEnabled(params, false); 303 | HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); 304 | 305 | // to make connection pool more fault tolerant 306 | ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRoute() { 307 | public int getMaxForRoute(HttpRoute route) { 308 | return 10; 309 | } 310 | }); 311 | 312 | HttpConnectionParams.setSoTimeout(params, 20 * 1000); 313 | 314 | HttpConnectionParams.setSocketBufferSize(params, 8192); 315 | 316 | HttpClientParams.setRedirecting(params, false); 317 | 318 | HttpProtocolParams.setUserAgent(params, userAgent); 319 | 320 | SSLSocketFactory sslSocketFactory = null; 321 | 322 | if (acceptAllSslCertificates) { 323 | try { 324 | sslSocketFactory = new AcceptAllSocketFactory(); 325 | } catch (Exception e) { 326 | // omitted 327 | } 328 | } 329 | 330 | if (sslSocketFactory == null) { 331 | sslSocketFactory = SSLSocketFactory.getSocketFactory(); 332 | } 333 | 334 | SchemeRegistry schemeRegistry = new SchemeRegistry(); 335 | schemeRegistry.register(new Scheme("http", PlainSocketFactory 336 | .getSocketFactory(), 80)); 337 | schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); 338 | 339 | ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager( 340 | params, schemeRegistry); 341 | 342 | final DefaultHttpClient client = new DefaultHttpClient(manager, params); 343 | 344 | return client; 345 | } 346 | 347 | private static class AcceptAllSocketFactory extends SSLSocketFactory { 348 | SSLContext sslContext = SSLContext.getInstance("TLS"); 349 | 350 | private static KeyStore getTrustedKeyStore() { 351 | try { 352 | KeyStore trusted = KeyStore.getInstance(KeyStore 353 | .getDefaultType()); 354 | 355 | trusted.load(null, null); 356 | 357 | return trusted; 358 | } catch (Exception e) { 359 | throw new AssertionError(e); 360 | } 361 | } 362 | 363 | AcceptAllSocketFactory() throws NoSuchAlgorithmException, 364 | KeyManagementException, KeyStoreException, 365 | UnrecoverableKeyException { 366 | super(getTrustedKeyStore()); 367 | setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); 368 | 369 | TrustManager tm = new X509TrustManager() { 370 | public void checkClientTrusted(X509Certificate[] chain, 371 | String authType) throws CertificateException { 372 | Log.i("connection", "checkClientTrusted: " + authType 373 | + " chain: " + Arrays.asList(chain)); 374 | } 375 | 376 | public void checkServerTrusted(X509Certificate[] chain, 377 | String authType) throws CertificateException { 378 | Log.i("connection", "checkServerTrusted: " + authType 379 | + " chain: " + Arrays.asList(chain)); 380 | } 381 | 382 | public X509Certificate[] getAcceptedIssuers() { 383 | Log.i("connection", "getAcceptedIssuers: "); 384 | return null; 385 | } 386 | 387 | }; 388 | sslContext.init(null, new TrustManager[] { tm }, null); 389 | } 390 | 391 | @Override 392 | public Socket createSocket(Socket socket, String host, int port, 393 | boolean autoClose) throws IOException, UnknownHostException { 394 | return sslContext.getSocketFactory().createSocket(socket, host, 395 | port, autoClose); 396 | } 397 | 398 | @Override 399 | public Socket createSocket() throws IOException { 400 | return sslContext.getSocketFactory().createSocket(); 401 | } 402 | 403 | } 404 | 405 | static byte[] compress(String string) throws IOException { 406 | ByteArrayOutputStream os = new ByteArrayOutputStream(string.length()); 407 | GZIPOutputStream gos = new GZIPOutputStream(os); 408 | gos.write(string.getBytes("UTF-8")); 409 | gos.close(); 410 | byte[] compressed = os.toByteArray(); 411 | os.close(); 412 | return compressed; 413 | } 414 | 415 | static Date parseIsoDate(String string) { 416 | final String[] formats = new String[] { "yyyy-MM-dd'T'HH:mm:ss.SSSZ", 417 | "yyyy-MM-dd HH:mm:ss.SSSZ", "yyyy-MM-dd HH:mm:ssZ", 418 | "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mmZ", "yyyy-MM-dd HH:mm", 419 | "yyyy-MM-dd", }; 420 | 421 | for (String format : formats) { 422 | final SimpleDateFormat simpleDateFormat = new SimpleDateFormat( 423 | format, Locale.US); 424 | try { 425 | return simpleDateFormat.parse(string); 426 | } catch (ParseException e) { 427 | continue; 428 | } 429 | } 430 | 431 | return null; 432 | } 433 | 434 | static boolean isPackageInstalled(Context context, String packageName) { 435 | 436 | checkArgumentNotNull("context", context); 437 | final PackageManager packageManager = context.getPackageManager(); 438 | if (packageManager == null) { 439 | throw new IllegalStateException("packageManager is null."); 440 | } 441 | ApplicationInfo ai = null; 442 | try { 443 | ai = packageManager.getApplicationInfo(packageName, 0); 444 | } catch (NameNotFoundException e) { 445 | return false; 446 | } 447 | 448 | return ai != null; 449 | } 450 | 451 | static boolean isPackageInstalled(Context context, String packageName, 452 | int minVersionCode) { 453 | checkArgumentNotNull("context", context); 454 | final PackageManager packageManager = context.getPackageManager(); 455 | if (packageManager == null) { 456 | throw new IllegalStateException("packageManager is null."); 457 | } 458 | PackageInfo pi = null; 459 | try { 460 | pi = packageManager.getPackageInfo(packageName, 0); 461 | } catch (NameNotFoundException e) { 462 | return false; 463 | } 464 | 465 | return pi != null && pi.versionCode >= minVersionCode; 466 | } 467 | 468 | static void pipe(InputStream is, OutputStream os) throws IOException { 469 | byte[] buffer = new byte[1024]; 470 | int i; 471 | while ((i = is.read(buffer)) > -1) { 472 | os.write(buffer, 0, i); 473 | } 474 | } 475 | 476 | /** 477 | * Copies contents of the stream to a byte array and closes stream. 478 | * 479 | * @param is 480 | * source input stream 481 | * @return created byte array 482 | * @throws IOException 483 | */ 484 | static byte[] getAsByteArray(InputStream is) throws IOException { 485 | if (is == null) { 486 | return null; 487 | } 488 | final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 489 | 490 | try { 491 | Utilities.pipe(is, baos); 492 | } finally { 493 | try { 494 | is.close(); 495 | } catch (IOException e) { 496 | e.printStackTrace(); 497 | } 498 | 499 | baos.close(); 500 | } 501 | 502 | return baos.toByteArray(); 503 | } 504 | 505 | @SuppressLint("NewApi") 506 | static int getScreenOrientation(Activity activity) { 507 | if (Build.VERSION.SDK_INT < 8) { 508 | switch (activity.getResources().getConfiguration().orientation) { 509 | case Configuration.ORIENTATION_PORTRAIT: 510 | return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 511 | case Configuration.ORIENTATION_LANDSCAPE: 512 | return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 513 | default: 514 | return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 515 | } 516 | } 517 | 518 | int rotation = activity.getWindowManager().getDefaultDisplay() 519 | .getRotation(); 520 | DisplayMetrics dm = new DisplayMetrics(); 521 | activity.getWindowManager().getDefaultDisplay().getMetrics(dm); 522 | int width = dm.widthPixels; 523 | int height = dm.heightPixels; 524 | int orientation; 525 | // if the device's natural orientation is portrait: 526 | if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) 527 | && height > width 528 | || (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) 529 | && width > height) { 530 | switch (rotation) { 531 | case Surface.ROTATION_0: 532 | orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 533 | break; 534 | case Surface.ROTATION_90: 535 | orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 536 | break; 537 | case Surface.ROTATION_180: 538 | orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; 539 | break; 540 | case Surface.ROTATION_270: 541 | orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 542 | break; 543 | default: 544 | orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 545 | break; 546 | } 547 | } 548 | // if the device's natural orientation is landscape or if the device 549 | // is square: 550 | else { 551 | switch (rotation) { 552 | case Surface.ROTATION_0: 553 | orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 554 | break; 555 | case Surface.ROTATION_90: 556 | orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 557 | break; 558 | case Surface.ROTATION_180: 559 | orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 560 | break; 561 | case Surface.ROTATION_270: 562 | orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; 563 | break; 564 | default: 565 | orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 566 | break; 567 | } 568 | } 569 | 570 | return orientation; 571 | } 572 | 573 | static int lockScreenOrientation(Activity activity) { 574 | int result = activity.getRequestedOrientation(); 575 | final int screenOrientation = getScreenOrientation(activity); 576 | activity.setRequestedOrientation(screenOrientation); 577 | return result; 578 | } 579 | 580 | static void unlockScreenOrientation(Activity activity, 581 | int previousActivityOrientation) { 582 | activity.setRequestedOrientation(previousActivityOrientation); 583 | } 584 | 585 | static int dpToPixels(Context context, int dp) { 586 | Resources r = context.getResources(); 587 | return (int) Math.ceil(TypedValue.applyDimension( 588 | TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics())); 589 | } 590 | 591 | // FEFF because this is the Unicode char represented by the UTF-8 byte order 592 | // mark (EF BB BF). 593 | private static final String UTF8_BOM = "\uFEFF"; 594 | 595 | static String removeUTF8BOM(String s) { 596 | if (s.startsWith(UTF8_BOM)) { 597 | s = s.substring(1); 598 | } 599 | return s; 600 | } 601 | } 602 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/VersionsMap.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (C) 2013 Turkcell 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 | package tr.com.turkcellteknoloji.turkcellupdater; 17 | 18 | import android.content.Context; 19 | 20 | import org.json.JSONArray; 21 | import org.json.JSONObject; 22 | 23 | import java.util.List; 24 | import java.util.Vector; 25 | 26 | class VersionsMap { 27 | 28 | final String packageName; 29 | private final List updateEntries; 30 | private final List messageEntries; 31 | 32 | VersionsMap(String packageName, List updateEntries, List messageEntries) throws UpdaterException { 33 | super(); 34 | this.packageName = Utilities.removeWhiteSpaces(packageName); 35 | this.updateEntries = updateEntries; 36 | this.messageEntries = messageEntries; 37 | validate(); 38 | } 39 | 40 | VersionsMap(JSONObject jsonObject) throws UpdaterException { 41 | this.packageName = Utilities.removeWhiteSpaces(jsonObject.optString("packageName", null)); 42 | this.updateEntries = new Vector(); 43 | final JSONArray updatesList = jsonObject.optJSONArray("updates"); 44 | if (updatesList != null) { 45 | for (int i = 0; i < updatesList.length(); i++) { 46 | final JSONObject o = updatesList.optJSONObject(i); 47 | if (o != null) { 48 | try { 49 | UpdateEntry ue = new UpdateEntry(o); 50 | updateEntries.add(ue); 51 | } catch (Exception e) { 52 | Log.e("Error occured while processing update entry. Entry is omitted.", e); 53 | } 54 | } 55 | } 56 | } 57 | this.messageEntries = new Vector(); 58 | final JSONArray messagesList = jsonObject.optJSONArray("messages"); 59 | if (messagesList != null) { 60 | for (int i = 0; i < messagesList.length(); i++) { 61 | final JSONObject o = messagesList.optJSONObject(i); 62 | if (o != null) { 63 | try { 64 | MessageEntry me = new MessageEntry(o); 65 | messageEntries.add(me); 66 | } catch (Exception e) { 67 | Log.e("Error occured while processing message entry. Entry is omitted.", e); 68 | } 69 | } 70 | } 71 | } 72 | validate(); 73 | } 74 | 75 | static boolean isVersionMapOfPackageId(String packageName, JSONObject jsonObject) { 76 | if (jsonObject == null) { 77 | return false; 78 | } 79 | packageName = Utilities.removeWhiteSpaces(packageName); 80 | if (packageName.length() < 1) { 81 | return false; 82 | } 83 | String s = jsonObject.optString("packageName", null); 84 | s = Utilities.removeWhiteSpaces(s); 85 | return packageName.equals(s); 86 | } 87 | 88 | Update getUpdate(Properties currentProperties, UpdateDisplayRecords records, Context context) throws UpdaterException { 89 | if (updateEntries == null) { 90 | return null; 91 | } 92 | for (UpdateEntry updateEntry : updateEntries) { 93 | if (updateEntry == null) { 94 | continue; 95 | } 96 | try { 97 | if (updateEntry.shouldDisplay(currentProperties, records, context)) { 98 | return updateEntry.getUpdate(currentProperties, records); 99 | } 100 | } catch (Exception e) { 101 | Log.e("Error occured while searching update entry to display", e); 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | Message getMessage(Properties currentProperties, MessageDisplayRecords records, Context context) { 108 | if (messageEntries == null) { 109 | return null; 110 | } 111 | for (MessageEntry entry : messageEntries) { 112 | if (entry == null) { 113 | continue; 114 | } 115 | try { 116 | if (entry.shouldDisplay(currentProperties, records, context)) { 117 | return entry.getMessageToDisplay(currentProperties, records); 118 | } 119 | } catch (Exception e) { 120 | Log.e("Error occured while searching message entry to display", e); 121 | } 122 | } 123 | return null; 124 | } 125 | 126 | private void validate() throws UpdaterException { 127 | if (packageName == null || packageName.length() < 1) { 128 | throw new UpdaterException("'packageName' shoud not be a null or empty."); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/java/tr/com/turkcellteknoloji/turkcellupdater/package-info.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (C) 2013 Turkcell 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | *******************************************************************************/ 18 | /** 19 | * This library provides mechanism for updating Android applications and displaying messages configured at a configuration file. 20 | *
    21 | * See {@link tr.com.turkcellteknoloji.turkcellupdater.UpdaterDialogManager} for usage. 22 | *
    23 | * See Configuration Reference for configuration details. 24 | */ 25 | package tr.com.turkcellteknoloji.turkcellupdater; 26 | 27 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-hdpi/updater_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-hdpi/updater_warning.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-mdpi/updater_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-mdpi/updater_warning.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-xhdpi/updater_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/drawable-xhdpi/updater_warning.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/layout/updater_dialog_message.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 22 | 23 | 28 | 29 | 34 | 35 | 41 | 42 | 48 | 49 | 50 | 51 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/layout/updater_dialog_update_found.xml: -------------------------------------------------------------------------------- 1 | 16 | 19 | 20 | 26 | 27 | 32 | 33 | 41 | 42 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/values-tr/updater_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Güncelleme gerekli 4 | Güncelleme bulundu 5 | Kur 6 | Yeni versiyon indiriliyor… 7 | Uygulamadan çık 8 | Daha sonra hatırlat 9 | Hata oluştu 10 | Güncelleme tamamlanamadı. 11 | Devam et 12 | Görüntüle 13 | Kapat 14 | Hizmet kullanılamıyor 15 | Çalıştır 16 | 17 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdater/src/main/res/values/updater_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Update required 4 | Update found 5 | Install 6 | Downloading new version… 7 | Exit application 8 | Remind me later 9 | Error occurred 10 | Update couldn\'t be completed. 11 | Continue 12 | View 13 | Close 14 | Service is not available 15 | Launch 16 | 17 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | 7 | defaultConfig { 8 | applicationId "tr.com.turkcellteknoloji.turkcellupdatersampleapp" 9 | minSdkVersion 9 10 | targetSdkVersion 25 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile project(':turkcellUpdater') 23 | compile 'com.android.support:support-v4:25.0.0' 24 | } 25 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/java/tr/com/turkcellteknoloji/turkcellupdatersampleapp/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package tr.com.turkcellteknoloji.turkcellupdatersampleapp; 2 | 3 | import tr.com.turkcellteknoloji.turkcellupdater.Message; 4 | import tr.com.turkcellteknoloji.turkcellupdater.UpdaterDialogManager; 5 | import android.app.Activity; 6 | import android.app.Dialog; 7 | import android.os.Bundle; 8 | import tr.com.turkcellteknoloji.turkcellupdatersampleapp.R; 9 | 10 | /** 11 | * Activity which displays a login screen to the user, offering registration as 12 | * well. 13 | */ 14 | public class LoginActivity extends Activity { 15 | 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | 21 | if(savedInstanceState==null) { 22 | Message message = (Message) getIntent().getSerializableExtra("message"); 23 | if(message!=null) { 24 | final Dialog messageDialog = UpdaterDialogManager.createMessageDialog(this, message, null); 25 | messageDialog.show(); 26 | } 27 | } 28 | 29 | setContentView(R.layout.activity_login); 30 | 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/java/tr/com/turkcellteknoloji/turkcellupdatersampleapp/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package tr.com.turkcellteknoloji.turkcellupdatersampleapp; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.os.Bundle; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.Button; 11 | import android.widget.CheckBox; 12 | import android.widget.EditText; 13 | 14 | import java.io.Serializable; 15 | 16 | import tr.com.turkcellteknoloji.turkcellupdater.Message; 17 | import tr.com.turkcellteknoloji.turkcellupdater.TurkcellUpdater; 18 | import tr.com.turkcellteknoloji.turkcellupdater.TurkcellUpdater.TurkcellUpdaterCallback; 19 | import tr.com.turkcellteknoloji.turkcellupdater.UpdaterDialogManager.UpdaterUiListener; 20 | 21 | public class SplashActivity extends Activity { 22 | 23 | Message message; 24 | 25 | private EditText serverAddressEditText; 26 | 27 | private CheckBox postPropertiesCheckBox; 28 | 29 | private Button startUpdateCheckButton; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setTheme(android.R.style.Theme_NoTitleBar); 35 | setContentView(R.layout.activity_splash); 36 | serverAddressEditText = (EditText) findViewById(R.id.serverAddressEditText); 37 | postPropertiesCheckBox = (CheckBox) findViewById(R.id.postPropertiesCheckbox); 38 | startUpdateCheckButton = (Button) findViewById(R.id.startUpdateCheckButton); 39 | startUpdateCheckButton.setOnClickListener(new OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | v.setEnabled(false); 43 | // Eski yontem: 44 | // UpdaterDialogManager updaterUI = new UpdaterDialogManager(serverAddressEditText.getText().toString()); 45 | // updaterUI.setPostProperties(postPropertiesCheckBox.isChecked()); 46 | // updaterUI.setPostProperties(true); 47 | // updaterUI.startUpdateCheck(SplashActivity.this, SplashActivity.this); 48 | ////////////// 49 | //Yeni yontem: 50 | } 51 | }); 52 | TurkcellUpdater updater = new TurkcellUpdater(SplashActivity.this, "http://10.0.2.2/hop.json"); 53 | updater.setTurkcellUpdaterCallback(mTurkcellUpdaterCallback); 54 | updater.setDefaultDialogCallback(mUpdaterUiListener); 55 | updater.check(false); 56 | } 57 | 58 | private TurkcellUpdaterCallback mTurkcellUpdaterCallback = new TurkcellUpdaterCallback() { 59 | @Override 60 | public void onForceUpdateReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton) { 61 | Log.e("onForceUpdateReceive", message + " " + warnings + " " + whatIsNew); 62 | } 63 | 64 | @Override 65 | public void onForceExitReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton) { 66 | Log.e("onForceExitReceive", message + " " + warnings + " " + whatIsNew + " " + positiveButton + " " + negativeButton); 67 | } 68 | 69 | @Override 70 | public void onNonForceUpdateReceive(String message, String warnings, String whatIsNew, String positiveButton, String negativeButton) { 71 | Log.e("onNonForceUpdateReceive", message + " " + warnings + " " + whatIsNew + " " + positiveButton + " " + negativeButton); 72 | } 73 | 74 | @Override 75 | public void onMessageReceive(String title, String message, String positiveButton, String negativeButton, String imageUrl, Uri redirectionUri) { 76 | Log.e("onMessageReceive", title + " " + message + " " + imageUrl + " " + redirectionUri.toString() + " " + positiveButton + " " + negativeButton); 77 | } 78 | 79 | @Override 80 | public void onUpdateNotFoundReceive() { 81 | Log.e("onUpdateNotFoundReceive", "asd"); 82 | } 83 | 84 | @Override 85 | public void onUpdaterErrorReceive(Exception e) { 86 | Log.e("onUpdaterErrorReceive", e.toString()); 87 | } 88 | }; 89 | 90 | private UpdaterUiListener mUpdaterUiListener = new UpdaterUiListener() { 91 | 92 | @Override 93 | public void onExitApplication() { 94 | finish(); 95 | } 96 | 97 | @Override 98 | public void onUpdateCheckCompleted() { 99 | final Intent intent = new Intent(SplashActivity.this, LoginActivity.class); 100 | intent.putExtra("message", (Serializable) message); 101 | startActivity(intent); 102 | finish(); 103 | } 104 | 105 | @Override 106 | public boolean onDisplayMessage(Message message) { 107 | // To automatically display message: 108 | // return false; 109 | SplashActivity.this.message = message; 110 | return true; 111 | } 112 | }; 113 | } 114 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turkcell/TurkcellUpdater_android_sdk/eedf22c0944deb0d9c8b7f2a835ed26bf2b0553d/TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/drawable/splash.png -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /TurkcellUpdaterSampleApp/turkcellUpdaterSampleApp/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 21 | 28 |