Skip to content

Commit

Permalink
Include day/night mode in resource id cache keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
sjudd committed Aug 14, 2019
1 parent 502ba75 commit 1b391c4
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 9 deletions.
18 changes: 9 additions & 9 deletions library/src/main/java/com/bumptech/glide/RequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import com.bumptech.glide.request.target.PreloadTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.target.ViewTarget;
import com.bumptech.glide.signature.ApplicationVersionSignature;
import com.bumptech.glide.signature.AndroidResourceSignature;
import com.bumptech.glide.util.Executors;
import com.bumptech.glide.util.Preconditions;
import com.bumptech.glide.util.Synthetic;
Expand Down Expand Up @@ -495,12 +495,12 @@ public RequestBuilder<TranscodeType> load(@Nullable File file) {
* load the image represented by the given {@link Integer} resource id. Defaults to {@link
* com.bumptech.glide.load.model.ResourceLoader} to load resource id models.
*
* <p>By default this method adds a version code based signature to the cache key used to cache
* this resource in Glide. This signature is sufficient to guarantee that end users will see the
* most up to date versions of your Drawables, but during development if you do not increment your
* version code before each install and you replace a Drawable with different data without
* changing the Drawable name, you may see inconsistent cached data. To get around this, consider
* using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} via {@link
* <p>By default this method adds a version code and night mode based signature to the cache key
* used to cache this resource in Glide. This signature is sufficient to guarantee that end users
* will see the most up to date versions of your Drawables, but during development if you do not
* increment your version code before each install and you replace a Drawable with different data
* without changing the Drawable name, you may see inconsistent cached data. To get around this,
* consider using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} via {@link
* RequestOptions#diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy)} during
* development, and re-enabling the default {@link
* com.bumptech.glide.load.engine.DiskCacheStrategy#RESOURCE} for release builds.
Expand All @@ -519,13 +519,13 @@ public RequestBuilder<TranscodeType> load(@Nullable File file) {
* caution for non-{@link Bitmap} {@link Drawable}s.
*
* @see #load(Integer)
* @see com.bumptech.glide.signature.ApplicationVersionSignature
* @see com.bumptech.glide.signature.AndroidResourceSignature
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
return loadGeneric(resourceId).apply(signatureOf(AndroidResourceSignature.obtain(context)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.bumptech.glide.signature;

import android.content.Context;
import android.content.res.Configuration;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.util.Util;
import java.nio.ByteBuffer;
import java.security.MessageDigest;

public final class AndroidResourceSignature implements Key {

private final int nightMode;
private final Key applicationVersion;

@NonNull
public static Key obtain(@NonNull Context context) {
Key signature = ApplicationVersionSignature.obtain(context);
int nightMode =
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
return new AndroidResourceSignature(nightMode, signature);
}

private AndroidResourceSignature(int nightMode, Key applicationVersion) {
this.nightMode = nightMode;
this.applicationVersion = applicationVersion;
}

@Override
public boolean equals(Object o) {
if (o instanceof AndroidResourceSignature) {
AndroidResourceSignature that = (AndroidResourceSignature) o;
return nightMode == that.nightMode && applicationVersion.equals(that.applicationVersion);
}
return false;
}

@Override
public int hashCode() {
return Util.hashCode(applicationVersion, nightMode);
}

@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
applicationVersion.updateDiskCacheKey(messageDigest);
byte[] nightModeData = ByteBuffer.allocate(4).putInt(nightMode).array();
messageDigest.update(nightModeData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.bumptech.glide.signature;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import androidx.test.core.app.ApplicationProvider;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.tests.KeyTester;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = 28)
public class AndroidResourceSignatureTest {
@Rule public final KeyTester keyTester = new KeyTester();
private Context context;

@Before
public void setUp() {
context = ApplicationProvider.getApplicationContext();
}

@Test
public void testCanGetKeyForSignature() {
Key key = AndroidResourceSignature.obtain(context);
assertNotNull(key);
}

@Test
public void testKeyForSignatureIsTheSameAcrossCallsInTheSamePackage() {
keyTester
.addEquivalenceGroup(
AndroidResourceSignature.obtain(context), AndroidResourceSignature.obtain(context))
.addEquivalenceGroup(new ObjectKey("test"))
.addRegressionTest(
ApplicationVersionSignature.obtain(context),
"5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9")
.test();
}

@Test
public void testKeyForSignatureDiffersByNightMode() {
RuntimeEnvironment.setQualifiers("notnight");
keyTester
.addEquivalenceGroup(
AndroidResourceSignature.obtain(context), AndroidResourceSignature.obtain(context))
.addRegressionTest(
AndroidResourceSignature.obtain(context),
"265d958bdae1bea56e45cc31f4db672c22893b66fef85617bbc78742bd912207");
RuntimeEnvironment.setQualifiers("night");
keyTester
.addEquivalenceGroup(
AndroidResourceSignature.obtain(context), AndroidResourceSignature.obtain(context))
.addRegressionTest(
AndroidResourceSignature.obtain(context),
"96c9b8d5bb071ccd67df50cd9a0059640ebd02db78d08f07611ec145ce44a638");

keyTester.test();
}

@Test
public void testUnresolvablePackageInfo() throws NameNotFoundException {
Context context = mock(Context.class, Answers.RETURNS_DEEP_STUBS);
String packageName = "my.package";
when(context.getPackageName()).thenReturn(packageName);
when(context.getPackageManager().getPackageInfo(packageName, 0))
.thenThrow(new NameNotFoundException("test"));

Key key = AndroidResourceSignature.obtain(context);

assertNotNull(key);
}

@Test
public void testMissingPackageInfo() throws NameNotFoundException {
Context context = mock(Context.class, Answers.RETURNS_DEEP_STUBS);
String packageName = "my.package";
when(context.getPackageName()).thenReturn(packageName);
when(context.getPackageManager().getPackageInfo(packageName, 0)).thenReturn(null);

Key key = AndroidResourceSignature.obtain(context);

assertNotNull(key);
}
}

0 comments on commit 1b391c4

Please sign in to comment.