Skip to content

Commit

Permalink
Simplify on fade listener
Browse files Browse the repository at this point in the history
Reviewed By: oprisnik

Differential Revision: D24799754

fbshipit-source-id: b5a094c3fce11ab13c04e1bdc8868341b47e51e3
  • Loading branch information
defHLT authored and facebook-github-bot committed Dec 16, 2020
1 parent 29c0ff1 commit 9aa485d
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 37 deletions.
67 changes: 32 additions & 35 deletions drawee/src/main/java/com/facebook/drawee/drawable/FadeDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ public class FadeDrawable extends ArrayDrawable {
@VisibleForTesting int mPreventInvalidateCount;

private @Nullable OnFadeListener mOnFadeListener;
private boolean mCallOnFadeStartedListener;
private boolean mCallOnFadeFinishedListener;
private boolean mIsFadingActualImage;

/**
* Creates a new fade drawable. The first layer is displayed with full opacity whereas all other
Expand Down Expand Up @@ -98,7 +97,6 @@ public FadeDrawable(Drawable[] layers, boolean allLayersVisible, int actualImage
mPreventInvalidateCount = 0;
mDefaultLayerIsOn = allLayersVisible;
mDefaultLayerAlpha = mDefaultLayerIsOn ? 255 : 0;
mCallOnFadeStartedListener = true;
mActualImageLayer = actualImageLayer;
resetInternal();
}
Expand Down Expand Up @@ -162,9 +160,6 @@ public void reset() {
* @param index the index of the layer to fade in.
*/
public void fadeInLayer(int index) {
mCallOnFadeFinishedListener = index == mActualImageLayer;
maybeNotifyOnFadeStarted(index);

mTransitionState = TRANSITION_STARTING;
mIsLayerOn[index] = true;
invalidateSelf();
Expand All @@ -176,10 +171,6 @@ public void fadeInLayer(int index) {
* @param index the index of the layer to fade out.
*/
public void fadeOutLayer(int index) {
if (index == mActualImageLayer) {
mCallOnFadeStartedListener = true;
mCallOnFadeFinishedListener = true;
}
mTransitionState = TRANSITION_STARTING;
mIsLayerOn[index] = false;
invalidateSelf();
Expand Down Expand Up @@ -299,11 +290,8 @@ public void draw(Canvas canvas) {
ratio = (mDurationMs == 0) ? 1.0f : 0.0f;
// if all the layers have reached their target opacity, transition is done
done = updateAlphas(ratio);
onFadeStarted();
mTransitionState = done ? TRANSITION_NONE : TRANSITION_RUNNING;

if (done) {
maybeNotifyOnFadeFinished();
}
break;

case TRANSITION_RUNNING:
Expand All @@ -313,43 +301,25 @@ public void draw(Canvas canvas) {
// if all the layers have reached their target opacity, transition is done
done = updateAlphas(ratio);
mTransitionState = done ? TRANSITION_NONE : TRANSITION_RUNNING;

if (done) {
maybeNotifyOnFadeFinished();
}
break;

case TRANSITION_NONE:
// there is no transition in progress and mAlphas should be left as is.
done = true;

maybeNotifyOnFadeFinished();
break;
}

for (int i = 0; i < mLayers.length; i++) {
drawDrawableWithAlpha(canvas, mLayers[i], (int) Math.ceil(mAlphas[i] * mAlpha / 255.0));
}

if (!done) {
if (done) {
onFadeFinished();
} else {
invalidateSelf();
}
}

private void maybeNotifyOnFadeStarted(int index) {
if (mOnFadeListener != null && index == mActualImageLayer && mCallOnFadeStartedListener) {
mOnFadeListener.onFadeStarted();
mCallOnFadeStartedListener = false;
}
}

private void maybeNotifyOnFadeFinished() {
if (mOnFadeListener != null && mCallOnFadeFinishedListener) {
mOnFadeListener.onFadeFinished();
mCallOnFadeFinishedListener = false;
}
}

private void drawDrawableWithAlpha(Canvas canvas, Drawable drawable, int alpha) {
if (drawable != null && alpha > 0) {
mPreventInvalidateCount++;
Expand Down Expand Up @@ -403,6 +373,33 @@ public void setOnFadeListener(OnFadeListener onFadeListener) {
mOnFadeListener = onFadeListener;
}

private void onFadeStarted() {
if (mIsFadingActualImage) {
return;
}

if (!mIsLayerOn[mActualImageLayer]) {
return;
}

mIsFadingActualImage = true;

if (mOnFadeListener != null) {
mOnFadeListener.onFadeStarted();
}
}

private void onFadeFinished() {
if (!mIsFadingActualImage) {
return;
}
mIsFadingActualImage = false;

if (mOnFadeListener != null) {
mOnFadeListener.onFadeFinished();
}
}

public interface OnFadeListener {
void onFadeStarted();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ private static class FakeFadeDrawable extends FadeDrawable {
private long mCurrentTimeMs;

public FakeFadeDrawable(Drawable[] layers) {
super(layers, true, -1);
super(layers, true, 0);
mCurrentTimeMs = 0;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.drawee.drawable;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import com.facebook.testing.robolectric.v4.WithTestDefaultsRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;

/** Tests {@link FadeDrawable.OnFadeListener} */
@RunWith(WithTestDefaultsRunner.class)
@PrepareForTest({
// SystemClock.class,
Rect.class,
})
public class FadeDrawableOnFadeListenerTest {

public static final int DURATION = 1000;
public static final int ACTUAL_LAYER_INDEX = 1;
public static final int OTHER_LAYER_INDEX = 2;

private Drawable[] mLayers =
new Drawable[] {
DrawableTestUtils.mockDrawable(),
DrawableTestUtils.mockDrawable(),
DrawableTestUtils.mockDrawable(),
};

private FadeDrawable mFadeDrawable;
private FadeDrawable.OnFadeListener mOnFadeListener = mock(FadeDrawable.OnFadeListener.class);

private Canvas mCanvas = mock(Canvas.class);

@Before
public void setUp() {
// PowerMockito.mockStatic(SystemClock.class);
mFadeDrawable = new FadeDrawable(mLayers, false, 1);
mFadeDrawable.setTransitionDuration(DURATION);
mFadeDrawable.setOnFadeListener(mOnFadeListener);
}

@Test
public void testSimple() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();

SystemClock.setCurrentTimeMillis((long) (DURATION * 0.5));
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, never()).onFadeFinished();

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.5));
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testComplex() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.fadeOutLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();

SystemClock.setCurrentTimeMillis((long) (DURATION * 0.5));
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, never()).onFadeFinished();

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.1));
// mFadeDrawable.fadeInAllLayers();
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testFinishImmediately() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();

mFadeDrawable.finishTransitionImmediately();
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testFadeInAll() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInAllLayers();
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.1));
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testFadeTheOtherLayer() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInLayer(OTHER_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.1));
mFadeDrawable.draw(mCanvas);

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testFadeOut() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));
mFadeDrawable.fadeInAllLayers();
// Notice we finish immediately before the draw call:
mFadeDrawable.finishTransitionImmediately();
mFadeDrawable.draw(mCanvas);

