diff options
author | Alan Newberger <alann@google.com> | 2014-12-03 10:47:03 -0800 |
---|---|---|
committer | Alan Newberger <alann@google.com> | 2014-12-03 10:47:03 -0800 |
commit | 617200ae32e6671631846ae0f840115c4463c8d4 (patch) | |
tree | 17fb77eadd24974e99a5b1a44df32f5ea81f1665 | |
parent | 9dbd132bec874fdb47231ffe45d4df2b1ae05764 (diff) | |
parent | a311d4835cdede5757e203d52a1bb5e707cfd989 (diff) | |
download | glide-617200ae32e6671631846ae0f840115c4463c8d4.tar.gz |
Merge tag 'v3.4.0' of https://github.com/bumptech/glide into ub-camera-haleakala
Change-Id: Ic290a947323184bfd15576a781bceb88258a5dd1
149 files changed, 1343 insertions, 1958 deletions
diff --git a/.travis.yml b/.travis.yml index 14fe933d..c1a2a27c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,4 @@ script: 'travis_retry ./gradlew build --parallel' after_success: - scripts/travis-sonatype-publish.sh +- ./gradlew jacocoTestReport coveralls @@ -28,7 +28,7 @@ repositories { dependencies { compile 'com.github.bumptech.glide:glide:3.3.+' - compile 'com.android.support:support-v4:19.0.0' + compile 'com.android.support:support-v4:19.1.0' } ``` @@ -171,6 +171,10 @@ public void onCreate() { } ``` +Android SDK Version +------------------- +Glide requires a minimum sdk version of 10. + License ------- BSD, part MIT and Apache 2.0. See LICENSE file for details. diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 797a9ede..00000000 --- a/build.gradle +++ /dev/null @@ -1,57 +0,0 @@ -buildscript { - repositories { - jcenter() - // TODO: remove this when robolectric 2.4 is released. - maven { - url 'https://oss.sonatype.org/content/repositories/snapshots' - } - } - - dependencies { - classpath 'org.robolectric:robolectric-gradle-plugin:0.12.+' - classpath 'com.android.tools.build:gradle:0.13.+' - } -} - -subprojects { project -> - repositories { - jcenter() - // TODO: remove this when robolectric 2.4 is released. - maven { - url 'https://oss.sonatype.org/content/repositories/snapshots' - } - } - - apply plugin: 'checkstyle' - - checkstyle { - configFile = new File(rootDir, 'checkstyle.xml') - } - - task checkstyle(type: Checkstyle) { - source 'src' - include '**/*.java' - exclude '**/gen/**' - - // empty classpath - classpath = files() - } - - afterEvaluate { - if (project.tasks.findByName('check')) { - check.dependsOn('checkstyle') - } - } - - gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - if (!name.contains('Test')) { - options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' - } - } - } -} - -task wrapper(type: Wrapper) { - gradleVersion = '2.1' -} diff --git a/checkstyle.xml b/checkstyle.xml deleted file mode 100644 index bdf87125..00000000 --- a/checkstyle.xml +++ /dev/null @@ -1,150 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> -<module name="Checker"> - <module name="FileLength"/> - <module name="FileTabCharacter"/> - - <module name="SuppressionFilter"> - <property name="file" value="checkstyle_suppressions.xml" /> - </module> - - <!-- Trailing spaces --> - <module name="RegexpSingleline"> - <property name="format" value="\s+$"/> - <property name="message" value="Line has trailing spaces."/> - </module> - - <!-- Space after 'for' and 'if' --> - <module name="RegexpSingleline"> - <property name="format" value="^\s*(for|if)\b[^ ]"/> - <property name="message" value="Space needed before opening parenthesis."/> - </module> - - <!-- For each spacing --> - <module name="RegexpSingleline"> - <property name="format" value="^\s*for \(.*?([^ ]:|:[^ ])"/> - <property name="message" value="Space needed around ':' character."/> - </module> - - <module name="TreeWalker"> - <!-- Checks for uncommented main() methods (debugging leftovers). --> - <!-- Checks that long constants are defined with an upper ell. --> - <!-- See http://checkstyle.sourceforge.net/config_misc.html#UpperEll --> - <module name="UpperEll" /> - - <!-- Checks the style of array type definitions. --> - <!-- See http://checkstyle.sourceforge.net/config_misc.html#ArrayTypeStyle --> - <module name="ArrayTypeStyle" /> - - <!-- Checks that the outer type name and the file name match. --> - <!-- See http://checkstyle.sourceforge.net/config_misc.html#OuterTypeFilename --> - <module name="OuterTypeFilename" /> - - <!-- Validates Javadoc comments to help ensure they are well formed. --> - <!-- See http://checkstyle.sourceforge.net/config_javadoc.html#JavadocStyle --> - <module name="JavadocStyle" /> - <module name="JavadocType"> - <property name="scope" value="public"/> - </module> - - <!-- Each of these naming modules validates identifiers for particular - code elements. --> - <!-- See http://checkstyle.sourceforge.net/config_naming.html --> - <module name="ConstantName"> - <property name="format" value="^[A-Z][A-Z0-9\$]*(_[A-Z0-9\$]+)*$" /> - </module> - <module name="LocalFinalVariableName" /> - <module name="LocalVariableName" /> - <module name="MemberName"> - <property name="format" value="^[a-z][a-zA-Z0-9_\$]*$" /> - </module> - <module name="MethodName" /> - <module name="PackageName" /> - <module name="ParameterName" /> - <module name="StaticVariableName" /> - <module name="TypeName" /> - - <module name="TrailingComment" /> - - <!-- Checks for imports. --> - <!-- See http://checkstyle.sourceforge.net/config_imports.html --> - <module name="AvoidStarImport"/> - <module name="RedundantImport"/> - <module name="UnusedImports"/> - <!-- Default sun.* packages --> - <module name="IllegalImport"> - <property name="illegalPkgs" value="sun" /> - <message key="import.illegal" value="Import from illegal package - {0}. Programs that contain direct calls to the sun.* packages are not 100% Pure Java." /> - </module> - <!-- Prevent importing JUnit 3 classes and Assert methods --> - <module name="IllegalImport"> - <property name="illegalPkgs" value="junit" /> - <message key="import.illegal" value="Import from illegal package - {0}. Tests are written in JUnit 4, use org.junit.* equivalents." /> - </module> - <!-- Prevent importing Mockito matchers directly --> - <module name="IllegalImport"> - <property name="illegalPkgs" value="org.mockito.internal" /> - <message key="import.illegal" value="Import from illegal package - {0}. Use org.mockito.Matchers to instantiate argument matchers; or org.hamcrest.Matchers for assertThat." /> - </module> - - <!-- Checks for whitespace. --> - <!-- See http://checkstyle.sourceforge.net/config_whitespace.html --> - <module name="GenericWhitespace" /> - <module name="MethodParamPad" /> - <module name="NoWhitespaceAfter"> - <property name="tokens" - value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS" /> - </module> - <module name="NoWhitespaceBefore" /> - <module name="OperatorWrap" /> - <module name="ParenPad" /> - <module name="TypecastParenPad" /> - <module name="WhitespaceAfter" /> - <module name="WhitespaceAround" /> - - - <!-- Modifier Checks. --> - <!-- See http://checkstyle.sourceforge.net/config_modifier.html --> - <module name="ModifierOrder" /> - - <!-- Checks for blocks. --> - <!-- See http://checkstyle.sourceforge.net/config_blocks.html --> - <module name="AvoidNestedBlocks" /> - <module name="EmptyBlock" > - <property name="option" value="text"/> - </module> - <module name="NeedBraces"/> - - <module name="LeftCurly" /> - <module name="RightCurly"> - <property name="tokens" - value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_ELSE" /> - </module> - - <!-- Checks for common coding problems. --> - <!-- See http://checkstyle.sourceforge.net/config_coding.html --> - <module name="CovariantEquals" /> - <module name="DefaultComesLast" /> - <module name="EmptyStatement" /> - <module name="EqualsHashCode" /> - <module name="NoClone" /> - <module name="NoFinalizer" /> - <module name="OneStatementPerLine" /> - <module name="RedundantThrows" > - <property name="suppressLoadErrors" value="true" /> - </module> - <module name="IllegalInstantiation"/> - <module name="SimplifyBooleanExpression" /> - <module name="SimplifyBooleanReturn" /> - <module name="StringLiteralEquality" /> - <module name="UnnecessaryParentheses" /> - <module name="LineLength"> - <property name="max" value="120" /> - </module> - - <!-- Checks for class design. --> - <!-- See http://checkstyle.sourceforge.net/config_design.html --> - <module name="FinalClass" /> - <module name="InterfaceIsType" /> - </module> -</module> diff --git a/checkstyle_suppressions.xml b/checkstyle_suppressions.xml deleted file mode 100644 index 1d8da750..00000000 --- a/checkstyle_suppressions.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> - -<!DOCTYPE suppressions PUBLIC - "-//Puppy Crawl//DTD Suppressions 1.1//EN" - "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> - -<suppressions> - <suppress files=".*[/\\]library[/\\]src[/\\]androidTest[/\\].*" checks="Javadoc.*"/> - <suppress files=".*[/\\]gif_encoder[/\\].*" checks=".*"/> - <suppress files=".*RequestBuilder.java|ChildLoadProvider.java" checks="NoClone" /> -</suppressions> - diff --git a/glide/build.gradle b/glide/build.gradle deleted file mode 100644 index 410a1df7..00000000 --- a/glide/build.gradle +++ /dev/null @@ -1,106 +0,0 @@ -apply plugin: 'java' - -evaluationDependsOn(':third_party:gif_decoder') -evaluationDependsOn(':third_party:disklrucache') -evaluationDependsOn(':library') - -def getAndroidSdkDirectory() { - project(':library').android.sdkDirectory -} - -def getAndroidCompileSdkVersion() { - project(':library').android.compileSdkVersion -} - -def getInternalAndroidProjects() { - [':third_party:gif_decoder', ':third_party:gif_encoder', ':library'].collect { project(it) } -} -def getInternalJavaProjects() { - [':third_party:disklrucache'].collect { project(it) } -} - -def getAllInternalProjects() { - getInternalAndroidProjects() + getInternalJavaProjects() -} - -def getReleaseVariantAndroidProjects() { - getAndroidLibraryVariants('release') -} - -def getAndroidLibraryVariants(variantName) { - getInternalAndroidProjects().collect { project -> - project.android.libraryVariants.findAll { type -> - type.buildType.name.equalsIgnoreCase(variantName) - } - }.sum() -} - -def getSourceFilesForVariant(variantName) { - getAndroidLibraryVariants(variantName).collect { it.javaCompile.source } + - getInternalJavaProjects().collect { it.sourceSets.main.allJava } -} - -def getAndroidJar() { - "${getAndroidSdkDirectory()}/platforms/${getAndroidCompileSdkVersion()}/android.jar" -} - -// Generate javadocs and sources containing batched documentation and sources for all internal projects. -['release', 'debug'].each { variantName -> - - task("${variantName}SourceJar", type: Jar) { - from getSourceFilesForVariant(variantName) - } - - def javadocTask = task("${variantName}Javadoc", type: Javadoc) { - source = getSourceFilesForVariant(variantName) - - classpath = files(getAndroidLibraryVariants(variantName).collect { - files(it.javaCompile.classpath.files, getAndroidJar()) - }) - classpath += getInternalJavaProjects().collect { files(it.configurations.compile) } - - options { - links("http://docs.oracle.com/javase/7/docs/api/") - linksOffline("http://d.android.com/reference", "${getAndroidSdkDirectory()}/docs/reference") - } - - exclude '**/BuildConfig.java' - exclude '**/R.java' - } - - def cleanJavadocTask = task("clean${variantName.capitalize()}Javadoc", type: Delete) { - delete javadocTask.destinationDir - } - clean.dependsOn(cleanJavadocTask) - - def javadocJarTask = task("${variantName}JavadocJar", type: Jar) { - from javadocTask.destinationDir - } - javadocJarTask.dependsOn(javadocTask) -} - -jar { - from files( - getReleaseVariantAndroidProjects().collect { variant -> - variant.javaCompile.destinationDir - } - ) - exclude "**/R.class" - exclude "**/BuildConfig.class" - from files(getInternalJavaProjects().collect { it.sourceSets.main.output }) -} - -getAllInternalProjects().each { project -> - jar.dependsOn(project.build) -} - -artifacts { - archives releaseJavadocJar { - classifier 'javadoc' - } - archives releaseSourceJar { - classifier 'sources' - } -} - -apply from: "$rootProject.projectDir/scripts/upload.gradle"
\ No newline at end of file diff --git a/glide/gradle.properties b/glide/gradle.properties deleted file mode 100644 index f205a7f3..00000000 --- a/glide/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -POM_NAME=Glide -POM_ARTIFACT_ID=glide -POM_PACKAGING=jar - diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index cd214548..00000000 --- a/gradle.properties +++ /dev/null @@ -1,15 +0,0 @@ -VERSION_NAME=3.4.0-SNAPSHOT -VERSION_MAJOR=3 -VERSION_MINOR=4 -VERSION_PATCH=0 -VERSION_CODE=7 -GROUP=com.github.bumptech.glide - -POM_DESCRIPTION=A fast and efficient image loading library for Android focused on smooth scrolling. -POM_URL=https://github.com/bumptech/glide -POM_SCM_URL=https://github.com/bumptech/glide -POM_SCM_CONNECTION=scm:git@github.com:bumptech/glide.git -POM_SCM_DEV_CONNECTION=scm:git@github.com:bumptech/glide.git -POM_DEVELOPER_ID=sjudd -POM_DEVELOPER_NAME=Sam Judd -POM_DEVELOPER_EMAIL=judds@google.com diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differdeleted file mode 100644 index 3d0dee6e..00000000 --- a/gradle/wrapper/gradle-wrapper.jar +++ /dev/null diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 53a7b2a7..00000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Sep 19 07:33:32 PDT 2014 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip diff --git a/gradlew b/gradlew deleted file mode 100755 index 91a7e269..00000000 --- a/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/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 deleted file mode 100644 index aec99730..00000000 --- a/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/library/build.gradle b/library/build.gradle deleted file mode 100644 index 66c86131..00000000 --- a/library/build.gradle +++ /dev/null @@ -1,88 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'robolectric' -apply plugin: 'maven' -apply plugin: 'findbugs' -apply plugin: 'pmd' - -findbugs { - toolVersion = "2.0.3" -} - -dependencies { - compile project(':third_party:gif_decoder') - compile project(':third_party:gif_encoder') - compile project(':third_party:disklrucache') - compile 'com.android.support:support-v4:19.1.+' - - androidTestCompile 'org.hamcrest:hamcrest-core:1.3' - androidTestCompile 'org.hamcrest:hamcrest-library:1.3' - androidTestCompile 'junit:junit:4.11' - androidTestCompile 'org.mockito:mockito-all:1.9.5' - androidTestCompile 'org.robolectric:robolectric:2.4-SNAPSHOT' - // TODO: increase this to 2.0.+ when we compile against Java 7. - androidTestCompile 'com.squareup.okhttp:mockwebserver:1.2.+' -} - -android { - compileSdkVersion 19 - buildToolsVersion '19.1.0' - - defaultConfig { - applicationId 'com.bumptech.glide' - minSdkVersion 10 - - targetSdkVersion 19 - versionCode = VERSION_CODE - versionName = VERSION_NAME - } -} - -afterEvaluate { - task findbugs(type: FindBugs, dependsOn: assembleDebug) { - - description 'Run findbugs' - group 'verification' - - classes = fileTree('build/intermediates/classes/debug/') - source = fileTree('src/main/java') - classpath = files(project.configurations.compile.asPath) - - effort = 'max' - - excludeFilter = file("findbugs-exclude.xml") - - reports { - xml.enabled = false - html.enabled = true - } - } - - findbugsTestDebug { - enabled = false - } - - check.dependsOn('findbugs') - - task pmd(type: Pmd) { - - description 'Run pmd' - group 'verification' - - // If ruleSets is not empty, it seems to contain some - // defaults which override rules in the ruleset file... - ruleSets = [] - ruleSetFiles = files('pmd-ruleset.xml') - source = fileTree('src/main/java') - - reports { - xml.enabled = false - html.enabled = true - } - } - - pmdTestDebug { - enabled = false - } - - check.dependsOn('pmd') -} diff --git a/library/findbugs-exclude.xml b/library/findbugs-exclude.xml deleted file mode 100644 index eff7240f..00000000 --- a/library/findbugs-exclude.xml +++ /dev/null @@ -1,35 +0,0 @@ -<FindBugsFilter> - - <Match> - <Class name="~.*R\$.*"/> - </Match> - <Match> - <Class name="~.*Manifest\$.*"/> - </Match> - - <!-- BytesResource is the wrapper that is given control of the data. --> - <Match> - <Class name="com.bumptech.glide.load.resource.bytes.BytesResource" /> - <Method name="get" /> - <Bug pattern="EI_EXPOSE_REP" /> - </Match> - - <!-- We would rather expose the internal bytes than box or copy them. --> - <Match> - <Class name="com.bumptech.glide.load.resource.bytes.BytesResource" /> - <Bug pattern="EI_EXPOSE_REP2" /> - </Match> - - <!-- Byte array fetcher just wraps a byte array to return an InputStream, data is not mutated. --> - <Match> - <Class name="com.bumptech.glide.load.data.ByteArrayFetcher" /> - <Bug pattern="EI_EXPOSE_REP2" /> - </Match> - - <!-- RecyclableBufferedInputStream safely re-uses pooled byte arrays --> - <Match> - <Class name="com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream" /> - <Bug pattern="EI_EXPOSE_REP2" /> - </Match> - -</FindBugsFilter> diff --git a/library/gradle.properties b/library/gradle.properties deleted file mode 100644 index 6f3b8429..00000000 --- a/library/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -POM_NAME=Glide Library -POM_ARTIFACT_ID=library -POM_PACKAGING=aar diff --git a/library/pmd-ruleset.xml b/library/pmd-ruleset.xml deleted file mode 100644 index 94220cb6..00000000 --- a/library/pmd-ruleset.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no" ?> -<ruleset name="PMD.rul" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"> - - <description>This ruleset was created from PMD.rul</description> - - <rule ref="rulesets/java/basic.xml" > - <exclude name="AvoidBranchingStatementAsLastInLoop" /> - </rule> - <rule ref="rulesets/java/braces.xml" /> - <rule ref="rulesets/java/strings.xml" /> - <rule ref="rulesets/java/unusedcode.xml" /> - - <rule ref="rulesets/java/design.xml" > - <exclude name="ConfusingTernary" /> - <exclude name="EmptyMethodInAbstractClassShouldBeAbstract" /> - <exclude name="AvoidSynchronizedAtMethodLevel" /> - - <!-- This check breaks on double checked locking which is safe in Java 6/7 --> - <exclude name="NonThreadSafeSingleton" /> - - <!-- TODO: Fix these --> - <exclude name="AvoidReassigningParameters" /> - <exclude name="GodClass" /> - </rule> - - <rule ref="rulesets/java/empty.xml/EmptyCatchBlock" message="Commented blocks are ok"> - <properties> - <property name="allowCommentedBlocks" value="true" /> - </properties> - </rule> -</ruleset> diff --git a/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java b/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java index 15b4ca85..07e7c4ab 100644 --- a/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java @@ -5,6 +5,7 @@ import android.graphics.drawable.Drawable; import android.os.ParcelFileDescriptor; import android.view.animation.Animation; import android.widget.ImageView; + import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Key; @@ -391,7 +392,7 @@ public class BitmapRequestBuilder<ModelType, TranscodeType> */ @Override public BitmapRequestBuilder<ModelType, TranscodeType> listener( - RequestListener<ModelType, TranscodeType> requestListener) { + RequestListener<? super ModelType, TranscodeType> requestListener) { super.listener(requestListener); return this; } diff --git a/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java b/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java index 485b10fd..8e2b227c 100644 --- a/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java +++ b/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java @@ -2,6 +2,7 @@ package com.bumptech.glide; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.load.model.ImageVideoModelLoader; import com.bumptech.glide.load.model.ImageVideoWrapper; import com.bumptech.glide.load.model.ModelLoader; diff --git a/library/src/main/java/com/bumptech/glide/DownloadOptions.java b/library/src/main/java/com/bumptech/glide/DownloadOptions.java index dc4c73ba..ae472c85 100644 --- a/library/src/main/java/com/bumptech/glide/DownloadOptions.java +++ b/library/src/main/java/com/bumptech/glide/DownloadOptions.java @@ -21,8 +21,8 @@ interface DownloadOptions { * Loads the original unmodified data into the cache and returns a {@link java.util.concurrent.Future} that can be * used to retrieve the cache File containing the data. * - * @param width The width to use to fetch the data. - * @param height The height to use to fetch the data. + * @param width The width in pixels to use to fetch the data. + * @param height The height in pixels to use to fetch the data. * @return A {@link java.util.concurrent.Future} that can be used to retrieve the cache File containing the data. */ FutureTarget<File> downloadOnly(int width, int height); diff --git a/library/src/main/java/com/bumptech/glide/DrawableOptions.java b/library/src/main/java/com/bumptech/glide/DrawableOptions.java index 74e7eae9..ebc1aa5c 100644 --- a/library/src/main/java/com/bumptech/glide/DrawableOptions.java +++ b/library/src/main/java/com/bumptech/glide/DrawableOptions.java @@ -41,6 +41,7 @@ interface DrawableOptions { * asked to start an animation using a single {@link android.view.animation.Animation} object which results in * views animating repeatedly. Use {@link #crossFade(int, int)}} instead, or be sure to call this method once * per call to {@link com.bumptech.glide.GenericRequestBuilder#load(Object)} to avoid re-using animation objects. + * Scheduled to be removed in Glide 4.0. * @param animation The Animation to use if no placeholder is set. * @param duration The duration of the cross fade animation. * @return This request builder. diff --git a/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java b/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java index 78802765..845a01e8 100644 --- a/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java @@ -5,6 +5,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.view.animation.Animation; import android.widget.ImageView; + import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; @@ -21,7 +22,7 @@ import com.bumptech.glide.manager.Lifecycle; import com.bumptech.glide.manager.RequestTracker; import com.bumptech.glide.provider.LoadProvider; import com.bumptech.glide.request.RequestListener; -import com.bumptech.glide.request.animation.DrawableCrossFadeViewAnimation; +import com.bumptech.glide.request.animation.DrawableCrossFadeFactory; import com.bumptech.glide.request.animation.ViewPropertyAnimation; import com.bumptech.glide.request.target.Target; @@ -242,7 +243,7 @@ public class DrawableRequestBuilder<ModelType> * {@inheritDoc} */ public final DrawableRequestBuilder<ModelType> crossFade() { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GlideDrawable>()); + super.animate(new DrawableCrossFadeFactory<GlideDrawable>()); return this; } @@ -250,7 +251,7 @@ public class DrawableRequestBuilder<ModelType> * {@inheritDoc} */ public DrawableRequestBuilder<ModelType> crossFade(int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GlideDrawable>(duration)); + super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration)); return this; } @@ -259,7 +260,7 @@ public class DrawableRequestBuilder<ModelType> */ @Deprecated public DrawableRequestBuilder<ModelType> crossFade(Animation animation, int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GlideDrawable>(animation, duration)); + super.animate(new DrawableCrossFadeFactory<GlideDrawable>(animation, duration)); return this; } @@ -267,7 +268,7 @@ public class DrawableRequestBuilder<ModelType> * {@inheritDoc} */ public DrawableRequestBuilder<ModelType> crossFade(int animationId, int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GlideDrawable>(context, animationId, + super.animate(new DrawableCrossFadeFactory<GlideDrawable>(context, animationId, duration)); return this; } @@ -350,7 +351,8 @@ public class DrawableRequestBuilder<ModelType> * {@inheritDoc} */ @Override - public DrawableRequestBuilder<ModelType> listener(RequestListener<ModelType, GlideDrawable> requestListener) { + public DrawableRequestBuilder<ModelType> listener( + RequestListener<? super ModelType, GlideDrawable> requestListener) { super.listener(requestListener); return this; } diff --git a/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java b/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java index 84d3a273..ee67f1a3 100644 --- a/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java +++ b/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java @@ -2,6 +2,7 @@ package com.bumptech.glide; import android.content.Context; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.load.model.ImageVideoModelLoader; import com.bumptech.glide.load.model.ImageVideoWrapper; import com.bumptech.glide.load.model.ModelLoader; diff --git a/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java b/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java index 84b1828f..13319d73 100644 --- a/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java @@ -4,7 +4,7 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.view.animation.Animation; import android.widget.ImageView; -import com.bumptech.glide.signature.EmptySignature; + import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.MultiTransformation; @@ -27,10 +27,12 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.ThumbnailRequestCoordinator; import com.bumptech.glide.request.animation.GlideAnimationFactory; import com.bumptech.glide.request.animation.NoAnimation; -import com.bumptech.glide.request.animation.ViewAnimation; +import com.bumptech.glide.request.animation.ViewAnimationFactory; import com.bumptech.glide.request.animation.ViewPropertyAnimation; +import com.bumptech.glide.request.animation.ViewPropertyAnimationFactory; import com.bumptech.glide.request.target.PreloadTarget; import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.signature.EmptySignature; import com.bumptech.glide.util.Util; import java.io.File; @@ -60,7 +62,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT private boolean isModelSet; private int placeholderId; private int errorId; - private RequestListener<ModelType, TranscodeType> requestListener; + private RequestListener<? super ModelType, TranscodeType> requestListener; private Float thumbSizeMultiplier; private GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequestBuilder; private Float sizeMultiplier = 1f; @@ -367,7 +369,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT * @return This request builder. */ public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(int animationId) { - return animate(new ViewAnimation.ViewAnimationFactory<TranscodeType>(context, animationId)); + return animate(new ViewAnimationFactory<TranscodeType>(context, animationId)); } /** @@ -380,13 +382,14 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT * @deprecated If this builder is used for multiple loads, using this method will result in multiple view's being * asked to start an animation using a single {@link android.view.animation.Animation} object which results in * views animating repeatedly. Use {@link #animate(int)} or - * {@link #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator)}. + * {@link #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator)}. Scheduled to be removed in + * Glide 4.0. * @param animation The animation to run * @return This request builder. */ @Deprecated public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(Animation animation) { - return animate(new ViewAnimation.ViewAnimationFactory<TranscodeType>(animation)); + return animate(new ViewAnimationFactory<TranscodeType>(animation)); } /** @@ -399,7 +402,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT */ public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate( ViewPropertyAnimation.Animator animator) { - return animate(new ViewPropertyAnimation.ViewPropertyAnimationFactory<TranscodeType>(animator)); + return animate(new ViewPropertyAnimationFactory<TranscodeType>(animator)); } GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate( @@ -474,7 +477,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT * @return This request builder. */ public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> listener( - RequestListener<ModelType, TranscodeType> requestListener) { + RequestListener<? super ModelType, TranscodeType> requestListener) { this.requestListener = requestListener; return this; @@ -502,8 +505,8 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT * thumbnails, and should only be used when you both need a very specific sized image and when it is impossible or * impractical to return that size from {@link Target#getSize(com.bumptech.glide.request.target.SizeReadyCallback)}. * - * @param width The width to use to load the resource. - * @param height The height to use to load the resource. + * @param width The width in pixels to use to load the resource. + * @param height The height in pixels to use to load the resource. * @return This request builder. */ public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> override(int width, int height) { @@ -651,10 +654,10 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT /** * Returns a future that can be used to do a blocking get on a background thread. * - * @param width The desired width (note this will be overriden by {@link #override(int, int)} if - * previously called. - * @param height The desired height (note this will be overriden by {@link #override(int, int)}} - * if previously called. + * @param width The desired width in pixels (note this will be overriden by {@link #override(int, int)} if + * previously called). + * @param height The desired height in pixels (note this will be overriden by {@link #override(int, int)}} + * if previously called). * * @see Glide#clear(com.bumptech.glide.request.FutureTarget) * diff --git a/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java b/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java index 9c0b4efa..ca629236 100644 --- a/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java +++ b/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java @@ -1,6 +1,7 @@ package com.bumptech.glide; import android.content.Context; + import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; diff --git a/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java b/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java index ffde6fe1..474f2e7c 100644 --- a/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java @@ -3,6 +3,7 @@ package com.bumptech.glide; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.view.animation.Animation; + import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; @@ -15,7 +16,7 @@ import com.bumptech.glide.load.resource.gif.GifDrawableTransformation; import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; import com.bumptech.glide.provider.LoadProvider; import com.bumptech.glide.request.RequestListener; -import com.bumptech.glide.request.animation.DrawableCrossFadeViewAnimation; +import com.bumptech.glide.request.animation.DrawableCrossFadeFactory; import com.bumptech.glide.request.animation.ViewPropertyAnimation; import java.io.File; @@ -229,7 +230,7 @@ public class GifRequestBuilder<ModelType> */ @Override public GifRequestBuilder<ModelType> crossFade() { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GifDrawable>()); + super.animate(new DrawableCrossFadeFactory<GifDrawable>()); return this; } @@ -238,7 +239,7 @@ public class GifRequestBuilder<ModelType> */ @Override public GifRequestBuilder<ModelType> crossFade(int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GifDrawable>(duration)); + super.animate(new DrawableCrossFadeFactory<GifDrawable>(duration)); return this; } @@ -248,7 +249,7 @@ public class GifRequestBuilder<ModelType> @Deprecated @Override public GifRequestBuilder<ModelType> crossFade(Animation animation, int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GifDrawable>(animation, duration)); + super.animate(new DrawableCrossFadeFactory<GifDrawable>(animation, duration)); return this; } @@ -257,7 +258,7 @@ public class GifRequestBuilder<ModelType> */ @Override public GifRequestBuilder<ModelType> crossFade(int animationId, int duration) { - super.animate(new DrawableCrossFadeViewAnimation.DrawableCrossFadeFactory<GifDrawable>(context, animationId, + super.animate(new DrawableCrossFadeFactory<GifDrawable>(context, animationId, duration)); return this; } @@ -341,7 +342,7 @@ public class GifRequestBuilder<ModelType> */ @Override public GifRequestBuilder<ModelType> listener( - RequestListener<ModelType, GifDrawable> requestListener) { + RequestListener<? super ModelType, GifDrawable> requestListener) { super.listener(requestListener); return this; } diff --git a/library/src/main/java/com/bumptech/glide/Glide.java b/library/src/main/java/com/bumptech/glide/Glide.java index 905c3a5e..5439a42a 100644 --- a/library/src/main/java/com/bumptech/glide/Glide.java +++ b/library/src/main/java/com/bumptech/glide/Glide.java @@ -15,12 +15,13 @@ import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.View; import android.widget.ImageView; + import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.engine.Engine; -import com.bumptech.glide.load.engine.prefill.PreFillBitmapAttribute; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; -import com.bumptech.glide.load.engine.prefill.BitmapPreFiller; import com.bumptech.glide.load.engine.cache.MemoryCache; +import com.bumptech.glide.load.engine.prefill.BitmapPreFiller; +import com.bumptech.glide.load.engine.prefill.PreFillType; import com.bumptech.glide.load.model.GenericLoaderFactory; import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.ImageVideoWrapper; @@ -82,7 +83,7 @@ public class Glide { private static final String TAG = "Glide"; private static volatile Glide glide; - private final GenericLoaderFactory loaderFactory = new GenericLoaderFactory(); + private final GenericLoaderFactory loaderFactory; private final Engine engine; private final BitmapPool bitmapPool; private final MemoryCache memoryCache; @@ -188,8 +189,9 @@ public class Glide { this.bitmapPool = bitmapPool; this.memoryCache = memoryCache; this.decodeFormat = decodeFormat; + loaderFactory = new GenericLoaderFactory(context); mainHandler = new Handler(Looper.getMainLooper()); - bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool); + bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); dataLoadProviderRegistry = new DataLoadProviderRegistry(); @@ -206,7 +208,7 @@ public class Glide { dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider); GifDrawableLoadProvider gifDrawableLoadProvider = - new GifDrawableLoadProvider(context, bitmapPool, decodeFormat); + new GifDrawableLoadProvider(context, bitmapPool); dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider); dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class, @@ -333,12 +335,12 @@ public class Glide { * pre-filling only happens when the Activity is first created, rather than on every rotation. * </p> * - * @param bitmapAttributes The list of {@link com.bumptech.glide.load.engine.prefill.PreFillBitmapAttribute}s - * representing individual sizes and configurations of {@link android.graphics.Bitmap}s to - * be pre-filled. + * @param bitmapAttributeBuilders The list of + * {@link com.bumptech.glide.load.engine.prefill.PreFillType.Builder Builders} representing + * individual sizes and configurations of {@link android.graphics.Bitmap}s to be pre-filled. */ - public void preFillBitmapPool(PreFillBitmapAttribute... bitmapAttributes) { - bitmapPreFiller.preFill(bitmapAttributes); + public void preFillBitmapPool(PreFillType.Builder... bitmapAttributeBuilders) { + bitmapPreFiller.preFill(bitmapAttributeBuilders); } /** @@ -492,7 +494,7 @@ public class Glide { } return null; } - return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass, context); + return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass); } /** diff --git a/library/src/main/java/com/bumptech/glide/GlideBuilder.java b/library/src/main/java/com/bumptech/glide/GlideBuilder.java index f7ffcecb..49e4d2fe 100644 --- a/library/src/main/java/com/bumptech/glide/GlideBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GlideBuilder.java @@ -2,6 +2,7 @@ package com.bumptech.glide; import android.content.Context; import android.os.Build; + import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.engine.Engine; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index 17a3f280..071a91e7 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -5,10 +5,9 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.load.Key; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.signature.ApplicationVersionSignature; -import com.bumptech.glide.signature.MediaStoreSignature; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader; import com.bumptech.glide.load.model.stream.MediaStoreStreamLoader; @@ -19,6 +18,8 @@ import com.bumptech.glide.manager.ConnectivityMonitorFactory; import com.bumptech.glide.manager.Lifecycle; import com.bumptech.glide.manager.LifecycleListener; import com.bumptech.glide.manager.RequestTracker; +import com.bumptech.glide.signature.ApplicationVersionSignature; +import com.bumptech.glide.signature.MediaStoreSignature; import com.bumptech.glide.signature.StringSignature; import com.bumptech.glide.util.Util; @@ -52,7 +53,7 @@ public class RequestManager implements LifecycleListener { RequestManager(Context context, final Lifecycle lifecycle, RequestTracker requestTracker, ConnectivityMonitorFactory factory) { - this.context = context; + this.context = context.getApplicationContext(); this.lifecycle = lifecycle; this.requestTracker = requestTracker; this.glide = Glide.get(context); @@ -297,6 +298,10 @@ public class RequestManager implements LifecycleListener { * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key) * @see com.bumptech.glide.signature.MediaStoreSignature * + * @deprecated Use {@link #loadFromMediaStore(android.net.Uri)}, + * {@link com.bumptech.glide.signature.MediaStoreSignature}, and + * {@link com.bumptech.glide.DrawableRequestBuilder#signature(com.bumptech.glide.load.Key)} instead. Scheduled to be + * removed in Glide 4.0. * @param uri The uri representing the media. * @param mimeType The mime type of the media store media. Ok to default to empty string "". See * {@link android.provider.MediaStore.Images.ImageColumns#MIME_TYPE} or @@ -307,6 +312,7 @@ public class RequestManager implements LifecycleListener { * @param orientation The orientation of the media store media. Ok to default to 0. See * {@link android.provider.MediaStore.Images.ImageColumns#ORIENTATION}. */ + @Deprecated public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri, String mimeType, long dateModified, int orientation) { Key signature = new MediaStoreSignature(mimeType, dateModified, orientation); return (DrawableTypeRequest<Uri>) loadFromMediaStore(uri).signature(signature); @@ -481,7 +487,8 @@ public class RequestManager implements LifecycleListener { * @see #load(byte[]) * * @deprecated Use {@link #load(byte[])} along with - * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} instead. + * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} instead. Scheduled to be + * removed in Glide 4.0. * @param model The data to load. * @param id A unique id that identifies the image represented by the model suitable for use as a cache key * (url, filepath etc). If there is no suitable id, use {@link #load(byte[])} instead. diff --git a/library/src/main/java/com/bumptech/glide/load/ResourceDecoder.java b/library/src/main/java/com/bumptech/glide/load/ResourceDecoder.java index 4f686e1b..3de450f6 100644 --- a/library/src/main/java/com/bumptech/glide/load/ResourceDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/ResourceDecoder.java @@ -26,8 +26,8 @@ public interface ResourceDecoder<T, Z> { * </p> * * @param source The data the resource should be decoded from. - * @param width The ideal width of the decoded resource. - * @param height The ideal height of the decoded resource. + * @param width The ideal width in pixels of the decoded resource. + * @param height The ideal height in pixels of the decoded resource. * @throws IOException */ Resource<Z> decode(T source, int width, int height) throws IOException; diff --git a/library/src/main/java/com/bumptech/glide/load/data/AssetPathFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/AssetPathFetcher.java index 7bac767e..7c9e6229 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/AssetPathFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/AssetPathFetcher.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.data; import android.content.res.AssetManager; import android.util.Log; + import com.bumptech.glide.Priority; import java.io.IOException; diff --git a/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java index a2175603..7662eb2c 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/HttpUrlFetcher.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.data; import android.text.TextUtils; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.model.GlideUrl; diff --git a/library/src/main/java/com/bumptech/glide/load/data/LocalUriFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/LocalUriFetcher.java index 6a9d046a..8c3a999a 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/LocalUriFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/LocalUriFetcher.java @@ -4,6 +4,7 @@ import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.util.Log; + import com.bumptech.glide.Priority; import java.io.FileNotFoundException; diff --git a/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java index af47dd2f..b9b622a1 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java @@ -6,6 +6,7 @@ import android.database.Cursor; import android.net.Uri; import android.provider.MediaStore; import android.text.TextUtils; + import com.bumptech.glide.Priority; import java.io.File; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java index 024dfa1c..f3d9c008 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/DecodeJob.java @@ -1,7 +1,7 @@ package com.bumptech.glide.load.engine; -import android.os.SystemClock; import android.util.Log; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.Key; @@ -10,6 +10,7 @@ import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.engine.cache.DiskCache; import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; import com.bumptech.glide.provider.DataLoadProvider; +import com.bumptech.glide.util.LogTime; import java.io.BufferedOutputStream; import java.io.File; @@ -28,6 +29,7 @@ import java.io.OutputStream; */ class DecodeJob<A, T, Z> { private static final String TAG = "DecodeJob"; + private static final FileOpener DEFAULT_FILE_OPENER = new FileOpener(); private final EngineKey resultKey; private final int width; @@ -39,11 +41,21 @@ class DecodeJob<A, T, Z> { private final DiskCacheStrategy diskCacheStrategy; private final DiskCache diskCache; private final Priority priority; + private final FileOpener fileOpener; + private volatile boolean isCancelled; public DecodeJob(EngineKey resultKey, int width, int height, DataFetcher<A> fetcher, DataLoadProvider<A, T> loadProvider, Transformation<T> transformation, ResourceTranscoder<T, Z> transcoder, DiskCache diskCache, DiskCacheStrategy diskCacheStrategy, Priority priority) { + this(resultKey, width, height, fetcher, loadProvider, transformation, transcoder, diskCache, diskCacheStrategy, + priority, DEFAULT_FILE_OPENER); + } + + // Visible for testing. + DecodeJob(EngineKey resultKey, int width, int height, DataFetcher<A> fetcher, + DataLoadProvider<A, T> loadProvider, Transformation<T> transformation, ResourceTranscoder<T, Z> transcoder, + DiskCache diskCache, DiskCacheStrategy diskCacheStrategy, Priority priority, FileOpener fileOpener) { this.resultKey = resultKey; this.width = width; this.height = height; @@ -54,6 +66,7 @@ class DecodeJob<A, T, Z> { this.diskCacheStrategy = diskCacheStrategy; this.diskCache = diskCache; this.priority = priority; + this.fileOpener = fileOpener; } /** @@ -67,8 +80,17 @@ class DecodeJob<A, T, Z> { return null; } + long startTime = LogTime.getLogTime(); Resource<T> transformed = loadFromCache(resultKey); - return transcode(transformed); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Decoded transformed from cache", startTime); + } + startTime = LogTime.getLogTime(); + Resource<Z> result = transcode(transformed); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Transcoded transformed from cache", startTime); + } + return result; } /** @@ -82,7 +104,11 @@ class DecodeJob<A, T, Z> { return null; } + long startTime = LogTime.getLogTime(); Resource<T> decoded = loadFromCache(resultKey.getOriginalKey()); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Decoded source from cache", startTime); + } return transformEncodeAndTranscode(decoded); } @@ -108,23 +134,42 @@ class DecodeJob<A, T, Z> { } private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) { + long startTime = LogTime.getLogTime(); Resource<T> transformed = transform(decoded); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Transformed resource from source", startTime); + } + writeTransformedToCache(transformed); - return transcode(transformed); + + startTime = LogTime.getLogTime(); + Resource<Z> result = transcode(transformed); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Transcoded transformed from source", startTime); + } + return result; } private void writeTransformedToCache(Resource<T> transformed) { if (transformed == null || !diskCacheStrategy.cacheResult()) { return; } + long startTime = LogTime.getLogTime(); SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed); diskCache.put(resultKey, writer); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Wrote transformed from source to cache", startTime); + } } private Resource<T> decodeSource() throws Exception { Resource<T> decoded = null; try { + long startTime = LogTime.getLogTime(); final A data = fetcher.loadData(priority); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Fetched data", startTime); + } if (isCancelled) { return null; } @@ -140,15 +185,29 @@ class DecodeJob<A, T, Z> { if (diskCacheStrategy.cacheSource()) { decoded = cacheAndDecodeSourceData(data); } else { + long startTime = LogTime.getLogTime(); decoded = loadProvider.getSourceDecoder().decode(data, width, height); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Decoded from source", startTime); + } } return decoded; } private Resource<T> cacheAndDecodeSourceData(A data) throws IOException { + long startTime = LogTime.getLogTime(); SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data); diskCache.put(resultKey.getOriginalKey(), writer); - return loadFromCache(resultKey.getOriginalKey()); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + logWithTimeAndKey("Wrote source to cache", startTime); + } + + startTime = LogTime.getLogTime(); + Resource<T> result = loadFromCache(resultKey.getOriginalKey()); + if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) { + logWithTimeAndKey("Decoded source from cache", startTime); + } + return result; } private Resource<T> loadFromCache(Key key) throws IOException { @@ -187,23 +246,26 @@ class DecodeJob<A, T, Z> { return transcoder.transcode(transformed); } - static class SourceWriter<T> implements DiskCache.Writer { + private void logWithTimeAndKey(String message, long startTime) { + Log.v(TAG, message + " in " + LogTime.getElapsedMillis(startTime) + resultKey); + } + + class SourceWriter<DataType> implements DiskCache.Writer { - private final Encoder<T> encoder; - private final T data; + private final Encoder<DataType> encoder; + private final DataType data; - public SourceWriter(Encoder<T> encoder, T data) { + public SourceWriter(Encoder<DataType> encoder, DataType data) { this.encoder = encoder; this.data = data; } @Override public boolean write(File file) { - long start = SystemClock.currentThreadTimeMillis(); boolean success = false; OutputStream os = null; try { - os = new BufferedOutputStream(new FileOutputStream(file)); + os = fileOpener.open(file); success = encoder.encode(data, os); } catch (FileNotFoundException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -218,10 +280,13 @@ class DecodeJob<A, T, Z> { } } } - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "wrote to disk cache in " + (SystemClock.currentThreadTimeMillis() - start)); - } return success; } } + + static class FileOpener { + public OutputStream open(File file) throws FileNotFoundException { + return new BufferedOutputStream(new FileOutputStream(file)); + } + } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java index c8c028e2..1e7a9e7f 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java @@ -1,10 +1,9 @@ package com.bumptech.glide.load.engine; -import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.os.MessageQueue; import android.util.Log; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.Transformation; @@ -35,7 +34,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis private final EngineJobFactory engineJobFactory; private final Map<Key, WeakReference<EngineResource<?>>> activeResources; private final ReferenceQueue<EngineResource<?>> resourceReferenceQueue; - private final Handler mainHandler; + private final ResourceRecycler resourceRecycler; /** * Allows a request to indicate it no longer is interested in a given load. @@ -56,13 +55,14 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis public Engine(MemoryCache memoryCache, DiskCache diskCache, ExecutorService diskCacheService, ExecutorService sourceService) { - this(memoryCache, diskCache, diskCacheService, sourceService, null, null, null, null); + this(memoryCache, diskCache, diskCacheService, sourceService, null, null, null, null, null); } // Visible for testing. Engine(MemoryCache cache, DiskCache diskCache, ExecutorService diskCacheService, ExecutorService sourceService, Map<Key, EngineJob> jobs, EngineKeyFactory keyFactory, - Map<Key, WeakReference<EngineResource<?>>> activeResources, EngineJobFactory engineJobFactory) { + Map<Key, WeakReference<EngineResource<?>>> activeResources, EngineJobFactory engineJobFactory, + ResourceRecycler resourceRecycler) { this.cache = cache; this.diskCache = diskCache; @@ -86,12 +86,15 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis } this.engineJobFactory = engineJobFactory; + if (resourceRecycler == null) { + resourceRecycler = new ResourceRecycler(); + } + this.resourceRecycler = resourceRecycler; + resourceReferenceQueue = new ReferenceQueue<EngineResource<?>>(); MessageQueue queue = Looper.myQueue(); queue.addIdleHandler(new RefQueueIdleHandler(activeResources, resourceReferenceQueue)); cache.setResourceRemovedListener(this); - - mainHandler = new Handler(Looper.getMainLooper(), new ResourceRecyclerCallback()); } /** @@ -118,8 +121,8 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis * * @param signature A non-null unique key to be mixed into the cache key that identifies the version of the data to * be loaded. - * @param width The target width of the retrieved resource. - * @param height The target height of the retrieved resource. + * @param width The target width in pixels of the desired resource. + * @param height The target height in pixels of the desired resource. * @param fetcher The fetcher to use to retrieve data not in the disk cache. * @param loadProvider The load provider containing various encoders and decoders use to decode and encode data. * @param transformation The transformation to use to transform the decoded resource. @@ -244,7 +247,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis @Override public void onResourceRemoved(final Resource<?> resource) { - recycleResource(resource); + resourceRecycler.recycle(resource); } @Override @@ -253,27 +256,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis if (resource.isCacheable()) { cache.put(cacheKey, resource); } else { - recycleResource(resource); - } - } - - private void recycleResource(Resource<?> resource) { - // If a resource has sub-resources, releasing a sub resource can cause it's parent to be synchronously - // evicted which leads to a recycle loop when the parent the releases it's children. Posting breaks this loops. - mainHandler.obtainMessage(ResourceRecyclerCallback.RECYCLE_RESOURCE, resource).sendToTarget(); - } - - private static class ResourceRecyclerCallback implements Handler.Callback { - public static final int RECYCLE_RESOURCE = 1; - - @Override - public boolean handleMessage(Message message) { - if (message.what == RECYCLE_RESOURCE) { - Resource resource = (Resource) message.obj; - resource.recycle(); - return true; - } - return false; + resourceRecycler.recycle(resource); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java index ef9ffcac..06926317 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineJob.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.engine; import android.os.Handler; import android.os.Message; + import com.bumptech.glide.load.Key; import com.bumptech.glide.request.ResourceCallback; import com.bumptech.glide.util.Util; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java index 92574e1f..49bf096a 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineResource.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.engine; import android.os.Looper; + import com.bumptech.glide.load.Key; /** @@ -22,6 +23,9 @@ class EngineResource<Z> implements Resource<Z> { } EngineResource(Resource<Z> toWrap, boolean isCacheable) { + if (toWrap == null) { + throw new NullPointerException("Wrapped resource must not be null"); + } resource = toWrap; this.isCacheable = isCacheable; } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineRunnable.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineRunnable.java index 949f5978..98ec65ec 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineRunnable.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineRunnable.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.engine; import android.util.Log; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.engine.executor.Prioritized; import com.bumptech.glide.request.ResourceCallback; @@ -63,6 +64,9 @@ class EngineRunnable implements Runnable, Prioritized { } if (isCancelled) { + if (resource != null) { + resource.recycle(); + } return; } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java b/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java new file mode 100644 index 00000000..c30376cf --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/engine/ResourceRecycler.java @@ -0,0 +1,42 @@ +package com.bumptech.glide.load.engine; + +import android.os.Handler; +import android.os.Message; + +import com.bumptech.glide.util.Util; + +/** + * A class that can safely recycle recursive resources. + */ +class ResourceRecycler { + private boolean isRecycling; + private final Handler handler = new Handler(new ResourceRecyclerCallback()); + + public void recycle(Resource<?> resource) { + Util.assertMainThread(); + + if (isRecycling) { + // If a resource has sub-resources, releasing a sub resource can cause it's parent to be synchronously + // evicted which leads to a recycle loop when the parent releases it's children. Posting breaks this loop. + handler.obtainMessage(ResourceRecyclerCallback.RECYCLE_RESOURCE, resource).sendToTarget(); + } else { + isRecycling = true; + resource.recycle(); + isRecycling = false; + } + } + + private static class ResourceRecyclerCallback implements Handler.Callback { + public static final int RECYCLE_RESOURCE = 1; + + @Override + public boolean handleMessage(Message message) { + if (message.what == RECYCLE_RESOURCE) { + Resource resource = (Resource) message.obj; + resource.recycle(); + return true; + } + return false; + } + } +} diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java index ef57437e..eebd1fd5 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/AttributeStrategy.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.engine.bitmap_recycle; import android.graphics.Bitmap; + import com.bumptech.glide.util.Util; /** @@ -56,7 +57,8 @@ class AttributeStrategy implements LruPoolStrategy { return "[" + width + "x" + height + "], " + config; } - private static class KeyPool extends BaseKeyPool<Key> { + // Visible for testing. + static class KeyPool extends BaseKeyPool<Key> { public Key get(int width, int height, Bitmap.Config config) { Key result = get(); result.init(width, height, config); @@ -69,7 +71,8 @@ class AttributeStrategy implements LruPoolStrategy { } } - private static class Key implements Poolable { + // Visible for testing. + static class Key implements Poolable { private final KeyPool pool; private int width; private int height; @@ -88,26 +91,13 @@ class AttributeStrategy implements LruPoolStrategy { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Key key = (Key) o; - - if (height != key.height) { - return false; - } - if (width != key.width) { - return false; + if (o instanceof Key) { + Key other = (Key) o; + return width == other.width + && height == other.height + && config == other.config; } - if (config != key.config) { - return false; - } - - return true; + return false; } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/BitmapPool.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/BitmapPool.java index 3dd4c38d..0390a668 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/BitmapPool.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/BitmapPool.java @@ -71,8 +71,8 @@ public interface BitmapPool { * * @see #getDirty(int, int, android.graphics.Bitmap.Config) * - * @param width The width of the desired {@link android.graphics.Bitmap}. - * @param height The height of the desired {@link android.graphics.Bitmap}. + * @param width The width in pixels of the desired {@link android.graphics.Bitmap}. + * @param height The height in pixels of the desired {@link android.graphics.Bitmap}. * @param config The {@link android.graphics.Bitmap.Config} of the desired {@link android.graphics.Bitmap}. */ Bitmap get(int width, int height, Bitmap.Config config); @@ -89,8 +89,8 @@ public interface BitmapPool { * * @see #get(int, int, android.graphics.Bitmap.Config) * - * @param width The width of the desired {@link android.graphics.Bitmap}. - * @param height The height of the desired {@link android.graphics.Bitmap}. + * @param width The width in pixels of the desired {@link android.graphics.Bitmap}. + * @param height The height in pixels of the desired {@link android.graphics.Bitmap}. * @param config The {@link android.graphics.Bitmap.Config} of the desired {@link android.graphics.Bitmap}. * @return A {@link android.graphics.Bitmap} with exactly the given width, height, and config potentially containing * random image data or null if no such {@link android.graphics.Bitmap} could be obtained from the pool. diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java index cc59abc1..79d8c6c4 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/LruBitmapPool.java @@ -63,6 +63,10 @@ public class LruBitmapPool implements BitmapPool { @Override public synchronized boolean put(Bitmap bitmap) { if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize) { + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Reject bitmap from pool=" + strategy.logBitmap(bitmap) + " is mutable=" + + bitmap.isMutable()); + } return false; } @@ -73,8 +77,8 @@ public class LruBitmapPool implements BitmapPool { puts++; currentSize += size; - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap)); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap)); } dump(); @@ -118,8 +122,8 @@ public class LruBitmapPool implements BitmapPool { result.setHasAlpha(true); } } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Get bitmap=" + strategy.logBitmap(width, height, config)); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "Get bitmap=" + strategy.logBitmap(width, height, config)); } dump(); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeStrategy.java b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeStrategy.java index b33d13ac..2716d337 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeStrategy.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/bitmap_recycle/SizeStrategy.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.engine.bitmap_recycle; import android.annotation.TargetApi; import android.graphics.Bitmap; import android.os.Build; + import com.bumptech.glide.util.Util; import java.util.TreeMap; @@ -119,7 +120,8 @@ class SizeStrategy implements LruPoolStrategy { return "[" + size + "]"; } - private static class KeyPool extends BaseKeyPool<Key> { + // Visible for testing. + static class KeyPool extends BaseKeyPool<Key> { public Key get(int size) { Key result = get(); @@ -133,7 +135,8 @@ class SizeStrategy implements LruPoolStrategy { } } - private static final class Key implements Poolable { + // Visible for testing. + static final class Key implements Poolable { private final KeyPool pool; private int size; @@ -147,16 +150,11 @@ class SizeStrategy implements LruPoolStrategy { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; + if (o instanceof Key) { + Key other = (Key) o; + return size == other.size; } - - Key key = (Key) o; - - return size == key.size; + return false; } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/engine/cache/LruResourceCache.java b/library/src/main/java/com/bumptech/glide/load/engine/cache/LruResourceCache.java index 3cb8b5c2..ffe5a6f9 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/cache/LruResourceCache.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/cache/LruResourceCache.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.engine.cache; import android.annotation.SuppressLint; + import com.bumptech.glide.load.Key; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.util.LruCache; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/executor/FifoPriorityThreadPoolExecutor.java b/library/src/main/java/com/bumptech/glide/load/engine/executor/FifoPriorityThreadPoolExecutor.java index 9972fc6d..db0a128a 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/executor/FifoPriorityThreadPoolExecutor.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/executor/FifoPriorityThreadPoolExecutor.java @@ -34,7 +34,7 @@ public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor { @Override protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { - return new FifoPriorityLoadTask<T>(runnable, value, ordering.getAndIncrement()); + return new LoadTask<T>(runnable, value, ordering.getAndIncrement()); } /** @@ -57,11 +57,12 @@ public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor { } } - private static class FifoPriorityLoadTask<T> extends FutureTask<T> implements Comparable<FifoPriorityLoadTask<?>> { + // Visible for testing. + static class LoadTask<T> extends FutureTask<T> implements Comparable<LoadTask<?>> { private final int priority; private final int order; - public FifoPriorityLoadTask(Runnable runnable, T result, int order) { + public LoadTask(Runnable runnable, T result, int order) { super(runnable, result); if (!(runnable instanceof Prioritized)) { throw new IllegalArgumentException("FifoPriorityThreadPoolExecutor must be given Runnables that " @@ -71,25 +72,14 @@ public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor { this.order = order; } + @SuppressWarnings("unchecked") @Override public boolean equals(Object o) { - if (this == o) { - return true; + if (o instanceof LoadTask) { + LoadTask<Object> other = (LoadTask<Object>) o; + return order == other.order && priority == other.priority; } - if (o == null || getClass() != o.getClass()) { - return false; - } - - FifoPriorityLoadTask that = (FifoPriorityLoadTask) o; - - if (order != that.order) { - return false; - } - if (priority != that.priority) { - return false; - } - - return true; + return false; } @Override @@ -100,7 +90,7 @@ public class FifoPriorityThreadPoolExecutor extends ThreadPoolExecutor { } @Override - public int compareTo(FifoPriorityLoadTask<?> loadTask) { + public int compareTo(LoadTask<?> loadTask) { int result = priority - loadTask.priority; if (result == 0) { result = order - loadTask.order; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillIdleHandler.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillIdleHandler.java deleted file mode 100644 index 05be13b9..00000000 --- a/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillIdleHandler.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.bumptech.glide.load.engine.prefill; - -import android.graphics.Bitmap; -import android.os.MessageQueue; -import android.os.SystemClock; -import android.util.Log; -import com.bumptech.glide.load.Key; -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; -import com.bumptech.glide.load.engine.cache.MemoryCache; -import com.bumptech.glide.load.resource.bitmap.BitmapResource; -import com.bumptech.glide.util.Util; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; - -/** - * A class that allocates {@link android.graphics.Bitmap Bitmaps} when the main thread runs out of messages so that the - * {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} is pre-populated. - */ -final class BitmapPreFillIdleHandler implements MessageQueue.IdleHandler { - private static final String TAG = "PreFillIdleHandler"; - // Visisble for testing. - static final long MAX_DURATION_MILLIS = 32; - - private static final Clock DEFAULT_CLOCK = new Clock(); - - private final BitmapPool bitmapPool; - private final MemoryCache memoryCache; - private final PreFillQueue toPrefill; - private final Clock clock; - - private boolean isCancelled; - - public BitmapPreFillIdleHandler(BitmapPool bitmapPool, MemoryCache memoryCache, - PreFillQueue allocationOrder) { - this(bitmapPool, memoryCache, allocationOrder, DEFAULT_CLOCK); - } - - // Visible for testing. - BitmapPreFillIdleHandler(BitmapPool bitmapPool, MemoryCache memoryCache, - PreFillQueue allocationOrder, Clock clock) { - this.bitmapPool = bitmapPool; - this.memoryCache = memoryCache; - this.toPrefill = allocationOrder; - this.clock = clock; - } - - public void cancel() { - isCancelled = true; - } - - @Override - public boolean queueIdle() { - long start = clock.now(); - while (!toPrefill.isEmpty() && (clock.now() - start) < MAX_DURATION_MILLIS) { - PreFillBitmapAttribute toAllocate = toPrefill.remove(); - Bitmap bitmap = Bitmap.createBitmap(toAllocate.getWidth(), toAllocate.getHeight(), - toAllocate.getConfig()); - - // Don't over fill the memory cache to avoid evicting useful resources, but make sure it's not empty so - // we use all available space. - if ((memoryCache.getMaxSize() - memoryCache.getCurrentSize()) >= Util.getBitmapByteSize(bitmap)) { - memoryCache.put(new UniqueKey(), new BitmapResource(bitmap, bitmapPool)); - } else { - bitmapPool.put(bitmap); - } - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "allocated [" + toAllocate.getWidth() + "x" + toAllocate.getHeight() + "] " - + toAllocate.getConfig() + " size: " + Util.getBitmapByteSize(bitmap)); - } - } - - return !isCancelled && !toPrefill.isEmpty(); - } - - private static class UniqueKey implements Key { - - @Override - public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { - // Do nothing. - } - } - - // Visible for testing. - static class Clock { - public long now() { - return SystemClock.currentThreadTimeMillis(); - } - } -} diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillRunner.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillRunner.java new file mode 100644 index 00000000..6af89c19 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFillRunner.java @@ -0,0 +1,161 @@ +package com.bumptech.glide.load.engine.prefill; + +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import android.util.Log; + +import com.bumptech.glide.load.Key; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.engine.cache.MemoryCache; +import com.bumptech.glide.load.resource.bitmap.BitmapResource; +import com.bumptech.glide.util.Util; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * A class that allocates {@link android.graphics.Bitmap Bitmaps} to make sure that the + * {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} is pre-populated. + * + * <p>By posting to the main thread with backoffs, we try to avoid ANRs when the garbage collector gets into a state + * where a high percentage of {@link Bitmap} allocations trigger a stop the world GC. We try to detect whether or not a + * GC has occurred by only allowing our allocator to run for a limited number of milliseconds. Since the allocations + * themselves very fast, a GC is the most likely reason for a substantial delay. If we detect our allocator has run for + * more than our limit, we assume a GC has occurred, stop the current allocations, and try again after a delay. + */ +final class BitmapPreFillRunner implements Runnable { + private static final String TAG = "PreFillRunner"; + private static final Clock DEFAULT_CLOCK = new Clock(); + + /** + * The maximum number of millis we can run before posting. Set to match and detect the duration of non concurrent + * GCs. + */ + static final long MAX_DURATION_MS = 32; + + /** + * The amount of time in ms we wait before continuing to allocate after the first GC is detected. + */ + static final long INITIAL_BACKOFF_MS = 40; + + /** + * The amount by which the current backoff time is multiplied each time we detect a GC. + */ + static final int BACKOFF_RATIO = 4; + + /** + * The maximum amount of time in ms we wait before continuing to allocate. + */ + static final long MAX_BACKOFF_MS = TimeUnit.SECONDS.toMillis(1); + + private final BitmapPool bitmapPool; + private final MemoryCache memoryCache; + private final PreFillQueue toPrefill; + private final Clock clock; + private final Set<PreFillType> seenTypes = new HashSet<PreFillType>(); + private final Handler handler; + + private long currentDelay = INITIAL_BACKOFF_MS; + private boolean isCancelled; + + public BitmapPreFillRunner(BitmapPool bitmapPool, MemoryCache memoryCache, PreFillQueue allocationOrder) { + this(bitmapPool, memoryCache, allocationOrder, DEFAULT_CLOCK, new Handler(Looper.getMainLooper())); + } + + // Visible for testing. + BitmapPreFillRunner(BitmapPool bitmapPool, MemoryCache memoryCache, PreFillQueue allocationOrder, Clock clock, + Handler handler) { + this.bitmapPool = bitmapPool; + this.memoryCache = memoryCache; + this.toPrefill = allocationOrder; + this.clock = clock; + this.handler = handler; + } + + public void cancel() { + isCancelled = true; + } + + /** + * Attempts to allocate {@link android.graphics.Bitmap}s and returns {@code true} if there are more + * {@link android.graphics.Bitmap}s to allocate and {@code false} otherwise. + */ + private boolean allocate() { + long start = clock.now(); + while (!toPrefill.isEmpty() && !isGcDetected(start)) { + PreFillType toAllocate = toPrefill.remove(); + Bitmap bitmap = Bitmap.createBitmap(toAllocate.getWidth(), toAllocate.getHeight(), + toAllocate.getConfig()); + + // Don't over fill the memory cache to avoid evicting useful resources, but make sure it's not empty so + // we use all available space. + if (getFreeMemoryCacheBytes() >= Util.getBitmapByteSize(bitmap)) { + memoryCache.put(new UniqueKey(), BitmapResource.obtain(bitmap, bitmapPool)); + } else { + addToBitmapPool(toAllocate, bitmap); + } + + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "allocated [" + toAllocate.getWidth() + "x" + toAllocate.getHeight() + "] " + + toAllocate.getConfig() + " size: " + Util.getBitmapByteSize(bitmap)); + } + } + + return !isCancelled && !toPrefill.isEmpty(); + } + + private boolean isGcDetected(long startTimeMs) { + return clock.now() - startTimeMs >= MAX_DURATION_MS; + } + + private int getFreeMemoryCacheBytes() { + return memoryCache.getMaxSize() - memoryCache.getCurrentSize(); + } + + private void addToBitmapPool(PreFillType toAllocate, Bitmap bitmap) { + // The pool may not move sizes to the front of the LRU on put. Do a get here to make sure the size we're adding + // is at the front of the queue so that the Bitmap we're adding won't be evicted immediately. + if (seenTypes.add(toAllocate)) { + Bitmap fromPool = bitmapPool.get(toAllocate.getWidth(), toAllocate.getHeight(), + toAllocate.getConfig()); + if (fromPool != null) { + bitmapPool.put(fromPool); + } + } + + bitmapPool.put(bitmap); + } + + @Override + public void run() { + if (allocate()) { + handler.postDelayed(this, getNextDelay()); + } + } + + private long getNextDelay() { + long result = currentDelay; + currentDelay = Math.min(currentDelay * BACKOFF_RATIO, MAX_BACKOFF_MS); + return result; + } + + private static class UniqueKey implements Key { + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { + // Do nothing. + } + } + + // Visible for testing. + static class Clock { + public long now() { + return SystemClock.currentThreadTimeMillis(); + } + } +} diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFiller.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFiller.java index b4d9f1c4..f2e9accc 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFiller.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/prefill/BitmapPreFiller.java @@ -1,6 +1,10 @@ package com.bumptech.glide.load.engine.prefill; +import android.graphics.Bitmap; +import android.os.Handler; import android.os.Looper; + +import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.engine.cache.MemoryCache; import com.bumptech.glide.util.Util; @@ -16,36 +20,50 @@ public final class BitmapPreFiller { private final MemoryCache memoryCache; private final BitmapPool bitmapPool; + private final DecodeFormat defaultFormat; + private final Handler handler = new Handler(Looper.getMainLooper()); - private BitmapPreFillIdleHandler current; + private BitmapPreFillRunner current; - public BitmapPreFiller(MemoryCache memoryCache, BitmapPool bitmapPool) { + public BitmapPreFiller(MemoryCache memoryCache, BitmapPool bitmapPool, DecodeFormat defaultFormat) { this.memoryCache = memoryCache; this.bitmapPool = bitmapPool; + this.defaultFormat = defaultFormat; } - public void preFill(PreFillBitmapAttribute... bitmapAttributes) { + public void preFill(PreFillType.Builder... bitmapAttributeBuilders) { if (current != null) { current.cancel(); } + + PreFillType[] bitmapAttributes = new PreFillType[bitmapAttributeBuilders.length]; + for (int i = 0; i < bitmapAttributeBuilders.length; i++) { + PreFillType.Builder builder = bitmapAttributeBuilders[i]; + if (builder.getConfig() == null) { + builder.setConfig(defaultFormat == DecodeFormat.ALWAYS_ARGB_8888 + ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + } + bitmapAttributes[i] = builder.build(); + } + PreFillQueue allocationOrder = generateAllocationOrder(bitmapAttributes); - current = new BitmapPreFillIdleHandler(bitmapPool, memoryCache, allocationOrder); - Looper.myQueue().addIdleHandler(current); + current = new BitmapPreFillRunner(bitmapPool, memoryCache, allocationOrder); + handler.post(current); } // Visible for testing. - PreFillQueue generateAllocationOrder(PreFillBitmapAttribute[] preFillSizes) { + PreFillQueue generateAllocationOrder(PreFillType[] preFillSizes) { final int maxSize = memoryCache.getMaxSize() - memoryCache.getCurrentSize() + bitmapPool.getMaxSize(); int totalWeight = 0; - for (PreFillBitmapAttribute size : preFillSizes) { + for (PreFillType size : preFillSizes) { totalWeight += size.getWeight(); } final float bytesPerWeight = maxSize / (float) totalWeight; - Map<PreFillBitmapAttribute, Integer> attributeToCount = new HashMap<PreFillBitmapAttribute, Integer>(); - for (PreFillBitmapAttribute size : preFillSizes) { + Map<PreFillType, Integer> attributeToCount = new HashMap<PreFillType, Integer>(); + for (PreFillType size : preFillSizes) { int bytesForSize = Math.round(bytesPerWeight * size.getWeight()); int bytesPerBitmap = getSizeInBytes(size); int bitmapsForSize = bytesForSize / bytesPerBitmap; @@ -55,7 +73,7 @@ public final class BitmapPreFiller { return new PreFillQueue(attributeToCount); } - private static int getSizeInBytes(PreFillBitmapAttribute size) { + private static int getSizeInBytes(PreFillType size) { return Util.getBitmapByteSize(size.getWidth(), size.getHeight(), size.getConfig()); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillBitmapAttribute.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillBitmapAttribute.java deleted file mode 100644 index b84763fa..00000000 --- a/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillBitmapAttribute.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.bumptech.glide.load.engine.prefill; - -import android.graphics.Bitmap; - -/** - * A container for a set of options used to pre-fill a {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} - * with {@link Bitmap Bitmaps} of a single size and configuration. - */ -public final class PreFillBitmapAttribute { - // Visible for testing. - static final Bitmap.Config DEFAULT_CONFIG = Bitmap.Config.RGB_565; - private final int width; - private final int height; - private final Bitmap.Config config; - private final int weight; - - /** - * Constructor for a single type of {@link android.graphics.Bitmap}. - * - * @see #PreFillBitmapAttribute(int, int, int) - * @see #PreFillBitmapAttribute(int, int, android.graphics.Bitmap.Config, int) - * - * @param width The width in pixels of the {@link android.graphics.Bitmap} to pre-fill. - * @param height The height in pixels of the {@link android.graphics.Bitmap} to pre-fill. - */ - public PreFillBitmapAttribute(int width, int height) { - this(width, height, 1); - } - - /** - * Constructor for a single type of {@link android.graphics.Bitmap}. - * - * @see #PreFillBitmapAttribute(int, int) - * @see #PreFillBitmapAttribute(int, int, android.graphics.Bitmap.Config, int) - * - * @param width The width in pixels of the {@link android.graphics.Bitmap} to pre-fill. - * @param height The height in pixels of the {@link android.graphics.Bitmap} to pre-fill. - * @param weight An integer indicating how to balance pre-filling this size and configuration of - * {@link android.graphics.Bitmap} against any other sizes/configurations that may be being pre-filled. - */ - public PreFillBitmapAttribute(int width, int height, int weight) { - this(width, height, DEFAULT_CONFIG, weight); - } - - /** - * Constructor for a single type of {@link android.graphics.Bitmap}. - * - * @see #PreFillBitmapAttribute(int, int) - * @see #PreFillBitmapAttribute(int, int, int) - * - * @param width The width in pixels of the {@link android.graphics.Bitmap Bitmaps} to - * pre-fill. - * @param height The height in pixels of the {@link android.graphics.Bitmap Bitmaps} to - * pre-fill. - * @param config The {@link android.graphics.Bitmap.Config} of the {@link android.graphics.Bitmap Bitmaps} to - * pre-fill. - * @param weight An integer indicating how to balance pre-filling this size and configuration of - * {@link android.graphics.Bitmap} against any other sizes/configurations that may be being pre-filled. - */ - public PreFillBitmapAttribute(int width, int height, Bitmap.Config config, int weight) { - this.width = width; - this.height = height; - this.config = config; - this.weight = weight; - } - - /** - * Returns the width in pixels of the {@link android.graphics.Bitmap Bitmaps}. - */ - public int getWidth() { - return width; - } - - /** - * Returns the height in pixels of the {@link android.graphics.Bitmap Bitmaps}. - */ - public int getHeight() { - return height; - } - - /** - * Returns the {@link android.graphics.Bitmap.Config} of the {@link android.graphics.Bitmap Bitmaps}. - */ - public Bitmap.Config getConfig() { - return config; - } - - /** - * Returns the weight of the {@link android.graphics.Bitmap Bitmaps} of this type. - */ - public int getWeight() { - return weight; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o == null || getClass() != o.getClass()) { - return false; - } - - PreFillBitmapAttribute size = (PreFillBitmapAttribute) o; - - return height == size.height - && weight == size.weight - && width == size.width - && config == size.config; - } - - @Override - public int hashCode() { - int result = width; - result = 31 * result + height; - result = 31 * result + config.hashCode(); - result = 31 * result + weight; - return result; - } - - @Override - public String toString() { - return "PreFillSize{" - + "width=" + width - + ", height=" + height - + ", config=" + config - + ", weight=" + weight - + '}'; - } -} diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillQueue.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillQueue.java index abdc9e2b..f88032a8 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillQueue.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillQueue.java @@ -6,23 +6,23 @@ import java.util.Map; final class PreFillQueue { - private final Map<PreFillBitmapAttribute, Integer> bitmapsPerType; - private final List<PreFillBitmapAttribute> keyList; + private final Map<PreFillType, Integer> bitmapsPerType; + private final List<PreFillType> keyList; private int bitmapsRemaining; private int keyIndex; - public PreFillQueue(Map<PreFillBitmapAttribute, Integer> bitmapsPerType) { + public PreFillQueue(Map<PreFillType, Integer> bitmapsPerType) { this.bitmapsPerType = bitmapsPerType; // We don't particularly care about the initial order. - keyList = new ArrayList<PreFillBitmapAttribute>(bitmapsPerType.keySet()); + keyList = new ArrayList<PreFillType>(bitmapsPerType.keySet()); for (Integer count : bitmapsPerType.values()) { bitmapsRemaining += count; } } - public PreFillBitmapAttribute remove() { - PreFillBitmapAttribute result = keyList.get(keyIndex); + public PreFillType remove() { + PreFillType result = keyList.get(keyIndex); Integer countForResult = bitmapsPerType.get(result); if (countForResult == 1) { diff --git a/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillType.java b/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillType.java new file mode 100644 index 00000000..5037b352 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/engine/prefill/PreFillType.java @@ -0,0 +1,172 @@ +package com.bumptech.glide.load.engine.prefill; + +import android.graphics.Bitmap; + +/** + * A container for a set of options used to pre-fill a {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} + * with {@link Bitmap Bitmaps} of a single size and configuration. + */ +public final class PreFillType { + // Visible for testing. + static final Bitmap.Config DEFAULT_CONFIG = Bitmap.Config.RGB_565; + private final int width; + private final int height; + private final Bitmap.Config config; + private final int weight; + + /** + * Constructor for a single type of {@link android.graphics.Bitmap}. + * + * @param width The width in pixels of the {@link android.graphics.Bitmap Bitmaps} to + * pre-fill. + * @param height The height in pixels of the {@link android.graphics.Bitmap Bitmaps} to + * pre-fill. + * @param config The {@link android.graphics.Bitmap.Config} of the {@link android.graphics.Bitmap Bitmaps} to + * pre-fill. + * @param weight An integer indicating how to balance pre-filling this size and configuration of + * {@link android.graphics.Bitmap} against any other sizes/configurations that may be being pre-filled. + */ + PreFillType(int width, int height, Bitmap.Config config, int weight) { + if (config == null) { + throw new NullPointerException("Config must not be null"); + } + + this.width = width; + this.height = height; + this.config = config; + this.weight = weight; + } + + /** + * Returns the width in pixels of the {@link android.graphics.Bitmap Bitmaps}. + */ + int getWidth() { + return width; + } + + /** + * Returns the height in pixels of the {@link android.graphics.Bitmap Bitmaps}. + */ + int getHeight() { + return height; + } + + /** + * Returns the {@link android.graphics.Bitmap.Config} of the {@link android.graphics.Bitmap Bitmaps}. + */ + Bitmap.Config getConfig() { + return config; + } + + /** + * Returns the weight of the {@link android.graphics.Bitmap Bitmaps} of this type. + */ + int getWeight() { + return weight; + } + + @Override + public boolean equals(Object o) { + if (o instanceof PreFillType) { + PreFillType other = (PreFillType) o; + return height == other.height + && width == other.width + && weight == other.weight + && config == other.config; + } + return false; + } + + @Override + public int hashCode() { + int result = width; + result = 31 * result + height; + result = 31 * result + config.hashCode(); + result = 31 * result + weight; + return result; + } + + @Override + public String toString() { + return "PreFillSize{" + + "width=" + width + + ", height=" + height + + ", config=" + config + + ", weight=" + weight + + '}'; + } + + /** + * Builder for {@link PreFillType}. + */ + public static class Builder { + private final int width; + private final int height; + + private Bitmap.Config config; + private int weight = 1; + + /** + * Constructor for a builder that uses the given size as the width and height of the Bitmaps to prefill. + * @param size The width and height in pixels of the Bitmaps to prefill. + */ + public Builder(int size) { + this(size, size); + } + + /** + * Constructor for a builder that uses the given dimensions as the dimensions of the Bitmaps to prefill. + * @param width The width in pixels of the Bitmaps to prefill. + * @param height The height in pixels of the Bitmaps to prefill. + */ + public Builder(int width, int height) { + if (width <= 0) { + throw new IllegalArgumentException("Width must be > 0"); + } + if (height <= 0) { + throw new IllegalArgumentException("Height must be > 0"); + } + this.width = width; + this.height = height; + } + + /** + * Sets the {@link android.graphics.Bitmap.Config} for the Bitmaps to pre-fill. + * @param config The config to use, or null to use Glide's default. + * @return This builder. + */ + public Builder setConfig(Bitmap.Config config) { + this.config = config; + return this; + } + + /** + * Returns the current {@link android.graphics.Bitmap.Config}. + */ + Bitmap.Config getConfig() { + return config; + } + + /** + * Sets the weight to use to balance how many Bitmaps of this type are prefilled relative to the other requested + * types. + * @param weight An integer indicating how to balance pre-filling this size and configuration of + * {@link android.graphics.Bitmap} against any other sizes/configurations that may be being pre-filled. + * @return This builder. + */ + public Builder setWeight(int weight) { + if (weight <= 0) { + throw new IllegalArgumentException("Weight must be > 0"); + } + this.weight = weight; + return this; + } + + /** + * Returns a new {@link PreFillType}. + */ + PreFillType build() { + return new PreFillType(width, height, config, weight); + } + } +} diff --git a/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java b/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java index 146b9b3d..87d95172 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/FileLoader.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.model; import android.net.Uri; + import com.bumptech.glide.load.data.DataFetcher; import java.io.File; diff --git a/library/src/main/java/com/bumptech/glide/load/model/GenericLoaderFactory.java b/library/src/main/java/com/bumptech/glide/load/model/GenericLoaderFactory.java index d8ebf616..9900322f 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/GenericLoaderFactory.java +++ b/library/src/main/java/com/bumptech/glide/load/model/GenericLoaderFactory.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.model; import android.content.Context; + import com.bumptech.glide.load.data.DataFetcher; import java.util.HashMap; @@ -30,6 +31,12 @@ public class GenericLoaderFactory { } }; + private final Context context; + + public GenericLoaderFactory(Context context) { + this.context = context.getApplicationContext(); + } + /** * Removes and returns the registered {@link ModelLoaderFactory} for the given model and resource classes. Returns * null if no such factory is registered. Clears all cached model loaders. @@ -92,13 +99,30 @@ public class GenericLoaderFactory { * {@link ModelLoader} or building a new a new {@link ModelLoader} using registered {@link ModelLoaderFactory}s. * Returns null if no {@link ModelLoaderFactory} is registered for the given classes. * + * @deprecated Use {@link #buildModelLoader(Class, Class)} instead. Scheduled to be removed in Glide 4.0. * @param modelClass The model class. * @param resourceClass The resource class. + * @param context Unused * @param <T> The type of the model. * @param <Y> The type of the resource. */ + @Deprecated public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass, - Context context) { + Context context) { + return buildModelLoader(modelClass, resourceClass); + } + + /** + * Returns a {@link ModelLoader} for the given model and resource classes by either returning a cached + * {@link ModelLoader} or building a new a new {@link ModelLoader} using registered {@link ModelLoaderFactory}s. + * Returns null if no {@link ModelLoaderFactory} is registered for the given classes. + * + * @param modelClass The model class. + * @param resourceClass The resource class. + * @param <T> The type of the model. + * @param <Y> The type of the resource. + */ + public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) { ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass); if (result != null) { // We've already tried to create a model loader and can't with the currently registered set of factories, @@ -152,7 +176,6 @@ public class GenericLoaderFactory { result = resourceToFactories.get(resourceClass); } - if (result == null) { for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) { // This accounts for model subclasses, our map only works for exact matches. We should however still diff --git a/library/src/main/java/com/bumptech/glide/load/model/ImageVideoModelLoader.java b/library/src/main/java/com/bumptech/glide/load/model/ImageVideoModelLoader.java index 0e7c3763..3d057bac 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/ImageVideoModelLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/ImageVideoModelLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model; import android.os.ParcelFileDescriptor; import android.util.Log; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.data.DataFetcher; diff --git a/library/src/main/java/com/bumptech/glide/load/model/ModelCache.java b/library/src/main/java/com/bumptech/glide/load/model/ModelCache.java index 5a46cde6..55c0de0c 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/ModelCache.java +++ b/library/src/main/java/com/bumptech/glide/load/model/ModelCache.java @@ -35,8 +35,8 @@ public class ModelCache<A, B> { * Get a value. * * @param model The model. - * @param width The width of the view the image is being loaded into. - * @param height The height of the view the image is being loaded into. + * @param width The width in pixels of the view the image is being loaded into. + * @param height The height in pixels of the view the image is being loaded into. * * @return The cached result, or null. */ @@ -51,8 +51,8 @@ public class ModelCache<A, B> { * Add a value. * * @param model The model. - * @param width The width of the view the image is being loaded into. - * @param height The height of the view the image is being loaded into. + * @param width The width in pixels of the view the image is being loaded into. + * @param height The height in pixels of the view the image is being loaded into. * @param value The value to store. */ public void put(A model, int width, int height, B value) { @@ -60,14 +60,15 @@ public class ModelCache<A, B> { cache.put(key, value); } - private static final class ModelKey<A> { + // Visible for testing. + static final class ModelKey<A> { private static final Queue<ModelKey<?>> KEY_QUEUE = Util.createQueue(0); private int height; private int width; private A model; - public static <A> ModelKey<A> get(A model, int width, int height) { + static <A> ModelKey<A> get(A model, int width, int height) { @SuppressWarnings("unchecked") ModelKey<A> modelKey = (ModelKey<A>) KEY_QUEUE.poll(); if (modelKey == null) { @@ -92,26 +93,11 @@ public class ModelCache<A, B> { @Override public boolean equals(Object o) { - if (this == o) { - return true; + if (o instanceof ModelKey) { + ModelKey other = (ModelKey) o; + return width == other.width && height == other.height && model.equals(other.model); } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ModelKey<?> modelKey = (ModelKey<?>) o; - - if (height != modelKey.height) { - return false; - } - if (width != modelKey.width) { - return false; - } - if (!model.equals(modelKey.model)) { - return false; - } - - return true; + return false; } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/ModelLoader.java b/library/src/main/java/com/bumptech/glide/load/model/ModelLoader.java index f028209a..164f1d72 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/ModelLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/ModelLoader.java @@ -37,8 +37,8 @@ public interface ModelLoader<T, Y> { * </p> * * @param model The model representing the resource. - * @param width The width of the view or target the resource will be loaded into - * @param height The height of the view or target the resource will be loaded into + * @param width The width in pixels of the view or target the resource will be loaded into + * @param height The height in pixels of the view or target the resource will be loaded into * @return A {@link DataFetcher} that can obtain the data the resource can be decoded from if the resource is not * cached, or null if no valid {@link com.bumptech.glide.load.data.DataFetcher} could be constructed. */ diff --git a/library/src/main/java/com/bumptech/glide/load/model/ResourceLoader.java b/library/src/main/java/com/bumptech/glide/load/model/ResourceLoader.java index 06bb1e55..efc2bd6a 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/ResourceLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/ResourceLoader.java @@ -4,6 +4,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.net.Uri; + import com.bumptech.glide.load.data.DataFetcher; /** diff --git a/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java b/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java index c4f1a711..1022754d 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/model/StreamEncoder.java @@ -25,8 +25,8 @@ public class StreamEncoder implements Encoder<InputStream> { } return true; } catch (IOException e) { - if (Log.isLoggable(TAG, Log.WARN)) { - Log.w(TAG, "Failed to encode data onto the OutputStream", e); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Failed to encode data onto the OutputStream", e); } return false; } finally { diff --git a/library/src/main/java/com/bumptech/glide/load/model/StringLoader.java b/library/src/main/java/com/bumptech/glide/load/model/StringLoader.java index a8e793fc..efdf666c 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/StringLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/StringLoader.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.model; import android.net.Uri; + import com.bumptech.glide.load.data.DataFetcher; import java.io.File; diff --git a/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java b/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java index 6120db45..30db4a6c 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.model; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.load.data.DataFetcher; /** diff --git a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorFileLoader.java b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorFileLoader.java index 89590369..2431df3e 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorFileLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorFileLoader.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.model.file_descriptor; import android.content.Context; import android.net.Uri; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.FileLoader; import com.bumptech.glide.load.model.GenericLoaderFactory; @@ -24,8 +25,7 @@ public class FileDescriptorFileLoader extends FileLoader<ParcelFileDescriptor> public static class Factory implements ModelLoaderFactory<File, ParcelFileDescriptor> { @Override public ModelLoader<File, ParcelFileDescriptor> build(Context context, GenericLoaderFactory factories) { - return new FileDescriptorFileLoader(factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class, - context)); + return new FileDescriptorFileLoader(factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorResourceLoader.java b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorResourceLoader.java index b69db440..0f107bd1 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorResourceLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorResourceLoader.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.model.file_descriptor; import android.content.Context; import android.net.Uri; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.GenericLoaderFactory; import com.bumptech.glide.load.model.ModelLoader; @@ -23,7 +24,7 @@ public class FileDescriptorResourceLoader extends ResourceLoader<ParcelFileDescr @Override public ModelLoader<Integer, ParcelFileDescriptor> build(Context context, GenericLoaderFactory factories) { return new FileDescriptorResourceLoader(context, factories.buildModelLoader(Uri.class, - ParcelFileDescriptor.class, context)); + ParcelFileDescriptor.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorStringLoader.java b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorStringLoader.java index 23eead66..c6f335fa 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorStringLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorStringLoader.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.model.file_descriptor; import android.content.Context; import android.net.Uri; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.GenericLoaderFactory; import com.bumptech.glide.load.model.ModelLoader; @@ -22,8 +23,7 @@ public class FileDescriptorStringLoader extends StringLoader<ParcelFileDescripto public static class Factory implements ModelLoaderFactory<String, ParcelFileDescriptor> { @Override public ModelLoader<String, ParcelFileDescriptor> build(Context context, GenericLoaderFactory factories) { - return new FileDescriptorStringLoader(factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class, - context)); + return new FileDescriptorStringLoader(factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorUriLoader.java b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorUriLoader.java index 84a90f56..d950461a 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorUriLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/file_descriptor/FileDescriptorUriLoader.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.model.file_descriptor; import android.content.Context; import android.net.Uri; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.data.FileDescriptorAssetPathFetcher; @@ -25,7 +26,7 @@ public class FileDescriptorUriLoader extends UriLoader<ParcelFileDescriptor> imp @Override public ModelLoader<Uri, ParcelFileDescriptor> build(Context context, GenericLoaderFactory factories) { return new FileDescriptorUriLoader(context, factories.buildModelLoader(GlideUrl.class, - ParcelFileDescriptor.class, context)); + ParcelFileDescriptor.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/BaseGlideUrlLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/BaseGlideUrlLoader.java index a3af9053..a319c347 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/BaseGlideUrlLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/BaseGlideUrlLoader.java @@ -4,10 +4,10 @@ import android.content.Context; import android.text.TextUtils; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.model.ModelCache; +import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.ModelCache; import com.bumptech.glide.load.model.ModelLoader; -import com.bumptech.glide.load.data.DataFetcher; import java.io.InputStream; @@ -15,7 +15,7 @@ import java.io.InputStream; * A base class for loading images over http/https. Can be subclassed for use with any model that can be translated * in to {@link java.io.InputStream} data. * - * @param <T> The type of the model + * @param <T> The type of the model. */ public abstract class BaseGlideUrlLoader<T> implements StreamModelLoader<T> { private final ModelLoader<GlideUrl, InputStream> concreteLoader; @@ -64,10 +64,10 @@ public abstract class BaseGlideUrlLoader<T> implements StreamModelLoader<T> { /** * Get a valid url http:// or https:// for the given model and dimensions as a string. * - * @param model The model - * @param width The width of the view/target the image will be loaded into - * @param height The height of the view/target the image will be loaded into - * @return The String url + * @param model The model. + * @param width The width in pixels of the view/target the image will be loaded into. + * @param height The height in pixels of the view/target the image will be loaded into. + * @return The String url. */ protected abstract String getUrl(T model, int width, int height); } diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java index 694537bd..3ee3060d 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/HttpUrlGlideUrlLoader.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; + import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.data.HttpUrlFetcher; import com.bumptech.glide.load.model.GenericLoaderFactory; diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java index e069fd77..980997a6 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.data.MediaStoreThumbFetcher; import com.bumptech.glide.load.model.ModelLoader; diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamByteArrayLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamByteArrayLoader.java index a323d0c3..3f0277dc 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamByteArrayLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamByteArrayLoader.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; + import com.bumptech.glide.load.data.ByteArrayFetcher; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.model.GenericLoaderFactory; @@ -22,7 +23,7 @@ public class StreamByteArrayLoader implements StreamModelLoader<byte[]> { /** * @deprecated Use {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} - * and the empty constructor instead. + * and the empty constructor instead. Scheduled to be removed in Glide 4.0. */ @Deprecated public StreamByteArrayLoader(String id) { diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamFileLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamFileLoader.java index 3042a896..1aca470a 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamFileLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamFileLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.FileLoader; import com.bumptech.glide.load.model.GenericLoaderFactory; @@ -22,7 +23,7 @@ public class StreamFileLoader extends FileLoader<InputStream> implements StreamM public static class Factory implements ModelLoaderFactory<File, InputStream> { @Override public ModelLoader<File, InputStream> build(Context context, GenericLoaderFactory factories) { - return new StreamFileLoader(factories.buildModelLoader(Uri.class, InputStream.class, context)); + return new StreamFileLoader(factories.buildModelLoader(Uri.class, InputStream.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamResourceLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamResourceLoader.java index a385d3cc..a3825574 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamResourceLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamResourceLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.GenericLoaderFactory; import com.bumptech.glide.load.model.ModelLoader; @@ -22,7 +23,7 @@ public class StreamResourceLoader extends ResourceLoader<InputStream> implements @Override public ModelLoader<Integer, InputStream> build(Context context, GenericLoaderFactory factories) { - return new StreamResourceLoader(context, factories.buildModelLoader(Uri.class, InputStream.class, context)); + return new StreamResourceLoader(context, factories.buildModelLoader(Uri.class, InputStream.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamStringLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamStringLoader.java index 1f951ee4..80bbb7af 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamStringLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamStringLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.model.GenericLoaderFactory; import com.bumptech.glide.load.model.ModelLoader; @@ -22,7 +23,7 @@ public class StreamStringLoader extends StringLoader<InputStream> implements Str public static class Factory implements ModelLoaderFactory<String, InputStream> { @Override public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) { - return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class, context)); + return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUriLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUriLoader.java index 3b15b2f7..086f4c4c 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUriLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUriLoader.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; import android.net.Uri; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.data.DataFetcher; import com.bumptech.glide.load.data.StreamAssetPathFetcher; @@ -28,7 +29,7 @@ public class StreamUriLoader extends UriLoader<InputStream> implements StreamMod @Override public ModelLoader<Uri, InputStream> build(Context context, GenericLoaderFactory factories) { - return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class, context)); + return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUrlLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUrlLoader.java index c8d35252..ec6a207d 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUrlLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/StreamUrlLoader.java @@ -1,8 +1,9 @@ package com.bumptech.glide.load.model.stream; import android.content.Context; -import com.bumptech.glide.load.model.GlideUrl; + import com.bumptech.glide.load.model.GenericLoaderFactory; +import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.ModelLoaderFactory; import com.bumptech.glide.load.model.UrlLoader; @@ -23,7 +24,7 @@ public class StreamUrlLoader extends UrlLoader<InputStream> { public static class Factory implements ModelLoaderFactory<URL, InputStream> { @Override public ModelLoader<URL, InputStream> build(Context context, GenericLoaderFactory factories) { - return new StreamUrlLoader(factories.buildModelLoader(GlideUrl.class, InputStream.class, context)); + return new StreamUrlLoader(factories.buildModelLoader(GlideUrl.class, InputStream.class)); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/resource/SimpleResource.java b/library/src/main/java/com/bumptech/glide/load/resource/SimpleResource.java index 4dca7fb1..33ccbb8a 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/SimpleResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/SimpleResource.java @@ -13,6 +13,9 @@ public class SimpleResource<T> implements Resource<T> { protected final T data; public SimpleResource(T data) { + if (data == null) { + throw new NullPointerException("Data must not be null"); + } this.data = data; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDecoder.java index 7ca6f496..36c4df17 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDecoder.java @@ -1,8 +1,9 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; + import com.bumptech.glide.load.DecodeFormat; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; /** * A bitmap decoder for a given resource type. diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDrawableResource.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDrawableResource.java index 616204d5..9d062e17 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDrawableResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapDrawableResource.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.drawable.BitmapDrawable; + import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.drawable.DrawableResource; import com.bumptech.glide.util.Util; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java index 5bd2f935..ab6d8df8 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoder.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; import android.util.Log; + import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.util.LogTime; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapResource.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapResource.java index 0ce032ea..10785c6b 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapResource.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.util.Util; @@ -12,7 +13,28 @@ public class BitmapResource implements Resource<Bitmap> { private final Bitmap bitmap; private final BitmapPool bitmapPool; + /** + * Returns a new {@link BitmapResource} wrapping the given {@link Bitmap} if the Bitmap is non-null or null if the + * given Bitmap is null. + * + * @param bitmap A Bitmap. + * @param bitmapPool A non-null {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool}. + */ + public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) { + if (bitmap == null) { + return null; + } else { + return new BitmapResource(bitmap, bitmapPool); + } + } + public BitmapResource(Bitmap bitmap, BitmapPool bitmapPool) { + if (bitmap == null) { + throw new NullPointerException("Bitmap must not be null"); + } + if (bitmapPool == null) { + throw new NullPointerException("BitmapPool must not be null"); + } this.bitmap = bitmap; this.bitmapPool = bitmapPool; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapTransformation.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapTransformation.java index 3195504b..c3624b1c 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapTransformation.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/BitmapTransformation.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.bitmap; import android.content.Context; import android.graphics.Bitmap; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.Resource; @@ -52,7 +53,7 @@ public abstract class BitmapTransformation implements Transformation<Bitmap> { if (toTransform.equals(transformed)) { result = resource; } else { - result = new BitmapResource(transformed, bitmapPool); + result = BitmapResource.obtain(transformed, bitmapPool); } return result; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java index e6143197..904a7c45 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/Downsampler.java @@ -105,6 +105,7 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> { final byte[] bytesForOptions = byteArrayPool.getBytes(); final byte[] bytesForStream = byteArrayPool.getBytes(); final BitmapFactory.Options options = getDefaultOptions(); + // TODO(#126): when the framework handles exceptions better, consider removing. final ExceptionCatchingInputStream stream = ExceptionCatchingInputStream.obtain(new RecyclableBufferedInputStream(is, bytesForStream)); @@ -134,19 +135,13 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> { final int inHeight = inDimens[1]; final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation); - final int sampleSize; - if (degreesToRotate == 90 || degreesToRotate == 270) { - // If we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is - // decreased to near our target's height and the image height is decreased to near our target width. - sampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight); - } else { - sampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight); - } + final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight); final Bitmap downsampled = - downsampleWithSize(stream, options, pool, inWidth, inHeight, sampleSize, decodeFormat); + downsampleWithSize(stream, options, pool, inWidth, inHeight, sampleSize, + decodeFormat); - // BitmapDecoder swallows exceptions during decodes and in some cases when inBitmap is non null, may catch + // BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch // and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps, // we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here. final Exception streamException = stream.getException(); @@ -172,15 +167,37 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> { } } - protected Bitmap downsampleWithSize(InputStream is, BitmapFactory.Options options, - BitmapPool pool, int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) { + private int getRoundedSampleSize(int degreesToRotate, int inWidth, int inHeight, int outWidth, int outHeight) { + final int exactSampleSize; + if (degreesToRotate == 90 || degreesToRotate == 270) { + // If we're rotating the image +-90 degrees, we need to downsample accordingly so the image width is + // decreased to near our target's height and the image height is decreased to near our target width. + exactSampleSize = getSampleSize(inHeight, inWidth, outWidth, outHeight); + } else { + exactSampleSize = getSampleSize(inWidth, inHeight, outWidth, outHeight); + } + + // BitmapFactory only accepts powers of 2, so it will round down to the nearest power of two that is less than + // or equal to the sample size we provide. Because we need to estimate the final image width and height to + // re-use Bitmaps, we mirror BitmapFactory's calculation here. For bug, see issue #224. For algorithm see + // http://stackoverflow.com/a/17379704/800716. + final int powerOfTwoSampleSize = exactSampleSize == 0 ? 0 : Integer.highestOneBit(exactSampleSize - 1); + + // Although functionally equivalent to 0 for BitmapFactory, 1 is a safer default for our code than 0. + return Math.max(1, powerOfTwoSampleSize); + } + + private Bitmap downsampleWithSize(ExceptionCatchingInputStream is, BitmapFactory.Options options, BitmapPool pool, + int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) { // Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding. Bitmap.Config config = getConfig(is, decodeFormat); options.inSampleSize = sampleSize; options.inPreferredConfig = config; if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) { + int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize); + int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize); // BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe. - setInBitmap(options, pool.getDirty(inWidth, inHeight, config)); + setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config)); } return decodeStream(is, options); } @@ -265,15 +282,14 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> { * android.graphics.BitmapFactory.Options)}. * @return an array containing the dimensions of the image in the form {width, height}. */ - public int[] getDimensions(InputStream is, BitmapFactory.Options options) { + public int[] getDimensions(ExceptionCatchingInputStream is, BitmapFactory.Options options) { options.inJustDecodeBounds = true; decodeStream(is, options); options.inJustDecodeBounds = false; return new int[] { options.outWidth, options.outHeight }; } - - private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options) { + private static Bitmap decodeStream(ExceptionCatchingInputStream is, BitmapFactory.Options options) { if (options.inJustDecodeBounds) { // This is large, but jpeg headers are not size bounded so we need something large enough to minimize // the possibility of not being able to fit enough of the header in the buffer to get the image size so @@ -281,6 +297,11 @@ public abstract class Downsampler implements BitmapDecoder<InputStream> { // original size each time we use up the buffer space without passing the mark so this is a maximum // bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb. is.mark(MARK_POSITION); + } else { + // Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid + // unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our + // current buffer size here. See issue #225. + is.fixMarkLimit(); } final Bitmap result = BitmapFactory.decodeStream(is, null, options); diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDataLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDataLoadProvider.java index cbab4275..af27bc60 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDataLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDataLoadProvider.java @@ -4,13 +4,13 @@ import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; import com.bumptech.glide.load.DecodeFormat; -import com.bumptech.glide.provider.DataLoadProvider; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.NullEncoder; import com.bumptech.glide.load.resource.file.FileToStreamDecoder; +import com.bumptech.glide.provider.DataLoadProvider; import java.io.File; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDecoder.java index 3eb38934..f6f2bfbe 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/FileDescriptorBitmapDecoder.java @@ -3,11 +3,12 @@ package com.bumptech.glide.load.resource.bitmap; import android.content.Context; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.ResourceDecoder; +import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; -import com.bumptech.glide.load.DecodeFormat; import java.io.IOException; @@ -42,11 +43,7 @@ public class FileDescriptorBitmapDecoder implements ResourceDecoder<ParcelFileDe @Override public Resource<Bitmap> decode(ParcelFileDescriptor source, int width, int height) throws IOException { Bitmap bitmap = bitmapDecoder.decode(source, bitmapPool, width, height, decodeFormat); - if (bitmap == null) { - return null; - } else { - return new BitmapResource(bitmap, bitmapPool); - } + return BitmapResource.obtain(bitmap, bitmapPool); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GlideBitmapDrawable.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GlideBitmapDrawable.java index e2589131..27e05185 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GlideBitmapDrawable.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/GlideBitmapDrawable.java @@ -29,6 +29,10 @@ public class GlideBitmapDrawable extends GlideDrawable { } GlideBitmapDrawable(Resources res, BitmapState state) { + if (state == null) { + throw new NullPointerException("BitmapState must not be null"); + } + this.state = state; final int targetDensity; if (res != null) { diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageHeaderParser.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageHeaderParser.java index 593bbb42..cd787817 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageHeaderParser.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageHeaderParser.java @@ -1,5 +1,11 @@ package com.bumptech.glide.load.resource.bitmap; +import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.GIF; +import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.JPEG; +import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.PNG; +import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.PNG_A; +import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.UNKNOWN; + import android.util.Log; import java.io.IOException; @@ -8,12 +14,6 @@ import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.GIF; -import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.JPEG; -import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.PNG; -import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.PNG_A; -import static com.bumptech.glide.load.resource.bitmap.ImageHeaderParser.ImageType.UNKNOWN; - /** * A class for parsing the exif orientation and other data from an image header. */ diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoBitmapDecoder.java index 5edf2ceb..58cb6036 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoBitmapDecoder.java @@ -3,8 +3,9 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; import android.util.Log; -import com.bumptech.glide.load.engine.Resource; + import com.bumptech.glide.load.ResourceDecoder; +import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.model.ImageVideoWrapper; import java.io.IOException; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoDataLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoDataLoadProvider.java index b02e46c1..002a48f9 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoDataLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/ImageVideoDataLoadProvider.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; + import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java index b0811526..8699022b 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/RecyclableBufferedInputStream.java @@ -17,6 +17,8 @@ package com.bumptech.glide.load.resource.bitmap; * limitations under the License. */ +import android.util.Log; + import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; @@ -36,32 +38,33 @@ import java.io.InputStream; * </pre> */ public class RecyclableBufferedInputStream extends FilterInputStream { + private static final String TAG = "BufferedIs"; /** * The buffer containing the current bytes read from the target InputStream. */ - protected volatile byte[] buf; + private volatile byte[] buf; /** * The total number of bytes inside the byte array {@code buf}. */ - protected int count; + private int count; /** * The current limit, which when passed, invalidates the current mark. */ - protected int marklimit; + private int marklimit; /** * The currently marked position. -1 indicates no mark has been set or the * mark has been invalidated. */ - protected int markpos = -1; + private int markpos = -1; /** * The current position within the byte array {@code buf}. */ - protected int pos; + private int pos; public RecyclableBufferedInputStream(InputStream in, byte[] buffer) { super(in); @@ -95,6 +98,17 @@ public class RecyclableBufferedInputStream extends FilterInputStream { } /** + * Reduces the mark limit to match the current buffer length to prevent the buffer from + * continuing to increase in size. + * + * <p>Subsequent calls to {@link #mark(int)} will be obeyed and may cause the buffer size + * to increase. + */ + public synchronized void fixMarkLimit() { + marklimit = buf.length; + } + + /** * Closes this stream. The source stream is closed and any resources * associated with it are released. * @@ -134,6 +148,9 @@ public class RecyclableBufferedInputStream extends FilterInputStream { if (newLength > marklimit) { newLength = marklimit; } + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "allocate buffer of length: " + newLength); + } byte[] newbuf = new byte[newLength]; System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length); // Reassign buf, which will invalidate any local references diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDataLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDataLoadProvider.java index ae89ec9f..e05e4845 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDataLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDataLoadProvider.java @@ -3,13 +3,13 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; import com.bumptech.glide.load.DecodeFormat; -import com.bumptech.glide.provider.DataLoadProvider; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.model.StreamEncoder; import com.bumptech.glide.load.resource.file.FileToStreamDecoder; +import com.bumptech.glide.provider.DataLoadProvider; import java.io.File; import java.io.InputStream; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java index b9d8a8df..407b8cb6 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/StreamBitmapDecoder.java @@ -2,10 +2,11 @@ package com.bumptech.glide.load.resource.bitmap; import android.content.Context; import android.graphics.Bitmap; + import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.ResourceDecoder; +import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import java.io.InputStream; @@ -47,11 +48,7 @@ public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> @Override public Resource<Bitmap> decode(InputStream source, int width, int height) { Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat); - if (bitmap == null) { - return null; - } else { - return new BitmapResource(bitmap, bitmapPool); - } + return BitmapResource.obtain(bitmap, bitmapPool); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java index 2f3a3ef1..2a7d5f9a 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java @@ -9,6 +9,7 @@ import android.graphics.RectF; import android.media.ExifInterface; import android.os.Build; import android.util.Log; + import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; /** @@ -30,8 +31,8 @@ public final class TransformationUtils { * @param recycled A mutable Bitmap with dimensions width and height that we can load the cropped portion of toCrop * into. * @param toCrop The Bitmap to resize. - * @param width The width of the final Bitmap. - * @param height The height of the final Bitmap. + * @param width The width in pixels of the final Bitmap. + * @param height The height in pixels of the final Bitmap. * @return The resized Bitmap (will be recycled if recycled is not null). */ public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) { @@ -77,8 +78,8 @@ public final class TransformationUtils { * * @param toFit The Bitmap to shrink. * @param pool The BitmapPool to try to reuse a bitmap from. - * @param width The width the final image will fit within. - * @param height The height the final image will fit within. + * @param width The width in pixels the final image will fit within. + * @param height The height in pixels the final image will fit within. * @return A new Bitmap shrunk to fit within the given dimensions, or toFit if toFit's width or height matches the * given dimensions and toFit fits within the given dimensions */ @@ -149,22 +150,18 @@ public final class TransformationUtils { * Returns a matrix with rotation set based on Exif orientation tag. * If the orientation is undefined or 0 null is returned. * + * @deprecated No longer used by Glide, scheduled to be removed in Glide 4.0 * @param pathToOriginal Path to original image file that may have exif data. * @return A rotation in degrees based on exif orientation */ @TargetApi(Build.VERSION_CODES.ECLAIR) + @Deprecated public static int getOrientation(String pathToOriginal) { int degreesToRotate = 0; try { ExifInterface exif = new ExifInterface(pathToOriginal); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); - if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { - degreesToRotate = 90; - } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { - degreesToRotate = 180; - } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { - degreesToRotate = 270; - } + return getExifOrientationDegrees(orientation); } catch (Exception e) { if (Log.isLoggable(TAG, Log.ERROR)) { Log.e(TAG, "Unable to get orientation for image with path=" + pathToOriginal, e); @@ -177,10 +174,12 @@ public final class TransformationUtils { * This is an expensive operation that copies the image in place with the pixels rotated. * If possible rather use getOrientationMatrix, and set that as the imageMatrix on an ImageView. * + * @deprecated No longer used by Glide, scheduled to be removed in Glide 4.0 * @param pathToOriginal Path to original image file that may have exif data. * @param imageToOrient Image Bitmap to orient. * @return The oriented bitmap. May be the imageToOrient without modification, or a new Bitmap. */ + @Deprecated public static Bitmap orientImage(String pathToOriginal, Bitmap imageToOrient) { int degreesToRotate = getOrientation(pathToOriginal); return rotateImage(imageToOrient, degreesToRotate); @@ -255,7 +254,36 @@ public final class TransformationUtils { * @return The rotated and/or flipped image or toOrient if no rotation or flip was necessary. */ public static Bitmap rotateImageExif(Bitmap toOrient, BitmapPool pool, int exifOrientation) { + if (exifOrientation == ExifInterface.ORIENTATION_NORMAL + || exifOrientation == ExifInterface.ORIENTATION_UNDEFINED) { + return toOrient; + } final Matrix matrix = new Matrix(); + initializeMatrixForRotation(exifOrientation, matrix); + + // From Bitmap.createBitmap. + final RectF newRect = new RectF(0, 0, toOrient.getWidth(), toOrient.getHeight()); + matrix.mapRect(newRect); + + final int newWidth = Math.round(newRect.width()); + final int newHeight = Math.round(newRect.height()); + + Bitmap result = pool.get(newWidth, newHeight, toOrient.getConfig()); + if (result == null) { + result = Bitmap.createBitmap(newWidth, newHeight, toOrient.getConfig()); + } + + matrix.postTranslate(-newRect.left, -newRect.top); + + final Canvas canvas = new Canvas(result); + final Paint paint = new Paint(PAINT_FLAGS); + canvas.drawBitmap(toOrient, matrix, paint); + + return result; + } + + // Visible for testing. + static void initializeMatrixForRotation(int exifOrientation, Matrix matrix) { switch (exifOrientation) { case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: matrix.setScale(-1, 1); @@ -281,29 +309,8 @@ public final class TransformationUtils { case ExifInterface.ORIENTATION_ROTATE_270: matrix.setRotate(-90); break; - // case ExifInterface.ORIENTATION_NORMAL default: - return toOrient; - } - - // From Bitmap.createBitmap. - final RectF newRect = new RectF(0, 0, toOrient.getWidth(), toOrient.getHeight()); - matrix.mapRect(newRect); - - final int newWidth = Math.round(newRect.width()); - final int newHeight = Math.round(newRect.height()); - - Bitmap result = pool.get(newWidth, newHeight, toOrient.getConfig()); - if (result == null) { - result = Bitmap.createBitmap(newWidth, newHeight, toOrient.getConfig()); + // Do nothing. } - - matrix.postTranslate(-newRect.left, -newRect.top); - - final Canvas canvas = new Canvas(result); - final Paint paint = new Paint(PAINT_FLAGS); - canvas.drawBitmap(toOrient, matrix, paint); - - return result; } } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/VideoBitmapDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/VideoBitmapDecoder.java index 15990462..537b185c 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/VideoBitmapDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/VideoBitmapDecoder.java @@ -3,8 +3,9 @@ package com.bumptech.glide.load.resource.bitmap; import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; import android.os.ParcelFileDescriptor; -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; + import com.bumptech.glide.load.DecodeFormat; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import java.io.IOException; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bytes/BytesResource.java b/library/src/main/java/com/bumptech/glide/load/resource/bytes/BytesResource.java index eb29217d..a6368d26 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bytes/BytesResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bytes/BytesResource.java @@ -9,6 +9,9 @@ public class BytesResource implements Resource<byte[]> { private final byte[] bytes; public BytesResource(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException("Bytes must not be null"); + } this.bytes = bytes; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/drawable/DrawableResource.java b/library/src/main/java/com/bumptech/glide/load/resource/drawable/DrawableResource.java index b3efc621..643f7b40 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/drawable/DrawableResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/drawable/DrawableResource.java @@ -18,6 +18,9 @@ public abstract class DrawableResource<T extends Drawable> implements Resource<T private boolean returnedOriginalDrawable; public DrawableResource(T drawable) { + if (drawable == null) { + throw new NullPointerException("Drawable must not be null!"); + } this.drawable = drawable; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/file/StreamFileDataLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/file/StreamFileDataLoadProvider.java index c31e3a4a..13df0a20 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/file/StreamFileDataLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/file/StreamFileDataLoadProvider.java @@ -1,12 +1,12 @@ package com.bumptech.glide.load.resource.file; -import com.bumptech.glide.load.engine.Resource; -import com.bumptech.glide.provider.DataLoadProvider; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; +import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.model.StreamEncoder; import com.bumptech.glide.load.resource.NullResourceEncoder; +import com.bumptech.glide.provider.DataLoadProvider; import java.io.File; import java.io.InputStream; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifBitmapProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifBitmapProvider.java index 5bfdd626..de52039f 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifBitmapProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifBitmapProvider.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.gif; import android.graphics.Bitmap; + import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java index fd5ea782..47e06fb5 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawable.java @@ -11,8 +11,8 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; - import android.view.Gravity; + import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.gifdecoder.GifHeader; import com.bumptech.glide.load.Transformation; @@ -75,11 +75,15 @@ public class GifDrawable extends GlideDrawable implements GifFrameManager.FrameC } GifDrawable(GifState state) { + if (state == null) { + throw new NullPointerException("GifState must not be null"); + } + this.state = state; this.decoder = new GifDecoder(state.bitmapProvider); decoder.setData(state.gifHeader, state.data); - frameManager = new GifFrameManager(state.context, decoder, state.frameTransformation, state.targetWidth, - state.targetHeight); + frameManager = new GifFrameManager(state.context, decoder, state.targetWidth, state.targetHeight); + frameManager.setFrameTransformation(state.frameTransformation); } // Visible for testing. @@ -96,8 +100,15 @@ public class GifDrawable extends GlideDrawable implements GifFrameManager.FrameC } public void setFrameTransformation(Transformation<Bitmap> frameTransformation, Bitmap firstFrame) { + if (firstFrame == null) { + throw new NullPointerException("The first frame of the GIF must not be null"); + } + if (frameTransformation == null) { + throw new NullPointerException("The frame transformation must not be null"); + } state.frameTransformation = frameTransformation; state.firstFrame = firstFrame; + frameManager.setFrameTransformation(frameTransformation); } public GifDecoder getDecoder() { @@ -313,6 +324,9 @@ public class GifDrawable extends GlideDrawable implements GifFrameManager.FrameC public GifState(GifHeader header, byte[] data, Context context, Transformation<Bitmap> frameTransformation, int targetWidth, int targetHeight, GifDecoder.BitmapProvider provider, BitmapPool bitmapPool, Bitmap firstFrame) { + if (firstFrame == null) { + throw new NullPointerException("The first frame of the GIF must not be null"); + } gifHeader = header; this.data = data; this.bitmapPool = bitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableLoadProvider.java index 3e0fe3c1..971847d3 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableLoadProvider.java @@ -2,14 +2,13 @@ package com.bumptech.glide.load.resource.gif; import android.content.Context; -import com.bumptech.glide.load.DecodeFormat; -import com.bumptech.glide.provider.DataLoadProvider; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.model.StreamEncoder; import com.bumptech.glide.load.resource.file.FileToStreamDecoder; +import com.bumptech.glide.provider.DataLoadProvider; import java.io.File; import java.io.InputStream; @@ -24,8 +23,8 @@ public class GifDrawableLoadProvider implements DataLoadProvider<InputStream, Gi private final StreamEncoder sourceEncoder; private final FileToStreamDecoder<GifDrawable> cacheDecoder; - public GifDrawableLoadProvider(Context context, BitmapPool bitmapPool, DecodeFormat decodeFormat) { - decoder = new GifResourceDecoder(context, bitmapPool, decodeFormat); + public GifDrawableLoadProvider(Context context, BitmapPool bitmapPool) { + decoder = new GifResourceDecoder(context, bitmapPool); cacheDecoder = new FileToStreamDecoder<GifDrawable>(decoder); encoder = new GifResourceEncoder(bitmapPool); sourceEncoder = new StreamEncoder(); diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableTransformation.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableTransformation.java index 9261e0fc..2e17d290 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableTransformation.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifDrawableTransformation.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gif; import android.graphics.Bitmap; + import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameManager.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameManager.java index 661e84d9..ad2cdbc7 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameManager.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameManager.java @@ -6,6 +6,8 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; + +import com.bumptech.glide.GenericRequestBuilder; import com.bumptech.glide.Glide; import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.load.Encoder; @@ -14,6 +16,7 @@ import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.NullEncoder; +import com.bumptech.glide.load.resource.UnitTransformation; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; @@ -22,73 +25,75 @@ import java.security.MessageDigest; import java.util.UUID; class GifFrameManager { - /** 60fps is {@value #MIN_FRAME_DELAY}ms per frame. */ - private static final long MIN_FRAME_DELAY = 1000 / 60; - private final GifFrameModelLoader frameLoader; - private final GifFrameResourceDecoder frameResourceDecoder; private final GifDecoder decoder; private final Handler mainHandler; - private final Context context; - private final Encoder<GifDecoder> sourceEncoder; - private final Transformation<Bitmap>[] transformation; private final int targetWidth; private final int targetHeight; private final FrameSignature signature; + private final GenericRequestBuilder<GifDecoder, GifDecoder, Bitmap, Bitmap> requestBuilder; + private boolean isLoadInProgress; private DelayTarget current; private DelayTarget next; + private Transformation<Bitmap> transformation = UnitTransformation.get(); public interface FrameCallback { void onFrameRead(int index); } - public GifFrameManager(Context context, GifDecoder decoder, Transformation<Bitmap> transformation, int targetWidth, - int targetHeight) { - this(context, Glide.get(context).getBitmapPool(), decoder, new Handler(Looper.getMainLooper()), transformation, - targetWidth, targetHeight); + public GifFrameManager(Context context, GifDecoder decoder, int targetWidth, int targetHeight) { + this(context, Glide.get(context).getBitmapPool(), decoder, new Handler(Looper.getMainLooper()), targetWidth, + targetHeight); } - @SuppressWarnings("unchecked") public GifFrameManager(Context context, BitmapPool bitmapPool, GifDecoder decoder, Handler mainHandler, - Transformation<Bitmap> transformation, int targetWidth, int targetHeight) { - if (transformation == null) { - throw new NullPointerException("Transformation must not be null"); - } + int targetWidth, int targetHeight) { - this.context = context; - this.frameResourceDecoder = new GifFrameResourceDecoder(bitmapPool); this.decoder = decoder; this.mainHandler = mainHandler; - this.transformation = new Transformation[] {transformation}; this.targetWidth = targetWidth; this.targetHeight = targetHeight; - this.frameLoader = new GifFrameModelLoader(); - this.sourceEncoder = NullEncoder.get(); this.signature = new FrameSignature(); + + GifFrameResourceDecoder frameResourceDecoder = new GifFrameResourceDecoder(bitmapPool); + GifFrameModelLoader frameLoader = new GifFrameModelLoader(); + Encoder<GifDecoder> sourceEncoder = NullEncoder.get(); + + requestBuilder = Glide.with(context) + .using(frameLoader, GifDecoder.class) + .from(GifDecoder.class) + .as(Bitmap.class) + .signature(signature) + .sourceEncoder(sourceEncoder) + .decoder(frameResourceDecoder) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE); } - Transformation<Bitmap> getTransformation() { - return transformation[0]; + public void setFrameTransformation(Transformation<Bitmap> transformation) { + if (transformation == null) { + throw new NullPointerException("Transformation must not be null"); + } + this.transformation = transformation; } + @SuppressWarnings("unchecked") public void getNextFrame(FrameCallback cb) { + if (isLoadInProgress) { + return; + } + isLoadInProgress = true; + decoder.advance(); - long targetTime = SystemClock.uptimeMillis() + Math.max(MIN_FRAME_DELAY, decoder.getNextDelay()); + long targetTime = SystemClock.uptimeMillis() + decoder.getNextDelay(); next = new DelayTarget(cb, targetTime); next.setFrameIndex(decoder.getCurrentFrameIndex()); // Use an incrementing signature to make sure we never hit an active resource that matches one of our frames. signature.increment(); - Glide.with(context) - .using(frameLoader, GifDecoder.class) + requestBuilder .load(decoder) - .as(Bitmap.class) - .signature(signature) - .sourceEncoder(sourceEncoder) - .decoder(frameResourceDecoder) .transform(transformation) - .skipMemoryCache(true) - .diskCacheStrategy(DiskCacheStrategy.NONE) .into(next); } @@ -97,14 +102,15 @@ class GifFrameManager { } public void clear() { + isLoadInProgress = false; if (current != null) { - mainHandler.removeCallbacks(current); Glide.clear(current); + mainHandler.removeCallbacks(current); current = null; } if (next != null) { - mainHandler.removeCallbacks(next); Glide.clear(next); + mainHandler.removeCallbacks(next); next = null; } @@ -135,9 +141,17 @@ class GifFrameManager { @Override public void run() { + isLoadInProgress = false; cb.onFrameRead(index); if (current != null) { - Glide.clear(current); + // TODO: figure out why this is necessary and fix it. See issue #219. + final DelayTarget recycleCurrent = current; + mainHandler.post(new Runnable() { + @Override + public void run() { + Glide.clear(recycleCurrent); + } + }); } current = this; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameResourceDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameResourceDecoder.java index dbc0e172..1815c99d 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameResourceDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifFrameResourceDecoder.java @@ -1,9 +1,10 @@ package com.bumptech.glide.load.resource.gif; import android.graphics.Bitmap; -import com.bumptech.glide.load.engine.Resource; + import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.load.ResourceDecoder; +import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.bitmap.BitmapResource; @@ -17,7 +18,7 @@ class GifFrameResourceDecoder implements ResourceDecoder<GifDecoder, Bitmap> { @Override public Resource<Bitmap> decode(GifDecoder source, int width, int height) { Bitmap bitmap = source.getNextFrame(); - return new BitmapResource(bitmap, bitmapPool); + return BitmapResource.obtain(bitmap, bitmapPool); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceDecoder.java index f4cbb1e2..55a257fd 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceDecoder.java @@ -3,11 +3,11 @@ package com.bumptech.glide.load.resource.gif; import android.content.Context; import android.graphics.Bitmap; import android.util.Log; + import com.bumptech.glide.Glide; import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.gifdecoder.GifHeader; import com.bumptech.glide.gifdecoder.GifHeaderParser; -import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; @@ -31,7 +31,6 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa private final Context context; private final GifHeaderParserPool parserPool; private final BitmapPool bitmapPool; - private final DecodeFormat decodeFormat; private final GifDecoderPool decoderPool; private final GifBitmapProvider provider; @@ -39,24 +38,15 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa this(context, Glide.get(context).getBitmapPool()); } - public GifResourceDecoder(Context context, DecodeFormat decodeFormat) { - this(context, Glide.get(context).getBitmapPool(), decodeFormat); - } - public GifResourceDecoder(Context context, BitmapPool bitmapPool) { - this(context, bitmapPool, DecodeFormat.DEFAULT); - } - - public GifResourceDecoder(Context context, BitmapPool bitmapPool, DecodeFormat decodeFormat) { - this(context, bitmapPool, decodeFormat, PARSER_POOL, DECODER_POOL); + this(context, bitmapPool, PARSER_POOL, DECODER_POOL); } // Visible for testing. - GifResourceDecoder(Context context, BitmapPool bitmapPool, DecodeFormat decodeFormat, - GifHeaderParserPool parserPool, GifDecoderPool decoderPool) { + GifResourceDecoder(Context context, BitmapPool bitmapPool, GifHeaderParserPool parserPool, + GifDecoderPool decoderPool) { this.context = context; this.bitmapPool = bitmapPool; - this.decodeFormat = decodeFormat; this.decoderPool = decoderPool; this.provider = new GifBitmapProvider(bitmapPool); this.parserPool = parserPool; @@ -67,8 +57,6 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa byte[] data = inputStreamToBytes(source); final GifHeaderParser parser = parserPool.obtain(data); final GifDecoder decoder = decoderPool.obtain(provider); - decoder.setPreferredConfig(decodeFormat == DecodeFormat.PREFER_RGB_565 - ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888); try { return decode(data, width, height, parser, decoder); } finally { @@ -85,6 +73,10 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa } Bitmap firstFrame = decodeFirstFrame(decoder, header, data); + if (firstFrame == null) { + return null; + } + Transformation<Bitmap> unitTransformation = UnitTransformation.get(); GifDrawable gifDrawable = new GifDrawable(context, provider, bitmapPool, unitTransformation, width, height, @@ -152,6 +144,7 @@ public class GifResourceDecoder implements ResourceDecoder<InputStream, GifDrawa } public synchronized void release(GifHeaderParser parser) { + parser.clear(); pool.offer(parser); } } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceEncoder.java b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceEncoder.java index ab2e14c6..df3b51fb 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gif/GifResourceEncoder.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.gif; import android.graphics.Bitmap; import android.util.Log; + import com.bumptech.glide.gifdecoder.GifDecoder; import com.bumptech.glide.gifdecoder.GifHeader; import com.bumptech.glide.gifdecoder.GifHeaderParser; @@ -110,6 +111,7 @@ public class GifResourceEncoder implements ResourceEncoder<GifDrawable> { private Resource<Bitmap> getTransformedFrame(Bitmap currentFrame, Transformation<Bitmap> transformation, GifDrawable drawable) { + // TODO: what if current frame is null? Resource<Bitmap> bitmapResource = factory.buildFrameResource(currentFrame, bitmapPool); Resource<Bitmap> transformedResource = transformation.transform(bitmapResource, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapper.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapper.java index b5d73154..0b3b62ba 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapper.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapper.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.gif.GifDrawable; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResource.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResource.java index 7e10e008..0fcd2205 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResource.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResource.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.gif.GifDrawable; @@ -11,6 +12,9 @@ public class GifBitmapWrapperResource implements Resource<GifBitmapWrapper> { private final GifBitmapWrapper data; public GifBitmapWrapperResource(GifBitmapWrapper data) { + if (data == null) { + throw new NullPointerException("Data must not be null"); + } this.data = data; } diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceDecoder.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceDecoder.java index 1ec8d720..18b198a2 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceDecoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceDecoder.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceEncoder.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceEncoder.java index 175535f8..ee18ab71 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceEncoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperResourceEncoder.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.gif.GifDrawable; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperTransformation.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperTransformation.java index a985b318..791e81bd 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperTransformation.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/GifBitmapWrapperTransformation.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; + import com.bumptech.glide.load.Transformation; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/ImageVideoGifDrawableLoadProvider.java b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/ImageVideoGifDrawableLoadProvider.java index 56b2ebfa..e084fb52 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/ImageVideoGifDrawableLoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/gifbitmap/ImageVideoGifDrawableLoadProvider.java @@ -2,14 +2,14 @@ package com.bumptech.glide.load.resource.gifbitmap; import android.graphics.Bitmap; -import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; -import com.bumptech.glide.load.resource.gif.GifDrawable; -import com.bumptech.glide.provider.DataLoadProvider; import com.bumptech.glide.load.Encoder; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.model.ImageVideoWrapper; import com.bumptech.glide.load.resource.file.FileToStreamDecoder; +import com.bumptech.glide.load.resource.gif.GifDrawable; +import com.bumptech.glide.provider.DataLoadProvider; import java.io.File; import java.io.InputStream; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapBytesTranscoder.java b/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapBytesTranscoder.java index ef899eaf..01d94407 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapBytesTranscoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapBytesTranscoder.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.transcode; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.bytes.BytesResource; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapToGlideDrawableTranscoder.java b/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapToGlideDrawableTranscoder.java index 11783990..29343916 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapToGlideDrawableTranscoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/transcode/BitmapToGlideDrawableTranscoder.java @@ -2,6 +2,7 @@ package com.bumptech.glide.load.resource.transcode; import android.content.Context; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.drawable.GlideDrawable; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/transcode/GifBitmapWrapperDrawableTranscoder.java b/library/src/main/java/com/bumptech/glide/load/resource/transcode/GifBitmapWrapperDrawableTranscoder.java index 39b3a6a3..d226d68d 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/transcode/GifBitmapWrapperDrawableTranscoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/transcode/GifBitmapWrapperDrawableTranscoder.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.resource.transcode; import android.graphics.Bitmap; + import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable; import com.bumptech.glide.load.resource.drawable.GlideDrawable; diff --git a/library/src/main/java/com/bumptech/glide/load/resource/transcode/GlideBitmapDrawableTranscoder.java b/library/src/main/java/com/bumptech/glide/load/resource/transcode/GlideBitmapDrawableTranscoder.java index 9c7425bc..bdc03df8 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/transcode/GlideBitmapDrawableTranscoder.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/transcode/GlideBitmapDrawableTranscoder.java @@ -3,6 +3,7 @@ package com.bumptech.glide.load.resource.transcode; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.Resource; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; diff --git a/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java b/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java index d4830796..b0b80fa5 100644 --- a/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java +++ b/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java @@ -13,6 +13,7 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.util.Log; + import com.bumptech.glide.RequestManager; import com.bumptech.glide.util.Util; diff --git a/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java b/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java index c6ad8bd7..b5e73b6d 100644 --- a/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java +++ b/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java @@ -2,6 +2,7 @@ package com.bumptech.glide.manager; import android.annotation.SuppressLint; import android.support.v4.app.Fragment; + import com.bumptech.glide.RequestManager; /** diff --git a/library/src/main/java/com/bumptech/glide/provider/LoadProvider.java b/library/src/main/java/com/bumptech/glide/provider/LoadProvider.java index 568d0ee5..694ab54b 100644 --- a/library/src/main/java/com/bumptech/glide/provider/LoadProvider.java +++ b/library/src/main/java/com/bumptech/glide/provider/LoadProvider.java @@ -1,7 +1,7 @@ package com.bumptech.glide.provider; -import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; /** * An extension of {@link com.bumptech.glide.provider.DataLoadProvider} that also allows a diff --git a/library/src/main/java/com/bumptech/glide/request/GenericRequest.java b/library/src/main/java/com/bumptech/glide/request/GenericRequest.java index 423437cd..7472a02d 100644 --- a/library/src/main/java/com/bumptech/glide/request/GenericRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/GenericRequest.java @@ -3,6 +3,7 @@ package com.bumptech.glide.request; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.Log; + import com.bumptech.glide.Priority; import com.bumptech.glide.load.Key; import com.bumptech.glide.load.Transformation; @@ -67,7 +68,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb private boolean isMemoryCacheable; private Priority priority; private Target<R> target; - private RequestListener<A, R> requestListener; + private RequestListener<? super A, R> requestListener; private float sizeMultiplier; private Engine engine; private GlideAnimationFactory<R> animationFactory; @@ -96,7 +97,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb int placeholderResourceId, Drawable errorDrawable, int errorResourceId, - RequestListener<A, R> requestListener, + RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, @@ -168,7 +169,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb int placeholderResourceId, Drawable errorDrawable, int errorResourceId, - RequestListener<A, R> requestListener, + RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, @@ -181,7 +182,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb this.loadProvider = loadProvider; this.model = model; this.signature = signature; - this.context = context; + this.context = context.getApplicationContext(); this.priority = priority; this.target = target; this.sizeMultiplier = sizeMultiplier; diff --git a/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeFactory.java b/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeFactory.java new file mode 100644 index 00000000..5bd3305f --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeFactory.java @@ -0,0 +1,72 @@ +package com.bumptech.glide.request.animation; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; + +/** + * A factory class that produces a new {@link com.bumptech.glide.request.animation.GlideAnimation} that varies depending + * on whether or not the drawable was loaded from the memory cache and whether or not the drawable is the first + * image to be set on the target. + * + * <p> + * Resources are usually loaded from the memory cache just before the user can see the view, + * for example when the user changes screens or scrolls back and forth in a list. In those cases the user + * typically does not expect to see an animation. As a result, when the resource is loaded from the memory + * cache this factory produces an {@link com.bumptech.glide.request.animation.NoAnimation}. + * </p> + * + * @param <T> The type of the {@link android.graphics.drawable.Drawable} that will be animated. + */ +public class DrawableCrossFadeFactory<T extends Drawable> implements GlideAnimationFactory<T> { + private static final int DEFAULT_DURATION_MS = 300; + private final ViewAnimationFactory<T> animationFactory; + private final int duration; + private DrawableCrossFadeViewAnimation<T> animation; + + public DrawableCrossFadeFactory() { + this(DEFAULT_DURATION_MS); + } + + public DrawableCrossFadeFactory(int duration) { + this(new ViewAnimationFactory<T>(new DefaultAnimationFactory()), duration); + } + + public DrawableCrossFadeFactory(Context context, int defaultAnimationId, int duration) { + this(new ViewAnimationFactory<T>(context, defaultAnimationId), duration); + } + + public DrawableCrossFadeFactory(Animation defaultAnimation, int duration) { + this(new ViewAnimationFactory<T>(defaultAnimation), duration); + } + + DrawableCrossFadeFactory(ViewAnimationFactory<T> animationFactory, int duration) { + this.animationFactory = animationFactory; + this.duration = duration; + } + + @Override + public GlideAnimation<T> build(boolean isFromMemoryCache, boolean isFirstResource) { + if (isFromMemoryCache) { + return NoAnimation.get(); + } + + if (animation == null) { + GlideAnimation<T> defaultAnimation = animationFactory.build(false, isFirstResource); + animation = new DrawableCrossFadeViewAnimation<T>(defaultAnimation, duration); + } + + return animation; + } + + private static class DefaultAnimationFactory implements ViewAnimation.AnimationFactory { + + @Override + public Animation build() { + AlphaAnimation animation = new AlphaAnimation(0f, 1f); + animation.setDuration(DEFAULT_DURATION_MS / 2); + return animation; + } + } +} diff --git a/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeViewAnimation.java b/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeViewAnimation.java index bf2d3eea..a721aa1c 100644 --- a/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeViewAnimation.java +++ b/library/src/main/java/com/bumptech/glide/request/animation/DrawableCrossFadeViewAnimation.java @@ -1,10 +1,7 @@ package com.bumptech.glide.request.animation; -import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; /** * A cross fade {@link GlideAnimation} for {@link android.graphics.drawable.Drawable}s @@ -15,65 +12,10 @@ import android.view.animation.Animation; * @param <T> The type of the {@link android.graphics.drawable.Drawable} that will be animated. */ public class DrawableCrossFadeViewAnimation<T extends Drawable> implements GlideAnimation<T> { - // 150 ms. - public static final int DEFAULT_DURATION = 300; private final GlideAnimation<T> defaultAnimation; private final int duration; /** - * A factory class that produces a new {@link GlideAnimation} that varies depending - * on whether or not the drawable was loaded from the memory cache and whether or not the drawable is the first - * image to be set on the target. - * - * <p> - * Resources are usually loaded from the memory cache just before the user can see the view, - * for example when the user changes screens or scrolls back and forth in a list. In those cases the user - * typically does not expect to see an animation. As a result, when the resource is loaded from the memory - * cache this factory producdes an {@link NoAnimation}. - * </p> - */ - public static class DrawableCrossFadeFactory<T extends Drawable> implements GlideAnimationFactory<T> { - private final ViewAnimation.ViewAnimationFactory<T> animationFactory; - private final int duration; - private DrawableCrossFadeViewAnimation<T> animation; - - public DrawableCrossFadeFactory() { - this(DEFAULT_DURATION); - } - - public DrawableCrossFadeFactory(int duration) { - this(new ViewAnimation.ViewAnimationFactory<T>(new DefaultAnimationFactory()), duration); - } - - public DrawableCrossFadeFactory(Context context, int defaultAnimationId, int duration) { - this(new ViewAnimation.ViewAnimationFactory<T>(context, defaultAnimationId), duration); - } - - public DrawableCrossFadeFactory(Animation defaultAnimation, int duration) { - this(new ViewAnimation.ViewAnimationFactory<T>(defaultAnimation), duration); - } - - DrawableCrossFadeFactory(ViewAnimation.ViewAnimationFactory<T> animationFactory, int duration) { - this.animationFactory = animationFactory; - this.duration = duration; - } - - @Override - public GlideAnimation<T> build(boolean isFromMemoryCache, boolean isFirstResource) { - if (isFromMemoryCache) { - return NoAnimation.get(); - } - - if (animation == null) { - GlideAnimation<T> defaultAnimation = animationFactory.build(false, isFirstResource); - animation = new DrawableCrossFadeViewAnimation<T>(defaultAnimation, duration); - } - - return animation; - } - } - - /** * Constructor that takes a default animation and a duration in milliseconds that the cross fade animation should * last. * @param duration The duration that the cross fade animation should run if there is something to cross fade from @@ -111,14 +53,4 @@ public class DrawableCrossFadeViewAnimation<T extends Drawable> implements Glide return false; } } - - private static class DefaultAnimationFactory implements ViewAnimation.AnimationFactory { - - @Override - public Animation build() { - AlphaAnimation animation = new AlphaAnimation(0f, 1f); - animation.setDuration(DEFAULT_DURATION / 2); - return animation; - } - } } diff --git a/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimation.java b/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimation.java index aeea7187..7f62719d 100644 --- a/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimation.java +++ b/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimation.java @@ -1,9 +1,7 @@ package com.bumptech.glide.request.animation; -import android.content.Context; import android.view.View; import android.view.animation.Animation; -import android.view.animation.AnimationUtils; /** * A {@link com.bumptech.glide.request.animation.GlideAnimation GlideAnimation} that can apply a @@ -45,76 +43,6 @@ public class ViewAnimation<R> implements GlideAnimation<R> { return false; } - /** - * A {@link com.bumptech.glide.request.animation.GlideAnimationFactory} that produces ViewAnimations. - */ - public static class ViewAnimationFactory<R> implements GlideAnimationFactory<R> { - private final AnimationFactory animationFactory; - private GlideAnimation<R> glideAnimation; - - public ViewAnimationFactory(Animation animation) { - this(new ConcreteAnimationFactory(animation)); - } - - public ViewAnimationFactory(Context context, int animationId) { - this(new ResourceAnimationFactory(context, animationId)); - } - - ViewAnimationFactory(AnimationFactory animationFactory) { - this.animationFactory = animationFactory; - } - - /** - * Returns a new {@link com.bumptech.glide.request.animation.GlideAnimation} for the given arguments. If - * isFromMemoryCache is {@code true} or isFirstImage is {@code false}, returns a - * {@link com.bumptech.glide.request.animation.NoAnimation} and otherwise returns a new - * {@link com.bumptech.glide.request.animation.ViewAnimation}. - * - * @param isFromMemoryCache {@inheritDoc} - * @param isFirstResource {@inheritDoc} - */ - @Override - public GlideAnimation<R> build(boolean isFromMemoryCache, boolean isFirstResource) { - if (isFromMemoryCache || !isFirstResource) { - return NoAnimation.get(); - } - - if (glideAnimation == null) { - glideAnimation = new ViewAnimation<R>(animationFactory); - } - - return glideAnimation; - } - } - - private static class ConcreteAnimationFactory implements AnimationFactory { - private final Animation animation; - - public ConcreteAnimationFactory(Animation animation) { - this.animation = animation; - } - - @Override - public Animation build() { - return animation; - } - } - - private static class ResourceAnimationFactory implements AnimationFactory { - private final Context context; - private final int animationId; - - public ResourceAnimationFactory(Context context, int animationId) { - this.context = context.getApplicationContext(); - this.animationId = animationId; - } - - @Override - public Animation build() { - return AnimationUtils.loadAnimation(context, animationId); - } - } - interface AnimationFactory { Animation build(); } diff --git a/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimationFactory.java b/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimationFactory.java new file mode 100644 index 00000000..df2761aa --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/request/animation/ViewAnimationFactory.java @@ -0,0 +1,78 @@ +package com.bumptech.glide.request.animation; + +import android.content.Context; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +/** + * A {@link com.bumptech.glide.request.animation.GlideAnimationFactory} that produces + * {@link com.bumptech.glide.request.animation.ViewAnimation}s. + * + * @param <R> The type of the resource displayed in the view that is animated + */ +public class ViewAnimationFactory<R> implements GlideAnimationFactory<R> { + private final ViewAnimation.AnimationFactory animationFactory; + private GlideAnimation<R> glideAnimation; + + public ViewAnimationFactory(Animation animation) { + this(new ConcreteAnimationFactory(animation)); + } + + public ViewAnimationFactory(Context context, int animationId) { + this(new ResourceAnimationFactory(context, animationId)); + } + + ViewAnimationFactory(ViewAnimation.AnimationFactory animationFactory) { + this.animationFactory = animationFactory; + } + + /** + * Returns a new {@link com.bumptech.glide.request.animation.GlideAnimation} for the given arguments. If + * isFromMemoryCache is {@code true} or isFirstImage is {@code false}, returns a + * {@link com.bumptech.glide.request.animation.NoAnimation} and otherwise returns a new + * {@link com.bumptech.glide.request.animation.ViewAnimation}. + * + * @param isFromMemoryCache {@inheritDoc} + * @param isFirstResource {@inheritDoc} + */ + @Override + public GlideAnimation<R> build(boolean isFromMemoryCache, boolean isFirstResource) { + if (isFromMemoryCache || !isFirstResource) { + return NoAnimation.get(); + } + + if (glideAnimation == null) { + glideAnimation = new ViewAnimation<R>(animationFactory); + } + + return glideAnimation; + } + + private static class ConcreteAnimationFactory implements ViewAnimation.AnimationFactory { + private final Animation animation; + + public ConcreteAnimationFactory(Animation animation) { + this.animation = animation; + } + + @Override + public Animation build() { + return animation; + } + } + + private static class ResourceAnimationFactory implements ViewAnimation.AnimationFactory { + private final Context context; + private final int animationId; + + public ResourceAnimationFactory(Context context, int animationId) { + this.context = context.getApplicationContext(); + this.animationId = animationId; + } + + @Override + public Animation build() { + return AnimationUtils.loadAnimation(context, animationId); + } + } +} diff --git a/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimation.java b/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimation.java index 9c664df4..6b42e81f 100644 --- a/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimation.java +++ b/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimation.java @@ -54,34 +54,4 @@ public class ViewPropertyAnimation<R> implements GlideAnimation<R> { void animate(View view); } - /** - * A {@link com.bumptech.glide.request.animation.GlideAnimationFactory} that produces ViewPropertyAnimations. - */ - public static class ViewPropertyAnimationFactory<R> implements GlideAnimationFactory<R> { - private final Animator animator; - private ViewPropertyAnimation<R> animation; - - public ViewPropertyAnimationFactory(Animator animator) { - this.animator = animator; - } - - /** - * Returns a new {@link com.bumptech.glide.request.animation.GlideAnimation} for the given arguments. If - * isMemoryCache is {@code true} or isFirstImage is {@code false}, returns a - * {@link com.bumptech.glide.request.animation.NoAnimation} and otherwise returns a new - * {@link com.bumptech.glide.request.animation.ViewPropertyAnimation} for the - * {@link com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator} provided in the constructor. - */ - @Override - public GlideAnimation<R> build(boolean isFromMemoryCache, boolean isFirstResource) { - if (isFromMemoryCache || !isFirstResource) { - return NoAnimation.get(); - } - if (animation == null) { - animation = new ViewPropertyAnimation<R>(animator); - } - - return animation; - } - } } diff --git a/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimationFactory.java b/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimationFactory.java new file mode 100644 index 00000000..f8c5002f --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/request/animation/ViewPropertyAnimationFactory.java @@ -0,0 +1,34 @@ +package com.bumptech.glide.request.animation; + +/** + * A {@link GlideAnimationFactory} that produces ViewPropertyAnimations. + * + * @param <R> The type of the resource displayed in the view that is animated + */ +public class ViewPropertyAnimationFactory<R> implements GlideAnimationFactory<R> { + private final ViewPropertyAnimation.Animator animator; + private ViewPropertyAnimation<R> animation; + + public ViewPropertyAnimationFactory(ViewPropertyAnimation.Animator animator) { + this.animator = animator; + } + + /** + * Returns a new {@link GlideAnimation} for the given arguments. If + * isMemoryCache is {@code true} or isFirstImage is {@code false}, returns a + * {@link NoAnimation} and otherwise returns a new + * {@link ViewPropertyAnimation} for the + * {@link com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator} provided in the constructor. + */ + @Override + public GlideAnimation<R> build(boolean isFromMemoryCache, boolean isFirstResource) { + if (isFromMemoryCache || !isFirstResource) { + return NoAnimation.get(); + } + if (animation == null) { + animation = new ViewPropertyAnimation<R>(animator); + } + + return animation; + } +} diff --git a/library/src/main/java/com/bumptech/glide/request/target/ImageViewTargetFactory.java b/library/src/main/java/com/bumptech/glide/request/target/ImageViewTargetFactory.java index 24790c74..97e84f37 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/ImageViewTargetFactory.java +++ b/library/src/main/java/com/bumptech/glide/request/target/ImageViewTargetFactory.java @@ -3,6 +3,7 @@ package com.bumptech.glide.request.target; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.widget.ImageView; + import com.bumptech.glide.load.resource.drawable.GlideDrawable; /** diff --git a/library/src/main/java/com/bumptech/glide/request/target/PreloadTarget.java b/library/src/main/java/com/bumptech/glide/request/target/PreloadTarget.java index 8dfbe600..a8a9b5a2 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/PreloadTarget.java +++ b/library/src/main/java/com/bumptech/glide/request/target/PreloadTarget.java @@ -14,8 +14,8 @@ public final class PreloadTarget<Z> extends SimpleTarget<Z> { /** * Returns a PreloadTarget. * - * @param width The width of the desired resourece. - * @param height The height of the desired resource. + * @param width The width in pixels of the desired resource. + * @param height The height in pixels of the desired resource. * @param <Z> The type of the desired resource. */ public static <Z> PreloadTarget<Z> obtain(int width, int height) { diff --git a/library/src/main/java/com/bumptech/glide/request/target/SimpleTarget.java b/library/src/main/java/com/bumptech/glide/request/target/SimpleTarget.java index 78522c32..cdbc9a49 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/SimpleTarget.java +++ b/library/src/main/java/com/bumptech/glide/request/target/SimpleTarget.java @@ -44,8 +44,8 @@ public abstract class SimpleTarget<Z> extends BaseTarget<Z> { /** * Constructor for the target that takes the desired dimensions of the decoded and/or transformed resource. * - * @param width The desired width of the resource. - * @param height The desired height of the resource. + * @param width The width in pixels of the desired resource. + * @param height The height in pixels of the desired resource. */ public SimpleTarget(int width, int height) { this.width = width; diff --git a/library/src/main/java/com/bumptech/glide/request/target/SizeReadyCallback.java b/library/src/main/java/com/bumptech/glide/request/target/SizeReadyCallback.java index eb382cd6..22b41180 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/SizeReadyCallback.java +++ b/library/src/main/java/com/bumptech/glide/request/target/SizeReadyCallback.java @@ -8,8 +8,8 @@ public interface SizeReadyCallback { /** * A callback called on the main thread. * - * @param width The width of the target. - * @param height The height of the target. + * @param width The width in pixels of the target. + * @param height The height in pixels of the target. */ void onSizeReady(int width, int height); } diff --git a/library/src/main/java/com/bumptech/glide/request/target/ViewTarget.java b/library/src/main/java/com/bumptech/glide/request/target/ViewTarget.java index cff57f70..dcf7f5d0 100644 --- a/library/src/main/java/com/bumptech/glide/request/target/ViewTarget.java +++ b/library/src/main/java/com/bumptech/glide/request/target/ViewTarget.java @@ -7,6 +7,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; + import com.bumptech.glide.request.Request; import java.lang.ref.WeakReference; diff --git a/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java b/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java index 667b3dff..1ea2ca10 100644 --- a/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java +++ b/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java @@ -3,6 +3,7 @@ package com.bumptech.glide.signature; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; + import com.bumptech.glide.load.Key; import java.util.UUID; diff --git a/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java b/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java index 4774a69b..dbeb876d 100644 --- a/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java +++ b/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java @@ -15,6 +15,18 @@ public class MediaStoreSignature implements Key { private final long dateModified; private final int orientation; + /** + * Constructor for {@link com.bumptech.glide.signature.MediaStoreSignature}. + * + * @param mimeType The mime type of the media store media. Ok to default to empty string "". See + * {@link android.provider.MediaStore.Images.ImageColumns#MIME_TYPE} or + * {@link android.provider.MediaStore.Video.VideoColumns#MIME_TYPE}. + * @param dateModified The date modified time of the media store media. Ok to default to 0. See + * {@link android.provider.MediaStore.Images.ImageColumns#DATE_MODIFIED} or + * {@link android.provider.MediaStore.Video.VideoColumns#DATE_MODIFIED}. + * @param orientation The orientation of the media store media. Ok to default to 0. See + * {@link android.provider.MediaStore.Images.ImageColumns#ORIENTATION}. + */ public MediaStoreSignature(String mimeType, long dateModified, int orientation) { this.mimeType = mimeType; this.dateModified = dateModified; diff --git a/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java b/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java index 12df71c3..344a2894 100644 --- a/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java +++ b/library/src/main/java/com/bumptech/glide/util/ExceptionCatchingInputStream.java @@ -1,5 +1,7 @@ package com.bumptech.glide.util; +import com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream; + import java.io.IOException; import java.io.InputStream; import java.util.Queue; @@ -15,10 +17,10 @@ public class ExceptionCatchingInputStream extends InputStream { private static final Queue<ExceptionCatchingInputStream> QUEUE = Util.createQueue(0); - private InputStream wrapped; + private RecyclableBufferedInputStream wrapped; private IOException exception; - public static ExceptionCatchingInputStream obtain(InputStream toWrap) { + public static ExceptionCatchingInputStream obtain(RecyclableBufferedInputStream toWrap) { ExceptionCatchingInputStream result; synchronized (QUEUE) { result = QUEUE.poll(); @@ -41,7 +43,7 @@ public class ExceptionCatchingInputStream extends InputStream { // Do nothing. } - void setInputStream(InputStream toWrap) { + void setInputStream(RecyclableBufferedInputStream toWrap) { wrapped = toWrap; } @@ -118,6 +120,10 @@ public class ExceptionCatchingInputStream extends InputStream { return result; } + public void fixMarkLimit() { + wrapped.fixMarkLimit(); + } + public IOException getException() { return exception; } diff --git a/library/src/main/java/com/bumptech/glide/util/Util.java b/library/src/main/java/com/bumptech/glide/util/Util.java index 5d03cfdd..cc0743fe 100644 --- a/library/src/main/java/com/bumptech/glide/util/Util.java +++ b/library/src/main/java/com/bumptech/glide/util/Util.java @@ -53,7 +53,8 @@ public final class Util { * * @see #getBitmapByteSize(android.graphics.Bitmap) * - * @deprecated + * @deprecated Use {@link #getBitmapByteSize(android.graphics.Bitmap)} instead. Scheduled to be removed in Glide + * 4.0. */ @Deprecated public static int getSize(Bitmap bitmap) { diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 8e11f324..00000000 --- a/settings.gradle +++ /dev/null @@ -1,13 +0,0 @@ -include ':library' -include ':glide' -include ':third_party:gif_decoder' -include ':third_party:disklrucache' -include ':third_party:gif_encoder' -include ':samples:flickr' -include ':samples:giphy' -include ':samples:svg' -include ':integration' -include ':integration:volley' -include ':integration:okhttp' - -rootProject.name = 'glide-parent' diff --git a/static/glide_logo.png b/static/glide_logo.png Binary files differdeleted file mode 100644 index f9f4d799..00000000 --- a/static/glide_logo.png +++ /dev/null diff --git a/testutil/src/main/java/com/bumptech/glide/testutil/TestResourceUtil.java b/testutil/src/main/java/com/bumptech/glide/testutil/TestResourceUtil.java new file mode 100644 index 00000000..e523b67d --- /dev/null +++ b/testutil/src/main/java/com/bumptech/glide/testutil/TestResourceUtil.java @@ -0,0 +1,23 @@ +package com.bumptech.glide.testutil; + +import java.io.InputStream; + +/** + * Test only utility for opening resources in androidTest/resources. + */ +public final class TestResourceUtil { + private TestResourceUtil() { + // Utility class + } + + /** + * Returns an InputStream for the given test class and sub-path. + * + * @param testClass A Junit test class. + * @param subPath The sub-path under androidTest/resources where the desired resource is located. + * Should not be prefixed with a '/' + */ + public static InputStream openResource(Class testClass, String subPath) { + return testClass.getResourceAsStream("/" + subPath); + } +} diff --git a/testutil/src/main/java/com/bumptech/glide/testutil/TestUtil.java b/testutil/src/main/java/com/bumptech/glide/testutil/TestUtil.java new file mode 100644 index 00000000..0ad40e0e --- /dev/null +++ b/testutil/src/main/java/com/bumptech/glide/testutil/TestUtil.java @@ -0,0 +1,37 @@ +package com.bumptech.glide.testutil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Shared utility classes for tests. + */ +public final class TestUtil { + private TestUtil() { + // Utility class. + } + + public static byte[] resourceToBytes(Class testClass, String resourceName) throws IOException { + return isToBytes(TestResourceUtil.openResource(testClass, resourceName)); + } + + public static byte[] isToBytes(InputStream is) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int read; + try { + while ((read = is.read(buffer)) != -1) { + os.write(buffer, 0, read); + } + } finally { + is.close(); + } + return os.toByteArray(); + } + + public static String isToString(InputStream is) throws IOException { + return new String(isToBytes(is)); + } + +} diff --git a/third_party/disklrucache/README.md b/third_party/disklrucache/README.md index a02e39cd..5f27ca26 100644 --- a/third_party/disklrucache/README.md +++ b/third_party/disklrucache/README.md @@ -43,22 +43,6 @@ appropriately. *Note: This implementation specifically targets Android compatibility.* - - -Obtaining -========= - -If you are a Maven user you can also add this library as a dependency. Add the -following to your `pom.xml`: - -```xml -<dependency> - <groupId>com.bumptech.glide</groupId> - <artifactId>disklrucache</artifactId> - <version>(insert latest version)</version> -</dependency> -``` - License ======= diff --git a/third_party/disklrucache/README.third_party b/third_party/disklrucache/README.third_party index 9ffe3cbd..88189ae3 100644 --- a/third_party/disklrucache/README.third_party +++ b/third_party/disklrucache/README.third_party @@ -1,5 +1,5 @@ -URL: https://github.com/judds/DiskLruCache/tarball/b9ed9f4501d90e59128203b62e14b4cad91b6cdd -Version: b9ed9f4501d90e59128203b62e14b4cad91b6cdd +URL: https://github.com/JakeWharton/DiskLruCache/tarball/7a1ecbd38d2ad0873fb843e911d60235b7434acb +Version: 7a1ecbd38d2ad0873fb843e911d60235b7434acb License: Apache 2.0 License File: LICENSE @@ -7,4 +7,4 @@ Description: Java implementation of a Disk-based LRU cache which specifically targets Android compatibility. Local Modifications: -Exposed File objects directly to gets, removed test sources. +Exposed File objects directly to gets, removed key validation, removed test sources. diff --git a/third_party/disklrucache/build.gradle b/third_party/disklrucache/build.gradle deleted file mode 100644 index 0e876389..00000000 --- a/third_party/disklrucache/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -apply plugin: 'java' -apply plugin: 'checkstyle' - -repositories { - jcenter() -} - -checkstyle { - configFile = new File(projectDir, 'checkstyle.xml') -} - -dependencies { - testCompile 'junit:junit:4.10' - testCompile 'commons-io:commons-io:2.1' - testCompile 'org.easytesting:fest-assert-core:2.0M10' -} diff --git a/third_party/disklrucache/checkstyle.xml b/third_party/disklrucache/checkstyle.xml deleted file mode 100644 index de84efb9..00000000 --- a/third_party/disklrucache/checkstyle.xml +++ /dev/null @@ -1,129 +0,0 @@ -<?xml version="1.0"?>
-<!DOCTYPE module PUBLIC
- "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
- "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
-
-<module name="Checker">
- <module name="NewlineAtEndOfFile"/>
- <module name="FileLength"/>
- <module name="FileTabCharacter"/>
-
- <!-- Trailing spaces -->
- <module name="RegexpSingleline">
- <property name="format" value="\s+$"/>
- <property name="message" value="Line has trailing spaces."/>
- </module>
-
- <!-- Space after 'for' and 'if' -->
- <module name="RegexpSingleline">
- <property name="format" value="^\s*(for|if)\b[^ ]"/>
- <property name="message" value="Space needed before opening parenthesis."/>
- </module>
-
- <!-- For each spacing -->
- <module name="RegexpSingleline">
- <property name="format" value="^\s*for \(.*?([^ ]:|:[^ ])"/>
- <property name="message" value="Space needed around ':' character."/>
- </module>
-
- <module name="TreeWalker">
- <!-- Checks for Javadoc comments. -->
- <!-- See http://checkstyle.sf.net/config_javadoc.html -->
- <!--module name="JavadocMethod"/-->
- <!--module name="JavadocType"/-->
- <!--module name="JavadocVariable"/-->
- <module name="JavadocStyle"/>
-
-
- <!-- Checks for Naming Conventions. -->
- <!-- See http://checkstyle.sf.net/config_naming.html -->
- <!--<module name="ConstantName"/>-->
- <module name="LocalFinalVariableName"/>
- <module name="LocalVariableName"/>
- <module name="MemberName"/>
- <module name="MethodName"/>
- <module name="PackageName"/>
- <module name="ParameterName"/>
- <module name="StaticVariableName"/>
- <module name="TypeName"/>
-
-
- <!-- Checks for imports -->
- <!-- See http://checkstyle.sf.net/config_import.html -->
- <module name="AvoidStarImport"/>
- <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
- <module name="RedundantImport"/>
- <module name="UnusedImports"/>
-
-
- <!-- Checks for Size Violations. -->
- <!-- See http://checkstyle.sf.net/config_sizes.html -->
- <module name="LineLength">
- <property name="max" value="100"/>
- </module>
- <module name="MethodLength"/>
- <module name="ParameterNumber"/>
-
-
- <!-- Checks for whitespace -->
- <!-- See http://checkstyle.sf.net/config_whitespace.html -->
- <module name="GenericWhitespace"/>
- <!--<module name="EmptyForIteratorPad"/>-->
- <module name="MethodParamPad"/>
- <!--<module name="NoWhitespaceAfter"/>-->
- <!--<module name="NoWhitespaceBefore"/>-->
- <module name="OperatorWrap"/>
- <module name="ParenPad"/>
- <module name="TypecastParenPad"/>
- <module name="WhitespaceAfter"/>
- <module name="WhitespaceAround"/>
-
-
- <!-- Modifier Checks -->
- <!-- See http://checkstyle.sf.net/config_modifiers.html -->
- <module name="ModifierOrder"/>
- <module name="RedundantModifier"/>
-
-
- <!-- Checks for blocks. You know, those {}'s -->
- <!-- See http://checkstyle.sf.net/config_blocks.html -->
- <module name="AvoidNestedBlocks"/>
- <!--module name="EmptyBlock"/-->
- <module name="LeftCurly"/>
- <!--<module name="NeedBraces"/>-->
- <module name="RightCurly"/>
-
-
- <!-- Checks for common coding problems -->
- <!-- See http://checkstyle.sf.net/config_coding.html -->
- <!--module name="AvoidInlineConditionals"/-->
- <module name="CovariantEquals"/>
- <module name="EmptyStatement"/>
- <!--<module name="EqualsAvoidNull"/>-->
- <module name="EqualsHashCode"/>
- <!--module name="HiddenField"/-->
- <module name="IllegalInstantiation"/>
- <!--module name="InnerAssignment"/-->
- <!--module name="MagicNumber"/-->
- <!--module name="MissingSwitchDefault"/-->
- <module name="RedundantThrows"/>
- <module name="SimplifyBooleanExpression"/>
- <module name="SimplifyBooleanReturn"/>
-
- <!-- Checks for class design -->
- <!-- See http://checkstyle.sf.net/config_design.html -->
- <!--module name="DesignForExtension"/-->
- <!--<module name="FinalClass"/>-->
- <module name="HideUtilityClassConstructor"/>
- <module name="InterfaceIsType"/>
- <!--module name="VisibilityModifier"/-->
-
-
- <!-- Miscellaneous other checks. -->
- <!-- See http://checkstyle.sf.net/config_misc.html -->
- <module name="ArrayTypeStyle"/>
- <!--module name="FinalParameters"/-->
- <!--module name="TodoComment"/-->
- <module name="UpperEll"/>
- </module>
-</module>
diff --git a/third_party/disklrucache/gradle/wrapper/gradle-wrapper.jar b/third_party/disklrucache/gradle/wrapper/gradle-wrapper.jar Binary files differdeleted file mode 100644 index 0087cd3b..00000000 --- a/third_party/disklrucache/gradle/wrapper/gradle-wrapper.jar +++ /dev/null diff --git a/third_party/disklrucache/gradle/wrapper/gradle-wrapper.properties b/third_party/disklrucache/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index d9c5a25c..00000000 --- a/third_party/disklrucache/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Sat Jun 28 20:49:51 PDT 2014 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/third_party/disklrucache/gradlew b/third_party/disklrucache/gradlew deleted file mode 100755 index 91a7e269..00000000 --- a/third_party/disklrucache/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/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/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/DiskLruCache.java b/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/DiskLruCache.java index a6cbd78d..7fb4479e 100644 --- a/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/DiskLruCache.java +++ b/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/DiskLruCache.java @@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit; /** * A cache that uses a bounded amount of space on a filesystem. Each cache * entry has a string key and a fixed number of values. Each key must match - * the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences, + * the regex <strong>[a-z0-9_-]{1,120}</strong>. Values are byte sequences, * accessible as streams or files. Each value must be between {@code 0} and * {@code Integer.MAX_VALUE} bytes in length. * @@ -219,8 +219,6 @@ public final class DiskLruCache implements Closeable { try { cache.readJournal(); cache.processJournal(); - cache.journalWriter = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII)); return cache; } catch (IOException journalIsCorrupt) { System.out @@ -267,6 +265,14 @@ public final class DiskLruCache implements Closeable { } } redundantOpCount = lineCount - lruEntries.size(); + + // If we ended on a truncated line, rebuild the journal before appending to it. + if (reader.hasUnterminatedLine()) { + rebuildJournal(); + } else { + journalWriter = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(journalFile, true), Util.US_ASCII)); + } } finally { Util.closeQuietly(reader); } diff --git a/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/StrictLineReader.java b/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/StrictLineReader.java index 96b68608..11135db0 100644 --- a/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/StrictLineReader.java +++ b/third_party/disklrucache/src/main/java/com/bumptech/glide/disklrucache/StrictLineReader.java @@ -176,6 +176,10 @@ class StrictLineReader implements Closeable { } } + public boolean hasUnterminatedLine() { + return end == -1; + } + /** * Reads new input data into the buffer. Call only with pos == end or end == -1, * depending on the desired outcome if the function throws. diff --git a/third_party/gif_decoder/build.gradle b/third_party/gif_decoder/build.gradle deleted file mode 100644 index 8834279f..00000000 --- a/third_party/gif_decoder/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'robolectric' - -dependencies { - androidTestCompile 'com.android.support:support-v4:19.1.0' - androidTestCompile 'org.hamcrest:hamcrest-core:1.3' - androidTestCompile 'org.hamcrest:hamcrest-library:1.3' - androidTestCompile 'junit:junit:4.11' - androidTestCompile 'org.mockito:mockito-all:1.9.5' - androidTestCompile 'org.robolectric:robolectric:2.4-SNAPSHOT' -} - -android { - compileSdkVersion 19 - buildToolsVersion '19.1.0' - - defaultConfig { - applicationId 'com.bumptech.glide.gifdecoder' - minSdkVersion 10 - targetSdkVersion 19 - } -} diff --git a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java index 92dc3bfc..c4b4281d 100644 --- a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java +++ b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java @@ -98,6 +98,11 @@ public class GifDecoder { private static final int INITIAL_FRAME_POINTER = -1; + // We can't tell if a gif has transparency to decode a partial frame on top of a previous frame, or if the final + // frame will actually have transparent pixels, so we must always use a format that supports transparency. We can't + // use ARGB_4444 because of framework issues drawing onto ARGB_4444 Bitmaps using Canvas. + private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; + // Global File Header values and parsing flags. // Active color table. private int[] act; @@ -123,7 +128,6 @@ public class GifDecoder { private BitmapProvider bitmapProvider; private Bitmap previousImage; private boolean savePrevious; - private Bitmap.Config config; private int status; /** @@ -135,8 +139,8 @@ public class GifDecoder { * Returns an {@link Bitmap} with exactly the given dimensions and config, or null if no such {@link Bitmap} * could be obtained. * - * @param width The width of the desired {@link android.graphics.Bitmap}. - * @param height The height of the desired {@link android.graphics.Bitmap}. + * @param width The width in pixels of the desired {@link android.graphics.Bitmap}. + * @param height The height in pixels of the desired {@link android.graphics.Bitmap}. * @param config The {@link android.graphics.Bitmap.Config} of the desired {@link android.graphics.Bitmap}. */ public Bitmap obtain(int width, int height, Bitmap.Config config); @@ -164,10 +168,6 @@ public class GifDecoder { return data; } - public void setPreferredConfig(Bitmap.Config config) { - this.config = config; - } - /** * Returns the current status of the decoder. * @@ -202,7 +202,7 @@ public class GifDecoder { } /** - * Gets display duration for the upcoming frame. + * Gets display duration for the upcoming frame in ms. */ public int getNextDelay() { if (header.frameCount <= 0 || framePointer < 0) { @@ -248,46 +248,59 @@ public class GifDecoder { * * @return Bitmap representation of frame. */ - public Bitmap getNextFrame() { + public synchronized Bitmap getNextFrame() { if (header.frameCount <= 0 || framePointer < 0) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "unable to decode frame, frameCount=" + header.frameCount + " framePointer=" + framePointer); + } status = STATUS_FORMAT_ERROR; } if (status == STATUS_FORMAT_ERROR || status == STATUS_OPEN_ERROR) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Unable to decode frame, status=" + status); + } return null; } status = STATUS_OK; - GifFrame frame = header.frames.get(framePointer); + GifFrame currentFrame = header.frames.get(framePointer); + GifFrame previousFrame = null; + int previousIndex = framePointer - 1; + if (previousIndex >= 0) { + previousFrame = header.frames.get(previousIndex); + } // Set the appropriate color table. - if (frame.lct == null) { + if (currentFrame.lct == null) { act = header.gct; } else { - act = frame.lct; - if (header.bgIndex == frame.transIndex) { + act = currentFrame.lct; + if (header.bgIndex == currentFrame.transIndex) { header.bgColor = 0; } } int save = 0; - if (frame.transparency) { - save = act[frame.transIndex]; + if (currentFrame.transparency) { + save = act[currentFrame.transIndex]; // Set transparent color if specified. - act[frame.transIndex] = 0; + act[currentFrame.transIndex] = 0; } if (act == null) { - Log.w(TAG, "No Valid Color Table"); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "No Valid Color Table"); + } // No color table defined. status = STATUS_FORMAT_ERROR; return null; } // Transfer pixel data to image. - Bitmap result = setPixels(framePointer); + Bitmap result = setPixels(currentFrame, previousFrame); // Reset the transparent pixel in the color table - if (frame.transparency) { - act[frame.transIndex] = save; + if (currentFrame.transparency) { + act[currentFrame.transIndex] = save; } return result; @@ -408,13 +421,8 @@ public class GifDecoder { /** * Creates new frame image from current data (and previous frames as specified by their disposition codes). */ - private Bitmap setPixels(int frameIndex) { - GifFrame currentFrame = header.frames.get(frameIndex); - GifFrame previousFrame = null; - int previousIndex = frameIndex - 1; - if (previousIndex >= 0) { - previousFrame = header.frames.get(previousIndex); - } + private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) { + int width = header.width; int height = header.height; @@ -676,21 +684,10 @@ public class GifDecoder { return n; } - private Bitmap.Config getPreferredConfig() { - // We can't tell if a gif has transparency to decode a partial frame on top of a previous frame, or if the final - // frame will actually have transparent pixels, so we must always use a format that supports transparency. - if (config == Bitmap.Config.RGB_565 || config == Bitmap.Config.ARGB_4444) { - return Bitmap.Config.ARGB_4444; - } else { - return Bitmap.Config.ARGB_8888; - } - } - private Bitmap getNextBitmap() { - Bitmap.Config targetConfig = getPreferredConfig(); - Bitmap result = bitmapProvider.obtain(header.width, header.height, targetConfig); + Bitmap result = bitmapProvider.obtain(header.width, header.height, BITMAP_CONFIG); if (result == null) { - result = Bitmap.createBitmap(header.width, header.height, targetConfig); + result = Bitmap.createBitmap(header.width, header.height, BITMAP_CONFIG); } setAlpha(result); return result; diff --git a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java index 286a5602..cf61531c 100644 --- a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java +++ b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java @@ -1,5 +1,7 @@ package com.bumptech.glide.gifdecoder; +import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR; + import android.util.Log; import java.nio.BufferUnderflowException; @@ -7,8 +9,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; -import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR; - /** * A class responsible for creating {@link com.bumptech.glide.gifdecoder.GifHeader}s from data representing animated * gifs. @@ -16,6 +16,11 @@ import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR; public class GifHeaderParser { public static final String TAG = "GifHeaderParser"; + // The minimum frame delay in hundredths of a second. + static final int MIN_FRAME_DELAY = 3; + // The default frame delay in hundredths of a second for GIFs with frame delays less than the minimum. + static final int DEFAULT_FRAME_DELAY = 10; + private static final int MAX_BLOCK_SIZE = 256; // Raw data read working array. private final byte[] block = new byte[MAX_BLOCK_SIZE]; @@ -37,6 +42,11 @@ public class GifHeaderParser { return this; } + public void clear() { + rawData = null; + header = null; + } + private void reset() { rawData = null; Arrays.fill(block, (byte) 0); @@ -147,7 +157,12 @@ public class GifHeaderParser { } header.currentFrame.transparency = (packed & 1) != 0; // Delay in milliseconds. - header.currentFrame.delay = readShort() * 10; + int delayInHundredthsOfASecond = readShort(); + // TODO: consider allowing -1 to indicate show forever. + if (delayInHundredthsOfASecond < MIN_FRAME_DELAY) { + delayInHundredthsOfASecond = DEFAULT_FRAME_DELAY; + } + header.currentFrame.delay = delayInHundredthsOfASecond * 10; // Transparent color index header.currentFrame.transIndex = read(); // Block terminator @@ -275,7 +290,9 @@ public class GifHeaderParser { tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; } } catch (BufferUnderflowException e) { - Log.w(TAG, "Format Error Reading Color Table", e); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Format Error Reading Color Table", e); + } header.status = STATUS_FORMAT_ERROR; } @@ -321,7 +338,9 @@ public class GifHeaderParser { n += count; } } catch (Exception e) { - Log.w(TAG, "Error Reading Block n: " + n + " count: " + count + " blockSize: " + blockSize, e); + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Error Reading Block n: " + n + " count: " + count + " blockSize: " + blockSize, e); + } header.status = STATUS_FORMAT_ERROR; } } diff --git a/third_party/gif_encoder/build.gradle b/third_party/gif_encoder/build.gradle deleted file mode 100644 index d13e5e10..00000000 --- a/third_party/gif_encoder/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion 19 - buildToolsVersion '19.1.0' - - defaultConfig { - applicationId 'com.bumptech.glide.gifencod:' - minSdkVersion 10 - targetSdkVersion 19 - } -} diff --git a/third_party/gif_encoder/src/main/java/com/bumptech/glide/gifencoder/AnimatedGifEncoder.java b/third_party/gif_encoder/src/main/java/com/bumptech/glide/gifencoder/AnimatedGifEncoder.java index 2442a0d4..aa1123f6 100644 --- a/third_party/gif_encoder/src/main/java/com/bumptech/glide/gifencoder/AnimatedGifEncoder.java +++ b/third_party/gif_encoder/src/main/java/com/bumptech/glide/gifencoder/AnimatedGifEncoder.java @@ -4,6 +4,7 @@ package com.bumptech.glide.gifencoder; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.util.Log; import java.io.BufferedOutputStream; import java.io.FileOutputStream; @@ -35,6 +36,10 @@ import java.io.OutputStream; */ public class AnimatedGifEncoder { + private static final String TAG = "AnimatedGifEncoder"; + + // The minimum % of an images pixels that must be transparent for us to set a transparent index automatically. + private static final double MIN_TRANSPARENT_PERCENTAGE = 4d; private int width; // image size @@ -384,14 +389,23 @@ public class AnimatedGifEncoder { int pixelsIndex = 0; hasTransparentPixels = false; + int totalTransparentPixels = 0; for (final int pixel : pixelsInt) { if (pixel == Color.TRANSPARENT) { - hasTransparentPixels = true; + totalTransparentPixels++; } pixels[pixelsIndex++] = (byte) (pixel & 0xFF); pixels[pixelsIndex++] = (byte) ((pixel >> 8) & 0xFF); pixels[pixelsIndex++] = (byte) ((pixel >> 16) & 0xFF); } + + double transparentPercentage = 100 * totalTransparentPixels / (double) pixelsInt.length; + // Assume images with greater where more than n% of the pixels are transparent actually have transparency. + // See issue #214. + hasTransparentPixels = transparentPercentage > MIN_TRANSPARENT_PERCENTAGE; + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "got pixels for frame with " + transparentPercentage + "% transparent pixels"); + } } /** |