diff --git a/gradle.properties b/gradle.properties index c4404c520e..fa0fa84343 100644 --- a/gradle.properties +++ b/gradle.properties @@ -64,6 +64,7 @@ ANDROID_X_FRAGMENT_VERSION=1.3.6 ANDROID_X_RECYCLERVIEW_VERSION=1.2.1 ANDROID_X_TEST_CORE_VERSION=1.4.0 ANDROID_X_TEST_ESPRESSO_VERSION=3.4.0 +ANDROID_X_FRAGMENT_TESTING_VERSION=1.5.0 ANDROID_X_TEST_JUNIT_VERSION=1.1.3 ANDROID_X_TEST_RULES_VERSION=1.4.0 ANDROID_X_TEST_RUNNER_VERSION=1.4.0 @@ -74,6 +75,8 @@ ANDROID_X_VECTOR_DRAWABLE_ANIMATED_VERSION=1.1.0 ANDROID_X_CORE_KTX_VERSION=1.8.0 ANDROID_X_LIFECYCLE_KTX_VERSION=2.4.1 +ANDROID_SUPPORT_MULTIDEX_VERSION=1.0.3 + # org.jetbrains versions JETBRAINS_KOTLINX_COROUTINES_VERSION=1.6.4 JETBRAINS_KOTLINX_COROUTINES_TEST_VERSION=1.6.4 diff --git a/instrumentation/build.gradle b/instrumentation/build.gradle index e3d8ff943d..c20ab4b8ba 100644 --- a/instrumentation/build.gradle +++ b/instrumentation/build.gradle @@ -6,24 +6,28 @@ tasks.whenTaskAdded { task -> apply plugin: 'com.android.application' dependencies { - debugImplementation 'androidx.fragment:fragment-testing:1.5.0' annotationProcessor project(":annotation:compiler") implementation project(":library") + implementation "com.android.support:multidex:$ANDROID_SUPPORT_MULTIDEX_VERSION" + implementation "androidx.appcompat:appcompat:$ANDROID_X_APPCOMPAT_VERSION" androidTestImplementation project(':library') androidTestImplementation project(':mocks') androidTestImplementation project(':testutil') - androidTestImplementation "org.mockito:mockito-android:${MOCKITO_ANDROID_VERSION}" - androidTestImplementation "androidx.test.ext:junit:${ANDROID_X_TEST_JUNIT_VERSION}" - androidTestImplementation "androidx.test:rules:${ANDROID_X_TEST_RULES_VERSION}" - androidTestImplementation "androidx.test:core:${ANDROID_X_TEST_CORE_VERSION}" - androidTestImplementation "com.google.truth:truth:${TRUTH_VERSION}" - androidTestImplementation "junit:junit:${JUNIT_VERSION}" - androidTestImplementation "androidx.exifinterface:exifinterface:${ANDROID_X_EXIF_INTERFACE_VERSION}" + androidTestImplementation "org.mockito:mockito-android:$MOCKITO_ANDROID_VERSION" + androidTestImplementation "androidx.test.ext:junit:$ANDROID_X_TEST_JUNIT_VERSION" + androidTestImplementation "androidx.test:rules:$ANDROID_X_TEST_RULES_VERSION" + androidTestImplementation "androidx.test:core:$ANDROID_X_TEST_CORE_VERSION" + androidTestImplementation "androidx.test.espresso.idling:idling-concurrent:$ANDROID_X_TEST_ESPRESSO_VERSION" + androidTestImplementation "androidx.test.espresso:espresso-core:$ANDROID_X_TEST_ESPRESSO_VERSION" + androidTestImplementation "androidx.fragment:fragment-testing:$ANDROID_X_FRAGMENT_TESTING_VERSION" + androidTestImplementation "com.google.truth:truth:$TRUTH_VERSION" + androidTestImplementation "junit:junit:$JUNIT_VERSION" + androidTestImplementation "androidx.exifinterface:exifinterface:$ANDROID_X_EXIF_INTERFACE_VERSION" // Not totally clear why this is required, but it seems to be missing when tests are run on // 4.1.2 and 4.2.0 emulators. - androidTestImplementation "com.google.code.findbugs:jsr305:${JSR_305_VERSION}" + androidTestImplementation "com.google.code.findbugs:jsr305:$JSR_305_VERSION" } android { @@ -36,11 +40,18 @@ android { versionCode 1 versionName '1.0' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true } compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } + + buildTypes { + debug { + isDefault = true + } + } } diff --git a/instrumentation/src/androidTest/java/com/bumptech/glide/DarkModeTest.java b/instrumentation/src/androidTest/java/com/bumptech/glide/DarkModeTest.java new file mode 100644 index 0000000000..94dd8e856e --- /dev/null +++ b/instrumentation/src/androidTest/java/com/bumptech/glide/DarkModeTest.java @@ -0,0 +1,329 @@ +package com.bumptech.glide; + +import static androidx.test.espresso.Espresso.onIdle; +import static com.bumptech.glide.testutil.BitmapSubject.assertThat; +import static org.junit.Assume.assumeTrue; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.test.core.app.ActivityScenario; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.bumptech.glide.instrumentation.R; +import com.bumptech.glide.load.engine.executor.IdlingGlideRule; +import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.test.ForceDarkOrLightModeActivity; +import com.google.common.base.Function; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class DarkModeTest { + private final Context context = ApplicationProvider.getApplicationContext(); + + @Rule + public final IdlingGlideRule idlingGlideRule = + IdlingGlideRule.newGlideRule(glideBuilder -> glideBuilder); + + @Before + public void before() { + // Dark mode wasn't supported prior to Q. + assumeTrue(VERSION.SDK_INT >= VERSION_CODES.Q); + } + + // TODO(judds): The way we handle data loads in the background for resoures is not Theme + // compatible. In particular, the theme gets lost when we convert the resource id to a Uri and + // we don't use the user provided theme. While ResourceBitmapDecoder and ResourceDrawableDecoder + // will use the theme, they're not called for most resource ids because those instead go through + // UriLoader, which just calls contentResolver.openStream. This isn't sufficient to use to theme. + // We could: + // 1. Avoid using contentResolver for android resource Uris and use ResourceBitmapDecoder instead. + // 2. #1 but only for non-raw resources which won't be themed + // 3. Always use Theme.getResources().openRawResource, which, despite the name, works find on + // Drawables and takes into account the theme. + // In addition we'd also need to consider just passing through the theme always, rather than only + // when it's specified by the user. Otherwise whether or not we'd obey dark mode would depend on + // the user also providing the theme from the activity. We'd want to try to make sure that doesn't + // leak the Activity. + // TODO(judds): Add tests for Fragments for load(). + @Test + public void load_withDarkModeActivity_usesLightModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_light, + activity -> Glide.with(activity).load(R.drawable.dog).override(Target.SIZE_ORIGINAL)); + } + + @Test + public void load_withDarkModeFragment_usesLightModeDrawable() { + runFragmentTest( + darkModeActivity(), + R.raw.dog_light, + fragment -> Glide.with(fragment).load(R.drawable.dog).override(Target.SIZE_ORIGINAL)); + } + + @Test + public void load_withLightModeActivity_usesLightModeDrawable() { + runActivityTest( + lightModeActivity(), + R.raw.dog_light, + activity -> Glide.with(activity).load(R.drawable.dog).override(Target.SIZE_ORIGINAL)); + } + + @Test + public void load_withLightModeFragment_usesLightModeDrawable() { + runFragmentTest( + lightModeActivity(), + R.raw.dog_light, + fragment -> Glide.with(fragment).load(R.drawable.dog).override(Target.SIZE_ORIGINAL)); + } + + @Ignore("We do not asynchronously load resources correctly") + @Test + public void load_withDarkModeActivity_darkModeTheme_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + activity -> + Glide.with(activity) + .load(R.drawable.dog) + .override(Target.SIZE_ORIGINAL) + .theme(activity.getTheme())); + } + + @Ignore("We do not asynchronously load resources correctly") + @Test + public void load_withDarkModeFragment_darkModeTheme_usesDarkModeDrawable() { + runFragmentTest( + darkModeActivity(), + R.raw.dog_dark, + fragment -> + Glide.with(fragment) + .load(R.drawable.dog) + .override(Target.SIZE_ORIGINAL) + .theme(fragment.requireActivity().getTheme())); + } + + @Test + public void load_withLightModeActivity_lightModeTheme_usesLightModeDrawable() { + runActivityTest( + lightModeActivity(), + R.raw.dog_light, + activity -> + Glide.with(activity) + .load(R.drawable.dog) + .override(Target.SIZE_ORIGINAL) + .theme(activity.getTheme())); + } + + @Test + public void placeholder_withDarkModeActivity_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withDarkModeFragment_usesDarkModeDrawable() { + runFragmentTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).placeholder(R.drawable.dog)); + } + + @Test + public void error_withDarkModeActivity_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).error(R.drawable.dog)); + } + + @Test + public void error_withDarkModeFragment_usesDarkModeDrawable() { + runFragmentTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).error(R.drawable.dog)); + } + + @Test + public void fallback_withDarkModeActivity_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).fallback(R.drawable.dog)); + } + + @Test + public void fallback_withDarkModeFragment_usesDarkModeDrawable() { + runFragmentTest( + darkModeActivity(), + R.raw.dog_dark, + input -> Glide.with(input).load((Object) null).fallback(R.drawable.dog)); + } + + @Test + public void placeholder_withLightModeActivity_usesLightModeDrawable() { + runActivityTest( + lightModeActivity(), + R.raw.dog_light, + input -> Glide.with(input).load((Object) null).placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withLightModeFragment_usesLightModeDrawable() { + runFragmentTest( + lightModeActivity(), + R.raw.dog_light, + input -> Glide.with(input).load((Object) null).placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withDarkModeActivityAndTheme_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + input -> + Glide.with(input) + .load((Object) null) + .theme(input.getTheme()) + .placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withLightModeActivityAndTheme_usesLightModeDrawable() { + runActivityTest( + lightModeActivity(), + R.raw.dog_light, + input -> + Glide.with(input) + .load((Object) null) + .theme(input.getTheme()) + .placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withApplicationContext_darkTheme_usesDarkModeDrawable() { + runActivityTest( + darkModeActivity(), + R.raw.dog_dark, + input -> + Glide.with(input.getApplicationContext()) + .load((Object) null) + .theme(input.getTheme()) + .placeholder(R.drawable.dog)); + } + + @Test + public void placeholder_withApplicationContext_lightTheme_usesLightModeDrawable() { + runActivityTest( + lightModeActivity(), + R.raw.dog_light, + input -> + Glide.with(input.getApplicationContext()) + .load((Object) null) + .theme(input.getTheme()) + .placeholder(R.drawable.dog)); + } + + private ActivityScenario darkModeActivity() { + return ActivityScenario.launch(ForceDarkOrLightModeActivity.forceDarkMode(context)); + } + + private ActivityScenario lightModeActivity() { + return ActivityScenario.launch(ForceDarkOrLightModeActivity.forceLightMode(context)); + } + + private static void runFragmentTest( + ActivityScenario scenario, + int expectedResource, + Function> requestBuilder) { + try (scenario) { + scenario.onActivity( + activity -> { + ImageViewFragment fragment = new ImageViewFragment(); + activity + .getSupportFragmentManager() + .beginTransaction() + .add(R.id.container, fragment) + .commitNowAllowingStateLoss(); + ViewGroup container = findContainer(activity); + ImageView imageView = (ImageView) container.getChildAt(0); + + requestBuilder.apply(fragment).into(imageView); + }); + + assertImageViewContainerChildHasContent(scenario, expectedResource); + } + } + + /** Fragment that displays a single fixed size ImageView. */ + public static final class ImageViewFragment extends Fragment { + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return newFixedSizeImageView(getContext()); + } + } + + private static ImageView newFixedSizeImageView(Context context) { + ImageView imageView = new ImageView(context); + imageView.setLayoutParams(new LayoutParams(200, 200)); + return imageView; + } + + private static void runActivityTest( + ActivityScenario scenario, + int expectedResource, + Function> glideBuilder) { + try (scenario) { + scenario.onActivity( + activity -> { + ViewGroup container = findContainer(activity); + ImageView imageView = newFixedSizeImageView(activity); + container.addView(imageView); + + glideBuilder.apply(activity).into(imageView); + }); + + assertImageViewContainerChildHasContent(scenario, expectedResource); + } + } + + private static void assertImageViewContainerChildHasContent( + ActivityScenario scenario, int expectedResource) { + onIdle(); + scenario.onActivity( + activity -> { + ViewGroup container = findContainer(activity); + ImageView imageView = (ImageView) container.getChildAt(0); + Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); + assertThat(bitmap).sameAs(expectedResource); + }); + } + + private static ViewGroup findContainer(FragmentActivity activity) { + return activity.findViewById(R.id.container); + } +} diff --git a/instrumentation/src/androidTest/java/com/bumptech/glide/load/engine/executor/IdlingGlideRule.java b/instrumentation/src/androidTest/java/com/bumptech/glide/load/engine/executor/IdlingGlideRule.java new file mode 100644 index 0000000000..fae2d2d157 --- /dev/null +++ b/instrumentation/src/androidTest/java/com/bumptech/glide/load/engine/executor/IdlingGlideRule.java @@ -0,0 +1,79 @@ +package com.bumptech.glide.load.engine.executor; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.espresso.IdlingRegistry; +import androidx.test.espresso.idling.concurrent.IdlingThreadPoolExecutor; +import com.bumptech.glide.Glide; +import com.bumptech.glide.GlideBuilder; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.function.UnaryOperator; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** Creates idling executors and registers them with espresso's {@link IdlingRegistry}. */ +public final class IdlingGlideRule implements TestRule { + + private final UnaryOperator additionalOptions; + + public static IdlingGlideRule newGlideRule(UnaryOperator additionalOptions) { + return new IdlingGlideRule(additionalOptions); + } + + private IdlingGlideRule(UnaryOperator additionalOptions) { + this.additionalOptions = additionalOptions; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + IdlingRegistry idlingRegistry = IdlingRegistry.getInstance(); + + IdlingThreadPoolExecutor sourceExecutor = + newIdlingThreadPoolExecutor( + GlideExecutor.DEFAULT_SOURCE_EXECUTOR_NAME, + GlideExecutor.calculateBestThreadCount()); + idlingRegistry.register(sourceExecutor); + IdlingThreadPoolExecutor diskCacheExecutor = + newIdlingThreadPoolExecutor( + GlideExecutor.DEFAULT_DISK_CACHE_EXECUTOR_NAME, + /* poolSize= */ GlideExecutor.DEFAULT_DISK_CACHE_EXECUTOR_THREADS); + idlingRegistry.register(diskCacheExecutor); + IdlingThreadPoolExecutor animationExecutor = + newIdlingThreadPoolExecutor( + GlideExecutor.DEFAULT_ANIMATION_EXECUTOR_NAME, + GlideExecutor.calculateAnimationExecutorThreadCount()); + idlingRegistry.register(animationExecutor); + try { + Glide.init( + ApplicationProvider.getApplicationContext(), + additionalOptions + .apply(new GlideBuilder()) + .setSourceExecutor(new GlideExecutor(sourceExecutor)) + .setDiskCacheExecutor(new GlideExecutor(diskCacheExecutor)) + .setAnimationExecutor(new GlideExecutor(animationExecutor))); + base.evaluate(); + } finally { + idlingRegistry.unregister(sourceExecutor); + idlingRegistry.unregister(diskCacheExecutor); + idlingRegistry.unregister(animationExecutor); + Glide.tearDown(); + } + } + }; + } + + private static IdlingThreadPoolExecutor newIdlingThreadPoolExecutor(String name, int poolSize) { + return new IdlingThreadPoolExecutor( + name, + /* corePoolSize= */ poolSize, + /* maximumPoolSize= */ poolSize, + /* keepAliveTime= */ 1, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(), + Thread::new); + } +} diff --git a/instrumentation/src/main/AndroidManifest.xml b/instrumentation/src/main/AndroidManifest.xml index 63e45240d0..1c9610257a 100644 --- a/instrumentation/src/main/AndroidManifest.xml +++ b/instrumentation/src/main/AndroidManifest.xml @@ -13,5 +13,9 @@ + diff --git a/instrumentation/src/main/java/com/bumptech/glide/test/ForceDarkOrLightModeActivity.java b/instrumentation/src/main/java/com/bumptech/glide/test/ForceDarkOrLightModeActivity.java new file mode 100644 index 0000000000..ebd83d6b58 --- /dev/null +++ b/instrumentation/src/main/java/com/bumptech/glide/test/ForceDarkOrLightModeActivity.java @@ -0,0 +1,41 @@ +package com.bumptech.glide.test; + +import android.content.Context; +import android.content.Intent; +import android.os.Build.VERSION_CODES; +import android.os.Bundle; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; +import com.bumptech.glide.instrumentation.R; +import com.bumptech.glide.util.Preconditions; + +public class ForceDarkOrLightModeActivity extends AppCompatActivity { + private static final int INVALID_MODE = -1; + private static final String ARGS_NIGHT_MODE = "args_night_mode"; + + public static Intent forceLightMode(Context context) { + return newArgs(context, AppCompatDelegate.MODE_NIGHT_NO); + } + + public static Intent forceDarkMode(Context context) { + return newArgs(context, AppCompatDelegate.MODE_NIGHT_YES); + } + + private static Intent newArgs(Context context, int nightMode) { + Intent intent = new Intent(context, ForceDarkOrLightModeActivity.class); + intent.putExtra(ARGS_NIGHT_MODE, nightMode); + return intent; + } + + @RequiresApi(api = VERSION_CODES.JELLY_BEAN_MR1) + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + int modeToForce = getIntent().getExtras().getInt(ARGS_NIGHT_MODE, INVALID_MODE); + Preconditions.checkArgument(modeToForce != INVALID_MODE, "Invalid mode: " + modeToForce); + getDelegate().setLocalNightMode(modeToForce); + setContentView(R.layout.default_fragment_activity); + } +} diff --git a/instrumentation/src/main/res/drawable-night/dog.jpg b/instrumentation/src/main/res/drawable-night/dog.jpg new file mode 100644 index 0000000000..c91c8b2d17 Binary files /dev/null and b/instrumentation/src/main/res/drawable-night/dog.jpg differ diff --git a/instrumentation/src/main/res/drawable/dog.jpg b/instrumentation/src/main/res/drawable/dog.jpg new file mode 100644 index 0000000000..889ba27624 Binary files /dev/null and b/instrumentation/src/main/res/drawable/dog.jpg differ diff --git a/instrumentation/src/main/res/raw/dog_dark.jpg b/instrumentation/src/main/res/raw/dog_dark.jpg new file mode 100644 index 0000000000..c91c8b2d17 Binary files /dev/null and b/instrumentation/src/main/res/raw/dog_dark.jpg differ diff --git a/instrumentation/src/main/res/raw/dog_light.jpg b/instrumentation/src/main/res/raw/dog_light.jpg new file mode 100644 index 0000000000..889ba27624 Binary files /dev/null and b/instrumentation/src/main/res/raw/dog_light.jpg differ 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 84f419a37e..38193cb051 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 @@ -28,19 +28,19 @@ public final class GlideExecutor implements ExecutorService { * The default thread name prefix for executors used to load/decode/transform data not found in * cache. */ - private static final String DEFAULT_SOURCE_EXECUTOR_NAME = "source"; + static final String DEFAULT_SOURCE_EXECUTOR_NAME = "source"; /** * The default thread name prefix for executors used to load/decode/transform data found in * Glide's cache. */ - private static final String DEFAULT_DISK_CACHE_EXECUTOR_NAME = "disk-cache"; + static final String DEFAULT_DISK_CACHE_EXECUTOR_NAME = "disk-cache"; /** * The default thread count for executors used to load/decode/transform data found in Glide's * cache. */ - private static final int DEFAULT_DISK_CACHE_EXECUTOR_THREADS = 1; + static final int DEFAULT_DISK_CACHE_EXECUTOR_THREADS = 1; private static final String TAG = "GlideExecutor"; @@ -50,7 +50,7 @@ public final class GlideExecutor implements ExecutorService { */ private static final String DEFAULT_SOURCE_UNLIMITED_EXECUTOR_NAME = "source-unlimited"; - private static final String DEFAULT_ANIMATION_EXECUTOR_NAME = "animation"; + static final String DEFAULT_ANIMATION_EXECUTOR_NAME = "animation"; /** The default keep alive time for threads in our cached thread pools in milliseconds. */ private static final long KEEP_ALIVE_TIME_MS = TimeUnit.SECONDS.toMillis(10); @@ -190,17 +190,20 @@ public static GlideExecutor newUnlimitedSourceExecutor() { *

