/*
* 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.imagepipeline.producers;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import java.util.ArrayList;
import java.util.List;
import com.facebook.imagepipeline.common.Priority;
import com.facebook.imagepipeline.request.ImageRequest;
/**
* ProducerContext that can be cancelled. Exposes low level API to manipulate state of the
* ProducerContext.
*/
public class BaseProducerContext implements ProducerContext {
private final ImageRequest mImageRequest;
private final String mId;
private final ProducerListener mProducerListener;
private final Object mCallerContext;
private final ImageRequest.RequestLevel mLowestPermittedRequestLevel;
@GuardedBy("this")
private boolean mIsPrefetch;
@GuardedBy("this")
private Priority mPriority;
@GuardedBy("this")
private boolean mIsIntermediateResultExpected;
@GuardedBy("this")
private boolean mIsCancelled;
@GuardedBy("this")
private final List<ProducerContextCallbacks> mCallbacks;
public BaseProducerContext(
ImageRequest imageRequest,
String id,
ProducerListener producerListener,
Object callerContext,
ImageRequest.RequestLevel lowestPermittedRequestLevel,
boolean isPrefetch,
boolean isIntermediateResultExpected,
Priority priority) {
mImageRequest = imageRequest;
mId = id;
mProducerListener = producerListener;
mCallerContext = callerContext;
mLowestPermittedRequestLevel = lowestPermittedRequestLevel;
mIsPrefetch = isPrefetch;
mPriority = priority;
mIsIntermediateResultExpected = isIntermediateResultExpected;
mIsCancelled = false;
mCallbacks = new ArrayList<>();
}
@Override
public ImageRequest getImageRequest() {
return mImageRequest;
}
@Override
public String getId() {
return mId;
}
@Override
public ProducerListener getListener() {
return mProducerListener;
}
@Override
public Object getCallerContext() {
return mCallerContext;
}
@Override
public ImageRequest.RequestLevel getLowestPermittedRequestLevel() {
return mLowestPermittedRequestLevel;
}
@Override
public synchronized boolean isPrefetch() {
return mIsPrefetch;
}
@Override
public synchronized Priority getPriority() {
return mPriority;
}
@Override
public synchronized boolean isIntermediateResultExpected() {
return mIsIntermediateResultExpected;
}
public synchronized boolean isCancelled() {
return mIsCancelled;
}
@Override
public void addCallbacks(ProducerContextCallbacks callbacks) {
boolean cancelImmediately = false;
synchronized (this) {
mCallbacks.add(callbacks);
if (mIsCancelled) {
cancelImmediately = true;
}
}
if (cancelImmediately) {
callbacks.onCancellationRequested();
}
}
/**
* Cancels the request processing and calls appropriate callbacks.
*/
public void cancel() {
BaseProducerContext.callOnCancellationRequested(cancelNoCallbacks());
}
/**
* Changes isPrefetch property.
*
* <p> This method does not call any callbacks. Instead, caller of this method is responsible for
* iterating over returned list and calling appropriate method on each callback object.
* {@see #callOnIsPrefetchChanged}
*
* @return list of callbacks if the value actually changes, null otherwise
*/
@Nullable
public synchronized List<ProducerContextCallbacks> setIsPrefetchNoCallbacks(boolean isPrefetch) {
if (isPrefetch == mIsPrefetch) {
return null;
}
mIsPrefetch = isPrefetch;
return new ArrayList<>(mCallbacks);
}
/**
* Changes priority.
*
* <p> This method does not call any callbacks. Instead, caller of this method is responsible for
* iterating over returned list and calling appropriate method on each callback object.
* {@see #callOnPriorityChanged}
*
* @return list of callbacks if the value actually changes, null otherwise
*/
@Nullable
public synchronized List<ProducerContextCallbacks> setPriorityNoCallbacks(Priority priority) {
if (priority == mPriority) {
return null;
}
mPriority = priority;
return new ArrayList<>(mCallbacks);
}
/**
* Changes isIntermediateResultExpected property.
*
* <p> This method does not call any callbacks. Instead, caller of this method is responsible for
* iterating over returned list and calling appropriate method on each callback object.
* {@see #callOnIntermediateResultChanged}
*
* @return list of callbacks if the value actually changes, null otherwise
*/
@Nullable
public synchronized List<ProducerContextCallbacks> setIsIntermediateResultExpectedNoCallbacks(
boolean isIntermediateResultExpected) {
if (isIntermediateResultExpected == mIsIntermediateResultExpected) {
return null;
}
mIsIntermediateResultExpected = isIntermediateResultExpected;
return new ArrayList<>(mCallbacks);
}
/**
* Marks this ProducerContext as cancelled.
*
* <p> This method does not call any callbacks. Instead, caller of this method is responsible for
* iterating over returned list and calling appropriate method on each callback object.
* {@see #callOnCancellationRequested}
*
* @return list of callbacks if the value actually changes, null otherwise
*/
@Nullable
public synchronized List<ProducerContextCallbacks> cancelNoCallbacks() {
if (mIsCancelled) {
return null;
}
mIsCancelled = true;
return new ArrayList<>(mCallbacks);
}
/**
* Calls {@code onCancellationRequested} on each element of the list. Does nothing if list == null
*/
public static void callOnCancellationRequested(
@Nullable List<ProducerContextCallbacks> callbacks) {
if (callbacks == null) {
return;
}
for (ProducerContextCallbacks callback : callbacks) {
callback.onCancellationRequested();
}
}
/**
* Calls {@code onIsPrefetchChanged} on each element of the list. Does nothing if list == null
*/
public static void callOnIsPrefetchChanged(
@Nullable List<ProducerContextCallbacks> callbacks) {
if (callbacks == null) {
return;
}
for (ProducerContextCallbacks callback : callbacks) {
callback.onIsPrefetchChanged();
}
}
/**
* Calls {@code onIsIntermediateResultExpected} on each element of the list. Does nothing if
* list == null
*/
public static void callOnIsIntermediateResultExpectedChanged(
@Nullable List<ProducerContextCallbacks> callbacks) {
if (callbacks == null) {
return;
}
for (ProducerContextCallbacks callback : callbacks) {
callback.onIsIntermediateResultExpectedChanged();
}
}
/**
* Calls {@code onPriorityChanged} on each element of the list. Does nothing if list == null
*/
public static void callOnPriorityChanged(@Nullable List<ProducerContextCallbacks> callbacks) {
if (callbacks == null) {
return;
}
for (ProducerContextCallbacks callback : callbacks) {
callback.onPriorityChanged();
}
}
}