blob: 5aced321c96cb1c713c906fd2d6c754f7aae422d [file] [log] [blame]
// Copyright 2018 The Feed Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.android.libraries.feed.piet;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import com.google.android.libraries.feed.common.functional.Consumer;
/**
* Handles loading images from the host. In particular, handles the resizing of images as well as
* the fading animation.
*/
public class LoadImageCallback implements Consumer</*@Nullable*/ Drawable> {
static final int FADE_IN_ANIMATION_TIME_MS = 300;
private final ImageView imageView;
private final ScaleType scaleType;
private final long initialTime;
/*@Nullable*/ private final Integer overlayColor;
private final boolean fadeImage;
private final AdapterParameters parameters;
private boolean cancelled;
/*@Nullable*/ private Drawable finalDrawable;
LoadImageCallback(
ImageView imageView,
ScaleType scaleType,
/*@Nullable*/ Integer overlayColor,
boolean fadeImage,
AdapterParameters parameters,
FrameContext frameContext) {
this.imageView = imageView;
this.scaleType = scaleType;
this.overlayColor = overlayColor;
this.fadeImage = fadeImage;
this.parameters = parameters;
this.initialTime = parameters.clock.elapsedRealtime();
}
@Override
public void accept(/*@Nullable*/ Drawable drawable) {
if (cancelled || drawable == null) {
return;
}
imageView.setScaleType(scaleType);
final Drawable localDrawable = ViewUtils.applyOverlayColor(drawable, overlayColor);
this.finalDrawable = localDrawable;
// If we are in the process of binding when we get the image, we should not fade in the
// image as the image was cached.
if (!shouldFadeInImage()) {
imageView.setImageDrawable(localDrawable);
// Invalidating the view as the view doesn't update if not manually updated here.
imageView.invalidate();
return;
}
Drawable initialDrawable =
imageView.getDrawable() != null
? imageView.getDrawable()
: new ColorDrawable(Color.TRANSPARENT);
TransitionDrawable transitionDrawable =
new TransitionDrawable(new Drawable[] {initialDrawable, localDrawable});
imageView.setImageDrawable(transitionDrawable);
transitionDrawable.setCrossFadeEnabled(true);
transitionDrawable.startTransition(FADE_IN_ANIMATION_TIME_MS);
imageView.postDelayed(
() -> {
if (cancelled) {
return;
}
// Allows GC of the initial drawable and the transition drawable. Additionally
// fixes the issue where the transition sometimes doesn't occur, which would
// result in blank images.
imageView.setImageDrawable(this.finalDrawable);
},
FADE_IN_ANIMATION_TIME_MS);
}
private boolean shouldFadeInImage() {
return fadeImage
&& (parameters.clock.elapsedRealtime() - initialTime)
> parameters.hostProviders.getAssetProvider().getFadeImageThresholdMs();
}
void cancel() {
this.cancelled = true;
}
}