diff --git a/.gitignore b/.gitignore index c9c2248a..536999a8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,9 @@ proguard/ # Android Studio captures folder captures/ + +# Directory-based project format +.idea/ + +# IntelliJ +*.iml diff --git a/README.md b/README.md index a0073510..952669ec 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,76 @@ -# AppUpdater -Library that checks for new app updates using Google Play, GitHub and Amazon. API 8+ required. +

AppUpdater

+

Android Library

+ +

+ + + +

+ +

Android Library that checks for new app updates using Google Play, GitHub and Amazon.

+ +## How to include +Add the repository to your project **build.gradle**: +```Java +repositories { + maven { + url "https://jitpack.io" + } +} +``` + +And add the library to your module **build.gradle**: +```Java +dependencies { + compile 'com.github.javiersantos:AppUpdater:1.0' +} +``` + +## Usage +Add **INTERNET** and **ACCESS_NETWORK_STATE** permissions to your app's Manifest: +```Java + + +``` + +### Activity +```Java +AppUpdater appUpdater = new AppUpdater(this); +appUpdater.init(); +``` + +## Customization + +### Display dialog only once +Use the builder and add following: +```Java +// (Optional) Provide a Display mode (DIALOG, SNACKBAR, NOTIFICATION) +.setDisplay(Display.DIALOG) +// (Optional) Provide a duration for the Snackbars (NORMAL, INDEFINITE) +.setDuration(Duration.NORMAL) +// (Optional) Provide a source for the updates (GOOGLE_PLAY, GITHUB, AMAZON) +.setUpdateFrom(UpdateFrom.GOOGLE_PLAY) +// (Required for GITHUB, optional otherwise) Provide the GitHub user and repo where releases are available +.setGitHubUserAndRepo("javiersantos", "AppUpdater") +// (Optional) Updates will be displayed only every X times the app ascertains that a new update is availabl +.showEvery(5) +// (Optional) Show dialog, snackbar or notification although there aren't updates +.showAppUpdated(false); +``` + +![ML Manager](https://raw.githubusercontent.com/javiersantos/AppUpdater/master/Screenshots/banner.png) + +## License + Copyright 2016 Javier Santos + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Screenshots/banner.png b/Screenshots/banner.png new file mode 100755 index 00000000..9df5c15b Binary files /dev/null and b/Screenshots/banner.png differ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..67e5bd98 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + + defaultConfig { + applicationId "com.github.javiersantos.appupdater.demo" + minSdkVersion 11 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + + applicationVariants.all { variant -> + variant.outputs.each { output -> + output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", applicationId + "_" + versionName + "_" + versionCode + ".apk")) + } + } + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:design:23.1.1' + compile 'com.android.support:cardview-v7:23.1.1' + compile 'com.mikepenz:iconics-core:2.5.5@aar' + compile 'com.mikepenz:material-design-iconic-typeface:2.2.0.1@aar' + compile project(':library') +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 00000000..dee88bfe --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/javiersantos/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/github/javiersantos/demo/ApplicationTest.java b/app/src/androidTest/java/com/github/javiersantos/demo/ApplicationTest.java new file mode 100644 index 00000000..9592fa08 --- /dev/null +++ b/app/src/androidTest/java/com/github/javiersantos/demo/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.github.javiersantos.demo; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..39d57ec0 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/github/javiersantos/demo/MainActivity.java b/app/src/main/java/com/github/javiersantos/demo/MainActivity.java new file mode 100644 index 00000000..08b6617f --- /dev/null +++ b/app/src/main/java/com/github/javiersantos/demo/MainActivity.java @@ -0,0 +1,88 @@ +package com.github.javiersantos.demo; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.CardView; +import android.support.v7.widget.Toolbar; +import android.view.View; + +import com.github.javiersantos.appupdater.AppUpdater; +import com.github.javiersantos.appupdater.demo.R; +import com.github.javiersantos.appupdater.enums.Display; +import com.github.javiersantos.appupdater.enums.UpdateFrom; +import com.mikepenz.iconics.IconicsDrawable; +import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic; + +public class MainActivity extends AppCompatActivity { + private Context context; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + this.context = this; + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + CardView dialog = (CardView) findViewById(R.id.dialog); + CardView snackbar = (CardView) findViewById(R.id.snackbar); + CardView notification = (CardView) findViewById(R.id.notification); + + fab.setImageDrawable(new IconicsDrawable(this).icon(MaterialDesignIconic.Icon.gmi_github).color(Color.WHITE).sizeDp(24)); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/javiersantos/AppUpdater"))); + } + }); + + dialog.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AppUpdater appUpdater = new AppUpdater(context); + appUpdater.setUpdateFrom(UpdateFrom.GOOGLE_PLAY); + // appUpdater.setUpdateFrom(UpdateFrom.AMAZON); + // appUpdater.setUpdateFrom(UpdateFrom.GITHUB); + // appUpdater.setGitHubUserAndRepo("javiersantos", "AppUpdater"); + appUpdater.setDisplay(Display.DIALOG); + appUpdater.showAppUpdated(true); + appUpdater.init(); + } + }); + + snackbar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AppUpdater appUpdater = new AppUpdater(context); + appUpdater.setUpdateFrom(UpdateFrom.GOOGLE_PLAY); + // appUpdater.setUpdateFrom(UpdateFrom.AMAZON); + // appUpdater.setUpdateFrom(UpdateFrom.GITHUB); + // appUpdater.setGitHubUserAndRepo("javiersantos", "AppUpdater"); + appUpdater.setDisplay(Display.SNACKBAR); + appUpdater.showAppUpdated(true); + appUpdater.init(); + } + }); + + notification.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + AppUpdater appUpdater = new AppUpdater(context); + appUpdater.setUpdateFrom(UpdateFrom.GOOGLE_PLAY); + // appUpdater.setUpdateFrom(UpdateFrom.AMAZON); + // appUpdater.setUpdateFrom(UpdateFrom.GITHUB); + // appUpdater.setGitHubUserAndRepo("javiersantos", "AppUpdater"); + appUpdater.setDisplay(Display.NOTIFICATION); + appUpdater.showAppUpdated(true); + appUpdater.init(); + } + }); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..9567fe41 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml new file mode 100644 index 00000000..edf92310 --- /dev/null +++ b/app/src/main/res/layout/content_main.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..cde69bcc Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c133a0cb Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..bfa42f0e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..324e72cd Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..aee44e13 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml new file mode 100644 index 00000000..251fb9fb --- /dev/null +++ b/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,9 @@ +> + + + diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..63fc8164 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..3ab3e9cb --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..41ee0756 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,8 @@ + + + 16dp + 16dp + 16dp + 240dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..e59a7161 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ + + AppUpdater Library (Demo) + + A library that checks for new app updates using Google Play, GitHub and Amazon. + Show dialog + Show snackbar + Show notification + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..78ec711b --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/app/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java b/app/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java new file mode 100644 index 00000000..0c3a06e2 --- /dev/null +++ b/app/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package com.github.javiersantos.appupdater; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..f83b67d5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,24 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.5.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + maven { url "https://jitpack.io" } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..1d3591c8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..05ef575b Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..f23df6e4 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Oct 21 11:34:03 PDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..9d82f789 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library/build.gradle b/library/build.gradle new file mode 100644 index 00000000..2720fbc6 --- /dev/null +++ b/library/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.2" + useLibrary 'org.apache.http.legacy' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:design:23.1.1' + compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true } +} diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro new file mode 100644 index 00000000..dee88bfe --- /dev/null +++ b/library/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/javiersantos/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/library/src/androidTest/java/com/github/javiersantos/appupdater/ApplicationTest.java b/library/src/androidTest/java/com/github/javiersantos/appupdater/ApplicationTest.java new file mode 100644 index 00000000..0cd9d9d8 --- /dev/null +++ b/library/src/androidTest/java/com/github/javiersantos/appupdater/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.github.javiersantos.appupdater; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml new file mode 100644 index 00000000..60f72a55 --- /dev/null +++ b/library/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/library/src/main/java/com/github/javiersantos/appupdater/AppUpdater.java b/library/src/main/java/com/github/javiersantos/appupdater/AppUpdater.java new file mode 100644 index 00000000..2c611318 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/AppUpdater.java @@ -0,0 +1,57 @@ +package com.github.javiersantos.appupdater; + +import android.content.Context; + +import com.github.javiersantos.appupdater.enums.Display; +import com.github.javiersantos.appupdater.enums.Duration; +import com.github.javiersantos.appupdater.enums.UpdateFrom; +import com.github.javiersantos.appupdater.objects.GitHub; + +public class AppUpdater { + private Context context; + private Display display; + private UpdateFrom updateFrom; + private Duration duration; + private GitHub gitHub; + private Integer showEvery; + private Boolean showAppUpdated; + + public AppUpdater(Context context) { + this.context = context; + this.display = Display.DIALOG; + this.updateFrom = UpdateFrom.GOOGLE_PLAY; + this.duration = Duration.NORMAL; + this.showEvery = 5; + this.showAppUpdated = false; + } + + public void setDisplay(Display display) { + this.display = display; + } + + public void setUpdateFrom(UpdateFrom updateFrom) { + this.updateFrom = updateFrom; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } + + public void setGitHubUserAndRepo(String user, String repo) { + this.gitHub = new GitHub(user, repo); + } + + public void showEvery(Integer times) { + this.showEvery = times; + } + + public void showAppUpdated(Boolean res) { + this.showAppUpdated = res; + } + + public void init() { + UtilsAsync.LatestAppVersion latestAppVersion = new UtilsAsync.LatestAppVersion(context, showEvery, showAppUpdated, updateFrom, display, duration, gitHub); + latestAppVersion.execute(); + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/Config.java b/library/src/main/java/com/github/javiersantos/appupdater/Config.java new file mode 100644 index 00000000..9c20c096 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/Config.java @@ -0,0 +1,12 @@ +package com.github.javiersantos.appupdater; + +class Config { + static final String PLAY_STORE_URL = "https://play.google.com/store/apps/details?id="; + static final String GITHUB_URL = "https://github.com/"; + static final String AMAZON_URL = "http://www.amazon.com/gp/mas/dl/android?p="; + + static final String PLAY_STORE_TAG_RELEASE = "itemprop=\"softwareVersion\"> "; + static final String GITHUB_TAG_RELEASE = "/tree/"; + static final String AMAZON_TAG_RELEASE = "Version:"; + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/LibraryPreferences.java b/library/src/main/java/com/github/javiersantos/appupdater/LibraryPreferences.java new file mode 100644 index 00000000..5f541fe6 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/LibraryPreferences.java @@ -0,0 +1,37 @@ +package com.github.javiersantos.appupdater; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +class LibraryPreferences { + private SharedPreferences sharedPreferences; + private SharedPreferences.Editor editor; + + static final String KeyAppUpdaterShow = "prefAppUpdaterShow"; + static final String KeySuccessfulChecks = "prefSuccessfulChecks"; + + public LibraryPreferences(Context context) { + this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + this.editor = sharedPreferences.edit(); + } + + public Boolean getAppUpdaterShow() { + return sharedPreferences.getBoolean(KeyAppUpdaterShow, true); + } + + public void setAppUpdaterShow(Boolean res) { + editor.putBoolean(KeyAppUpdaterShow, res); + editor.commit(); + } + + public Integer getSuccessfulChecks() { + return sharedPreferences.getInt(KeySuccessfulChecks, 0); + } + + public void setSuccessfulChecks(Integer checks) { + editor.putInt(KeySuccessfulChecks, checks); + editor.commit(); + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/UtilsAsync.java b/library/src/main/java/com/github/javiersantos/appupdater/UtilsAsync.java new file mode 100644 index 00000000..eccbd6d9 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/UtilsAsync.java @@ -0,0 +1,92 @@ +package com.github.javiersantos.appupdater; + +import android.content.Context; +import android.os.AsyncTask; + +import com.github.javiersantos.appupdater.enums.Display; +import com.github.javiersantos.appupdater.enums.Duration; +import com.github.javiersantos.appupdater.enums.UpdateFrom; +import com.github.javiersantos.appupdater.objects.GitHub; + +class UtilsAsync { + + static class LatestAppVersion extends AsyncTask { + private Context context; + private LibraryPreferences libraryPreferences; + private Integer showEvery; + private Boolean showAppUpdated; + private UpdateFrom updateFrom; + private Display display; + private Duration duration; + private GitHub gitHub; + + public LatestAppVersion(Context context, Integer showEvery, Boolean showAppUpdated, UpdateFrom updateFrom, Display display, Duration duration, GitHub gitHub) { + this.context = context; + this.libraryPreferences = new LibraryPreferences(context); + this.showEvery = showEvery; + this.showAppUpdated = showAppUpdated; + this.updateFrom = updateFrom; + this.display = display; + this.duration = duration; + this.gitHub = gitHub; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + + if (UtilsLibrary.isNetworkAvailable(context) && libraryPreferences.getAppUpdaterShow()) { + switch (updateFrom) { + case GITHUB: + if (gitHub == null) { + throw new NullPointerException("GitHub user and repo are not set!!"); + } + break; + } + } else { + cancel(true); + } + } + + @Override + protected String doInBackground(Void... voids) { + return UtilsLibrary.getLatestAppVersion(context, updateFrom, gitHub); + } + + @Override + protected void onPostExecute(String version) { + super.onPostExecute(version); + + if (UtilsLibrary.isUpdateAvailable(UtilsLibrary.getAppInstalledVersion(context), version)) { + Integer successfulChecks = libraryPreferences.getSuccessfulChecks(); + libraryPreferences.setSuccessfulChecks(successfulChecks++); + if (UtilsLibrary.isAbleToShow(context, showEvery)) { + switch (display) { + case DIALOG: + UtilsDisplay.showUpdateAvailableDialog(context, context.getResources().getString(R.string.appupdater_update_available), String.format(context.getResources().getString(R.string.appupdater_update_available_description_dialog), version, UtilsLibrary.getAppName(context)), updateFrom, gitHub); + break; + case SNACKBAR: + UtilsDisplay.showUpdateAvailableSnackbar(context, String.format(context.getResources().getString(R.string.appupdater_update_available_description_snackbar), UtilsLibrary.getAppInstalledVersion(context)), UtilsLibrary.getDurationEnumToBoolean(duration), updateFrom, gitHub); + break; + case NOTIFICATION: + UtilsDisplay.showUpdateAvailableNotification(context, context.getResources().getString(R.string.appupdater_update_available), String.format(context.getResources().getString(R.string.appupdater_update_available_description_notification), version, UtilsLibrary.getAppName(context)), updateFrom, gitHub); + break; + } + } + } else if (showAppUpdated) { + switch (display) { + case DIALOG: + UtilsDisplay.showUpdateNotAvailableDialog(context, context.getResources().getString(R.string.appupdater_update_not_available), String.format(context.getResources().getString(R.string.appupdater_update_not_available_description), UtilsLibrary.getAppName(context))); + break; + case SNACKBAR: + UtilsDisplay.showUpdateNotAvailableSnackbar(context, context.getResources().getString(R.string.appupdater_update_not_available_description), UtilsLibrary.getDurationEnumToBoolean(duration)); + break; + case NOTIFICATION: + UtilsDisplay.showUpdateNotAvailableNotification(context, context.getResources().getString(R.string.appupdater_update_not_available), String.format(context.getResources().getString(R.string.appupdater_update_not_available_description), UtilsLibrary.getAppName(context))); + break; + } + } + } + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/UtilsDisplay.java b/library/src/main/java/com/github/javiersantos/appupdater/UtilsDisplay.java new file mode 100644 index 00000000..e42e6f02 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/UtilsDisplay.java @@ -0,0 +1,129 @@ +package com.github.javiersantos.appupdater; + +import android.app.Activity; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.media.RingtoneManager; +import android.support.design.widget.Snackbar; +import android.support.v4.app.NotificationCompat; +import android.view.View; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; +import com.github.javiersantos.appupdater.enums.UpdateFrom; +import com.github.javiersantos.appupdater.objects.GitHub; + +class UtilsDisplay { + + static void showUpdateAvailableDialog(final Context context, String title, String content, final UpdateFrom updateFrom, final GitHub gitHub) { + final LibraryPreferences libraryPreferences = new LibraryPreferences(context); + + MaterialDialog materialDialog = new MaterialDialog.Builder(context) + .title(title) + .content(content) + .positiveText(context.getResources().getString(R.string.appupdater_btn_update)) + .negativeText(context.getResources().getString(android.R.string.cancel)) + .neutralText(context.getResources().getString(R.string.appupdater_btn_disable)) + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(MaterialDialog dialog, DialogAction which) { + UtilsLibrary.goToUpdate(context, updateFrom, gitHub); + } + }) + .onNeutral(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(MaterialDialog dialog, DialogAction which) { + libraryPreferences.setAppUpdaterShow(false); + } + }).show(); + } + + static void showUpdateNotAvailableDialog(final Context context, String title, String content) { + MaterialDialog materialDialog = new MaterialDialog.Builder(context) + .title(title) + .content(content) + .positiveText(context.getResources().getString(android.R.string.ok)) + .show(); + } + + static void showUpdateAvailableSnackbar(final Context context, String content, Boolean indefinite, final UpdateFrom updateFrom, final GitHub gitHub) { + Activity activity = (Activity) context; + int snackbarTime; + + if (indefinite) { + snackbarTime = Snackbar.LENGTH_INDEFINITE; + } else { + snackbarTime = Snackbar.LENGTH_LONG; + } + + Snackbar snackbar = Snackbar.make(activity.getWindow().getDecorView().getRootView(), content, snackbarTime); + snackbar.setAction(context.getResources().getString(R.string.appupdater_btn_update), new View.OnClickListener() { + @Override + public void onClick(View view) { + UtilsLibrary.goToUpdate(context, updateFrom, gitHub); + } + }).show(); + } + + static void showUpdateNotAvailableSnackbar(final Context context, String content, Boolean indefinite) { + Activity activity = (Activity) context; + int snackbarTime; + + if (indefinite) { + snackbarTime = Snackbar.LENGTH_INDEFINITE; + } else { + snackbarTime = Snackbar.LENGTH_LONG; + } + + Snackbar.make(activity.getWindow().getDecorView().getRootView(), content, snackbarTime).show(); + } + + static void showUpdateAvailableNotification(Context context, String title, String content, UpdateFrom updateFrom, GitHub gitHub) { + PendingIntent contentIntent = PendingIntent.getActivity(context, 0, context.getPackageManager().getLaunchIntentForPackage(UtilsLibrary.getAppPackageName(context)), PendingIntent.FLAG_CANCEL_CURRENT); + PendingIntent pendingIntentUpdate = PendingIntent.getActivity(context, 0, UtilsLibrary.intentToUpdate(context, updateFrom, gitHub), PendingIntent.FLAG_CANCEL_CURRENT); + NotificationCompat.Style style = new NotificationCompat.BigTextStyle().bigText(content); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context) + .setContentIntent(contentIntent) + .setContentTitle(title) + .setContentText(content) + .setStyle(style) + .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) + .setOnlyAlertOnce(true) + .setAutoCancel(true) + .addAction(R.drawable.ic_system_update_white_24dp, context.getResources().getString(R.string.appupdater_btn_update), pendingIntentUpdate); + + try { + ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + builder.setSmallIcon(applicationInfo.icon); + } catch (PackageManager.NameNotFoundException ignore) {} + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(0, builder.build()); + } + + static void showUpdateNotAvailableNotification(Context context, String title, String content) { + PendingIntent contentIntent = PendingIntent.getActivity(context, 0, context.getPackageManager().getLaunchIntentForPackage(UtilsLibrary.getAppPackageName(context)), PendingIntent.FLAG_CANCEL_CURRENT); + NotificationCompat.Style style = new NotificationCompat.BigTextStyle().bigText(content); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context) + .setContentIntent(contentIntent) + .setContentTitle(title) + .setContentText(content) + .setStyle(style) + .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) + .setOnlyAlertOnce(true) + .setAutoCancel(true); + try { + ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0); + builder.setSmallIcon(applicationInfo.icon); + } catch (PackageManager.NameNotFoundException ignore) {} + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(0, builder.build()); + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/UtilsLibrary.java b/library/src/main/java/com/github/javiersantos/appupdater/UtilsLibrary.java new file mode 100644 index 00000000..bb769261 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/UtilsLibrary.java @@ -0,0 +1,218 @@ +package com.github.javiersantos.appupdater; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.util.Log; + +import com.github.javiersantos.appupdater.enums.Duration; +import com.github.javiersantos.appupdater.enums.UpdateFrom; +import com.github.javiersantos.appupdater.objects.GitHub; +import com.github.javiersantos.appupdater.objects.Version; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +class UtilsLibrary { + + static String getAppName(Context context) { + return context.getString(context.getApplicationInfo().labelRes); + } + + static String getAppPackageName(Context context) { + return context.getPackageName(); + } + + static String getAppInstalledVersion(Context context) { + String version = "0.0.0.0"; + + try { + version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + + return version; + } + + static Boolean isUpdateAvailable(String installedVersion, String latestVersion) { + Boolean res = false; + + if (!installedVersion.equals("0.0.0.0") && !latestVersion.equals("0.0.0.0")) { + Version installed = new Version(installedVersion); + Version latest = new Version(latestVersion); + res = installed.compareTo(latest) < 0; + } + + return res; + } + + static Boolean getDurationEnumToBoolean(Duration duration) { + Boolean res = false; + + switch (duration) { + case INDEFINITE: + res = true; + break; + } + + return res; + } + + static String getUpdateURL(Context context, UpdateFrom updateFrom, GitHub gitHub) { + String res; + + switch (updateFrom) { + default: + res = Config.PLAY_STORE_URL + getAppPackageName(context); + break; + case GITHUB: + res = Config.GITHUB_URL + gitHub.getGithubUser() + "/" + gitHub.getGithubRepo() + "/releases"; + break; + case AMAZON: + res = Config.AMAZON_URL + getAppPackageName(context); + break; + } + + return res; + } + + static String getLatestAppVersion(Context context, UpdateFrom updateFrom, GitHub gitHub) { + Boolean notAvailable = false; + String res = "0.0.0.0"; + String source = ""; + + try { + HttpParams params = new BasicHttpParams(); + HttpConnectionParams.setConnectionTimeout(params, 4000); + HttpConnectionParams.setSoTimeout(params, 5000); + + HttpClient client = new DefaultHttpClient(params); + HttpGet request = new HttpGet(getUpdateURL(context, updateFrom, gitHub)); + + HttpResponse response = client.execute(request); + + InputStream in = response.getEntity().getContent(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuilder str = new StringBuilder(); + String line; + while((line = reader.readLine()) != null) { + switch (updateFrom) { + default: + if (line.contains(Config.PLAY_STORE_TAG_RELEASE)) { + str.append(line); + } + break; + case GITHUB: + if (line.contains(Config.GITHUB_TAG_RELEASE)) { + str.append(line); + } + break; + case AMAZON: + if (line.contains(Config.AMAZON_TAG_RELEASE)) { + str.append(line); + } + break; + } + } + + if (str.length() == 0) { + notAvailable = true; + Log.e("AppUpdater", "Cannot retrieve latest version. Is it configured properly?"); + } + + in.close(); + source = str.toString(); + } catch (IOException e) { + e.printStackTrace(); + } + + if (!notAvailable) { + switch (updateFrom) { + default: + String[] splitPlayStore = source.split(Config.PLAY_STORE_TAG_RELEASE); + splitPlayStore = splitPlayStore[1].split("(<)"); + res = splitPlayStore[0].trim(); + break; + case GITHUB: + String[] splitGitHub = source.split(Config.GITHUB_TAG_RELEASE); + splitGitHub = splitGitHub[1].split("(\")"); + res = splitGitHub[0].trim(); + if (res.contains("v")) { // Some repo uses vX.X.X + splitGitHub = res.split("(v)"); + res = splitGitHub[1].trim(); + } + break; + case AMAZON: + String[] splitAmazon = source.split(Config.AMAZON_TAG_RELEASE); + splitAmazon = splitAmazon[1].split("(<)"); + res = splitAmazon[0].trim(); + break; + } + } + + return res; + } + + static Intent intentToUpdate(Context context, UpdateFrom updateFrom, GitHub gitHub) { + String updateURL = getUpdateURL(context, updateFrom, gitHub); + Intent intent; + + if (updateFrom.equals(UpdateFrom.GOOGLE_PLAY)) { + intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getAppPackageName(context))); + } else { + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(updateURL)); + } + + return intent; + } + + static void goToUpdate(Context context, UpdateFrom updateFrom, GitHub gitHub) { + Intent intent = intentToUpdate(context, updateFrom, gitHub); + String updateURL = getUpdateURL(context, updateFrom, gitHub); + + if (updateFrom.equals(UpdateFrom.GOOGLE_PLAY)) { + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(updateURL)); + context.startActivity(intent); + } + } else { + context.startActivity(intent); + } + } + + static Boolean isAbleToShow(Context context, Integer showEvery) { + LibraryPreferences libraryPreferences = new LibraryPreferences(context); + return libraryPreferences.getSuccessfulChecks() % showEvery == 0; + } + + static Boolean isNetworkAvailable(Context context) { + Boolean res = false; + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm != null) { + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + if (networkInfo != null) { + res = networkInfo.isConnected(); + } + } + + return res; + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/enums/Display.java b/library/src/main/java/com/github/javiersantos/appupdater/enums/Display.java new file mode 100644 index 00000000..1b77efa1 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/enums/Display.java @@ -0,0 +1,7 @@ +package com.github.javiersantos.appupdater.enums; + +public enum Display { + DIALOG, + SNACKBAR, + NOTIFICATION +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/enums/Duration.java b/library/src/main/java/com/github/javiersantos/appupdater/enums/Duration.java new file mode 100644 index 00000000..d08c2b1d --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/enums/Duration.java @@ -0,0 +1,6 @@ +package com.github.javiersantos.appupdater.enums; + +public enum Duration { + NORMAL, + INDEFINITE +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/enums/UpdateFrom.java b/library/src/main/java/com/github/javiersantos/appupdater/enums/UpdateFrom.java new file mode 100644 index 00000000..c2d6cb74 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/enums/UpdateFrom.java @@ -0,0 +1,7 @@ +package com.github.javiersantos.appupdater.enums; + +public enum UpdateFrom { + GOOGLE_PLAY, + GITHUB, + AMAZON +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/objects/GitHub.java b/library/src/main/java/com/github/javiersantos/appupdater/objects/GitHub.java new file mode 100644 index 00000000..e971360a --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/objects/GitHub.java @@ -0,0 +1,35 @@ +package com.github.javiersantos.appupdater.objects; + +public class GitHub { + private String githubUser; + private String githubRepo; + + public GitHub(String githubUser, String githubRepo) { + checkGithub(githubUser, githubRepo); + this.githubUser = githubUser; + this.githubRepo = githubRepo; + } + + public String getGithubUser() { + return githubUser; + } + + public void setGithubUser(String user) { + this.githubUser = user; + } + + public String getGithubRepo() { + return githubRepo; + } + + public void setGithubRepo(String repo) { + this.githubRepo = repo; + } + + private void checkGithub(String user, String repo) { + if (user.length() == 0 || repo.length() == 0) { + throw new IllegalArgumentException("GitHub user or repo is empty"); + } + } + +} diff --git a/library/src/main/java/com/github/javiersantos/appupdater/objects/Version.java b/library/src/main/java/com/github/javiersantos/appupdater/objects/Version.java new file mode 100644 index 00000000..3cb85569 --- /dev/null +++ b/library/src/main/java/com/github/javiersantos/appupdater/objects/Version.java @@ -0,0 +1,50 @@ +package com.github.javiersantos.appupdater.objects; + +import android.util.Log; + +public class Version implements Comparable { + private String TAG = "AppUpdater"; + private String version; + + public final String get() { + return this.version; + } + + public Version(String version) { + if(version == null) + Log.e(TAG, "Version can not be null"); + if(!version.matches("[0-9]+(\\.[0-9]+)*")) + Log.e(TAG, "Invalid version format"); + this.version = version; + } + + @Override public int compareTo(Version that) { + if(that == null) + return 1; + String[] thisParts = this.get().split("\\."); + String[] thatParts = that.get().split("\\."); + int length = Math.max(thisParts.length, thatParts.length); + for(int i = 0; i < length; i++) { + int thisPart = i < thisParts.length ? + Integer.parseInt(thisParts[i]) : 0; + int thatPart = i < thatParts.length ? + Integer.parseInt(thatParts[i]) : 0; + if(thisPart < thatPart) + return -1; + if(thisPart > thatPart) + return 1; + } + return 0; + } + + @Override public boolean equals(Object that) { + if(this == that) + return true; + if(that == null) + return false; + if(this.getClass() != that.getClass()) + return false; + return this.compareTo((Version) that) == 0; + } + +} \ No newline at end of file diff --git a/library/src/main/res/drawable-hdpi/ic_clear_all_white_24dp.png b/library/src/main/res/drawable-hdpi/ic_clear_all_white_24dp.png new file mode 100644 index 00000000..e23d886c Binary files /dev/null and b/library/src/main/res/drawable-hdpi/ic_clear_all_white_24dp.png differ diff --git a/library/src/main/res/drawable-hdpi/ic_system_update_white_24dp.png b/library/src/main/res/drawable-hdpi/ic_system_update_white_24dp.png new file mode 100644 index 00000000..04b8e521 Binary files /dev/null and b/library/src/main/res/drawable-hdpi/ic_system_update_white_24dp.png differ diff --git a/library/src/main/res/drawable-mdpi/ic_clear_all_white_24dp.png b/library/src/main/res/drawable-mdpi/ic_clear_all_white_24dp.png new file mode 100644 index 00000000..dca30487 Binary files /dev/null and b/library/src/main/res/drawable-mdpi/ic_clear_all_white_24dp.png differ diff --git a/library/src/main/res/drawable-mdpi/ic_system_update_white_24dp.png b/library/src/main/res/drawable-mdpi/ic_system_update_white_24dp.png new file mode 100644 index 00000000..cccf9b3e Binary files /dev/null and b/library/src/main/res/drawable-mdpi/ic_system_update_white_24dp.png differ diff --git a/library/src/main/res/drawable-xhdpi/ic_clear_all_white_24dp.png b/library/src/main/res/drawable-xhdpi/ic_clear_all_white_24dp.png new file mode 100644 index 00000000..fef5dcd2 Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/ic_clear_all_white_24dp.png differ diff --git a/library/src/main/res/drawable-xhdpi/ic_system_update_white_24dp.png b/library/src/main/res/drawable-xhdpi/ic_system_update_white_24dp.png new file mode 100644 index 00000000..531eac6a Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/ic_system_update_white_24dp.png differ diff --git a/library/src/main/res/drawable-xxhdpi/ic_clear_all_white_24dp.png b/library/src/main/res/drawable-xxhdpi/ic_clear_all_white_24dp.png new file mode 100644 index 00000000..51d2d3da Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/ic_clear_all_white_24dp.png differ diff --git a/library/src/main/res/drawable-xxhdpi/ic_system_update_white_24dp.png b/library/src/main/res/drawable-xxhdpi/ic_system_update_white_24dp.png new file mode 100644 index 00000000..f88d6108 Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/ic_system_update_white_24dp.png differ diff --git a/library/src/main/res/drawable-xxxhdpi/ic_clear_all_white_24dp.png b/library/src/main/res/drawable-xxxhdpi/ic_clear_all_white_24dp.png new file mode 100644 index 00000000..9dbccf36 Binary files /dev/null and b/library/src/main/res/drawable-xxxhdpi/ic_clear_all_white_24dp.png differ diff --git a/library/src/main/res/drawable-xxxhdpi/ic_system_update_white_24dp.png b/library/src/main/res/drawable-xxxhdpi/ic_system_update_white_24dp.png new file mode 100644 index 00000000..ac4ce15e Binary files /dev/null and b/library/src/main/res/drawable-xxxhdpi/ic_system_update_white_24dp.png differ diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml new file mode 100644 index 00000000..22cbf89d --- /dev/null +++ b/library/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + AppUpdater + + New update available! + Update %1$s is available to download. Downloading the latest update you will get the latest features, improvements and bug fixes of %2$s. + Update %1$s is available! + Update %1$s of %2$s is available to download + + No update available + You\'ve the latest version available of %s! + + Update + Don\'t show again + Dismiss + diff --git a/library/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java b/library/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java new file mode 100644 index 00000000..0c3a06e2 --- /dev/null +++ b/library/src/test/java/com/github/javiersantos/appupdater/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package com.github.javiersantos.appupdater; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..33069973 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app', ':library'