diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb4d1a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,86 @@ +# Created by https://www.gitignore.io + +### Java ### +*.class + + + + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the follwing: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +## File-based project format: +# *.ipr +# *.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml + +#Generated files +build/ + +#Build folders of Android Studio +**/build/ + +### Android ### +# Built application files +*.apk +# *.ap_ + +# Files for the Dalvik VM +*.dex + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +# proguard/ + +# Log Files +*.log + +#Ignorando SVN!! +**/.svn/ +.svn/ + +app/mirror diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..1b7886d --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +// 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.3.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /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 0000000..8c0fb64 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 0000000..4762009 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Sep 10 09:54:12 BRT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/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 + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# 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\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +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"` + + # 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 0000000..8a0b282 --- /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/medescope/build.gradle b/medescope/build.gradle new file mode 100644 index 0000000..52df0f8 --- /dev/null +++ b/medescope/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.0" + + defaultConfig { + minSdkVersion 10 + targetSdkVersion 23 + versionCode 2 + versionName "1.0.1" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:23.0.0' + compile 'com.google.code.gson:gson:2.3' +} diff --git a/medescope/proguard-rules.pro b/medescope/proguard-rules.pro new file mode 100644 index 0000000..a9ca86e --- /dev/null +++ b/medescope/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 /home/bruno.costa/android-sdks/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/medescope/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java b/medescope/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java new file mode 100644 index 0000000..497d423 --- /dev/null +++ b/medescope/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java @@ -0,0 +1,13 @@ +package br.com.bemobi.medescope; + +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/medescope/src/main/AndroidManifest.xml b/medescope/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b68e455 --- /dev/null +++ b/medescope/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/medescope/src/main/java/br/com/bemobi/medescope/DownloadFileUtils.java b/medescope/src/main/java/br/com/bemobi/medescope/DownloadFileUtils.java new file mode 100644 index 0000000..bb07239 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/DownloadFileUtils.java @@ -0,0 +1,29 @@ +package br.com.bemobi.medescope; + +import android.os.Environment; + +/** + * Created by bruno.costa on 10/07/15. + */ +public class DownloadFileUtils { + + /* Checks if external storage is available for read and write */ + public static boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + return false; + } + + /* Checks if external storage is available to at least read */ + public static boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + return false; + } + +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/Medescope.java b/medescope/src/main/java/br/com/bemobi/medescope/Medescope.java new file mode 100644 index 0000000..e048c53 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/Medescope.java @@ -0,0 +1,219 @@ +package br.com.bemobi.medescope; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Environment; +import android.text.TextUtils; + +import java.io.File; +import java.util.Map; + +import br.com.bemobi.medescope.callback.DownloadStatusCallback; +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.exception.DirectoryNotMountedException; +import br.com.bemobi.medescope.exception.PathNotFoundException; +import br.com.bemobi.medescope.log.Logger; +import br.com.bemobi.medescope.model.DownloadRequest; +import br.com.bemobi.medescope.service.impl.DownloadCommandService; + +/** + * Created by bruno.costa on 26/06/15. + */ +public class Medescope { + + + private final String TAG = Medescope.class.getSimpleName(); + + public static final String ACTION_BROADCAST_IN_PROGRESS = "br.com.bemobi.medescope.ACTION_BROADCAST_IN_PROGRESS"; + public static final String ACTION_BROADCAST_PAUSED = "br.com.bemobi.medescope.ACTION_BROADCAST_PAUSED"; + public static final String ACTION_BROADCAST_NOT_ENQUEUED = "br.com.bemobi.medescope.ACTION_BROADCAST_NOT_ENQUEUED"; + public static final String ACTION_BROADCAST_CANCELLED = "br.com.bemobi.medescope.ACTION_BROADCAST_CANCELLED"; + public static final String ACTION_BROADCAST_FINISH_WITH_SUCCESS = "br.com.bemobi.medescope.ACTION_BROADCAST_FINISH_WITH_SUCCESS"; + public static final String ACTION_BROADCAST_FINISH_WITH_ERROR = "br.com.bemobi.medescope.ACTION_BROADCAST_FINISH_WITH_ERROR"; + + private Context mContext; + + private static Medescope instance; + + private static StatusBroadcastReceiver mReceiver; + + private String applicationName; + + private Medescope(Context context) { + this.mContext = context.getApplicationContext(); + Logger.setContext(context.getApplicationContext()); + this.applicationName = ""; + } + + public static Medescope getInstance(Context context) { + if( instance == null) { + instance = new Medescope(context); + mReceiver = new StatusBroadcastReceiver(); + } + return instance; + } + + public void setApplicationName(String applicationName){ + this.applicationName = applicationName; + } + + public void enqueue(String id, String uri, String fileName, String downloadName, String developerPayload) { + DownloadRequest downloadRequest = new DownloadRequest(); + downloadRequest.setId(id); + downloadRequest.setUri(uri); + downloadRequest.setFileName(fileName); + downloadRequest.setDownloadName(downloadName); + downloadRequest.setDownloadDescription(this.applicationName); + downloadRequest.setClientPayload(developerPayload); + downloadRequest.setShouldDownloadOnlyInWifi(false); + enqueue(downloadRequest); + } + + public void enqueue(String id, String uri, String fileName, String downloadName, String developerPayload, boolean shouldDownloadOnlyInWifi) { + DownloadRequest downloadRequest = new DownloadRequest(); + downloadRequest.setId(id); + downloadRequest.setUri(uri); + downloadRequest.setFileName(fileName); + downloadRequest.setDownloadName(downloadName); + downloadRequest.setDownloadDescription(this.applicationName); + downloadRequest.setClientPayload(developerPayload); + downloadRequest.setShouldDownloadOnlyInWifi(shouldDownloadOnlyInWifi); + enqueue(downloadRequest); + } + + public void enqueue(String id, String uri, String fileName, String downloadName, String developerPayload, boolean shouldDownloadOnlyInWifi, Map customHeaders) { + DownloadRequest downloadRequest = new DownloadRequest(); + downloadRequest.setId(id); + downloadRequest.setUri(uri); + downloadRequest.setFileName(fileName); + downloadRequest.setDownloadName(downloadName); + downloadRequest.setDownloadDescription(this.applicationName); + downloadRequest.setClientPayload(developerPayload); + if(customHeaders != null && !customHeaders.isEmpty()) { + downloadRequest.setCustomHeaders(customHeaders); + } else { + Logger.error(TAG, "YOU, NASTY DEVELOPER, ARE PASSING A NULL OR EMPTY HEADER MAP"); + } + downloadRequest.setShouldDownloadOnlyInWifi(shouldDownloadOnlyInWifi); + enqueue(downloadRequest); + } + + public void enqueue(DownloadRequest request) { + if(request.isValid()){ + DownloadCommandService.actionEnqueue(mContext, request); + return; + } + Logger.error(TAG, "This is not a valid Request!"); + Logger.error(TAG, "Please fill it up with the basic data"); + } + + public void cancel(String id){ + DownloadCommandService.actionCancel(mContext, id); + } + + public void updateSubscriptionStatusId(Context context, String id){ + if(mReceiver.isCallbackSet()){ + Logger.error(TAG, "YOU HAVE NOT SET A CALLBACK YET!!"); + Logger.error(TAG, "YOU SHOULD IMPLEMENT A BROADCAST RECEIVER BY YOURSELF"); + } + DownloadCommandService.actionSubscribeStatusUpdate(context, id); + } + + public void subscribeStatus(Activity activity, String id, DownloadStatusCallback callback){ + mReceiver.setCallback(callback); + activity.registerReceiver(mReceiver, getStatusBroadcastFilter()); + DownloadCommandService.actionSubscribeStatusUpdate(mContext, id); + } + + public void unsubscribeStatus(Activity activity){ + activity.unregisterReceiver(mReceiver); + DownloadCommandService.actionUnsubscribeStatusUpdate(mContext); + } + + public String getDownloadDirectoryToRead(String subPath) throws DirectoryNotMountedException, PathNotFoundException { + if( !DownloadFileUtils.isExternalStorageReadable() ) { + throw new DirectoryNotMountedException("Directory is not mounted to read!"); + } + return getDownloadDirectory(subPath); + } + + public String getDownloadDirectoryToWrite(String subPath) throws DirectoryNotMountedException, PathNotFoundException { + if( !DownloadFileUtils.isExternalStorageWritable() ) { + throw new DirectoryNotMountedException("Directory is not mounted to write!"); + } + return getDownloadDirectory(subPath); + } + + private String getDownloadDirectory(String subPath) throws PathNotFoundException { + File file = mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); + if(file == null) { + throw new PathNotFoundException("External Path DIRECTORY_DOWNLOADS was not found!!"); + } + if(TextUtils.isEmpty(subPath)){ + return file.getAbsolutePath(); + } + return file.getAbsolutePath() + (subPath.startsWith("/") ? subPath : "/" + subPath); + } + + private IntentFilter getStatusBroadcastFilter(){ + IntentFilter filter = new IntentFilter(); + filter.addAction(Medescope.ACTION_BROADCAST_NOT_ENQUEUED); + filter.addAction(Medescope.ACTION_BROADCAST_PAUSED); + filter.addAction(Medescope.ACTION_BROADCAST_IN_PROGRESS); + filter.addAction(Medescope.ACTION_BROADCAST_CANCELLED); + filter.addAction(Medescope.ACTION_BROADCAST_FINISH_WITH_ERROR); + filter.addAction(Medescope.ACTION_BROADCAST_FINISH_WITH_SUCCESS); + return filter; + } + + + private static class StatusBroadcastReceiver extends BroadcastReceiver { + + private final String TAG = StatusBroadcastReceiver.class.getName(); + + private DownloadStatusCallback mCallback; + + public StatusBroadcastReceiver() { + } + + public void setCallback(DownloadStatusCallback callback){ + this.mCallback = callback; + } + + @Override + public void onReceive(Context context, Intent intent) { + if(mCallback != null) { + String downloadId = intent.getStringExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID); + String action = intent.getAction(); + if (Medescope.ACTION_BROADCAST_IN_PROGRESS.equals(action)) { + int progress = intent.getIntExtra(DownloadConstants.EXTRA_INT_PROGRESS_PERCENTAGE, 0); + mCallback.onDownloadInProgress(downloadId, progress); + } else if (Medescope.ACTION_BROADCAST_PAUSED.equals(action)) { + int reason = intent.getIntExtra(DownloadConstants.EXTRA_INT_REASON_KEY, 0); + mCallback.onDownloadPaused(downloadId, reason); + } else if (Medescope.ACTION_BROADCAST_NOT_ENQUEUED.equals(action)) { + mCallback.onDownloadNotEnqueued(downloadId); + } else if (Medescope.ACTION_BROADCAST_CANCELLED.equals(action)){ + mCallback.onDownloadCancelled(downloadId); + } else if (Medescope.ACTION_BROADCAST_FINISH_WITH_ERROR.equals(action)) { + int reason = intent.getIntExtra(DownloadConstants.EXTRA_INT_REASON_KEY, 0); + String data = intent.getStringExtra(DownloadConstants.EXTRA_STRING_JSON_DATA); + mCallback.onDownloadOnFinishedWithError(downloadId, reason, data); + } else if (Medescope.ACTION_BROADCAST_FINISH_WITH_SUCCESS.equals(action)) { + String filePath = intent.getStringExtra(DownloadConstants.EXTRA_STRING_FILE_PATH); + String data = intent.getStringExtra(DownloadConstants.EXTRA_STRING_JSON_DATA); + mCallback.onDownloadOnFinishedWithSuccess(downloadId, filePath, data); + } + } else { + Logger.error(TAG, "You forgot to set a callback!!"); + } + } + + public boolean isCallbackSet() { + return mCallback != null; + } + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/callback/DownloadStatusCallback.java b/medescope/src/main/java/br/com/bemobi/medescope/callback/DownloadStatusCallback.java new file mode 100644 index 0000000..12681f1 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/callback/DownloadStatusCallback.java @@ -0,0 +1,18 @@ +package br.com.bemobi.medescope.callback; + +/** + * Created by bruno.costa on 08/07/15. + */ +public interface DownloadStatusCallback { + void onDownloadNotEnqueued(String downloadId); + + void onDownloadPaused(String downloadId, int reason); + + void onDownloadInProgress(String downloadId, int progress); + + void onDownloadOnFinishedWithError(String downloadId, int reason, String data); + + void onDownloadOnFinishedWithSuccess(String downloadId, String filePath, String data); + + void onDownloadCancelled(String downloadId); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadConstants.java b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadConstants.java new file mode 100644 index 0000000..a446409 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadConstants.java @@ -0,0 +1,33 @@ +package br.com.bemobi.medescope.constant; + +/** + * Created by bruno.costa on 26/06/15. + */ +public class DownloadConstants { +// public static final String EXTRA_STRING_ID = "EXTRA_STRING_ID"; +// public static final String EXTRA_STRING_URI = "EXTRA_STRING_URI"; +// public static final String EXTRA_STRING_DIRECTORY_PATH = "EXTRA_STRING_DIRECTORY_PATH"; +// public static final String EXTRA_STRING_FILE_NAME = "EXTRA_STRING_FILE_NAME"; + public static final String EXTRA_STRING_FILE_PATH = "EXTRA_STRING_FILE_PATH"; + public static final String EXTRA_STRING_DOWNLOAD_ID = "EXTRA_STRING_DOWNLOAD_ID"; + public static final String EXTRA_ARRAY_STRING_DOWNLOAD_IDS = "EXTRA_ARRAY_STRING_DOWNLOAD_IDS"; +// public static final String EXTRA_STRING_TITLE = "EXTRA_STRING_TITLE"; +// public static final String EXTRA_STRING_DESCRIPTION = "EXTRA_STRING_DESCRIPTION"; + public static final String EXTRA_STRING_JSON_DATA = "EXTRA_STRING_JSON_DATA"; +// public static final String EXTRA_MAP_STRING_CUSTOM_HEADERS = "EXTRA_MAP_STRING_CUSTOM_HEADERS"; + public static final String EXTRA_INT_PROGRESS_PERCENTAGE = "EXTRA_INT_PROGRESS_PERCENTAGE"; + public static final String EXTRA_INT_ERROR_REASON = "EXTRA_INT_ERROR_REASON"; + public static final String EXTRA_DOWNLOAD_INFO = "EXTRA_DOWNLOAD_INFO"; + public static final String EXTRA_INT_REASON_KEY = "EXTRA_INT_REASON_KEY"; + + public static final String DATA_MAP_PREF = "br.com.bemobi.download.DATA_MAP_PREF"; + public static final String DM_STRING_IDS_LIB_TO_DMIDS_MAP_PREF = "br.com.bemobi.medescope.DM_STRING_IDS_LIB_TO_DMIDS_MAP_PREF"; + public static final String DM_STRING_IDS_DMIDS_TO_LIB_MAP_PREF = "br.com.bemobi.medescope.DM_STRING_IDS_DMIDS_TO_LIB_MAP_PREF"; + + public static final String LOG_FEATURE_DOWNLOAD = "BEMOBI_DOWNLOAD_LIB"; + public static final String LOG_FEATURE_SERVICE_LIFECYCLE = "SERVICE_LIFECYCLE"; + public static final String LOG_FEATURE_DOWNLOAD_DATA_STATE = "DOWNLOAD_DATA_STATE"; + public static final String LOG_FEATURE_DOWNLOAD_SEND_PROGRESS = "LOG_FEATURE_DOWNLOAD_SEND_PROGRESS"; + + public static final String PREF_SUBSCRIBED_ID = "PREF_SUBSCRIBED_ID"; +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoReasonConstants.java b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoReasonConstants.java new file mode 100644 index 0000000..956d01f --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoReasonConstants.java @@ -0,0 +1,155 @@ +package br.com.bemobi.medescope.constant; + +/** + * Created by raphael on 7/7/15. + */ +public class DownloadInfoReasonConstants { + + /** + * Unknown error. :P + */ + //public final static int REASON_UNKNOWN_ERROR = 0; + public final static int PAUSED_GENERIC_ERROR = 2000; + + + /** + * Value of COLUMN_REASON when the download is paused because some network error occurred and the download manager is waiting before retrying the request. + */ + //public final static int REASON_PAUSED_WAITING_TO_RETRY = 1; + public final static int PAUSED_WAITING_NETWORK_AFTER_ERROR = 2001; + + /** + * Value of COLUMN_REASON when the download is waiting for network connectivity to proceed. + */ + //public final static int REASON_PAUSED_WAITING_FOR_NETWORK = 2; + public final static int PAUSED_WAITING_NETWORK = 2002; + + /** + * Value of COLUMN_REASON when the download exceeds a size limit for downloads over the mobile network and the download manager is waiting for a Wi-Fi connection to proceed. + */ + //public final static int PAUSED_QUEUED_FOR_WIFI = 3; + public final static int PAUSED_QUEUED_TO_DOWNLOAD_ON_WIFI = 2003; + + /** + * Value of COLUMN_REASON when the download is paused for some other reason. + */ + //public final static int REASON_PAUSED_UNKNOWN = 4; + public final static int PAUSED_GENERIC_REASON = 2004; + + + + + + + + /** + * Value of COLUMN_REASON when a storage issue arises which doesn't fit under any other error code. + */ + //public final static int REASON_ERROR_FILE_ERROR = 1001; + public final static int ERROR_FILE_GENERIC_PROBLEM = 3001; + + /** + * Value of COLUMN_REASON when an HTTP code was received that download manager can't handle. + */ + //public final static int REASON_ERROR_UNHANDLED_HTTP_CODE = 1002; + public final static int ERROR_UNHANDLED_HTTP_CODE = 3002; + + /** + * Value of COLUMN_REASON when an error receiving or processing data occurred at the HTTP level. + */ + //public final static int REASON_ERROR_HTTP_DATA_ERROR = 1004; + public final static int ERROR_HTTP_DATA_ERROR = 3004; + + /** + * Value of COLUMN_REASON when there were too many redirects. + */ + //public final static int REASON_ERROR_TOO_MANY_REDIRECTS = 1005; + public final static int ERROR_TOO_MANY_REDIRECTS = 3005; + + /** + * Value of COLUMN_REASON when there was insufficient storage space. + */ + //public final static int REASON_ERROR_INSUFFICIENT_SPACE = 1006; + public final static int ERROR_INSUFFICIENT_STORAGE = 3006; + + /** + * Value of COLUMN_REASON when no external storage device was found. + */ + //public final static int REASON_ERROR_DEVICE_NOT_FOUND = 1007; + public final static int ERROR_STORAGE_NOT_FOUND = 3007; + + /** + * Value of COLUMN_REASON when some possibly transient error occurred but we can't resume the download. + */ + //public final static int REASON_ERROR_CANNOT_RESUME = 1008; + public final static int ERROR_GENERIC = 3008; + + /** + * Value of COLUMN_REASON when the requested destination file already exists (the download manager will not overwrite an existing file). + */ + //public final static int REASON_ERROR_FILE_ALREADY_EXISTS = 1009; + public final static int ERROR_ALREADY_EXISTING_FILE = 3009; + + /** + * Value of COLUMN_REASON when a storage issue arises which doesn't fit under any other error code. + */ + //public final static int REASON_ERROR_BLOCKED = 1010; + public final static int ERROR_GENERIC_STORAGE_PROBLEM = 3010; + + public static String getDownloadReasonText(int reason) { + String reasonStr = ""; + + switch(reason) { + case DownloadInfoReasonConstants.ERROR_GENERIC: { + reasonStr = "ERROR_GENERIC"; + break; + } + case DownloadInfoReasonConstants.ERROR_STORAGE_NOT_FOUND: { + reasonStr = "ERROR_STORAGE_NOT_FOUND"; + break; + } + case DownloadInfoReasonConstants.ERROR_ALREADY_EXISTING_FILE: { + reasonStr = "ERROR_ALREADY_EXISTING_FILE"; + break; + } + case DownloadInfoReasonConstants.ERROR_FILE_GENERIC_PROBLEM: { + reasonStr = "ERROR_FILE_GENERIC_PROBLEM"; + break; + } + case DownloadInfoReasonConstants.ERROR_HTTP_DATA_ERROR: { + reasonStr = "ERROR_HTTP_DATA_ERROR"; + break; + } + case DownloadInfoReasonConstants.ERROR_INSUFFICIENT_STORAGE: { + reasonStr = "ERROR_INSUFFICIENT_STORAGE"; + break; + } + case DownloadInfoReasonConstants.ERROR_TOO_MANY_REDIRECTS: { + reasonStr = "ERROR_TOO_MANY_REDIRECTS"; + break; + } + case DownloadInfoReasonConstants.ERROR_UNHANDLED_HTTP_CODE: { + reasonStr = "ERROR_UNHANDLED_HTTP_CODE"; + break; + } + case DownloadInfoReasonConstants.PAUSED_QUEUED_TO_DOWNLOAD_ON_WIFI: { + reasonStr = "PAUSED_QUEUED_TO_DOWNLOAD_ON_WIFI"; + break; + } + case DownloadInfoReasonConstants.PAUSED_GENERIC_REASON: { + reasonStr = "PAUSED_GENERIC_REASON"; + break; + } + case DownloadInfoReasonConstants.PAUSED_WAITING_NETWORK: { + reasonStr = "PAUSED_WAITING_NETWORK"; + break; + } + case DownloadInfoReasonConstants.PAUSED_WAITING_NETWORK_AFTER_ERROR: { + reasonStr = "PAUSED_WAITING_NETWORK_AFTER_ERROR"; + break; + } + } + + return reasonStr; + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoStatusConstants.java b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoStatusConstants.java new file mode 100644 index 0000000..1cb5401 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/constant/DownloadInfoStatusConstants.java @@ -0,0 +1,20 @@ +package br.com.bemobi.medescope.constant; + +/** + * Created by raphael on 7/7/15. + */ +public class DownloadInfoStatusConstants { + public final static int NOT_ENQUEUED_STATUS = -1; + + public final static int PENDING_STATUS = 1 << 0; + + public final static int IN_PROGRESS_STATUS = 1 << 1; + + public final static int PAUSED_STATUS = 1 << 2; + + public final static int SUCCESSFUL_STATUS = 1 << 3; + + public final static int FAILED_STATUS = 1 << 4; + + public final static int UNKNOWN_ERROR = 1000; +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/constant/Extras.java b/medescope/src/main/java/br/com/bemobi/medescope/constant/Extras.java new file mode 100644 index 0000000..4d79e62 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/constant/Extras.java @@ -0,0 +1,9 @@ +package br.com.bemobi.medescope.constant; + +/** + * Created by luis.fernandez on 7/5/15. + */ +public class Extras { + + public static final String EXTRA_DOWNLOAD = "br.com.bemobi.medescope.EXTRA_DOWNLOAD"; +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/exception/DirectoryNotMountedException.java b/medescope/src/main/java/br/com/bemobi/medescope/exception/DirectoryNotMountedException.java new file mode 100644 index 0000000..af5f20c --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/exception/DirectoryNotMountedException.java @@ -0,0 +1,23 @@ +package br.com.bemobi.medescope.exception; + +/** + * Created by bruno.costa on 10/07/15. + */ +public class DirectoryNotMountedException extends DownloadBaseException { + + public DirectoryNotMountedException() { + } + + public DirectoryNotMountedException(String detailMessage) { + super(detailMessage); + } + + public DirectoryNotMountedException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public DirectoryNotMountedException(Throwable throwable) { + super(throwable); + } + +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/exception/DownloadBaseException.java b/medescope/src/main/java/br/com/bemobi/medescope/exception/DownloadBaseException.java new file mode 100644 index 0000000..d3079b3 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/exception/DownloadBaseException.java @@ -0,0 +1,23 @@ +package br.com.bemobi.medescope.exception; + +/** + * Created by bruno.costa on 10/07/15. + */ +public class DownloadBaseException extends Exception { + + public DownloadBaseException() { + } + + public DownloadBaseException(String detailMessage) { + super(detailMessage); + } + + public DownloadBaseException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public DownloadBaseException(Throwable throwable) { + super(throwable); + } + +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/exception/PathNotFoundException.java b/medescope/src/main/java/br/com/bemobi/medescope/exception/PathNotFoundException.java new file mode 100644 index 0000000..a3f423e --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/exception/PathNotFoundException.java @@ -0,0 +1,22 @@ +package br.com.bemobi.medescope.exception; + +/** + * Created by bruno.costa on 10/07/15. + */ +public class PathNotFoundException extends DownloadBaseException { + + public PathNotFoundException() { + } + + public PathNotFoundException(String detailMessage) { + super(detailMessage); + } + + public PathNotFoundException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public PathNotFoundException(Throwable throwable) { + super(throwable); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/log/IntentLogger.java b/medescope/src/main/java/br/com/bemobi/medescope/log/IntentLogger.java new file mode 100644 index 0000000..46f726e --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/log/IntentLogger.java @@ -0,0 +1,52 @@ +package br.com.bemobi.medescope.log; + +import android.content.Intent; +import android.os.Bundle; + +import java.util.Iterator; +import java.util.Set; + +/** + * Created by luisfernandez on 7/3/15. + */ +public class IntentLogger { + private static final String TAG = "IntentLogger"; + + private String from; + private String feature; + + public IntentLogger(String from, String feature) { + this.from = from; + this.feature = feature; + } + + public void logIntent(Intent intent) { + if (intent != null) { + this.logBundle(intent.getExtras()); + } + } + + public void logBundle(Bundle bundle) { + Logger.debug(TAG, feature, String.format(">>>>>>>>>>>>>>>>>>>>>>>>>> DUMPING BUNDLE from: %s", from)); + + if (bundle != null) { + Set keys = bundle.keySet(); + Iterator it = keys.iterator(); + while (it.hasNext()) { + String key = it.next(); + Object object = bundle.get(key); + + if (object != null) { + String[] values = object.toString().split(", "); + + for (int i = 0; i < values.length; i++) { + Logger.debug(TAG, feature, String.format(" [%s] = %s", key, values[i])); + } + } + + } + + Logger.debug(TAG, feature, "\n"); + } + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/log/Logger.java b/medescope/src/main/java/br/com/bemobi/medescope/log/Logger.java new file mode 100644 index 0000000..f77ed02 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/log/Logger.java @@ -0,0 +1,141 @@ +package br.com.bemobi.medescope.log; + +import android.content.Context; +import android.util.Log; + +/** + * Created by brunocosta on 9/10/15. + */ +public class Logger { + + private static final String TAG_tag = Logger.class.getSimpleName(); + + public static void setContext(Context mContext) { + LogConfig.getInstance().setContext(mContext); + } + + private static String getString(String word) { + return (word == null) ? "null" : word; + } + + public static void debug(String tag, String msg) { + if (LogConfig.getInstance().isDebug()) { + Log.d(TAG_tag, getString(tag) + ":" + getString(msg)); + } + } + + public static void debug(String tag, String feature, String msg) { + if (LogConfig.getInstance().isDebug()) { + if (LogConfig.getInstance().isDetailed()) { + Log.d(TAG_tag, getString(tag) + " [FEATURE:] " + getString(feature) + " > " + getString(msg)); + } else { + Log.d(TAG_tag, getString(feature) + " > " + getString(msg)); + } + } + } + + public static void debug(String tag, String msg, Throwable throwable) { + if (LogConfig.getInstance().isDebug()) { + Log.d(TAG_tag, getString(tag) + ":" + getString(msg), throwable); + } + } + + public static void error(String tag, String msg) { + if (LogConfig.getInstance().isError()) { + Log.e(TAG_tag, getString(tag) + ":" + getString(msg)); + } + } + + public static void error(String tag, String feature, String msg) { + if (LogConfig.getInstance().isDebug()) { + Log.e(TAG_tag, getString(tag) + " [FEATURE:] " + getString(feature) + " > " + getString(msg)); + } + } + + public static void error(String tag, String msg, Throwable th) { + if (LogConfig.getInstance().isError()) { + Log.e(TAG_tag, getString(tag) + ":" + getString(msg), th); + } + } + + public static class LogConfig { + private boolean detailed = false; + + private boolean debug = false; + + private boolean error = false; + + private int showWarnCount = 0; + + private static LogConfig instance; + + private Context mContext; + + protected static LogConfig getInstance() { + if (instance == null) { + instance = new LogConfig(); + } + return instance; + } + + protected void setContext(Context mContext) { + this.mContext = mContext.getApplicationContext(); + init(); + } + + private void init() { + initDetailedLog(); + initDebugLog(); + initErrorLog(); + } + + private void initDetailedLog() { + int id = mContext.getResources().getIdentifier("mcare_detailed_log", "bool", mContext.getPackageName()); + if (id > 0) { + detailed = mContext.getResources().getBoolean(id); + } + } + + private void initDebugLog() { + int id = mContext.getResources().getIdentifier("mcare_debug_log", "bool", mContext.getPackageName()); + if (id > 0) { + debug = mContext.getResources().getBoolean(id); + } + } + + private void initErrorLog() { + int id = mContext.getResources().getIdentifier("mcare_error_log", "bool", mContext.getPackageName()); + if (id > 0) { + error = mContext.getResources().getBoolean(id); + } + } + + protected boolean isDetailed() { + warningNullContext(); + return detailed; + } + + protected boolean isDebug() { + warningNullContext(); + return debug; + } + + protected boolean isError() { + warningNullContext(); + return error; + } + + private void warningNullContext() { + if (mContext == null) { + if (showWarnCount < 1) { + Log.w(">>>> MCareLogUtil", + "Use LogUtil.setContext(mContext) para que sua configuração no XML tenha efeito. Default: Todos os logs desligados.\n" + + "Exemplo de XML:\n" + "true\n" + + "true\n" + "true"); + showWarnCount++; + } + } + } + } + +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/log/MapLogger.java b/medescope/src/main/java/br/com/bemobi/medescope/log/MapLogger.java new file mode 100644 index 0000000..28a1431 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/log/MapLogger.java @@ -0,0 +1,37 @@ +package br.com.bemobi.medescope.log; + +import java.util.Map; + +/** + * Created by luis.fernandez on 7/5/15. + */ +public class MapLogger { + + private static final String TAG = "MapLogger"; + private String feature; + + public MapLogger(String feature) { + this.feature = feature; + } + + public void log(Map map) { + for (String key : map.keySet()) { + Logger.debug(TAG, feature, String.format(" [%s] = %s", key, map.get(key))); + } + Logger.debug(TAG, feature, "\n"); + } + + public void logStringLong(Map map) { + for (String key : map.keySet()) { + Logger.debug(TAG, feature, String.format(" [%s] = %s", key, map.get(key))); + } + Logger.debug(TAG, feature, "\n"); + } + + public void logLongString(Map map) { + for (Long key : map.keySet()) { + Logger.debug(TAG, feature, String.format(" [%s] = %s", key, map.get(key))); + } + Logger.debug(TAG, feature, "\n"); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadInfo.java b/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadInfo.java new file mode 100644 index 0000000..9ba51d3 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadInfo.java @@ -0,0 +1,194 @@ +package br.com.bemobi.medescope.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import br.com.bemobi.medescope.constant.DownloadInfoStatusConstants; + +/** + * Created by bruno.costa on 30/06/15. + */ +public class DownloadInfo implements Parcelable{ + + int status; + + int reason; + + String filename; + + String localURI; + + long lastModified; + + long downloadedSoFar; + + long totalSize; + + int progress; + + public DownloadInfo() { + } + + public DownloadInfo(int status, int reason, String filename, String localURI, long lastModified, long downloadedSoFar, long totalSize, int progress) { + this.status = status; + this.reason = reason; + this.filename = filename; + this.localURI = localURI; + this.lastModified = lastModified; + this.downloadedSoFar = downloadedSoFar; + this.totalSize = totalSize; + this.progress = progress; + } + + public DownloadInfo(int status, int reason) { + this.status = status; + this.reason = reason; + } + + @Override + public String toString() { + return "DownloadInfo{" + + "status=" + status + + ", reason=" + reason + + ", filename='" + filename + '\'' + + ", localURI='" + localURI + '\'' + + ", lastModified=" + lastModified + + ", downloadedSoFar=" + downloadedSoFar + + ", totalSize=" + totalSize + + ", progress=" + progress + + '}'; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public void setReason(int reason) { + this.reason = reason; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public void setLocalURI(String localURI) { + this.localURI = localURI; + } + + public void setLastModified(long lastModified) { + this.lastModified = lastModified; + } + + public void setDownloadedSoFar(long downloadedSoFar) { + this.downloadedSoFar = downloadedSoFar; + } + + public void setTotalSize(long totalSize) { + this.totalSize = totalSize; + } + + public void setProgress(int progress) { + this.progress = progress; + } + + public int getReason() { + return reason; + } + + public String getFilename() { + return filename; + } + + public String getLocalURI() { + return localURI; + } + + public long getLastModified() { + return lastModified; + } + + public long getDownloadedSoFar() { + return downloadedSoFar; + } + + public long getTotalSize() { + return totalSize; + } + + public int getProgress() { + return progress; + } + + public boolean isPaused() { + return status == DownloadInfoStatusConstants.PAUSED_STATUS; + } + + public boolean isInProgress() { + return status == DownloadInfoStatusConstants.IN_PROGRESS_STATUS; + } + + public boolean hasFinishedWithSuccess() { + return status == DownloadInfoStatusConstants.SUCCESSFUL_STATUS; + } + + public boolean hasFinishedWithError() { + return status == DownloadInfoStatusConstants.FAILED_STATUS; + } + + public boolean hasFinished() { + return status == DownloadInfoStatusConstants.SUCCESSFUL_STATUS + || status == DownloadInfoStatusConstants.FAILED_STATUS; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DownloadInfo that = (DownloadInfo) o; + + if (status != that.status) return false; + if (reason != that.reason) return false; + return (Double.compare(that.progress, progress) != 0); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(this.status); + out.writeInt(this.reason); + out.writeString(this.filename); + out.writeString(this.localURI); + out.writeLong(this.lastModified); + out.writeLong(this.downloadedSoFar); + out.writeLong(this.totalSize); + out.writeInt(this.progress); + } + + private DownloadInfo(Parcel in) { + this.status = in.readInt(); + this.reason = in.readInt(); + this.filename = in.readString(); + this.localURI = in.readString(); + this.lastModified = in.readLong(); + this.downloadedSoFar = in.readLong(); + this.totalSize = in.readLong(); + this.progress = in.readInt(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public DownloadInfo createFromParcel(Parcel in) { + return new DownloadInfo(in); + } + + public DownloadInfo[] newArray(int size) { + return new DownloadInfo[size]; + } + }; +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadRequest.java b/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadRequest.java new file mode 100644 index 0000000..fa38917 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/model/DownloadRequest.java @@ -0,0 +1,124 @@ +package br.com.bemobi.medescope.model; + +import android.text.TextUtils; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by luis.fernandez on 7/5/15. + */ +public class DownloadRequest implements Serializable { + + String id; + String uri; + String fileName; + String downloadName; + String downloadDescription; + String clientPayload; + boolean shouldDownloadOnlyInWifi; + Map customHeaders; + + public DownloadRequest() { + this.customHeaders = new HashMap<>(); + } + + public DownloadRequest(String id, String uri, String fileName, String downloadName, String downloadDescription, String clientPayload, boolean shouldDownloadOnlyInWifi, Map customHeaders) { + this.id = id; + this.uri = uri; + this.fileName = fileName; + this.downloadName = downloadName; + this.downloadDescription = downloadDescription; + this.clientPayload = clientPayload; + this.shouldDownloadOnlyInWifi = shouldDownloadOnlyInWifi; + this.customHeaders = customHeaders; + } + + public boolean isValid() { + return !TextUtils.isEmpty(id) && + !TextUtils.isEmpty(uri) && + !TextUtils.isEmpty(fileName) && + !TextUtils.isEmpty(downloadName) && + !TextUtils.isEmpty(downloadDescription) && + !TextUtils.isEmpty(clientPayload); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getDownloadName() { + return downloadName; + } + + public void setDownloadName(String downloadName) { + this.downloadName = downloadName; + } + + public String getDownloadDescription() { + return downloadDescription; + } + + public void setDownloadDescription(String downloadDescription) { + this.downloadDescription = downloadDescription; + } + + public String getClientPayload() { + return clientPayload; + } + + public void setClientPayload(String clientPayload) { + this.clientPayload = clientPayload; + } + + public Map getCustomHeaders() { + return customHeaders; + } + + public void setCustomHeaders(Map customHeaders) { + this.customHeaders = customHeaders; + } + + public boolean shouldDownloadOnlyInWifi() { + return shouldDownloadOnlyInWifi; + } + + public void setShouldDownloadOnlyInWifi(boolean shouldDownloadOnlyInWifi) { + this.shouldDownloadOnlyInWifi = shouldDownloadOnlyInWifi; + } + + @Override + public String toString() { + return "Download{" + + "id='" + id + '\'' + + ", uri='" + uri + '\'' + + ", fileName='" + fileName + '\'' + + ", downloadName='" + downloadName + '\'' + + ", downloadDescription='" + downloadDescription + '\'' + + ", clientPayload='" + clientPayload + '\'' + + ", shouldDownloadOnlyInWifi=" + shouldDownloadOnlyInWifi + + ", customHeaders=" + customHeaders + + '}'; + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/receiver/BroadcastReceiverLogger.java b/medescope/src/main/java/br/com/bemobi/medescope/receiver/BroadcastReceiverLogger.java new file mode 100644 index 0000000..d2c32fe --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/receiver/BroadcastReceiverLogger.java @@ -0,0 +1,33 @@ +package br.com.bemobi.medescope.receiver; + +import android.content.Context; +import android.content.Intent; + +import br.com.bemobi.medescope.log.IntentLogger; + +/** + * Created by luis.fernandez on 6/27/15. + */ +public class BroadcastReceiverLogger { + + private static final String TAG = "BroadcastReceiverLogger"; + + private String from; + private String feature; + +// public BroadcastReceiverLogger() { +// } + + public BroadcastReceiverLogger(String from, String feature) { + this.from = from; + this.feature = feature; + } + + public void onReceive(Context context, Intent intent) { +// LogUtil.debug(TAG, feature, ""); +// LogUtil.debug(TAG, feature, String.format(">>>>>>>>>>>>>>>>>>>>>>>>>> DUMPING BROADCAST INTENT from: %s", from)); +// LogUtil.debug(TAG, feature, String.format(" [%s] = %s", "ACTION", intent.getAction())); +// +// new IntentLogger(from, feature).logIntent(intent); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/receiver/DMDownloaderReceiver.java b/medescope/src/main/java/br/com/bemobi/medescope/receiver/DMDownloaderReceiver.java new file mode 100644 index 0000000..7951db7 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/receiver/DMDownloaderReceiver.java @@ -0,0 +1,46 @@ +package br.com.bemobi.medescope.receiver; + +import android.app.DownloadManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import br.com.bemobi.medescope.service.impl.DMIntentService; + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD; + +/** + * Created by bruno.costa on 26/06/15. + */ +public class DMDownloaderReceiver extends BroadcastReceiver { + public static final String TAG = DMDownloaderReceiver.class.getSimpleName(); + + public DMDownloaderReceiver() { + } + + @Override + public void onReceive(Context context, Intent intent) { + new BroadcastReceiverLogger(TAG, LOG_FEATURE_DOWNLOAD).onReceive(context, intent); + + String action = intent.getAction(); + + if(DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { + Log.d(TAG, "DM DOWNLOAD COMPLETED"); + Long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); + + DMIntentService.actionFinish(context, downloadId); + } + else if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) { + Log.d(TAG, "DM NOTIFICATION CLICKED"); + + long[] downloadIds = null; + + if (intent.hasExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS)){ + downloadIds = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); + } + + DMIntentService.actionNotificationClicked(context, downloadIds); + } + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/repository/DMRepository.java b/medescope/src/main/java/br/com/bemobi/medescope/repository/DMRepository.java new file mode 100644 index 0000000..7176463 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/repository/DMRepository.java @@ -0,0 +1,98 @@ +package br.com.bemobi.medescope.repository; + +import android.content.Context; +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.HashMap; +import java.util.Map; + +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.log.MapLogger; + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD_DATA_STATE; + +/** + * Created by bruno.costa on 01/07/15. + */ +public class DMRepository { + + private static final String TAG = DMRepository.class.getSimpleName(); + + private Context mContext; + private static DMRepository instance; + + private Map mapIdsClientToDM; + private Map mapIdsDMToClient; + + private DMRepository(Context context) { + this.mContext = context; + this.mapIdsClientToDM = new HashMap<>(); + this.mapIdsDMToClient = new HashMap<>(); + this.loadMaps(); + } + + public static DMRepository getInstance(Context context) { + if(instance == null){ + instance = new DMRepository(context); + } + return instance; + } + + public void persistIds(String downloadId, Long dmDownloadId) { + if( !mapIdsDMToClient.containsKey(dmDownloadId) && !mapIdsClientToDM.containsKey(downloadId)) { + mapIdsDMToClient.put(dmDownloadId, downloadId); + mapIdsClientToDM.put(downloadId, dmDownloadId); + persistMaps(); + } + + //TODO Should we give a feedback? + } + + public void removeId(String downloadId){ + Long dmDownloadId = mapIdsClientToDM.get(downloadId); + mapIdsDMToClient.remove(dmDownloadId); + mapIdsClientToDM.remove(downloadId); + persistMaps(); + } + + public void removeId(Long dmDownloadId){ + String downloadId = mapIdsDMToClient.get(dmDownloadId); + mapIdsDMToClient.remove(dmDownloadId); + mapIdsClientToDM.remove(downloadId); + persistMaps(); + } + + public Long getDMId(String clientId){ + return mapIdsClientToDM.get(clientId); + } + + public String getClientId(Long dmDownloadId){ + return mapIdsDMToClient.get(dmDownloadId); + } + + public void loadMaps(){ + String mapIdsLibtoDMStr = PreferencesUtils.getStringPreference(mContext.getApplicationContext(), DownloadConstants.DM_STRING_IDS_LIB_TO_DMIDS_MAP_PREF, ""); + if(!TextUtils.isEmpty(mapIdsLibtoDMStr)) { + Gson gson = new Gson(); + mapIdsClientToDM = gson.fromJson(mapIdsLibtoDMStr, new TypeToken>(){}.getType()); + } else { + mapIdsClientToDM = new HashMap<>(); + } + + String mapIdsDMtoLibStr = PreferencesUtils.getStringPreference(mContext.getApplicationContext(), DownloadConstants.DM_STRING_IDS_DMIDS_TO_LIB_MAP_PREF, ""); + if(!TextUtils.isEmpty(mapIdsDMtoLibStr)) { + Gson gson = new Gson(); + mapIdsDMToClient = gson.fromJson(mapIdsDMtoLibStr, new TypeToken>(){}.getType()); + } else { + mapIdsDMToClient = new HashMap<>(); + } + } + + public void persistMaps(){ + PreferencesUtils.savePreference(mContext.getApplicationContext(), DownloadConstants.DM_STRING_IDS_LIB_TO_DMIDS_MAP_PREF, new Gson().toJson(mapIdsClientToDM)); + PreferencesUtils.savePreference(mContext.getApplicationContext(), DownloadConstants.DM_STRING_IDS_DMIDS_TO_LIB_MAP_PREF, new Gson().toJson(mapIdsDMToClient)); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/repository/DownloadDataRepository.java b/medescope/src/main/java/br/com/bemobi/medescope/repository/DownloadDataRepository.java new file mode 100644 index 0000000..1024721 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/repository/DownloadDataRepository.java @@ -0,0 +1,29 @@ +package br.com.bemobi.medescope.repository; + +import java.util.Map; + +/** + * Created by bruno.costa on 02/07/15. + */ +public interface DownloadDataRepository { + + Map getDownloadsMap(); + + void setDownloadsMap(Map downloadsMap); + + void putDownloadData(String downloadId, String data); + + String getDownloadData(String downloadId); + + void removeDownloadData(String downloadId); + + boolean isEmptyDownloadData(); + + boolean containsDownloadDataKey(String key); + + void persistSubscribedId(String downloadId); + + String recoverSubscribedId(); + + void removeSubscribedId(); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/repository/PreferencesUtils.java b/medescope/src/main/java/br/com/bemobi/medescope/repository/PreferencesUtils.java new file mode 100644 index 0000000..d4f28d1 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/repository/PreferencesUtils.java @@ -0,0 +1,132 @@ +package br.com.bemobi.medescope.repository; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; + +/** + * Created by brunocosta on 9/10/15. + */ +public class PreferencesUtils { + // private static Map preferences = new HashMap(); + + public static SharedPreferences getSharedPreferences(Context context) { + SharedPreferences pref + // = preferences.get(context.getApplicationContext()) + ; + // if (pref == null) { + pref = context.getApplicationContext().getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE); + // preferences.put(context, pref); + // } + + return pref; + } + + public static void clearPreferences(Context context) { + SharedPreferences.Editor editor = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE).edit(); + editor.clear(); + editor.commit(); + } + + public static boolean getBooleanPreference(Context context, int resId, boolean defaultValue) { + return getSharedPreferences(context).getBoolean(context.getString(resId), defaultValue); + } + + public static boolean getBooleanPreference(Context context, String prefKey, boolean defaultValue) { + return getSharedPreferences(context).getBoolean(prefKey, defaultValue); + } + + public static int getIntPreference(Context context, int resId, int defaultValue) { + return getSharedPreferences(context).getInt(context.getString(resId), defaultValue); + } + + public static int getIntPreference(Context context, String prefKey, int defaultValue) { + return getSharedPreferences(context).getInt(prefKey, defaultValue); + } + + public static long getLongPreference(Context context, int resId, long defaultValue) { + return getSharedPreferences(context).getLong(context.getString(resId), defaultValue); + } + + public static long getLongPreference(Context context, String prefKey, long defaultValue) { + return getSharedPreferences(context).getLong(prefKey, defaultValue); + } + + public static String getStringPreference(Context context, int resId, String defaultValue) { + return getSharedPreferences(context).getString(context.getString(resId), defaultValue); + } + + public static String getStringPreference(Context context, String prefKey, String defaultValue) { + return getSharedPreferences(context).getString(prefKey, defaultValue); + } + + public static void savePreference(Context context, int resId, int newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putInt(context.getString(resId), newValue); + editor.commit(); + } + + public static void savePreference(Context context, String prefKey, int newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putInt(prefKey, newValue); + editor.commit(); + } + + public static void savePreference(Context context, int resId, long newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putLong(context.getString(resId), newValue); + editor.commit(); + } + + public static void savePreference(Context context, String prefKey, long newValue){ + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putLong(prefKey, newValue); + editor.commit(); + } + + public static void savePreference(Context context, int resId, String newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putString(context.getString(resId), newValue); + editor.commit(); + } + + public static void savePreference(Context context, String prefKey, String newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putString(prefKey, newValue); + editor.commit(); + } + + public static void savePreference(Context context, int resId, Boolean newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putBoolean(context.getString(resId), newValue); + editor.commit(); + } + + public static void savePreference(Context context, String prefKey, Boolean newValue) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.putBoolean(prefKey, newValue); + editor.commit(); + } + + public static void removePreference(Context context, int resId) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.remove(context.getString(resId)); + editor.commit(); + } + + public static void removePreference(Context context, String prefKey) { + SharedPreferences mPreferences = PreferencesUtils.getSharedPreferences(context); + Editor editor = mPreferences.edit(); + editor.remove(prefKey); + editor.commit(); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/repository/impl/MapDownloadDataRepository.java b/medescope/src/main/java/br/com/bemobi/medescope/repository/impl/MapDownloadDataRepository.java new file mode 100644 index 0000000..dcf10a0 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/repository/impl/MapDownloadDataRepository.java @@ -0,0 +1,112 @@ +package br.com.bemobi.medescope.repository.impl; + +import android.content.Context; +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.HashMap; +import java.util.Map; + +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.log.MapLogger; +import br.com.bemobi.medescope.repository.DownloadDataRepository; +import br.com.bemobi.medescope.repository.PreferencesUtils; + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD_DATA_STATE; +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_SERVICE_LIFECYCLE; + +/** + * Created by bruno.costa on 01/07/15. + */ +public class MapDownloadDataRepository implements DownloadDataRepository { + + private static final String TAG = MapDownloadDataRepository.class.getSimpleName(); + + private static DownloadDataRepository downloadDataRepository; + + private Map downloadsMap = new HashMap<>(); + + private Context mContext; + + public static DownloadDataRepository getInstance(Context context) { + if(downloadDataRepository == null) { + downloadDataRepository = new MapDownloadDataRepository(context); + } + return downloadDataRepository; + } + + private MapDownloadDataRepository(Context context) { + this.mContext = context.getApplicationContext(); + load(); + } + + @Override + public Map getDownloadsMap() { + return downloadsMap; + } + + @Override + public void setDownloadsMap(Map downloadsMap) { + this.downloadsMap = downloadsMap; + } + + @Override + public void putDownloadData(String downloadId, String data) { + this.downloadsMap.put(downloadId, data); + persistDownloadData(); + } + + @Override + public String getDownloadData(String downloadId) { + return this.downloadsMap.get(downloadId); + } + + @Override + public void removeDownloadData(String downloadId) { + + this.downloadsMap.remove(downloadId); + persistDownloadData(); + } + + @Override + public boolean isEmptyDownloadData() { + return this.downloadsMap.isEmpty(); + } + + @Override + public boolean containsDownloadDataKey(String key) { + return this.downloadsMap.containsKey(key); + } + + @Override + public void persistSubscribedId(String downloadId) { + PreferencesUtils.savePreference(mContext.getApplicationContext(), DownloadConstants.PREF_SUBSCRIBED_ID, downloadId); + } + + @Override + public String recoverSubscribedId() { + return PreferencesUtils.getStringPreference(mContext.getApplicationContext(), DownloadConstants.PREF_SUBSCRIBED_ID, ""); + } + + @Override + public void removeSubscribedId() { + PreferencesUtils.removePreference(mContext.getApplicationContext(), DownloadConstants.PREF_SUBSCRIBED_ID); + } + + private void load() { + String map = PreferencesUtils.getStringPreference(mContext.getApplicationContext(), DownloadConstants.DATA_MAP_PREF, ""); + if(!TextUtils.isEmpty(map)) { + Gson gson = new Gson(); + downloadsMap = gson.fromJson(map, new TypeToken>(){}.getType()); + } else { + downloadsMap = new HashMap<>(); + } + } + + private void persistDownloadData() + { + PreferencesUtils.savePreference(mContext.getApplicationContext(), DownloadConstants.DATA_MAP_PREF, new Gson().toJson(downloadsMap)); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/CommunicationService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/CommunicationService.java new file mode 100644 index 0000000..a787543 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/CommunicationService.java @@ -0,0 +1,21 @@ +package br.com.bemobi.medescope.service; + +/** + * Created by bruno.costa on 02/07/15. + */ +public interface CommunicationService { + + void sendFinishWithSuccessBroadcastData(String downloadId, String filePath, String data); + + void sendFinishWithErrorBroadcastData(String downloadId, int reason, String data); + + void sendDownloadStatusNotEnqueue(String downloadId); + + void sendDownloadStatusPaused(String downloadId, int reason); + + void sendDownloadStatusProgress(String downloadId, int progress); + + void showDownloadQueue(); + + void sendCancelled(String downloadId); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadCommand.java b/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadCommand.java new file mode 100644 index 0000000..1a7bca8 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadCommand.java @@ -0,0 +1,26 @@ +package br.com.bemobi.medescope.service; + +import android.os.Bundle; + +import br.com.bemobi.medescope.model.DownloadRequest; +import br.com.bemobi.medescope.model.DownloadInfo; + +/** + * Created by bruno.costa on 30/06/15. + */ +public interface DownloadCommand { + + void startCommand(); + + void executeCommand(String action, Bundle extras); + + void enqueue(DownloadRequest downloadRequest); + + void cancelAction(String downloadId); + + void finishAction(String downloadId, DownloadInfo downloadInfo); + + void clickNotificationAction(String[] downloadIds); + + void shutdownCommand(); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadService.java new file mode 100644 index 0000000..65e59b9 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/DownloadService.java @@ -0,0 +1,23 @@ +package br.com.bemobi.medescope.service; + +import java.util.Map; + +import br.com.bemobi.medescope.model.DownloadInfo; + +/** + * Created by bruno.costa on 30/06/15. + */ +public interface DownloadService { + + void shutdown(); + + boolean enqueue(String downloadId, String uri, String fileName, String title, String description, String data, boolean shouldDownloadOnlyInWifi, Map customHeaders); + + boolean cancel(String downloadId); + + void cleanupId(String downloadId); + + void notificationClicked(String[] downloadIds); + + DownloadInfo getDownloadInfo(String downloadId); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/impl/BroadcastCommunicationService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/BroadcastCommunicationService.java new file mode 100644 index 0000000..93fd365 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/BroadcastCommunicationService.java @@ -0,0 +1,108 @@ +package br.com.bemobi.medescope.service.impl; + +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; + +import br.com.bemobi.medescope.Medescope; +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.log.Logger; +import br.com.bemobi.medescope.service.CommunicationService; + +/** + * Created by bruno.costa on 02/07/15. + */ +public class BroadcastCommunicationService implements CommunicationService { + + private static final String TAG = BroadcastCommunicationService.class.getSimpleName(); + + private static CommunicationService instance; + + private final Context mContext; + + private BroadcastCommunicationService(Context context){ + this.mContext = context; + } + + public static CommunicationService getInstance(Context context){ + if(instance == null){ + instance = new BroadcastCommunicationService(context); + } + return instance; + } + + @Override + public void sendFinishWithSuccessBroadcastData(String downloadId, String filePath, String data) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendFinishWithSuccessBroadcastData with data: " + data); + Intent finishIntent = new Intent(); + finishIntent.setAction(Medescope.ACTION_BROADCAST_FINISH_WITH_SUCCESS); + finishIntent.setPackage(mContext.getPackageName()); + finishIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + finishIntent.putExtra(DownloadConstants.EXTRA_STRING_FILE_PATH, filePath); + finishIntent.putExtra(DownloadConstants.EXTRA_STRING_JSON_DATA, data); + mContext.sendBroadcast(finishIntent); + } + + @Override + public void sendFinishWithErrorBroadcastData(String downloadId, int reason, String data) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendFinishWithErrorBroadcastData with data: " + data + " and reason: " + reason); + Intent finishIntent = new Intent(); + finishIntent.setAction(Medescope.ACTION_BROADCAST_FINISH_WITH_ERROR); + finishIntent.setPackage(mContext.getPackageName()); + finishIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + finishIntent.putExtra(DownloadConstants.EXTRA_INT_ERROR_REASON, reason); + finishIntent.putExtra(DownloadConstants.EXTRA_STRING_JSON_DATA, data); + mContext.sendBroadcast(finishIntent); + } + + @Override + public void sendDownloadStatusNotEnqueue(String downloadId) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendDownloadStatusNotEnqueue"); + Intent progressIntent = new Intent(); + progressIntent.setAction(Medescope.ACTION_BROADCAST_NOT_ENQUEUED); + progressIntent.setPackage(mContext.getPackageName()); + progressIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + mContext.sendBroadcast(progressIntent); + } + + @Override + public void sendDownloadStatusPaused(String downloadId, int reason) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendDownloadStatusPaused"); + Intent progressIntent = new Intent(); + progressIntent.setAction(Medescope.ACTION_BROADCAST_PAUSED); + progressIntent.setPackage(mContext.getPackageName()); + progressIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + progressIntent.putExtra(DownloadConstants.EXTRA_INT_REASON_KEY, reason); + mContext.sendBroadcast(progressIntent); + } + + @Override + public void sendDownloadStatusProgress(String downloadId, int progress) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendDownloadStatusProgress"); + Intent progressIntent = new Intent(); + progressIntent.setAction(Medescope.ACTION_BROADCAST_IN_PROGRESS); + progressIntent.setPackage(mContext.getPackageName()); + progressIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + progressIntent.putExtra(DownloadConstants.EXTRA_INT_PROGRESS_PERCENTAGE, progress); + mContext.sendBroadcast(progressIntent); + } + + @Override + public void sendCancelled(String downloadId) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "sendCancelled"); + Intent progressIntent = new Intent(); + progressIntent.setAction(Medescope.ACTION_BROADCAST_CANCELLED); + progressIntent.setPackage(mContext.getPackageName()); + progressIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + mContext.sendBroadcast(progressIntent); + } + + @Override + public void showDownloadQueue() { + Intent i = new Intent(); + i.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS); + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(i); + } + +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMDownloadService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMDownloadService.java new file mode 100644 index 0000000..37735c0 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMDownloadService.java @@ -0,0 +1,206 @@ +package br.com.bemobi.medescope.service.impl; + +import android.app.DownloadManager; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.util.Log; + +import java.util.Map; + +import br.com.bemobi.medescope.DownloadFileUtils; +import br.com.bemobi.medescope.log.Logger; +import br.com.bemobi.medescope.model.DownloadInfo; +import br.com.bemobi.medescope.repository.DMRepository; +import br.com.bemobi.medescope.service.DownloadService; +import br.com.bemobi.medescope.wrapper.DownloadInfoWrapper; +import br.com.bemobi.medescope.wrapper.impl.DMDownloadInfoWrapper; + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD; + +/** + * Created by bruno.costa on 30/06/15. + */ +public class DMDownloadService implements DownloadService { + + public static final String TAG = DMDownloadService.class.getSimpleName(); + private static DMDownloadService instance; + private static DownloadManager downloadManager; + private DMRepository repository; + private Context mContext; + private boolean isHidden = false; + private DownloadInfoWrapper downloadInfoWrapper; + + private DMDownloadService(Context context) { + this.mContext = context; + this.repository = DMRepository.getInstance(context); + this.downloadInfoWrapper = new DMDownloadInfoWrapper(); + } + + public static DMDownloadService getInstance(Context context) { + if(instance == null) { + instance = new DMDownloadService(context); + } + return instance; + } + + private static DownloadManager getDMInstance(Context context) { + if (downloadManager == null) { + downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + } + return downloadManager; + } + + @Override + public void shutdown() { + Log.d(TAG, "shutdown"); + downloadManager = null; + } + + @Override + public boolean enqueue(String downloadId, String uri, String fileName, String title, String description, String data, boolean shouldDownloadOnlyInWifi, Map customHeaders) { + if (DownloadFileUtils.isExternalStorageWritable()) { + DownloadManager.Request request; + request = new DownloadManager.Request(Uri.parse(uri)); + request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, fileName); + request.setTitle(title); + request.setDescription(description); + request.setAllowedOverRoaming(false); + setAllowedNetworks(shouldDownloadOnlyInWifi, request); + + if (customHeaders != null && !customHeaders.isEmpty()) { + // TODO setar variavel no build para logar somente em debug http://toastdroid.com/2014/03/28/customizing-your-build-with-gradle/ + + //LogUtil.debug(TAG, LOG_FEATURE_DOWNLOAD, ">>>>>>>>>>> LOGGING CUSTOM HEADERS"); + //new MapLogger(LOG_FEATURE_DOWNLOAD).log(customHeaders); + + + for (String key : customHeaders.keySet()) { + request.addRequestHeader(key, customHeaders.get(key)); + } + } + +// request.allowScanningByMediaScanner(); + request = setHiddenDownload(request); + Long dmId = getDMInstance(mContext).enqueue(request); + repository.persistIds(downloadId, dmId); + return dmId >= 0; + } + + return false; + } + + private void setAllowedNetworks(boolean shouldDownloadOnlyInWifi, DownloadManager.Request request) { + if(shouldDownloadOnlyInWifi) { + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); + } else { + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE); + } + } + + private DownloadManager.Request setHiddenDownload(DownloadManager.Request request){ + if(isHidden) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); + } else { + request.setShowRunningNotification(false); + } + } + return request; + } + + @Override + public boolean cancel(String downloadId) { + return getDMInstance(mContext).remove(repository.getDMId(downloadId)) > 0; + } + + @Override + public void cleanupId(String downloadId) { + repository.removeId(downloadId); + } + + @Override + public void notificationClicked(String[] downloadIds) { + DownloadCommandService.actionNotificationClicked(mContext, downloadIds); + } + + @Override + public DownloadInfo getDownloadInfo(String downloadId) { + DownloadInfo downloadManagerInfo = null; + Long dmDownloadId = repository.getDMId(downloadId); + if (dmDownloadId != null) { + Cursor cursor = getDMInstance(mContext).query(new DownloadManager.Query().setFilterById(repository.getDMId(downloadId))); + + if (cursor != null) { + int status; + int reason; + String filename; + String localURI; + long lastModified; + long downloadedSoFar = 0; + long totalSize = 1; + int progress = 0; + + if (cursor.moveToFirst()) { + // TODO desligar esse log em producao + Logger.debug(TAG, LOG_FEATURE_DOWNLOAD, "dumpCursorToString\n" + DatabaseUtils.dumpCursorToString(cursor)); + + + //column for status + int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); + status = cursor.getInt(columnIndex); + + //column for reason code if the download failed or paused + int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON); + reason = cursor.getInt(columnReason); + + //get the download filename + filename = ""; + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + int filenameIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); + filename = cursor.getString(filenameIndex); + } else { + int filenameIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI); + String cursorString = cursor.getString(filenameIndex); + + if (cursorString != null) { + Logger.debug(TAG, LOG_FEATURE_DOWNLOAD, " [ cursor.getString(filenameIndex) ] = " + cursor.getString(filenameIndex)); + Uri uri = Uri.parse(cursorString); + + if (uri != null) { + Logger.debug(TAG, LOG_FEATURE_DOWNLOAD, "[ Uri.parse(cursor.getString(filenameIndex)).getPath() ] = " + Uri.parse(cursor.getString(filenameIndex)).getPath()); + filename = uri.getPath(); + } + } + } + + int columnLocalURI = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI); + localURI = cursor.getString(columnLocalURI); + + int columnLastModified = cursor.getColumnIndex(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP); + lastModified = cursor.getLong(columnLastModified); + + + int columnDownloadedSoFar = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); + downloadedSoFar = cursor.getLong(columnDownloadedSoFar); + + int columnTotalSize = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); + totalSize = cursor.getLong(columnTotalSize); + + if (status == DownloadManager.STATUS_RUNNING) { + progress = (int) Math.round(((1.0 * downloadedSoFar) / totalSize) * 100); + } else if (status == DownloadManager.STATUS_SUCCESSFUL) { + progress = 100; + } + + downloadManagerInfo = new DownloadInfo(downloadInfoWrapper.translateStatus(status), downloadInfoWrapper.translateReason(reason), filename, localURI, lastModified, downloadedSoFar, totalSize, progress); + } + cursor.close(); + } + } + return downloadManagerInfo; + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMIntentService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMIntentService.java new file mode 100644 index 0000000..1c068d5 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DMIntentService.java @@ -0,0 +1,72 @@ +package br.com.bemobi.medescope.service.impl; + +import android.app.DownloadManager; +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; + +import br.com.bemobi.medescope.model.DownloadInfo; +import br.com.bemobi.medescope.repository.DMRepository; +import br.com.bemobi.medescope.service.DownloadService; + +/** + * Created by bruno.costa on 01/07/15. + */ +public class DMIntentService extends IntentService { + + public static final String ACTION_DM_FINISH = "br.com.bemobi.medescope.ACTION_DM_FINISH"; + public static final String ACTION_DM_NOTIFICATION_CLICKED = "br.com.bemobi.medescope.ACTION_DM_NOTIFICATION_CLICKED"; + + public DMIntentService() { + super(DMIntentService.class.getName()); + } + + + public static void actionFinish(Context context, long downloadId) { + Intent intent = new Intent(context, DMIntentService.class); + intent.setAction(ACTION_DM_FINISH); + intent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId); + context.startService(intent); + } + + public static void actionNotificationClicked(Context context, long[] downloadIds) { + Intent serviceIntent = new Intent(context, DMIntentService.class); + serviceIntent.setAction(ACTION_DM_NOTIFICATION_CLICKED); + if (downloadIds != null) { + serviceIntent.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadIds); + } + context.startService(serviceIntent); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (intent != null) { + DownloadService downloadService = DMDownloadService.getInstance(this); + String action = intent.getAction(); + if (ACTION_DM_FINISH.equals(action) ) { + Long dmDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); + if(dmDownloadId >= 0) { + String libId = DMRepository.getInstance(getApplicationContext()).getClientId(dmDownloadId); + + DownloadInfo downloadInfo = downloadService.getDownloadInfo(libId); + + DownloadCommandService.actionFinishDownload(this, libId, downloadInfo); + } + } else if (ACTION_DM_NOTIFICATION_CLICKED.equals(action)) { + String[] downloadIds = {}; + long[] ids = {}; + if(intent.hasExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS)) { + ids = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); + } + + if(ids != null && ids.length > 0) { + for (int i = 0; i < ids.length; i++) { + downloadIds[i] = DMRepository.getInstance(getApplicationContext()).getClientId(ids[i]); + } + } + downloadService.notificationClicked(downloadIds); + } + } + + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DownloadCommandService.java b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DownloadCommandService.java new file mode 100644 index 0000000..4b38759 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/service/impl/DownloadCommandService.java @@ -0,0 +1,372 @@ +package br.com.bemobi.medescope.service.impl; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.text.TextUtils; + +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.constant.DownloadInfoReasonConstants; +import br.com.bemobi.medescope.constant.Extras; +import br.com.bemobi.medescope.log.IntentLogger; +import br.com.bemobi.medescope.log.Logger; +import br.com.bemobi.medescope.model.DownloadRequest; +import br.com.bemobi.medescope.model.DownloadInfo; +import br.com.bemobi.medescope.repository.DownloadDataRepository; +import br.com.bemobi.medescope.repository.impl.MapDownloadDataRepository; +import br.com.bemobi.medescope.service.CommunicationService; +import br.com.bemobi.medescope.service.DownloadCommand; +import br.com.bemobi.medescope.service.DownloadService; + + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD; +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_SERVICE_LIFECYCLE; + +/** + * Created by bruno.costa on 26/06/15. + */ +public class DownloadCommandService extends Service implements DownloadCommand { + + public static final String TAG = DownloadCommandService.class.getSimpleName(); + + public static final String ACTION_ENQUEUE = "br.com.bemobi.medescope.ACTION_ENQUEUE"; + public static final String ACTION_CANCEL = "br.com.bemobi.medescope.ACTION_CANCEL"; + public static final String ACTION_FINISH = "br.com.bemobi.medescope.ACTION_FINISH"; + public static final String ACTION_NOTIFICATION_CLICK = "br.com.bemobi.medescope.ACTION_NOTIFICATION_CLICK"; + public static final String ACTION_REGISTER_FOR_STATUS = "br.com.bemobi.medescope.ACTION_REGISTER_FOR_STATUS"; + public static final String ACTION_UNREGISTER_FOR_STATUS = "br.com.bemobi.medescope.ACTION_UNREGISTER_FOR_STATUS"; + + private DownloadService downloadService; + + private DownloadDataRepository downloadDataRepository; + + private CommunicationService communicationService; + + private Looper mServiceLooper; + + private ServiceHandler mServiceHandler; + + private String downloadIdRegisteredToSendProgress = ""; + + private boolean isStartedSendProgress = false; + + public static void actionEnqueue(Context context, DownloadRequest downloadRequest) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_ENQUEUE); + serviceIntent.putExtra(Extras.EXTRA_DOWNLOAD, downloadRequest); + context.startService(serviceIntent); + } + + public static void actionSubscribeStatusUpdate(Context context, String id) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_REGISTER_FOR_STATUS); + serviceIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, id); + context.startService(serviceIntent); + } + + public static void actionUnsubscribeStatusUpdate(Context context) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_UNREGISTER_FOR_STATUS); + context.startService(serviceIntent); + } + + public static void actionCancel(Context context, String id) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_CANCEL); + serviceIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, id); + context.startService(serviceIntent); + } + + public static void actionFinishDownload(Context context, String downloadId, DownloadInfo downloadInfo) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_FINISH); + serviceIntent.putExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID, downloadId); + serviceIntent.putExtra(DownloadConstants.EXTRA_DOWNLOAD_INFO, downloadInfo); + context.startService(serviceIntent); + } + + public static void actionNotificationClicked(Context context, String[] downloadIds) { + Intent serviceIntent = new Intent(context, DownloadCommandService.class); + serviceIntent.setAction(ACTION_NOTIFICATION_CLICK); + serviceIntent.putExtra(DownloadConstants.EXTRA_ARRAY_STRING_DOWNLOAD_IDS, downloadIds); + context.startService(serviceIntent); + } + + @Override + public IBinder onBind(Intent intent) { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "onBind()"); + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "onCreate()"); + initThreadHandler(); + startCommand(); + } + + private void initThreadHandler() { + HandlerThread thread = new HandlerThread("PROGRESS_SENDER", Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mServiceLooper = thread.getLooper(); + mServiceHandler = new ServiceHandler(mServiceLooper); + } + + @Override + public void startCommand() { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "startCommand()"); + this.downloadDataRepository = MapDownloadDataRepository.getInstance(getApplicationContext()); + this.downloadService = DMDownloadService.getInstance(getApplicationContext()); + this.communicationService = BroadcastCommunicationService.getInstance(getApplicationContext()); + this.isStartedSendProgress = false; + this.downloadIdRegisteredToSendProgress = downloadDataRepository.recoverSubscribedId(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "onStartCommand()"); + if (intent != null) { + executeCommand(intent.getAction(), intent.getExtras()); + } else { + startCommand(); + if( !TextUtils.isEmpty(this.downloadIdRegisteredToSendProgress )) { + startProgressSender(); + } + } + return START_STICKY; + } + + @Override + public void executeCommand(String action, Bundle extras) { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, String.format(">>>>>>>>>>>>>>>>>>>>>>>>>> ACTION RECEIVED: %s", action)); + new IntentLogger(TAG, LOG_FEATURE_DOWNLOAD).logBundle(extras); + + if (ACTION_ENQUEUE.equals(action)) { + //TODO transformar os parametros em um objeto Parcelable + DownloadRequest downloadRequest = (DownloadRequest) extras.getSerializable(Extras.EXTRA_DOWNLOAD); + this.enqueue(downloadRequest); + } else if (ACTION_CANCEL.equals(action)) { + cancelAction(getIdStringFromBundle(extras)); + } else if (ACTION_FINISH.equals(action)) { + finishAction(getDownloadIdFromBundle(extras), getDownloadInfoFromBundle(extras)); + } else if (ACTION_NOTIFICATION_CLICK.equals(action)) { + clickNotificationAction(getDownloadIdsFromBundle(extras)); + } else if (ACTION_REGISTER_FOR_STATUS.equals(action)) { + registerForStatus(getIdStringFromBundle(extras)); + } else if (ACTION_UNREGISTER_FOR_STATUS.equals(action)) { + unregisterForStatus(); + } + + if (downloadDataRepository.isEmptyDownloadData() && !isStartedSendProgress) { + stopSelf(); + shutdownCommand(); + } + } + + @Override + public void onDestroy() { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "onDestroy()"); + shutdownCommand(); + super.onDestroy(); + } + + @Override + public void shutdownCommand() { + downloadService.shutdown(); + } + + @Override + public void enqueue(DownloadRequest downloadRequest) { + if (downloadRequest == null || !downloadRequest.isValid()) { + Logger.error(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, String.format("Invalid download object param: %s", downloadRequest.toString())); + return; + } + + if (downloadDataRepository.containsDownloadDataKey(downloadRequest.getId())) { + DownloadInfo downloadInfo = downloadService.getDownloadInfo(downloadRequest.getId()); + + if (downloadInfo == null) { + this.enqueue(downloadService, downloadRequest); + return; + } + + if (downloadInfo.hasFinished()) { + downloadService.cleanupId(downloadRequest.getId()); + this.enqueue(downloadService, downloadRequest); + } else { + Logger.error(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, String.format("This download is in execution with status: %s", downloadInfo.getStatus())); + Logger.error(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "Do you would like to subscribe to receive status update? Medescope.subscribeStatus([downloadId])"); + } + + } else { + this.enqueue(downloadService, downloadRequest); + } + } + + private void enqueue(DownloadService downloadService, DownloadRequest downloadRequest){ + downloadService.cleanupId(downloadRequest.getId()); + downloadDataRepository.removeDownloadData(downloadRequest.getId()); + boolean enqueued = downloadService.enqueue( + downloadRequest.getId(), + downloadRequest.getUri(), + downloadRequest.getFileName(), + downloadRequest.getDownloadName(), + downloadRequest.getDownloadDescription(), + downloadRequest.getClientPayload(), + downloadRequest.shouldDownloadOnlyInWifi(), + downloadRequest.getCustomHeaders() + ); + downloadDataRepository.putDownloadData(downloadRequest.getId(), downloadRequest.getClientPayload()); + if (shouldStartSendProgressOnEnqueue(downloadRequest.getId())) { + startProgressSender(); + } + + if (!enqueued) { + communicationService + .sendFinishWithErrorBroadcastData( + downloadRequest.getId(), + DownloadInfoReasonConstants.ERROR_GENERIC, + downloadDataRepository.getDownloadData(downloadRequest.getId())); + } + } + + private boolean shouldStartSendProgressOnEnqueue(String enqueueDownloadId){ + return enqueueDownloadId.equals(downloadIdRegisteredToSendProgress) && !isStartedSendProgress; + } + + @Override + public void cancelAction(String downloadId) { + if (!TextUtils.isEmpty(downloadId) && downloadDataRepository.containsDownloadDataKey(downloadId)) { + downloadService.cancel(downloadId); + } + } + + @Override + public void finishAction(String downloadId, DownloadInfo downloadInfo) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "Finish Action"); + if (downloadInfo != null) { + if (downloadInfo.hasFinishedWithSuccess()) { + communicationService.sendFinishWithSuccessBroadcastData(downloadId, downloadInfo.getFilename(), downloadDataRepository.getDownloadData(downloadId)); + } else if (downloadInfo.hasFinishedWithError()) { + communicationService.sendFinishWithErrorBroadcastData(downloadId, downloadInfo.getReason(), downloadDataRepository.getDownloadData(downloadId)); + } + } else { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD, "Cancelled"); + communicationService.sendCancelled(downloadId); + } + downloadDataRepository.removeDownloadData(downloadId); + downloadService.cleanupId(downloadId); + } + + @Override + public void clickNotificationAction(String[] downloadIds) { + communicationService.showDownloadQueue(); + } + + private void registerForStatus(String downloadId) { + downloadIdRegisteredToSendProgress = downloadId; + downloadDataRepository.persistSubscribedId(downloadId); + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_SERVICE_LIFECYCLE, "isStartedSendProgress:" + isStartedSendProgress); + + if (!isStartedSendProgress) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_SERVICE_LIFECYCLE, "Starting Sender Progress!"); + startProgressSender(); + } + } + + private void unregisterForStatus() { + downloadIdRegisteredToSendProgress = ""; + downloadDataRepository.removeSubscribedId(); + } + + //TODO this method must be atomic(?) + public void startProgressSender() { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "startProgressSender()"); + + isStartedSendProgress = true; + Message msg = mServiceHandler.obtainMessage(); + mServiceHandler.sendMessage(msg); + } + + private final class ServiceHandler extends Handler { + + public ServiceHandler(Looper looper) { + super(looper); + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "ServiceHandler()"); + } + + @Override + public void handleMessage(Message msg) { + Logger.debug(TAG, LOG_FEATURE_SERVICE_LIFECYCLE, "ServiceHandler.handleMessage()"); + DownloadInfo lastSentDownloadInfo = null; + + while (!TextUtils.isEmpty(downloadIdRegisteredToSendProgress) && isStartedSendProgress) { + try { + if (!downloadDataRepository.containsDownloadDataKey(downloadIdRegisteredToSendProgress)) { + communicationService.sendDownloadStatusNotEnqueue(downloadIdRegisteredToSendProgress); + isStartedSendProgress = false; + break; + } + + DownloadInfo downloadInfo = downloadService.getDownloadInfo(downloadIdRegisteredToSendProgress); + if (downloadInfo == null) { + communicationService.sendDownloadStatusNotEnqueue(downloadIdRegisteredToSendProgress); + isStartedSendProgress = false; + break; + } + + if (downloadInfo.equals(lastSentDownloadInfo)) { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD_SEND_PROGRESS, "I have already sent this info"); + } else if (downloadInfo.hasFinished()) { + // TODO em alguns casos o download está com 100% e não está sendo enviado o evento de FINISHED. Tratar esse caso posteriormente + communicationService.sendDownloadStatusProgress(downloadIdRegisteredToSendProgress, downloadInfo.getProgress()); + isStartedSendProgress = false; + break; + }else if (downloadInfo.isPaused()) { + communicationService.sendDownloadStatusPaused(downloadIdRegisteredToSendProgress, downloadInfo.getReason()); + } else if (downloadInfo.isInProgress()) { + communicationService.sendDownloadStatusProgress(downloadIdRegisteredToSendProgress, downloadInfo.getProgress()); + } else { + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD_SEND_PROGRESS, "BIZARRE STATUS!! PANIC ALERT!!!"); + } + + lastSentDownloadInfo = downloadInfo; + + Thread.sleep(300); + + } catch (InterruptedException exception) { + Logger.error(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD_SEND_PROGRESS, "ERROR ON THREAD STATUS SENDER!!!!"); + isStartedSendProgress = false; + } + } + + isStartedSendProgress = false; + + Logger.debug(TAG, DownloadConstants.LOG_FEATURE_DOWNLOAD_SEND_PROGRESS, "Finishing Status Sender!!!!!"); + } + } + + private String getIdStringFromBundle(Bundle extras) { + return extras.getString(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID); + } + + private String getDownloadIdFromBundle(Bundle extras) { + return extras.getString(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID); + } + + private String[] getDownloadIdsFromBundle(Bundle extras) { + return extras.getStringArray(DownloadConstants.EXTRA_ARRAY_STRING_DOWNLOAD_IDS); + } + + private DownloadInfo getDownloadInfoFromBundle(Bundle extras) { + return extras.getParcelable(DownloadConstants.EXTRA_DOWNLOAD_INFO); + } +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/wrapper/DownloadInfoWrapper.java b/medescope/src/main/java/br/com/bemobi/medescope/wrapper/DownloadInfoWrapper.java new file mode 100644 index 0000000..62a3633 --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/wrapper/DownloadInfoWrapper.java @@ -0,0 +1,10 @@ +package br.com.bemobi.medescope.wrapper; + +/** + * Created by raphael on 7/7/15. + */ +public interface DownloadInfoWrapper { + int translateStatus(STATUS status); + + int translateReason(REASON reason); +} diff --git a/medescope/src/main/java/br/com/bemobi/medescope/wrapper/impl/DMDownloadInfoWrapper.java b/medescope/src/main/java/br/com/bemobi/medescope/wrapper/impl/DMDownloadInfoWrapper.java new file mode 100644 index 0000000..ecfd68b --- /dev/null +++ b/medescope/src/main/java/br/com/bemobi/medescope/wrapper/impl/DMDownloadInfoWrapper.java @@ -0,0 +1,69 @@ +package br.com.bemobi.medescope.wrapper.impl; + +import android.app.DownloadManager; + +import br.com.bemobi.medescope.constant.DownloadInfoReasonConstants; +import br.com.bemobi.medescope.wrapper.DownloadInfoWrapper; + +/** + * Created by raphael on 7/7/15. + */ +public class DMDownloadInfoWrapper implements DownloadInfoWrapper { + + @Override + public int translateStatus(Integer status) { + return status; + } + + @Override + public int translateReason(Integer reason) { + int translatedReason; + + switch(reason){ + case DownloadManager.ERROR_CANNOT_RESUME: + translatedReason = DownloadInfoReasonConstants.ERROR_GENERIC; + break; + case DownloadManager.ERROR_DEVICE_NOT_FOUND: + translatedReason = DownloadInfoReasonConstants.ERROR_STORAGE_NOT_FOUND; + break; + case DownloadManager.ERROR_FILE_ALREADY_EXISTS: + translatedReason = DownloadInfoReasonConstants.ERROR_ALREADY_EXISTING_FILE; + break; + case DownloadManager.ERROR_FILE_ERROR: + translatedReason = DownloadInfoReasonConstants.ERROR_FILE_GENERIC_PROBLEM; + break; + case DownloadManager.ERROR_HTTP_DATA_ERROR: + translatedReason = DownloadInfoReasonConstants.ERROR_HTTP_DATA_ERROR; + break; + case DownloadManager.ERROR_INSUFFICIENT_SPACE: + translatedReason = DownloadInfoReasonConstants.ERROR_INSUFFICIENT_STORAGE; + break; + case DownloadManager.ERROR_TOO_MANY_REDIRECTS: + translatedReason = DownloadInfoReasonConstants.ERROR_TOO_MANY_REDIRECTS; + break; + case DownloadManager.ERROR_UNHANDLED_HTTP_CODE: + translatedReason = DownloadInfoReasonConstants.ERROR_UNHANDLED_HTTP_CODE; + break; + case DownloadManager.ERROR_UNKNOWN: + translatedReason = DownloadInfoReasonConstants.ERROR_GENERIC; + break; + case DownloadManager.PAUSED_QUEUED_FOR_WIFI: + translatedReason = DownloadInfoReasonConstants.PAUSED_QUEUED_TO_DOWNLOAD_ON_WIFI; + break; + case DownloadManager.PAUSED_UNKNOWN: + translatedReason = DownloadInfoReasonConstants.PAUSED_GENERIC_REASON; + break; + case DownloadManager.PAUSED_WAITING_FOR_NETWORK: + translatedReason = DownloadInfoReasonConstants.PAUSED_WAITING_NETWORK; + break; + case DownloadManager.PAUSED_WAITING_TO_RETRY: + translatedReason = DownloadInfoReasonConstants.PAUSED_WAITING_NETWORK_AFTER_ERROR; + break; + default: + translatedReason = reason; + } + + + return translatedReason; + } +} \ No newline at end of file diff --git a/medescope/src/test/java/br/com/bemobi/download/DownloadDataRepoTest.java b/medescope/src/test/java/br/com/bemobi/download/DownloadDataRepoTest.java new file mode 100644 index 0000000..f0dc4f2 --- /dev/null +++ b/medescope/src/test/java/br/com/bemobi/download/DownloadDataRepoTest.java @@ -0,0 +1,45 @@ +package br.com.bemobi.medescope; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import br.com.bemobi.medescope.repository.DownloadDataRepository; +import br.com.bemobi.medescope.repository.impl.MapDownloadDataRepository; + +import static org.junit.Assert.assertTrue; +import static org.mockito.MockitoAnnotations.initMocks; + +/** + * Created by bruno.costa on 22/05/15. + */ +@RunWith(RobolectricTestRunner.class) +@Config(emulateSdk = 18) +public class DownloadDataRepoTest { + + @Mock + private DownloadDataRepository repository; + + @Before + public void setup(){ + //initMocks(this); + repository = MapDownloadDataRepository.getInstance(Robolectric.application.getApplicationContext()); + } + + @Test + public void shouldRufflingANumberBetweenTwoNumbers() { + String key = "key1"; + String value = "value1"; + + repository.putDownloadData(key, value); + +// repository = null; +// repository = MapDownloadDataRepository.getInstance(Robolectric.application.getApplicationContext()); + + assertTrue(value.equals(repository.getDownloadData(key))); + } +} diff --git a/sample/build.gradle b/sample/build.gradle new file mode 100644 index 0000000..b7c8fab --- /dev/null +++ b/sample/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.0" + + defaultConfig { + applicationId "br.com.bemobi.medescope.sample" + minSdkVersion 10 + 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']) + compile 'com.android.support:appcompat-v7:23.0.0' + compile 'com.facebook.stetho:stetho:1.1.1' + compile 'com.github.halysongoncalves:pugnotification:1.7.0' + compile project(':medescope') +} diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro new file mode 100644 index 0000000..a9ca86e --- /dev/null +++ b/sample/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 /home/bruno.costa/android-sdks/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/sample/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java b/sample/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java new file mode 100644 index 0000000..497d423 --- /dev/null +++ b/sample/src/androidTest/java/br/com/bemobi/medescope/ApplicationTest.java @@ -0,0 +1,13 @@ +package br.com.bemobi.medescope; + +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/sample/src/androidTest/java/br/com/bemobi/medescope/sample/ApplicationTest.java b/sample/src/androidTest/java/br/com/bemobi/medescope/sample/ApplicationTest.java new file mode 100644 index 0000000..30c78da --- /dev/null +++ b/sample/src/androidTest/java/br/com/bemobi/medescope/sample/ApplicationTest.java @@ -0,0 +1,13 @@ +package br.com.bemobi.medescope.sample; + +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/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b6b20ac --- /dev/null +++ b/sample/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/src/main/java/br/com/bemobi/medescope/sample/AppApplication.java b/sample/src/main/java/br/com/bemobi/medescope/sample/AppApplication.java new file mode 100644 index 0000000..b2707c2 --- /dev/null +++ b/sample/src/main/java/br/com/bemobi/medescope/sample/AppApplication.java @@ -0,0 +1,22 @@ +package br.com.bemobi.medescope.sample; + +import android.app.Application; + +import com.facebook.stetho.Stetho; + +/** + * Created by luisfernandez on 7/6/15. + */ +public class AppApplication extends Application { + + @Override + public void onCreate() { + super.onCreate(); + + Stetho.initialize( + Stetho.newInitializerBuilder(this) + .enableDumpapp(Stetho.defaultDumperPluginsProvider(this)) + .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this)) + .build()); + } +} diff --git a/sample/src/main/java/br/com/bemobi/medescope/sample/MainActivity.java b/sample/src/main/java/br/com/bemobi/medescope/sample/MainActivity.java new file mode 100644 index 0000000..da90332 --- /dev/null +++ b/sample/src/main/java/br/com/bemobi/medescope/sample/MainActivity.java @@ -0,0 +1,199 @@ +package br.com.bemobi.medescope.sample; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ProgressBar; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +import br.com.bemobi.medescope.Medescope; +import br.com.bemobi.medescope.sample.model.NotificationData; +import br.com.bemobi.medescope.callback.DownloadStatusCallback; +import br.com.bemobi.medescope.exception.DirectoryNotMountedException; +import br.com.bemobi.medescope.exception.PathNotFoundException; + + +public class MainActivity extends ActionBarActivity { + + public static final String TAG = MainActivity.class.getSimpleName(); + public static final String FILE_PATH = "FILE.zip"; + + String FILE_5MB = "http://download.thinkbroadband.com/5MB.zip"; + String FILE_10MB = "http://download.thinkbroadband.com/10MB.zip"; + String FILE_20MB = "http://download.thinkbroadband.com/20MB.zip"; + String FILE_50MB = "http://download.thinkbroadband.com/50MB.zip"; + String FILE_100MB = "http://download.thinkbroadband.com/100MB.zip"; + String [] files = {FILE_5MB, FILE_10MB, FILE_20MB, FILE_50MB, FILE_100MB}; + + String downloadName = FILE_5MB; + + Spinner spinner; + ProgressBar progressBar; + ArrayAdapter adapter; + + private TextView textStatus; + private TextView textAction; + private Medescope mMedescope; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + List spinnerArray = new ArrayList<>(); + spinnerArray.add("5MB File"); + spinnerArray.add("10MB File"); + spinnerArray.add("20MB File"); + spinnerArray.add("50MB File"); + spinnerArray.add("100MB File"); + + textStatus = (TextView) findViewById(R.id.text); + textAction = (TextView) findViewById(R.id.textAction); + + progressBar = (ProgressBar) findViewById(R.id.sample_progressBar); + + adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerArray); + + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner = (Spinner) findViewById(R.id.download_spinner); + spinner.setAdapter(adapter); + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + + @Override + public void onItemSelected(AdapterView parentView, View selectedItemView, int myPosition, long myID) { + downloadName = files[myPosition]; + mMedescope.updateSubscriptionStatusId(MainActivity.this, "" + myID); + hideProgress(); + } + + @Override + public void onNothingSelected(AdapterView parentView) { + // your code here + } + + }); + } + + private void hideProgress() { + progressBar.setVisibility(View.GONE); + progressBar.setProgress(0); + progressBar.setIndeterminate(false); + } + + private void showProgress() { + progressBar.setVisibility(View.VISIBLE); + progressBar.setProgress(0); + progressBar.setIndeterminate(true); + } + + private void setPercentProgress(int progress) { + progressBar.setVisibility(View.VISIBLE); + progressBar.setProgress(progress); + progressBar.setIndeterminate(false); + } + + @Override + protected void onResume() { + super.onResume(); + + mMedescope = Medescope.getInstance(this); + mMedescope.setApplicationName(getString(R.string.app_name)); + mMedescope.subscribeStatus(this, "" + spinner.getSelectedItemId(), new DownloadStatusCallback() { + @Override + public void onDownloadNotEnqueued(String downloadId) { + textAction.setText("ACTION NOT ENQUEUED"); + textStatus.setText("NOT ENQUEUED:"); + hideProgress(); + } + + @Override + public void onDownloadPaused(String downloadId, int reason) { + textAction.setText("ACTION PAUSED"); + textStatus.setText(String.format("NOT ENQUEUED: [reason: %s ]", reason)); + } + + @Override + public void onDownloadInProgress(String downloadId, int progress) { + textAction.setText("ACTION IN PROGRESS"); + Log.d(TAG, "Received download progress: " + progress); + setPercentProgress(progress); + textStatus.setText(String.format("PROGRESS: [progress: %s ]", progress)); + } + + @Override + public void onDownloadOnFinishedWithError(String downloadId, int reason, String data) { + textAction.setText("ACTION FINISH WITH ERROR"); + hideProgress(); + } + + @Override + public void onDownloadOnFinishedWithSuccess(String downloadId, String filePath, String data) { + textAction.setText("ACTION FINISH WITH SUCCESS"); + Log.d(TAG, "Received path: " + filePath); + checkFilePath(filePath); + + hideProgress(); + } + + @Override + public void onDownloadCancelled(String downloadId) { + textAction.setText("ACTION FINISH WITH SUCCESS"); + hideProgress(); + } + }); + } + + private void checkFilePath(String filePath) { + String originalFilePath = ""; + try { + originalFilePath = mMedescope.getDownloadDirectoryToRead(FILE_PATH); + Log.d(TAG, "Original path: " + originalFilePath); + } catch (DirectoryNotMountedException e) { + e.printStackTrace(); + } catch (PathNotFoundException e) { + e.printStackTrace(); + } + + if (filePath.equals(originalFilePath)) { + Toast.makeText(MainActivity.this, "Path sent is the expected", Toast.LENGTH_LONG).show(); + } + } + + @Override + protected void onPause() { + super.onPause(); + Medescope.getInstance(this).unsubscribeStatus(this); + } + + public void download(View view) { + NotificationData data = new NotificationData("" + spinner.getSelectedItemId(), downloadName, getString(R.string.app_name)); + + boolean shouldDownloadOnlyInWiFi = isLargeFile(downloadName); + + mMedescope.enqueue( + data.getId(), + downloadName, + FILE_PATH, + (String) spinner.getSelectedItem(), + data.toJson(), + shouldDownloadOnlyInWiFi); + showProgress(); + } + + public void cancel(View view) { + mMedescope.cancel("" + spinner.getSelectedItemId()); + hideProgress(); + } + + public boolean isLargeFile(String selected) { + return FILE_20MB.equals(selected) || FILE_50MB.equals(selected) || FILE_100MB.equals(selected); + } +} diff --git a/sample/src/main/java/br/com/bemobi/medescope/sample/model/NotificationData.java b/sample/src/main/java/br/com/bemobi/medescope/sample/model/NotificationData.java new file mode 100644 index 0000000..c7b8d79 --- /dev/null +++ b/sample/src/main/java/br/com/bemobi/medescope/sample/model/NotificationData.java @@ -0,0 +1,56 @@ +package br.com.bemobi.medescope.sample.model; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * Created by bruno.costa on 30/06/15. + */ +public class NotificationData { + + private String id; + + private String title; + + private String desc; + + public void setId(String id) { + this.id = id; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDesc() { + return desc; + } + + public NotificationData(String id) { + this.id = id; + } + + public NotificationData(String id, String title, String desc) { + this.id = id; + this.title = title; + this.desc = desc; + } + + public String toJson() { + Gson gson = new GsonBuilder().create(); + return gson.toJson(this); + } + +} diff --git a/sample/src/main/java/br/com/bemobi/medescope/sample/receiver/BemobiDownloadReceiver.java b/sample/src/main/java/br/com/bemobi/medescope/sample/receiver/BemobiDownloadReceiver.java new file mode 100644 index 0000000..d28f56e --- /dev/null +++ b/sample/src/main/java/br/com/bemobi/medescope/sample/receiver/BemobiDownloadReceiver.java @@ -0,0 +1,75 @@ +package br.com.bemobi.medescope.sample.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.text.TextUtils; +import android.util.Log; + +import com.google.gson.Gson; + +import br.com.bemobi.medescope.Medescope; +import br.com.bemobi.medescope.constant.DownloadConstants; +import br.com.bemobi.medescope.receiver.BroadcastReceiverLogger; +import br.com.bemobi.medescope.sample.R; +import br.com.bemobi.medescope.sample.model.NotificationData; +import br.com.goncalves.pugnotification.notification.PugNotification; + +import static br.com.bemobi.medescope.constant.DownloadConstants.LOG_FEATURE_DOWNLOAD; + +/** + * Created by bruno.costa on 02/07/15. + */ +public class BemobiDownloadReceiver extends BroadcastReceiver { + + private static final String TAG = BemobiDownloadReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + new BroadcastReceiverLogger(TAG, LOG_FEATURE_DOWNLOAD).onReceive(context, intent); + + if (intent != null) { + String action = intent.getAction(); + if (Medescope.ACTION_BROADCAST_FINISH_WITH_SUCCESS.equals(action)) { + String downloadId = intent.getStringExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID); + String filePath = intent.getStringExtra(DownloadConstants.EXTRA_STRING_FILE_PATH); + + if (!TextUtils.isEmpty(downloadId)) { + String data = intent.getStringExtra(DownloadConstants.EXTRA_STRING_JSON_DATA); + NotificationData nData = new Gson().fromJson(data, NotificationData.class); + + PugNotification.with(context).load() + .title(nData.getTitle()) + .message(nData.getDesc()) + .bigTextStyle(nData.getDesc()) + .smallIcon(R.mipmap.ic_launcher) + .largeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.bemobi_download_ic_notif_done)) + .autoCancel(true) + .simple() + .build(); + + Log.d(TAG, "File Path: " + filePath); + } + } else if (Medescope.ACTION_BROADCAST_FINISH_WITH_ERROR.equals(action)) { + String downloadId = intent.getStringExtra(DownloadConstants.EXTRA_STRING_DOWNLOAD_ID); + String errorMsg = intent.getStringExtra(DownloadConstants.EXTRA_INT_ERROR_REASON); + + if (!TextUtils.isEmpty(downloadId)) { + String data = intent.getStringExtra(DownloadConstants.EXTRA_STRING_JSON_DATA); + NotificationData nData = new Gson().fromJson(data, NotificationData.class); + + PugNotification.with(context).load() + .title(nData.getTitle()) + .message(errorMsg + " - " + nData.getDesc()) + .bigTextStyle(nData.getDesc()) + .smallIcon(R.mipmap.ic_launcher) + .largeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.bemobi_download_ic_notif_error)) + .autoCancel(true) + .simple() + .build(); + } + } + } + } +} diff --git a/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..e5e334f Binary files /dev/null and b/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..8b2e452 Binary files /dev/null and b/sample/src/main/res/drawable-hdpi-v11/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..9444af0 Binary files /dev/null and b/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..413177a Binary files /dev/null and b/sample/src/main/res/drawable-hdpi/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..f75a60a Binary files /dev/null and b/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..0819080 Binary files /dev/null and b/sample/src/main/res/drawable-mdpi-v11/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..b74224c Binary files /dev/null and b/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..07bc45e Binary files /dev/null and b/sample/src/main/res/drawable-mdpi/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..d9ad9d8 Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..84074dd Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi-v11/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..fb26431 Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..f642485 Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..cebdcf3 Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..081368f Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi-v11/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..420da4f Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..d7f5ae9 Binary files /dev/null and b/sample/src/main/res/drawable-xxhdpi/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..bdfd7a5 Binary files /dev/null and b/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..f1718d7 Binary files /dev/null and b/sample/src/main/res/drawable-xxxhdpi-v11/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_done.png b/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_done.png new file mode 100644 index 0000000..ef699e2 Binary files /dev/null and b/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_done.png differ diff --git a/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_error.png b/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_error.png new file mode 100644 index 0000000..663e2ce Binary files /dev/null and b/sample/src/main/res/drawable-xxxhdpi/bemobi_download_ic_notif_error.png differ diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..c2a8ab5 --- /dev/null +++ b/sample/src/main/res/layout/activity_main.xml @@ -0,0 +1,71 @@ + + + + + + +