blob: 25ab224528dc22ddc84d618fa2686bd8bd9d73e0 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 androidx.leanback.widget;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.ImageView;
import androidx.leanback.R;
import androidx.leanback.app.TestActivity;
import androidx.leanback.testutils.PollingCheck;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import java.util.Random;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ImageCardViewTest {
private static final String IMAGE_CARD_VIEW_ACTIVITY = "ImageCardViewActivity";
private static final float FINAL_ALPHA_STATE = 1.0f;
private static final float INITIAL_ALPHA_STATE = 0.0f;
private static final float DELTA = 0.0f;
private static final long ANIMATION_DURATION = 5000;
private static final int RANDOM_COLOR_ONE = 0xffffffff;
private static final int RANDOM_COLOR_TWO = 0x00000000;
@Rule
public TestName mUnitTestName = new TestName();
// Enable lifecycle based testing
private TestActivity.TestActivityTestRule mRule;
// Only support alpha animation
private static final String ALPHA = "alpha";
// Flag to represent if the callback has been called or not
private boolean mOnAnimationStartCalled;
private boolean mOnAnimationPauseCalled;
private boolean mOnAnimationResumeCalled;
private boolean mOnAnimationCancelCalled;
private boolean mOnAnimationEndCalled;
private boolean mOnAnimationRepeatCalled;
// ImageCardView for testing.
private ImageCardView mImageCardView;
// Animator for testing.
private ObjectAnimator mFadeInAnimator;
// ImageView on ImageCardView;
private ImageView mImageView;
// Sample Drawable which will be used as the parameter for some methods.
private Drawable mSampleDrawable;
// Another Sample Drawable.
private Drawable mSampleDrawable2;
// Generated Image View Id.
private int mImageCardViewId;
// Listener to capture animator's state
private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
mOnAnimationStartCalled = true;
}
@Override
public void onAnimationPause(Animator animation) {
super.onAnimationPause(animation);
mOnAnimationPauseCalled = true;
}
@Override
public void onAnimationResume(Animator animation) {
super.onAnimationResume(animation);
mOnAnimationResumeCalled = true; }
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
mOnAnimationCancelCalled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mOnAnimationEndCalled = true;
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
mOnAnimationRepeatCalled = true;
}
};
// Set up before executing test cases.
@Before
public void setUp() throws Exception {
// The following provider will create an Activity which can inflate the ImageCardView
// And the ImageCardView can be fetched through ID for future testing.
TestActivity.Provider imageCardViewProvider = new TestActivity.Provider() {
@Override
public void onCreate(TestActivity activity, Bundle savedInstanceState) {
super.onCreate(activity, savedInstanceState);
// The theme must be set to make sure imageCardView can be populated correctly.
activity.setTheme(R.style.Widget_Leanback_ImageCardView_BadgeStyle);
// Create Drawable using random color for test purpose.
mSampleDrawable = new ColorDrawable(RANDOM_COLOR_ONE);
// Create Drawable using random color for test purpose.
mSampleDrawable2 = new ColorDrawable(RANDOM_COLOR_TWO);
// Create imageCardView and save system generated ID.
ImageCardView imageCardView = new ImageCardView(activity);
mImageCardViewId = imageCardView.generateViewId();
imageCardView.setId(mImageCardViewId);
// Set up imageCardView with activity programmatically.
activity.setContentView(imageCardView);
}
};
// Initialize testing rule and testing activity
mRule = new TestActivity.TestActivityTestRule(imageCardViewProvider, generateProviderName(
IMAGE_CARD_VIEW_ACTIVITY));
final TestActivity imageCardViewTestActivity = mRule.launchActivity();
// Create card view and image view
mImageCardView = (ImageCardView) imageCardViewTestActivity.findViewById(mImageCardViewId);
mImageView = mImageCardView.getMainImageView();
// Create animator.
mFadeInAnimator = mImageCardView.mFadeInAnimator;
mFadeInAnimator.addListener(mAnimatorListener);
// Set animation duration with longer period of time for robust testing.
mFadeInAnimator.setDuration(ANIMATION_DURATION);
}
/**
* Test SetMainImage method when the parameters are null and false
*
* @throws Throwable
*/
@Test
public void testSetMainImageTest0() throws Throwable {
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(null, false);
// Currently, the animation hasn't started yet, the cancel event will not be
// triggered
assertFalse(mOnAnimationCancelCalled);
// The animation will not be started, check status immediately.
assertEquals(mImageCardView.getMainImage(), null);
assertEquals(mImageView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.INVISIBLE);
}
});
}
/**
* Test SetMainImage method when the parameters are mSampleDrawable and false
*
* @throws Throwable
*/
@Test
public void testSetMainImageTest1() throws Throwable {
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, false);
// Currently, the animation hasn't started yet, the cancel event will not be
// triggered
assertFalse(mOnAnimationCancelCalled);
// The animation will not be started, check status immediately.
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
}
/**
* Test SetMainImage method when the parameters are null and true
*
* @throws Throwable
*/
@Test
public void testSetMainImageTest2() throws Throwable {
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(null, true);
// Currently, the animation hasn't started yet, the cancel event will not be
// triggered
assertFalse(mOnAnimationCancelCalled);
// The animation will not be started, check status immediately.
assertEquals(mImageCardView.getMainImage(), null);
assertEquals(mImageView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.INVISIBLE);
}
});
}
/**
* Test SetMainImage method with sample drawable object and true parameter
*
* @throws Throwable
*/
@Test
public void testSetMainImageTest3() throws Throwable {
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, true);
// The fadeIn method should be triggered in this scenario
assertTrue(mOnAnimationStartCalled);
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// Set time out limitation to be 2 * ANIMATION_DURATION.
PollingCheck.waitFor(2 * ANIMATION_DURATION, new PollingCheck.PollingCheckCondition() {
@Override
public boolean canProceed() {
return mOnAnimationEndCalled;
}
});
// Test if animation ended successfully through alpha value.
assertTrue(mOnAnimationEndCalled);
assertEquals(mImageView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
}
/**
* Test SetMainImage method's behavior when the animation is already started
* In this test case, the parameters are set to null and false to interrupt existed animation
*
* @throws Throwable
*/
@Test
public void testSetMainImageInTransitionTest0() throws Throwable {
// The transition duration before the interruption happens.
long durationBeforeInterruption = (long) (0.5 * ANIMATION_DURATION);
// Perform an animation firstly
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, true);
// The fadeIn method should be triggered in this scenario
assertTrue(mOnAnimationStartCalled);
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// simulate the duration of animation
SystemClock.sleep(durationBeforeInterruption);
// Interrupt current animation using setMainImage(Drawable, boolean) method
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// Interrupt existed animation
mImageCardView.setMainImage(null, false);
// Existed animation will be cancelled immediately.
assertTrue(mOnAnimationCancelCalled);
// New animation will not be triggered, check the status immediately
assertEquals(mImageCardView.getMainImage(), null);
assertEquals(mImageCardView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.INVISIBLE);
}
});
}
/**
* Test SetMainImage method's behavior when the animation is already started
* In this test case, the parameters are set to mSampleDrawable2 and false to interrupt
* existed animation
*
* @throws Throwable
*/
@Test
public void testSetMainImageInTransitionTest1() throws Throwable {
// The transition duration before the interruption happens.
long durationBeforeInterruption = (long) (0.5 * ANIMATION_DURATION);
// Perform an animation firstly
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, true);
// The fadeIn method should be triggered in this scenario
assertTrue(mOnAnimationStartCalled);
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// simulate the duration of animation
SystemClock.sleep(durationBeforeInterruption);
// Interrupt current animation using setMainImage(Drawable, boolean) method
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// Interrupt existed animation
mImageCardView.setMainImage(mSampleDrawable2, false);
// Existed animation will be cancelled immediately.
assertTrue(mOnAnimationCancelCalled);
// New animation will not be triggered, check the status immediately
assertEquals(mImageCardView.getMainImage(), mSampleDrawable2);
assertEquals(mImageCardView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
}
/**
* Test SetMainImage method's behavior when the animation is already started
* In this test case, the parameters are set to null and true to interrupt existed animation
*
* @throws Throwable
*/
@Test
public void testSetMainImageInTransitionTest2() throws Throwable {
// The transition duration before the interruption happens.
long durationBeforeInterruption = (long) (0.5 * ANIMATION_DURATION);
// Perform an animation firstly
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, true);
// The fadeIn method should be triggered in this scenario
assertTrue(mOnAnimationStartCalled);
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// simulate the duration of animation
SystemClock.sleep(durationBeforeInterruption);
// Interrupt current animation using setMainImage(Drawable, boolean) method
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// Interrupt existed animation
mImageCardView.setMainImage(null, true);
// Existed animation will be cancelled immediately.
assertTrue(mOnAnimationCancelCalled);
// New animation will not be triggered, check the status immediately
assertEquals(mImageCardView.getMainImage(), null);
assertEquals(mImageCardView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
assertEquals(mImageView.getVisibility(), View.INVISIBLE);
}
});
}
/**
* Test SetMainImage method's behavior when the animation is already started
* In this test case, the parameters are set to mSampleDrawable2 and true to interrupt
* existed animation
*
* @throws Throwable
*/
@Test
public void testSetMainImageInTransitionTest3() throws Throwable {
// The transition duration before the interruption happens.
long durationBeforeInterruption = (long) (0.5 * ANIMATION_DURATION);
// Perform an animation firstly
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// set random alpha value initially
mImageView.setAlpha(generateInitialialAlphaValue());
mImageCardView.setMainImage(mSampleDrawable, true);
// The fadeIn method should be triggered in this scenario
assertTrue(mOnAnimationStartCalled);
assertEquals(mImageCardView.getMainImage(), mSampleDrawable);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// Simulate the duration of animation
SystemClock.sleep(durationBeforeInterruption);
// Interrupt current animation using setMainImage(Drawable, boolean) method
mRule.runOnUiThread(new Runnable() {
@Override
public void run() {
// Interrupt existed animation
mImageCardView.setMainImage(mSampleDrawable2, true);
// Existed animation will not be cancelled immediately.
assertFalse(mOnAnimationCancelCalled);
// New animation will not be triggered, check the status immediately
assertEquals(mImageCardView.getMainImage(), mSampleDrawable2);
assertEquals(mImageView.getVisibility(), View.VISIBLE);
}
});
// Set time out limitation to be 2 * ANIMATION_DURATION.
PollingCheck.waitFor(2 * ANIMATION_DURATION, new PollingCheck.PollingCheckCondition() {
@Override
public boolean canProceed() {
return mOnAnimationEndCalled;
}
});
// Test if animation ended successfully through alpha value.
assertEquals(mImageView.getAlpha(), FINAL_ALPHA_STATE, DELTA);
}
// Helper function to register provider's name
private String generateProviderName(String name) {
return mUnitTestName.getMethodName() + "_" + name;
}
// generate random number as the initial alpha value
private float generateInitialialAlphaValue() {
Random generator = new Random();
return generator.nextFloat();
}
}