diff --git a/.gitignore b/.gitignore index 37ac0c17dd..e90dca6f0d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,7 @@ docs/**/* # Intellij *.iml +*.ipr +*.iws .idea/** !.idea/codeStyleSettings.xml diff --git a/build.gradle b/build.gradle index d08837520a..ac4c7b5605 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ buildscript { dependencies { classpath "com.android.tools.build:gradle:${ANDROID_GRADLE_VERSION}" if (!hasProperty('DISABLE_ERROR_PRONE')) { - classpath "net.ltgt.gradle:gradle-errorprone-plugin:${ERROR_PRONE_VERSION}" + classpath "net.ltgt.gradle:gradle-errorprone-plugin:${ERROR_PRONE_PLUGIN_VERSION}" } classpath "se.bjurr.violations:violations-gradle-plugin:${VIOLATIONS_PLUGIN_VERSION}" } diff --git a/checkstyle.xml b/checkstyle.xml index 42a2c8a502..c2a00167d8 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -73,7 +73,7 @@ - + diff --git a/gradle.properties b/gradle.properties index ff78f7121c..dd0b3a3ae8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -32,9 +32,10 @@ JSR_305_VERSION=3.0.2 AUTO_SERVICE_VERSION=1.0-rc3 JAVAPOET_VERSION=1.9.0 -PMD_VERSION=5.4.0 +PMD_VERSION=5.8.1 FINDBUGS_VERSION=3.0.0 -ERROR_PRONE_VERSION=0.0.13 +ERROR_PRONE_VERSION=2.1.4-SNAPSHOT +ERROR_PRONE_PLUGIN_VERSION=0.0.13 VIOLATIONS_PLUGIN_VERSION=1.3 COMPILE_SDK_VERSION=27 diff --git a/integration/gifencoder/src/test/java/com/bumptech/glide/integration/gifencoder/ReEncodingGifResourceEncoderTest.java b/integration/gifencoder/src/test/java/com/bumptech/glide/integration/gifencoder/ReEncodingGifResourceEncoderTest.java index f4a971d977..641dc7357f 100644 --- a/integration/gifencoder/src/test/java/com/bumptech/glide/integration/gifencoder/ReEncodingGifResourceEncoderTest.java +++ b/integration/gifencoder/src/test/java/com/bumptech/glide/integration/gifencoder/ReEncodingGifResourceEncoderTest.java @@ -3,7 +3,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -95,6 +94,8 @@ public void setUp() { @After public void tearDown() { + // GC before delete() to release files on Windows (https://stackoverflow.com/a/4213208/253468) + System.gc(); if (file.exists() && !file.delete()) { throw new RuntimeException("Failed to delete file"); } @@ -120,8 +121,6 @@ public void testEncodeStrategy_withEncodeTransformationFalse_returnsSource() { @Test public void testEncode_withEncodeTransformationFalse_writesSourceDataToStream() throws IOException { - // Most likely an instance of http://stackoverflow.com/q/991489/253468 - assumeTrue(!System.getProperty("os.name").startsWith("Windows")); options.set(ReEncodingGifResourceEncoder.ENCODE_TRANSFORMATION, false); String expected = "testString"; byte[] data = expected.getBytes("UTF-8"); @@ -134,7 +133,6 @@ public void testEncode_withEncodeTransformationFalse_writesSourceDataToStream() @Test public void testEncode_WithEncodeTransformationFalse_whenOsThrows_returnsFalse() throws IOException { - options.set(ReEncodingGifResourceEncoder.ENCODE_TRANSFORMATION, false); byte[] data = "testString".getBytes("UTF-8"); when(gifDrawable.getBuffer()).thenReturn(ByteBuffer.wrap(data)); @@ -312,10 +310,7 @@ public void testRecyclesFrameResourceAfterWritingIfFrameResourceIsNotTransformed } @Test - public void testWritesBytesDirectlyToDiskIfTransformationIsUnitTransformation() - throws IOException { - // Most likely an instance of http://stackoverflow.com/q/991489/253468 - assumeTrue(!System.getProperty("os.name").startsWith("Windows")); + public void testWritesBytesDirectlyToDiskIfTransformationIsUnitTransformation() { when(gifDrawable.getFrameTransformation()).thenReturn(UnitTransformation.get()); String expected = "expected"; when(gifDrawable.getBuffer()).thenReturn(ByteBuffer.wrap(expected.getBytes())); diff --git a/library/build.gradle b/library/build.gradle index 22d3219330..8672d9ddb7 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -20,6 +20,10 @@ dependencies { testImplementation "org.robolectric:robolectric:${ROBOLECTRIC_VERSION}" testImplementation "com.squareup.okhttp3:mockwebserver:${MOCKWEBSERVER_VERSION}" testImplementation "com.android.support:support-v4:${ANDROID_SUPPORT_VERSION}" + + if (project.plugins.hasPlugin('net.ltgt.errorprone')) { + errorprone "com.google.errorprone:error_prone_core:${ERROR_PRONE_VERSION}" + } } android.testOptions.unitTests.all { Test testTask -> diff --git a/library/pmd-ruleset.xml b/library/pmd-ruleset.xml index 76249e191d..da8c961e38 100644 --- a/library/pmd-ruleset.xml +++ b/library/pmd-ruleset.xml @@ -3,15 +3,17 @@ 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"> - This ruleset was created from PMD.rul + Check for flaws in Glide's codebase. - - - + + + + + @@ -28,31 +30,39 @@ + + + + + + + - - - - + + - - - - - - + - - diff --git a/library/src/main/java/com/bumptech/glide/RequestBuilder.java b/library/src/main/java/com/bumptech/glide/RequestBuilder.java index 18dcbbce9f..ec4d145cd5 100644 --- a/library/src/main/java/com/bumptech/glide/RequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/RequestBuilder.java @@ -30,6 +30,7 @@ import com.bumptech.glide.request.target.ViewTarget; import com.bumptech.glide.signature.ApplicationVersionSignature; import com.bumptech.glide.util.Preconditions; +import com.bumptech.glide.util.Synthetic; import com.bumptech.glide.util.Util; import java.io.File; import java.net.URL; @@ -572,7 +573,7 @@ public > Y into(@NonNull Y target) { } @NonNull - private > Y into( + @Synthetic > Y into( @NonNull Y target, @Nullable RequestListener targetListener) { return into(target, targetListener, getMutableOptions()); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/ActiveResources.java b/library/src/main/java/com/bumptech/glide/load/engine/ActiveResources.java index 79f0573258..19671164c0 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/ActiveResources.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/ActiveResources.java @@ -91,7 +91,8 @@ EngineResource get(Key key) { return active; } - private void cleanupActiveReference(@NonNull ResourceWeakReference ref) { + @SuppressWarnings("WeakerAccess") + @Synthetic void cleanupActiveReference(@NonNull ResourceWeakReference ref) { Util.assertMainThread(); activeEngineResources.remove(ref.key); @@ -112,22 +113,7 @@ private ReferenceQueue> getReferenceQueue() { @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - ResourceWeakReference ref; - while (!isShutdown) { - try { - ref = (ResourceWeakReference) resourceReferenceQueue.remove(); - mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget(); - - // This section for testing only. - DequeuedResourceCallback current = cb; - if (current != null) { - current.onResourceDequeued(); - } - // End for testing only. - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + cleanReferenceQueue(); } }, "glide-active-resources"); cleanReferenceQueueThread.start(); @@ -135,6 +121,25 @@ public void run() { return resourceReferenceQueue; } + @SuppressWarnings("WeakerAccess") + @Synthetic void cleanReferenceQueue() { + while (!isShutdown) { + try { + ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove(); + mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget(); + + // This section for testing only. + DequeuedResourceCallback current = cb; + if (current != null) { + current.onResourceDequeued(); + } + // End for testing only. + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + @VisibleForTesting void setDequeuedResourceCallback(DequeuedResourceCallback cb) { this.cb = cb; 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 888bf71d3b..35a35ce80f 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 @@ -41,26 +41,22 @@ class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, Poolable { private static final String TAG = "DecodeJob"; - @SuppressWarnings("WeakerAccess") - @Synthetic - final DecodeHelper decodeHelper = new DecodeHelper<>(); + private final DecodeHelper decodeHelper = new DecodeHelper<>(); private final List throwables = new ArrayList<>(); private final StateVerifier stateVerifier = StateVerifier.newInstance(); private final DiskCacheProvider diskCacheProvider; private final Pools.Pool> pool; - @SuppressWarnings("WeakerAccess") - @Synthetic - final DeferredEncodeManager deferredEncodeManager = new DeferredEncodeManager<>(); + private final DeferredEncodeManager deferredEncodeManager = new DeferredEncodeManager<>(); private final ReleaseManager releaseManager = new ReleaseManager(); private GlideContext glideContext; - @SuppressWarnings("WeakerAccess") @Synthetic Key signature; + private Key signature; private Priority priority; private EngineKey loadKey; - @SuppressWarnings("WeakerAccess") @Synthetic int width; - @SuppressWarnings("WeakerAccess") @Synthetic int height; - @SuppressWarnings("WeakerAccess") @Synthetic DiskCacheStrategy diskCacheStrategy; - @SuppressWarnings("WeakerAccess") @Synthetic Options options; + private int width; + private int height; + private DiskCacheStrategy diskCacheStrategy; + private Options options; private Callback callback; private int order; private Stage stage; @@ -69,7 +65,7 @@ class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, private boolean onlyRetrieveFromCache; private Thread currentThread; - @SuppressWarnings("WeakerAccess") @Synthetic Key currentSourceKey; + private Key currentSourceKey; private Key currentAttemptingKey; private Object currentData; private DataSource currentDataSource; @@ -521,6 +517,65 @@ public StateVerifier getVerifier() { return stateVerifier; } + @Synthetic Resource onResourceDecoded(DataSource dataSource, Resource decoded) { + @SuppressWarnings("unchecked") + Class resourceSubClass = (Class) decoded.get().getClass(); + Transformation appliedTransformation = null; + Resource transformed = decoded; + if (dataSource != DataSource.RESOURCE_DISK_CACHE) { + appliedTransformation = decodeHelper.getTransformation(resourceSubClass); + transformed = appliedTransformation.transform(glideContext, decoded, width, height); + } + // TODO: Make this the responsibility of the Transformation. + if (!decoded.equals(transformed)) { + decoded.recycle(); + } + + final EncodeStrategy encodeStrategy; + final ResourceEncoder encoder; + if (decodeHelper.isResourceEncoderAvailable(transformed)) { + encoder = decodeHelper.getResultEncoder(transformed); + encodeStrategy = encoder.getEncodeStrategy(options); + } else { + encoder = null; + encodeStrategy = EncodeStrategy.NONE; + } + + Resource result = transformed; + boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey); + if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource, + encodeStrategy)) { + if (encoder == null) { + throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass()); + } + final Key key; + switch (encodeStrategy) { + case SOURCE: + key = new DataCacheKey(currentSourceKey, signature); + break; + case TRANSFORMED: + key = + new ResourceCacheKey( + decodeHelper.getArrayPool(), + currentSourceKey, + signature, + width, + height, + appliedTransformation, + resourceSubClass, + options); + break; + default: + throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy); + } + + LockedResource lockedResult = LockedResource.obtain(transformed); + deferredEncodeManager.init(key, encoder, lockedResult); + result = lockedResult; + } + return result; + } + private final class DecodeCallback implements DecodePath.DecodeCallback { private final DataSource dataSource; @@ -532,66 +587,7 @@ private final class DecodeCallback implements DecodePath.DecodeCallback { @Override public Resource onResourceDecoded(Resource decoded) { - Class resourceSubClass = getResourceClass(decoded); - Transformation appliedTransformation = null; - Resource transformed = decoded; - if (dataSource != DataSource.RESOURCE_DISK_CACHE) { - appliedTransformation = decodeHelper.getTransformation(resourceSubClass); - transformed = appliedTransformation.transform(glideContext, decoded, width, height); - } - // TODO: Make this the responsibility of the Transformation. - if (!decoded.equals(transformed)) { - decoded.recycle(); - } - - final EncodeStrategy encodeStrategy; - final ResourceEncoder encoder; - if (decodeHelper.isResourceEncoderAvailable(transformed)) { - encoder = decodeHelper.getResultEncoder(transformed); - encodeStrategy = encoder.getEncodeStrategy(options); - } else { - encoder = null; - encodeStrategy = EncodeStrategy.NONE; - } - - Resource result = transformed; - boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey); - if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource, - encodeStrategy)) { - if (encoder == null) { - throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass()); - } - final Key key; - switch (encodeStrategy) { - case SOURCE: - key = new DataCacheKey(currentSourceKey, signature); - break; - case TRANSFORMED: - key = - new ResourceCacheKey( - decodeHelper.getArrayPool(), - currentSourceKey, - signature, - width, - height, - appliedTransformation, - resourceSubClass, - options); - break; - default: - throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy); - } - - LockedResource lockedResult = LockedResource.obtain(transformed); - deferredEncodeManager.init(key, encoder, lockedResult); - result = lockedResult; - } - return result; - } - - @SuppressWarnings("unchecked") - private Class getResourceClass(Resource resource) { - return (Class) resource.get().getClass(); + return DecodeJob.this.onResourceDecoded(dataSource, decoded); } } 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 4431689fde..a5b89f53dd 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 @@ -111,7 +111,7 @@ static String getBitmapString(int size) { static class KeyPool extends BaseKeyPool { public Key get(int size) { - Key result = get(); + Key result = super.get(); result.init(size); return result; } @@ -149,6 +149,8 @@ public int hashCode() { return size; } + // PMD.AccessorMethodGeneration: https://github.com/pmd/pmd/issues/807 + @SuppressWarnings("PMD.AccessorMethodGeneration") @Override public String toString() { return getBitmapString(size); diff --git a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java index b697ca5568..b9b7211a18 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/cache/MemorySizeCalculator.java @@ -9,6 +9,7 @@ import android.util.DisplayMetrics; import android.util.Log; import com.bumptech.glide.util.Preconditions; +import com.bumptech.glide.util.Synthetic; /** * A calculator that tries to intelligently determine cache sizes for a given device based on some @@ -115,7 +116,7 @@ private String toMb(int bytes) { } @TargetApi(Build.VERSION_CODES.KITKAT) - private static boolean isLowMemoryDevice(ActivityManager activityManager) { + @Synthetic static boolean isLowMemoryDevice(ActivityManager activityManager) { // Explicitly check with an if statement, on some devices both parts of boolean expressions // can be evaluated even if we'd normally expect a short circuit. //noinspection SimplifiableIfStatement @@ -149,17 +150,17 @@ public static final class Builder { // 4MB. static final int ARRAY_POOL_SIZE_BYTES = 4 * 1024 * 1024; - private final Context context; + @Synthetic final Context context; - // Modifiable for testing. - private ActivityManager activityManager; - private ScreenDimensions screenDimensions; + // Modifiable (non-final) for testing. + @Synthetic ActivityManager activityManager; + @Synthetic ScreenDimensions screenDimensions; - private float memoryCacheScreens = MEMORY_CACHE_TARGET_SCREENS; - private float bitmapPoolScreens = BITMAP_POOL_TARGET_SCREENS; - private float maxSizeMultiplier = MAX_SIZE_MULTIPLIER; - private float lowMemoryMaxSizeMultiplier = LOW_MEMORY_MAX_SIZE_MULTIPLIER; - private int arrayPoolSizeBytes = ARRAY_POOL_SIZE_BYTES; + @Synthetic float memoryCacheScreens = MEMORY_CACHE_TARGET_SCREENS; + @Synthetic float bitmapPoolScreens = BITMAP_POOL_TARGET_SCREENS; + @Synthetic float maxSizeMultiplier = MAX_SIZE_MULTIPLIER; + @Synthetic float lowMemoryMaxSizeMultiplier = LOW_MEMORY_MAX_SIZE_MULTIPLIER; + @Synthetic int arrayPoolSizeBytes = ARRAY_POOL_SIZE_BYTES; public Builder(Context context) { this.context = context; diff --git a/library/src/main/java/com/bumptech/glide/load/engine/executor/GlideExecutor.java b/library/src/main/java/com/bumptech/glide/load/engine/executor/GlideExecutor.java index 57fecd8939..7f8845534d 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/executor/GlideExecutor.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/executor/GlideExecutor.java @@ -433,7 +433,8 @@ public synchronized Thread newThread(@NonNull Runnable runnable) { final Thread result = new Thread(runnable, "glide-" + name + "-thread-" + threadNum) { @Override public void run() { - android.os.Process.setThreadPriority(DEFAULT_PRIORITY); + // why PMD suppression is needed: https://github.com/pmd/pmd/issues/808 + android.os.Process.setThreadPriority(DEFAULT_PRIORITY); //NOPMD AccessorMethodGeneration if (preventNetworkOperations) { StrictMode.setThreadPolicy( new ThreadPolicy.Builder() diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/DrawableTransformation.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/DrawableTransformation.java index bcd23762d3..9275e34297 100644 --- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/DrawableTransformation.java +++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/DrawableTransformation.java @@ -69,7 +69,7 @@ public Resource transform(@NonNull Context context, } } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "PMD.UnnecessaryLocalBeforeReturn"}) private Resource newDrawableResource( Context context, Resource transformed) { Resource result = diff --git a/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java b/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java index b137956580..23fc35355e 100644 --- a/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java +++ b/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java @@ -28,8 +28,7 @@ public class RequestManagerFragment extends Fragment { private final ActivityFragmentLifecycle lifecycle; private final RequestManagerTreeNode requestManagerTreeNode = new FragmentRequestManagerTreeNode(); - private final HashSet childRequestManagerFragments = - new HashSet<>(); + private final Set childRequestManagerFragments = new HashSet<>(); @Nullable private RequestManager requestManager; @Nullable private RequestManagerFragment rootRequestManagerFragment; @@ -86,7 +85,7 @@ private void removeChildRequestManagerFragment(RequestManagerFragment child) { * our parent is the fragment that we are annotating). */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - private Set getDescendantRequestManagerFragments() { + @Synthetic Set getDescendantRequestManagerFragments() { if (this.equals(rootRequestManagerFragment)) { return Collections.unmodifiableSet(childRequestManagerFragments); } else if (rootRequestManagerFragment == null @@ -95,7 +94,7 @@ private Set getDescendantRequestManagerFragments() { // so just return an empty set. return Collections.emptySet(); } else { - HashSet descendants = new HashSet<>(); + Set descendants = new HashSet<>(); for (RequestManagerFragment fragment : rootRequestManagerFragment .getDescendantRequestManagerFragments()) { if (isDescendant(fragment.getParentFragment())) { @@ -212,7 +211,7 @@ private class FragmentRequestManagerTreeNode implements RequestManagerTreeNode { @Override public Set getDescendants() { Set descendantFragments = getDescendantRequestManagerFragments(); - HashSet descendants = new HashSet<>(descendantFragments.size()); + Set descendants = new HashSet<>(descendantFragments.size()); for (RequestManagerFragment fragment : descendantFragments) { if (fragment.getRequestManager() != null) { descendants.add(fragment.getRequestManager()); 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 1307a34c15..a44bb02e22 100644 --- a/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java +++ b/library/src/main/java/com/bumptech/glide/manager/SupportRequestManagerFragment.java @@ -27,8 +27,7 @@ public class SupportRequestManagerFragment extends Fragment { private final ActivityFragmentLifecycle lifecycle; private final RequestManagerTreeNode requestManagerTreeNode = new SupportFragmentRequestManagerTreeNode(); - private final HashSet childRequestManagerFragments = - new HashSet<>(); + private final Set childRequestManagerFragments = new HashSet<>(); @Nullable private SupportRequestManagerFragment rootRequestManagerFragment; @Nullable private RequestManager requestManager; @@ -86,13 +85,13 @@ private void removeChildRequestManagerFragment(SupportRequestManagerFragment chi * Returns the set of fragments that this RequestManagerFragment's parent is a parent to. (i.e. * our parent is the fragment that we are annotating). */ - private Set getDescendantRequestManagerFragments() { + @Synthetic Set getDescendantRequestManagerFragments() { if (rootRequestManagerFragment == null) { return Collections.emptySet(); } else if (this.equals(rootRequestManagerFragment)) { return Collections.unmodifiableSet(childRequestManagerFragments); } else { - HashSet descendants = new HashSet<>(); + Set descendants = new HashSet<>(); for (SupportRequestManagerFragment fragment : rootRequestManagerFragment .getDescendantRequestManagerFragments()) { if (isDescendant(fragment.getParentFragmentUsingHint())) { @@ -203,7 +202,7 @@ private class SupportFragmentRequestManagerTreeNode implements RequestManagerTre public Set getDescendants() { Set descendantFragments = getDescendantRequestManagerFragments(); - HashSet descendants = new HashSet<>(descendantFragments.size()); + Set descendants = new HashSet<>(descendantFragments.size()); for (SupportRequestManagerFragment fragment : descendantFragments) { if (fragment.getRequestManager() != null) { descendants.add(fragment.getRequestManager()); 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 90284f80c4..903522fc07 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 @@ -8,6 +8,7 @@ import android.support.annotation.Nullable; import com.bumptech.glide.RequestManager; import com.bumptech.glide.request.transition.Transition; +import com.bumptech.glide.util.Synthetic; /** * A one time use {@link com.bumptech.glide.request.target.Target} class that loads a resource into @@ -51,7 +52,8 @@ public void onResourceReady(@NonNull Z resource, @Nullable Transition HANDLER.obtainMessage(MESSAGE_CLEAR, this).sendToTarget(); } - private void clear() { + @SuppressWarnings("WeakerAccess") + @Synthetic void clear() { requestManager.clear(this); } } 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 e017e209b3..be500d87ca 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 @@ -112,26 +112,36 @@ public final ViewTarget clearOnDetach() { attachStateListener = new OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { - Request request = getRequest(); - if (request != null && request.isPaused()) { - request.begin(); - } + resumeMyRequest(); } @Override public void onViewDetachedFromWindow(View v) { - Request request = getRequest(); - if (request != null && !request.isCancelled() && !request.isPaused()) { - isClearedByUs = true; - request.pause(); - isClearedByUs = false; - } + pauseMyRequest(); } }; maybeAddAttachStateListener(); return this; } + @SuppressWarnings("WeakerAccess") + @Synthetic void resumeMyRequest() { + Request request = getRequest(); + if (request != null && request.isPaused()) { + request.begin(); + } + } + + @SuppressWarnings("WeakerAccess") + @Synthetic void pauseMyRequest() { + Request request = getRequest(); + if (request != null && !request.isCancelled() && !request.isPaused()) { + isClearedByUs = true; + request.pause(); + isClearedByUs = false; + } + } + /** * Indicates that Glide should always wait for any pending layout pass before checking * for the size an {@link View}. @@ -151,6 +161,7 @@ public void onViewDetachedFromWindow(View v) { * still be used instead of the {@link View}'s dimensions even if this method is called. This * parameter is a fallback only. */ + @SuppressWarnings("WeakerAccess") @NonNull public final ViewTarget waitForLayout() { sizeDeterminer.waitForLayout = true; @@ -319,7 +330,7 @@ static final class SizeDeterminer { static Integer maxDisplayLength; private final View view; private final List cbs = new ArrayList<>(); - private boolean waitForLayout; + @Synthetic boolean waitForLayout; @Nullable private SizeDeterminerLayoutListener layoutListener; diff --git a/library/src/test/java/com/bumptech/glide/load/engine/cache/DiskLruCacheWrapperTest.java b/library/src/test/java/com/bumptech/glide/load/engine/cache/DiskLruCacheWrapperTest.java index 06e2b7c126..24a1098e77 100644 --- a/library/src/test/java/com/bumptech/glide/load/engine/cache/DiskLruCacheWrapperTest.java +++ b/library/src/test/java/com/bumptech/glide/load/engine/cache/DiskLruCacheWrapperTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.mock; import android.support.annotation.NonNull; @@ -53,6 +54,8 @@ private static void deleteRecursive(File file) { } } } + // GC before delete() to release files on Windows (https://stackoverflow.com/a/4213208/253468) + System.gc(); if (!file.delete() && file.exists()) { throw new RuntimeException("Failed to delete: " + file); } @@ -139,6 +142,7 @@ public boolean write(@NonNull File file) { // Tests #2465. @Test public void clearDiskCache_afterOpeningDiskCache_andDeleteDirectoryOutsideGlide_doesNotThrow() { + assumeTrue("A file handle is likely open, so cannot delete dir", !Util.isWindows()); DiskCache cache = DiskLruCacheWrapper.create(dir, 1024 * 1024); cache.get(mock(Key.class)); deleteRecursive(dir); @@ -148,6 +152,7 @@ public void clearDiskCache_afterOpeningDiskCache_andDeleteDirectoryOutsideGlide_ // Tests #2465. @Test public void get_afterDeleteDirectoryOutsideGlideAndClose_doesNotThrow() { + assumeTrue("A file handle is likely open, so cannot delete dir", !Util.isWindows()); DiskCache cache = DiskLruCacheWrapper.create(dir, 1024 * 1024); cache.get(mock(Key.class)); deleteRecursive(dir); diff --git a/library/src/test/java/com/bumptech/glide/load/model/StreamEncoderTest.java b/library/src/test/java/com/bumptech/glide/load/model/StreamEncoderTest.java index f266fb214e..07dd655dc2 100644 --- a/library/src/test/java/com/bumptech/glide/load/model/StreamEncoderTest.java +++ b/library/src/test/java/com/bumptech/glide/load/model/StreamEncoderTest.java @@ -30,6 +30,8 @@ public void setUp() { @After public void tearDown() { + // GC before delete() to release files on Windows (https://stackoverflow.com/a/4213208/253468) + System.gc(); if (!file.delete()) { throw new IllegalStateException("Failed to delete: " + file); } diff --git a/library/src/test/java/com/bumptech/glide/load/model/StringLoaderTest.java b/library/src/test/java/com/bumptech/glide/load/model/StringLoaderTest.java index f772ad3ea5..b6554eabff 100644 --- a/library/src/test/java/com/bumptech/glide/load/model/StringLoaderTest.java +++ b/library/src/test/java/com/bumptech/glide/load/model/StringLoaderTest.java @@ -15,7 +15,6 @@ import com.bumptech.glide.tests.Util; import com.bumptech.glide.util.Preconditions; import java.io.File; -import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +41,7 @@ public class StringLoaderTest { private Options options; @Before - public void setUp() throws Exception { + public void setUp() { MockitoAnnotations.initMocks(this); options = new Options(); @@ -51,9 +50,9 @@ public void setUp() throws Exception { } @Test - public void testHandlesPaths() throws IOException { - // TODO on windows it will fail with schema being the drive letter (C:\... -> C) - assumeTrue(!Util.isWindows()); + public void testHandlesPaths() { + // TODO fix drive letter parsing somehow + assumeTrue("it will fail with schema being the drive letter (C:\\... -> C)", !Util.isWindows()); File f = RuntimeEnvironment.application.getCacheDir(); Uri expected = Uri.fromFile(f); @@ -69,8 +68,6 @@ public void testHandlesPaths() throws IOException { @Test public void testCanHandleComplexFilePaths() { - assumeTrue(!Util.isWindows()); - String testPath = "/storage/emulated/0/DCIM/Camera/IMG_20140520_100001:nopm:.jpg,mimeType=image/jpeg," + "2448x3264,orientation=0,date=Tue"; @@ -86,7 +83,7 @@ public void testCanHandleComplexFilePaths() { } @Test - public void testHandlesFileUris() throws IOException { + public void testHandlesFileUris() { File f = RuntimeEnvironment.application.getCacheDir(); Uri expected = Uri.fromFile(f); @@ -101,7 +98,7 @@ public void testHandlesFileUris() throws IOException { } @Test - public void testHandlesResourceUris() throws IOException { + public void testHandlesResourceUris() { Uri resourceUri = Uri.parse("android.resource://com.bumptech.glide.tests/raw/ic_launcher"); when(uriLoader.buildLoadData(eq(resourceUri), eq(IMAGE_SIDE), eq(IMAGE_SIDE), eq(options))) diff --git a/library/src/test/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoderTest.java b/library/src/test/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoderTest.java index 06f071de71..9db7c49946 100644 --- a/library/src/test/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoderTest.java +++ b/library/src/test/java/com/bumptech/glide/load/resource/bitmap/BitmapEncoderTest.java @@ -126,6 +126,8 @@ String encode() throws IOException { } void tearDown() { + // GC before delete() to release files on Windows (https://stackoverflow.com/a/4213208/253468) + System.gc(); if (file.exists() && !file.delete()) { throw new IllegalStateException("Failed to delete: " + file); }