Animation executors do not allow network operations on their threads. */ public static GlideExecutor.Builder newAnimationBuilder() { + int maximumPoolSize = calculateAnimationExecutorThreadCount(); + return new GlideExecutor.Builder(/* preventNetworkOperations= */ true) + .setThreadCount(maximumPoolSize) + .setName(DEFAULT_ANIMATION_EXECUTOR_NAME); + } + + static int calculateAnimationExecutorThreadCount() { int bestThreadCount = calculateBestThreadCount(); // We don't want to add a ton of threads running animations in parallel with our source and // disk cache executors. Doing so adds unnecessary CPU load and can also dramatically increase // our maximum memory usage. Typically one thread is sufficient here, but for higher end devices // with more cores, two threads can provide better performance if lots of GIFs are showing at // once. - int maximumPoolSize = bestThreadCount >= 4 ? 2 : 1; - - return new GlideExecutor.Builder(/* preventNetworkOperations= */ true) - .setThreadCount(maximumPoolSize) - .setName(DEFAULT_ANIMATION_EXECUTOR_NAME); + return bestThreadCount >= 4 ? 2 : 1; } /** Shortcut for calling {@link Builder#build()} on {@link #newAnimationBuilder()}. */ diff --git a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java index 839a4bd778..fb3f0579fa 100644 --- a/library/src/main/java/com/bumptech/glide/request/SingleRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/SingleRequest.java @@ -420,7 +420,7 @@ private Drawable getFallbackDrawable() { private Drawable loadDrawable(@DrawableRes int resourceId) { Theme theme = requestOptions.getTheme() != null ? requestOptions.getTheme() : context.getTheme(); - return DrawableDecoderCompat.getDrawable(glideContext, resourceId, theme); + return DrawableDecoderCompat.getDrawable(context, resourceId, theme); } @GuardedBy("requestLock")