mFadeDrawable.fadeOutLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.1));
mFadeDrawable.draw(mCanvas);

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testFadeOut2() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));
mFadeDrawable.fadeInAllLayers();
// Notice we call draw before finishing immediately
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();
mFadeDrawable.finishTransitionImmediately();
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}

@Test
public void testMultipleFades() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeStarted();

mFadeDrawable.fadeInLayer(OTHER_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
verifyNoMoreInteractions(mOnFadeListener);
SystemClock.setCurrentTimeMillis((long) (DURATION * 1.2));
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();
}

@Test
public void testLateListener() {
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.1));

// No listener set:
mFadeDrawable.setOnFadeListener(null);

mFadeDrawable.fadeInLayer(ACTUAL_LAYER_INDEX);
mFadeDrawable.draw(mCanvas);
SystemClock.setCurrentTimeMillis((long) (DURATION * 0.5));
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);
mFadeDrawable.draw(mCanvas);

// Set the listener back
mFadeDrawable.setOnFadeListener(mOnFadeListener);

SystemClock.setCurrentTimeMillis((long) (DURATION * 1.5));
mFadeDrawable.draw(mCanvas);
verify(mOnFadeListener, times(1)).onFadeFinished();

verifyNoMoreInteractions(mOnFadeListener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ private static class FakeFadeDrawable extends FadeDrawable {
private long mCurrentTimeMs;

public FakeFadeDrawable(Drawable[] layers) {
super(layers);
super(layers, false, 0);
mCurrentTimeMs = 0;
}

Expand Down

0 comments on commit 9aa485d

Please sign in to comment.