package com.mopub.common;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build.VERSION_CODES;
import android.view.MotionEvent;
import com.mopub.common.CloseableLayout.ClosePosition;
import com.mopub.common.CloseableLayout.OnCloseListener;
import com.mopub.common.test.support.SdkTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.robolectric.Robolectric;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@RunWith(SdkTestRunner.class)
public class CloseableLayoutTest {
private CloseableLayout subject;
@Mock private OnCloseListener mockCloseListener;
@Mock private Canvas mockCanvas;
private MotionEvent closeRegionDown;
private MotionEvent closeRegionUp;
private MotionEvent closeRegionCancel;
private MotionEvent contentRegionDown;
private MotionEvent contentRegionUp;
private MotionEvent contentRegionCancel;
@Before
public void setup() {
Activity activity = Robolectric.buildActivity(Activity.class).create().get();
subject = new CloseableLayout(activity);
subject.setClosePosition(ClosePosition.TOP_RIGHT);
// Fake the close bounds, which allows us to set up close regions
subject.setCloseBounds(new Rect(100, 10, 110, 20));
closeRegionDown = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_DOWN, 100, 10, 0);
closeRegionUp = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_UP, 100, 10, 0);
closeRegionCancel = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_CANCEL, 100, 10, 0);
contentRegionDown = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_DOWN, 0, 0, 0);
contentRegionUp = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_UP, 0, 0, 0);
contentRegionCancel = MotionEvent.obtain(
100, 200, MotionEvent.ACTION_CANCEL, 0, 0, 0);
}
@Test
public void setOnCloseListener_thenTouchCloseRegion_shouldCallOnClick() {
subject.setOnCloseListener(mockCloseListener);
subject.onTouchEvent(closeRegionDown);
subject.onTouchEvent(closeRegionUp);
verify(mockCloseListener).onClose();
}
@Test
public void setOnCloseListener_thenTouchContentRegion_shouldNotCallCloseListener() {
subject.setOnCloseListener(mockCloseListener);
subject.onTouchEvent(contentRegionDown);
subject.onTouchEvent(contentRegionUp);
verify(mockCloseListener, never()).onClose();
}
@Test
public void setCloseVisible_shouldToggleCloseDrawable() {
subject.setCloseVisible(false);
assertThat(subject.isCloseVisible()).isFalse();
subject.setCloseVisible(true);
assertThat(subject.isCloseVisible()).isTrue();
}
// setLeft, setTop, setRight, and setBottom, are not available before honeycomb. This
// annotation just supresses a warning.
@TargetApi(VERSION_CODES.HONEYCOMB)
@Test
public void draw_shouldUpdateCloseBounds() {
subject.setLeft(0);
subject.setTop(0);
subject.setRight(100);
subject.setBottom(200);
subject.onSizeChanged(100, 200, 0, 0);
int expectedTop = 0;
int expectedLeft = (int) (100 - CloseableLayout.CLOSE_REGION_SIZE_DP);
subject.draw(mockCanvas);
Rect closeBounds = subject.getCloseBounds();
assertThat(closeBounds.top).isEqualTo(expectedTop);
assertThat(closeBounds.bottom).isEqualTo(
(int) (expectedTop + CloseableLayout.CLOSE_REGION_SIZE_DP));
assertThat(closeBounds.left).isEqualTo(expectedLeft);
assertThat(closeBounds.right).isEqualTo(
(int) (expectedLeft + CloseableLayout.CLOSE_REGION_SIZE_DP));
}
@Test
public void draw_withoutCloseBoundsChanged_shouldNotUpdateCloseBounds() {
subject.draw(mockCanvas);
Rect originalCloseBounds = subject.getCloseBounds();
subject.setCloseBounds(new Rect(40, 41, 42, 43));
subject.setCloseBoundChanged(false);
subject.draw(mockCanvas);
assertThat(subject.getCloseBounds()).isEqualTo(originalCloseBounds);
}
@Test
public void onInterceptTouchEvent_closeRegionDown_shouldReturnTrue() {
boolean intercepted = subject.onInterceptTouchEvent(closeRegionDown);
assertThat(intercepted).isTrue();
}
@Test public void onInterceptTouchEvent_contentRegionDown_returnsTrue() {
boolean intercepted = subject.onInterceptTouchEvent(contentRegionDown);
assertThat(intercepted).isFalse();
}
@Test
public void
onTouchEvent_closeRegionDown_thenCloseRegionUp_shouldTogglePressedStateAfterDelay() {
assertThat(subject.isClosePressed()).isFalse();
subject.onTouchEvent(closeRegionDown);
assertThat(subject.isClosePressed()).isTrue();
subject.onTouchEvent(closeRegionUp);
assertThat(subject.isClosePressed()).isTrue();
Robolectric.getUiThreadScheduler().advanceToLastPostedRunnable();
assertThat(subject.isClosePressed()).isFalse();
}
@Test
public void onTouchEvent_closeRegionDown_thenCloseRegionCancel_shouldTogglePressedState() {
subject.onTouchEvent(closeRegionDown);
subject.onTouchEvent(closeRegionCancel);
assertThat(subject.isClosePressed()).isFalse();
}
@Test
public void onTouchEvent_closeRegionDown_thenContentRegionCancel_shouldTogglePressedState() {
subject.onTouchEvent(closeRegionDown);
subject.onTouchEvent(contentRegionCancel);
assertThat(subject.isClosePressed()).isFalse();
}
@Test
public void pointInCloseBounds_noSlop_shouldReturnValidValues() {
Rect bounds = new Rect();
bounds.left = 10;
bounds.right = 20;
bounds.top = 100;
bounds.bottom = 200;
subject.setCloseBounds(bounds);
assertThat(subject.pointInCloseBounds(9, 99, 0)).isFalse();
assertThat(subject.pointInCloseBounds(9, 100, 0)).isFalse();
assertThat(subject.pointInCloseBounds(9, 199, 0)).isFalse();
assertThat(subject.pointInCloseBounds(9, 200, 0)).isFalse();
assertThat(subject.pointInCloseBounds(10, 99, 0)).isFalse();
assertThat(subject.pointInCloseBounds(10, 100, 0)).isTrue();
assertThat(subject.pointInCloseBounds(10, 199, 0)).isTrue();
assertThat(subject.pointInCloseBounds(10, 200, 0)).isFalse();
assertThat(subject.pointInCloseBounds(19, 99, 0)).isFalse();
assertThat(subject.pointInCloseBounds(19, 100, 0)).isTrue();
assertThat(subject.pointInCloseBounds(19, 199, 0)).isTrue();
assertThat(subject.pointInCloseBounds(19, 200, 0)).isFalse();
assertThat(subject.pointInCloseBounds(20, 99, 0)).isFalse();
assertThat(subject.pointInCloseBounds(20, 100, 0)).isFalse();
assertThat(subject.pointInCloseBounds(20, 199, 0)).isFalse();
assertThat(subject.pointInCloseBounds(20, 200, 0)).isFalse();
}
@Test
public void pointInCloseBounds_slop_shouldReturnValidValues() {
int slop = 3;
// Same as above, but adjust given 3 px slop
Rect bounds = new Rect();
bounds.left = 13;
bounds.right = 17;
bounds.top = 103;
bounds.bottom = 197;
subject.setCloseBounds(bounds);
assertThat(subject.pointInCloseBounds(9, 99, slop)).isFalse();
assertThat(subject.pointInCloseBounds(9, 100, slop)).isFalse();
assertThat(subject.pointInCloseBounds(9, 199, slop)).isFalse();
assertThat(subject.pointInCloseBounds(9, 200, slop)).isFalse();
assertThat(subject.pointInCloseBounds(10, 99, slop)).isFalse();
assertThat(subject.pointInCloseBounds(10, 100, slop)).isTrue();
assertThat(subject.pointInCloseBounds(10, 199, slop)).isTrue();
assertThat(subject.pointInCloseBounds(10, 200, slop)).isFalse();
assertThat(subject.pointInCloseBounds(19, 99, slop)).isFalse();
assertThat(subject.pointInCloseBounds(19, 100, slop)).isTrue();
assertThat(subject.pointInCloseBounds(19, 199, slop)).isTrue();
assertThat(subject.pointInCloseBounds(19, 200, slop)).isFalse();
assertThat(subject.pointInCloseBounds(20, 99, slop)).isFalse();
assertThat(subject.pointInCloseBounds(20, 100, slop)).isFalse();
assertThat(subject.pointInCloseBounds(20, 199, slop)).isFalse();
assertThat(subject.pointInCloseBounds(20, 200, slop)).isFalse();
}
}