/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.backends.pipeline;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import com.facebook.common.internal.Objects;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.internal.Supplier;
import com.facebook.common.logging.FLog;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawable.base.DrawableWithCaches;
import com.facebook.drawee.components.DeferredReleaser;
import com.facebook.drawee.controller.AbstractDraweeController;
import com.facebook.imagepipeline.animated.factory.AnimatedDrawableFactory;
import com.facebook.imagepipeline.image.CloseableAnimatedImage;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.ImageInfo;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
/**
* Drawee controller that bridges the image pipeline with {@link SettableDraweeHierarchy}.
* <p>
* The hierarchy's actual image is set to the image(s) obtained by the provided data source.
* The data source is automatically obtained and closed based on attach / detach calls.
*/
public class PipelineDraweeController
extends AbstractDraweeController<CloseableReference<CloseableImage>, ImageInfo> {
private static final Class<?> TAG = PipelineDraweeController.class;
// Components
private final Resources mResources;
private final AnimatedDrawableFactory mAnimatedDrawableFactory;
// Constant state (non-final because controllers can be reused)
private Supplier<DataSource<CloseableReference<CloseableImage>>> mDataSourceSupplier;
public PipelineDraweeController(
Resources resources,
DeferredReleaser deferredReleaser,
AnimatedDrawableFactory animatedDrawableFactory,
Executor uiThreadExecutor,
Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
String id,
Object callerContext) {
super(deferredReleaser, uiThreadExecutor, id, callerContext);
mResources = resources;
mAnimatedDrawableFactory = animatedDrawableFactory;
init(dataSourceSupplier);
}
/**
* Initializes this controller with the new data source supplier, id and caller context.
* This allows for reusing of the existing controller instead of instantiating a new one.
* This method should be called when the controller is in detached state.
* @param dataSourceSupplier data source supplier
* @param id unique id for this controller
* @param callerContext tag and context for this controller
*/
public void initialize(
Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
String id,
Object callerContext) {
super.initialize(id, callerContext);
init(dataSourceSupplier);
}
private void init(Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier) {
mDataSourceSupplier = dataSourceSupplier;
}
protected Resources getResources() {
return mResources;
}
@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSource() {
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(TAG, "controller %x: getDataSource", System.identityHashCode(this));
}
return mDataSourceSupplier.get();
}
@Override
protected Drawable createDrawable(CloseableReference<CloseableImage> image) {
Preconditions.checkState(CloseableReference.isValid(image));
CloseableImage closeableImage = image.get();
if (closeableImage instanceof CloseableStaticBitmap) {
CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage;
return new BitmapDrawable(mResources, closeableStaticBitmap.getUnderlyingBitmap());
} else if (closeableImage instanceof CloseableAnimatedImage) {
return mAnimatedDrawableFactory.create(
((CloseableAnimatedImage) closeableImage).getImageResult());
} else {
throw new UnsupportedOperationException("Unrecognized image class: " + closeableImage);
}
}
@Override
protected ImageInfo getImageInfo(CloseableReference<CloseableImage> image) {
Preconditions.checkState(CloseableReference.isValid(image));
return image.get();
}
@Override
protected int getImageHash(@Nullable CloseableReference<CloseableImage> image) {
return (image != null) ? image.getValueHash() : 0;
}
@Override
protected void releaseImage(@Nullable CloseableReference<CloseableImage> image) {
CloseableReference.closeSafely(image);
}
@Override
protected void releaseDrawable(@Nullable Drawable drawable) {
if (drawable instanceof DrawableWithCaches) {
((DrawableWithCaches) drawable).dropCaches();
}
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("super", super.toString())
.add("dataSourceSupplier", mDataSourceSupplier)
.toString();
}
}