package com.mopub.mraid;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.view.View;
import android.widget.FrameLayout;
import com.mopub.common.AdReport;
import com.mopub.common.CloseableLayout.ClosePosition;
import com.mopub.common.MoPubBrowser;
import com.mopub.common.test.support.SdkTestRunner;
import com.mopub.mobileads.BaseVideoPlayerActivityTest;
import com.mopub.mobileads.MraidVideoPlayerActivity;
import com.mopub.mraid.MraidBridge.MraidBridgeListener;
import com.mopub.mraid.MraidBridge.MraidWebView;
import com.mopub.mraid.MraidController.MraidListener;
import com.mopub.mraid.MraidController.OrientationBroadcastReceiver;
import com.mopub.mraid.MraidController.ScreenMetricsWaiter;
import com.mopub.mraid.MraidController.ScreenMetricsWaiter.WaitRequest;
import com.mopub.mraid.MraidController.UseCustomCloseListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import java.net.URI;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SdkTestRunner.class)
public class MraidControllerTest {
private long broadcastIdentifier = 123;
@Mock private AdReport mockAdReport;
@Mock private MraidBridge mockBridge;
@Mock private MraidBridge mockTwoPartBridge;
@Mock private ScreenMetricsWaiter mockScreenMetricsWaiter;
@Mock private WaitRequest mockWaitRequest;
@Mock private MraidListener mockMraidListener;
@Mock private UseCustomCloseListener mockUseCustomCloseListener;
@Mock private OrientationBroadcastReceiver mockOrientationBroadcastReceiver;
@Captor private ArgumentCaptor<MraidBridgeListener> bridgeListenerCaptor;
private Activity activity;
private FrameLayout rootView;
private MraidController subject;
@Before
public void setUp() {
Robolectric.setDisplayMetricsDensity(1.0f);
activity = spy(Robolectric.buildActivity(Activity.class).create().get());
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
rootView = new FrameLayout(activity);
when(mockBridge.isVisible()).thenReturn(true);
// By default, immediately fulfill a screen metrics wait request. Individual tests can
// reset this, if desired.
when(mockScreenMetricsWaiter.waitFor(Mockito.<View>anyVararg()))
.thenReturn(mockWaitRequest);
doAnswer(new Answer<Void>() {
@Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
Runnable runnable = (Runnable) invocation.getArguments()[0];
runnable.run();
return null;
}
}).when(mockWaitRequest).start(any(Runnable.class));
subject = new MraidController(
activity, mockAdReport, PlacementType.INLINE,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
subject.setMraidListener(mockMraidListener);
subject.setOrientationBroadcastReceiver(mockOrientationBroadcastReceiver);
subject.setRootView(rootView);
subject.loadContent("fake_html_data");
verify(mockBridge).setMraidBridgeListener(bridgeListenerCaptor.capture());
}
@Test
public void constructor_shouldSetStateToLoading() {
ViewState state = subject.getViewState();
assertThat(state).isEqualTo(ViewState.LOADING);
}
@Test
public void bridgeOnReady_shouldSetStateToDefault_shouldCallListener() {
bridgeListenerCaptor.getValue().onPageLoaded();
ViewState state = subject.getViewState();
assertThat(state).isEqualTo(ViewState.DEFAULT);
verify(mockMraidListener).onLoaded(any(View.class));
}
@Test
public void handlePageLoad_shouldNotifyBridgeOfVisibilityPlacementScreenSizeAndSupports() {
when(mockBridge.isVisible()).thenReturn(true);
subject.handlePageLoad();
verify(mockBridge).notifyViewability(true);
verify(mockBridge).notifyPlacementType(PlacementType.INLINE);
verify(mockBridge).notifyScreenMetrics(any(MraidScreenMetrics.class));
// The actual values here are supplied by the Mraids class, which has separate tests.
verify(mockBridge).notifySupports(false, false, false, false, false);
}
@Test
public void handlePageLoad_shouldCancelLastRequest() {
subject.handlePageLoad();
verify(mockScreenMetricsWaiter).cancelLastRequest();
}
@Test
public void handlePageLoad_thenDestroy_shouldCancelLastRequest() {
subject.handlePageLoad();
subject.destroy();
verify(mockScreenMetricsWaiter, times(2)).cancelLastRequest();
}
@Test
public void bridgeOnVisibilityChanged_withTwoPartBridgeAttached_shouldNotNotifyVisibility() {
when(mockTwoPartBridge.isAttached()).thenReturn(true);
bridgeListenerCaptor.getValue().onVisibilityChanged(true);
bridgeListenerCaptor.getValue().onVisibilityChanged(false);
verify(mockBridge, never()).notifyViewability(anyBoolean());
verify(mockTwoPartBridge, never()).notifyViewability(anyBoolean());
}
@Test
public void handleResize_shouldBeIgnoredWhenLoadingOrHidden() throws MraidCommandException {
subject.setViewStateForTesting(ViewState.LOADING);
subject.handleResize(100, 200, 0, 0, ClosePosition.TOP_RIGHT, true);
assertThat(subject.getViewState()).isEqualTo(ViewState.LOADING);
subject.setViewStateForTesting(ViewState.HIDDEN);
subject.handleResize(100, 200, 0, 0, ClosePosition.TOP_RIGHT, true);
assertThat(subject.getViewState()).isEqualTo(ViewState.HIDDEN);
}
@Test(expected = MraidCommandException.class)
public void handleResize_shouldThrowExceptionWhenExpanded() throws MraidCommandException {
subject.setViewStateForTesting(ViewState.EXPANDED);
subject.handleResize(100, 200, 0, 0, ClosePosition.TOP_RIGHT, true);
}
@Test(expected = MraidCommandException.class)
public void handleResize_shouldThrowExceptionForInterstitial() throws MraidCommandException {
MraidListener listener = mock(MraidListener.class);
subject = new MraidController(activity, mockAdReport, PlacementType.INTERSTITIAL,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
subject.setMraidListener(listener);
subject.setRootView(rootView);
// Move to DEFAULT state
subject.loadContent("fake_html_data");
subject.handlePageLoad();
subject.handleResize(100, 200, 0, 0, ClosePosition.TOP_RIGHT, true);
}
@Test
public void handleResize_shouldMoveWebViewToResizedContainer_shouldSetResizedState()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(100, 100, 0, 0, ClosePosition.TOP_RIGHT, true);
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(2);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(0);
assertThat(subject.getViewState()).isEqualTo(ViewState.RESIZED);
}
@Test
public void handleResize_noAllowOffscreen_smallView_shouldResize()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(50, 50, 0, 0, ClosePosition.TOP_RIGHT, /* allowOffscreen */ false);
assertThat(subject.getViewState()).isEqualTo(ViewState.RESIZED);
}
@Test(expected = MraidCommandException.class)
public void handleResize_noAllowOffscreen_largeView_shouldThrowException()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(101, 101, 0, 0, ClosePosition.TOP_RIGHT, /* allowOffscreen */ false);
}
@Test(expected = MraidCommandException.class)
public void handleResize_allowOffscreen_largeView_closeButtonTopRight_shouldThrowException()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(150, 150, 0, 0, ClosePosition.TOP_RIGHT, /* allowOffscreen */ true);
}
@Test
public void handleResize_allowOffscreen_closeButtonTopLeft_shouldNotThrowException()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(150, 150, 0, 0, ClosePosition.TOP_LEFT, /* allowOffscreen */ true);
assertThat(subject.getViewState()).isEqualTo(ViewState.RESIZED);
}
@Test(expected = MraidCommandException.class)
public void handleResize_allowOffscreen_largeOffset_closeButtonBottomRight_shouldThrowException()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 1000);
// Throws an exception because the close button overlaps the edge
subject.handleResize(100, 100, 25, 25, ClosePosition.BOTTOM_RIGHT, /* allowOffscreen */
true);
}
@Test
public void handleResize_allowOffscreen_largeOffset_closeButtonBottomLeft_shouldNotThrowException()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.setRootViewSize(100, 1000);
subject.handleResize(100, 100, 25, 25, ClosePosition.BOTTOM_LEFT, /* allowOffscreen */ true);
assertThat(subject.getViewState()).isEqualTo(ViewState.RESIZED);
}
@Test(expected = MraidCommandException.class)
public void handleResize_heightSmallerThan50Dips_shouldFail() throws MraidCommandException {
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(100, 49, 25, 25, ClosePosition.BOTTOM_LEFT, /* allowOffscreen */ false);
}
@Test(expected = MraidCommandException.class)
public void handleResize_widthSmallerThan50Dips_shouldFail() throws MraidCommandException {
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(49, 100, 25, 25, ClosePosition.BOTTOM_LEFT, /* allowOffscreen */ false);
}
@Test
public void handleClose_fromResizedState_shouldMoveWebViewToOriginalContainer_shouldNotFireOnClose()
throws MraidCommandException {
// Move to RESIZED state
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(100, 100, 0, 0, ClosePosition.TOP_RIGHT, false);
subject.handleClose();
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
verify(mockMraidListener, never()).onClose();
}
@Test(expected = MraidCommandException.class)
public void handleExpand_afterDestroy_shouldThrowException() throws MraidCommandException {
subject.destroy();
subject.handleExpand(null, false);
}
@Test
public void handleExpand_shouldBeIgnoredForInterstitial() throws MraidCommandException {
MraidListener listener = mock(MraidListener.class);
subject = new MraidController(activity, mockAdReport, PlacementType.INTERSTITIAL,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
subject.setMraidListener(listener);
subject.setRootView(rootView);
// Move to DEFAULT state
subject.loadContent("fake_html_data");
subject.handlePageLoad();
subject.handleExpand(null, false);
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
verify(listener, never()).onExpand();
}
@Test
public void handleExpand_shouldBeIgnoredWhenLoadingHiddenOrExpanded()
throws MraidCommandException {
subject.setViewStateForTesting(ViewState.LOADING);
subject.handleExpand(null, false);
assertThat(subject.getViewState()).isEqualTo(ViewState.LOADING);
verify(mockMraidListener, never()).onExpand();
subject.setViewStateForTesting(ViewState.HIDDEN);
subject.handleExpand(null, false);
assertThat(subject.getViewState()).isEqualTo(ViewState.HIDDEN);
verify(mockMraidListener, never()).onExpand();
subject.setViewStateForTesting(ViewState.EXPANDED);
subject.handleExpand(null, false);
assertThat(subject.getViewState()).isEqualTo(ViewState.EXPANDED);
verify(mockMraidListener, never()).onExpand();
}
@Test
public void handleExpand_withNoUrl_shouldMoveWebViewToExpandedContainer_shouldCallOnExpand()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.handleExpand(null, false);
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(2);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(0);
verify(mockMraidListener).onExpand();
}
@Test
public void handleExpand_withTwoPartUrl_shouldAttachTwoPartBridge_shouldCallOnExpand()
throws MraidCommandException {
// Move to DEFAULT state
subject.handlePageLoad();
subject.handleExpand(URI.create("http://two-part-url"), false);
verify(mockTwoPartBridge).setMraidBridgeListener(any(MraidBridgeListener.class));
verify(mockTwoPartBridge).attachView(any(MraidWebView.class));
verify(mockTwoPartBridge).setContentUrl(URI.create("http://two-part-url").toString());
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(2);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(1);
verify(mockMraidListener).onExpand();
assertThat(subject.getViewState()).isEqualTo(ViewState.EXPANDED);
}
@Test
public void handleClose_afterDestroy_shouldNotFireOnClose() {
subject.destroy();
subject.handleClose();
verify(mockMraidListener, never()).onClose();
}
@Test
public void handleClose_fromExpandedState_shouldMoveWebViewToOriginalContainer_shouldNotFireOnClose() throws MraidCommandException {
// Move to EXPANDED state
subject.handlePageLoad();
subject.handleExpand(null, false);
subject.handleClose();
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
verify(mockMraidListener, never()).onClose();
}
@Test
public void handleClose_fromTwoPartExpandedState_shouldDetachTwoPartBridge_shouldMoveWebViewToOriginalContainer_shouldNotFireOnClose()
throws MraidCommandException {
URI uri = URI.create("http://two-part-url");
// Move to two part EXPANDED state
subject.handlePageLoad();
subject.handleExpand(uri, false);
when(mockTwoPartBridge.isAttached()).thenReturn(true);
subject.handleClose();
verify(mockTwoPartBridge).detach();
assertThat(subject.getExpandedAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getAdContainer().getChildCount()).isEqualTo(1);
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
verify(mockMraidListener, never()).onClose();
}
@Test
public void handleClose_fromDefaultState_shouldHideAdContainer_shouldCallOnClose() {
// Move to DEFAULT state
subject.handlePageLoad();
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
subject.handleClose();
assertThat(subject.getAdContainer().getVisibility()).isEqualTo(View.INVISIBLE);
assertThat(subject.getViewState()).isEqualTo(ViewState.HIDDEN);
verify(mockMraidListener).onClose();
}
@Test
public void handleShowVideo_shouldStartVideoPlayerActivity() {
subject.handleShowVideo("http://video");
BaseVideoPlayerActivityTest.assertMraidVideoPlayerActivityStarted(
MraidVideoPlayerActivity.class, "http://video");
}
@Test
public void handleCustomClose_shouldUpdateExpandedContainer() {
subject.handleCustomClose(true);
assertThat(subject.getExpandedAdContainer().isCloseVisible()).isFalse();
subject.handleCustomClose(false);
assertThat(subject.getExpandedAdContainer().isCloseVisible()).isTrue();
}
@Test
public void handleCustomClose_shouldCallCustomCloseChangedListener() {
subject.setUseCustomCloseListener(mockUseCustomCloseListener);
subject.handleCustomClose(true);
verify(mockUseCustomCloseListener).useCustomCloseChanged(true);
reset(mockUseCustomCloseListener);
subject.handleCustomClose(false);
verify(mockUseCustomCloseListener).useCustomCloseChanged(false);
}
@Test
public void handleOpen_withMoPubNativeBrowserUrl_shouldOpenExternalBrowser() {
subject.handleOpen("mopubnativebrowser://navigate?url=https%3A%2F%2Fwww.example.com");
Intent intent = Robolectric.getShadowApplication().getNextStartedActivity();
assertThat(intent.getDataString()).isEqualTo("https://www.example.com");
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW);
}
@Test
public void handleOpen_withMalformedMoPubNativeBrowserUrl_shouldNotStartNewActivity() {
// invalid host parameter 'nav'
subject.handleOpen("mopubnativebrowser://nav?url=https%3A%2F%2Fwww.example.com");
assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull();
}
@Test
public void handleOpen_withApplicationUrl_shouldStartNewIntent() {
String applicationUrl = "amzn://blah";
Robolectric.packageManager.addResolveInfoForIntent(new Intent(Intent.ACTION_VIEW, Uri
.parse(applicationUrl)), new ResolveInfo());
subject.handleOpen(applicationUrl);
Intent startedIntent = Robolectric.getShadowApplication().getNextStartedActivity();
assertThat(startedIntent).isNotNull();
// Since we are using an Activity context, we do not need FLAG_ACTIVITY_NEW_TASK
assertThat(startedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isEqualTo(0);
assertThat(startedIntent.getComponent()).isNull();
verify(mockMraidListener).onOpen();
}
@Test
public void handleOpen_withHttpApplicationUrl_shouldStartMoPubBrowser() {
String applicationUrl = "http://blah";
subject.handleOpen(applicationUrl);
Intent startedIntent = Robolectric.getShadowApplication().getNextStartedActivity();
assertThat(startedIntent).isNotNull();
// Since we are using an Activity context, we do not need FLAG_ACTIVITY_NEW_TASK
assertThat(startedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isEqualTo(0);
assertThat(startedIntent.getComponent().getClassName())
.isEqualTo("com.mopub.common.MoPubBrowser");
verify(mockMraidListener).onOpen();
}
@Test
public void handleOpen_withApplicationUrlThatCantBeHandled_shouldDefaultToMoPubBrowser()
throws Exception {
String applicationUrl = "canthandleme://blah";
subject.handleOpen(applicationUrl);
Intent startedIntent = Robolectric.getShadowApplication().getNextStartedActivity();
assertThat(startedIntent).isNotNull();
// Since we are using an Activity context, we do not need FLAG_ACTIVITY_NEW_TASK
assertThat(startedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isEqualTo(0);
assertThat(startedIntent.getComponent().getClassName())
.isEqualTo("com.mopub.common.MoPubBrowser");
assertThat(startedIntent.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY))
.isEqualTo(applicationUrl);
verify(mockMraidListener).onOpen();
}
@Test
public void orientationBroadcastReceiver_whenUnregistered_shouldIgnoreOnReceive() {
Intent intent = mock(Intent.class);
when(intent.getAction()).thenReturn("some bogus action which we hope never to see");
MraidController.OrientationBroadcastReceiver receiver =
subject.new OrientationBroadcastReceiver();
receiver.register(activity);
receiver.unregister();
receiver.onReceive(activity, intent);
verify(intent, never()).getAction();
}
@Test
public void orientationProperties_shouldDefaultToAllowChangeTrueAndForceOrientationNone() {
// These are the default values provided by the MRAID spec
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_withForcedOrientation_shouldUpdateProperties() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
assertThat(subject.getAllowOrientationChange()).isFalse();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.LANDSCAPE);
}
@Test
public void handleSetOrientationProperties_withOrientationNone_withApplicationContext_shouldUpdateProperties() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject = new MraidController(
activity.getApplicationContext(), mockAdReport, PlacementType.INLINE,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
subject.handleSetOrientationProperties(false, MraidOrientation.NONE);
assertThat(subject.getAllowOrientationChange()).isFalse();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_withForcedOrientation_withApplicationContext_shouldThrowMraidCommandExceptionAndNotUpdateProperties() throws PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject = new MraidController(
activity.getApplicationContext(), mockAdReport, PlacementType.INLINE,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
try {
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
fail("Expected MraidCommandException");
} catch (MraidCommandException e) {
// pass
}
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_withActivityInfoNotFound_shouldThrowMraidCommandException() throws PackageManager.NameNotFoundException {
setMockActivityInfo(false, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
try {
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
fail("Expected MraidCommandException");
} catch (MraidCommandException e) {
// pass
}
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_whenTryingToSetToOrientationDeclaredInManifest_shouldUpdateProperties() throws Exception {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handleSetOrientationProperties(true, MraidOrientation.PORTRAIT);
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.PORTRAIT);
}
@Test
public void handleSetOrientationProperties_whenTryingToSetToOrientationDifferentFromManifest_shouldThrowMraidCommandException() throws Exception {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
try {
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
fail("Expected MraidCommandException");
} catch (MraidCommandException e) {
// pass
}
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_withForcedOrientation_withMissingConfigChangeOrientation_shouldThrowMraidCommandException() throws Exception {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
/* missing CONFIG_ORIENTATION */ ActivityInfo.CONFIG_SCREEN_SIZE);
try {
subject.handleSetOrientationProperties(true, MraidOrientation.PORTRAIT);
fail("Expected MraidCommandException");
} catch (MraidCommandException e) {
// pass
}
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Config(reportSdk = Build.VERSION_CODES.HONEYCOMB_MR1)
@Test
public void handleSetOrientationProperties_beforeHoneycombMr2_withMissingConfigChangeScreenSize_shouldUpdateProperties() throws Exception {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, ActivityInfo.CONFIG_ORIENTATION);
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
assertThat(subject.getAllowOrientationChange()).isFalse();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.LANDSCAPE);
}
@Config(reportSdk = Build.VERSION_CODES.HONEYCOMB_MR2)
@Test
public void handleSetOrientationProperties_atLeastHoneycombMr2_withMissingConfigChangeScreenSize_shouldThrowMraidCommandException() throws Exception {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, ActivityInfo.CONFIG_ORIENTATION);
try {
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
fail("Expected MraidCommandException");
} catch (MraidCommandException e) {
// pass
}
assertThat(subject.getAllowOrientationChange()).isTrue();
assertThat(subject.getForceOrientation()).isEqualTo(MraidOrientation.NONE);
}
@Test
public void handleSetOrientationProperties_forExpandedBanner_shouldImmediatelyChangeScreenOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handlePageLoad();
subject.handleExpand(null, false);
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void handleSetOrientationProperties_forExpandedBanner_beforeExpandIsCalled_shouldChangeScreenOrientationUponExpand() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handlePageLoad();
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_PORTRAIT);
subject.handleExpand(null, false);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void handleSetOrientationProperties_forDefaultBanner_shouldNotChangeScreenOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handlePageLoad();
// don't expand the banner
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void handleSetOrientationProperties_forInterstitial_shouldChangeScreenOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject = new MraidController(
activity, mockAdReport, PlacementType.INTERSTITIAL,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_PORTRAIT);
subject.handlePageLoad();
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
assertThat(activity.getRequestedOrientation()).isEqualTo(ActivityInfo
.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void shouldAllowForceOrientation_withNoneOrientation_shouldReturnTrue() throws PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
final boolean result = subject.shouldAllowForceOrientation(MraidOrientation.NONE);
assertThat(result).isTrue();
}
@Test
public void shouldAllowForceOrientation_withApplicationContext_shouldReturnFalse() throws PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject = new MraidController(
activity.getApplicationContext(), mockAdReport, PlacementType.INLINE,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
final boolean result = subject.shouldAllowForceOrientation(MraidOrientation.PORTRAIT);
assertThat(result).isFalse();
}
@Test(expected = MraidCommandException.class)
public void lockOrientation_withApplicationContext_shouldThrowMraidCommandException() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject = new MraidController(
activity.getApplicationContext(), mockAdReport, PlacementType.INLINE,
mockBridge, mockTwoPartBridge, mockScreenMetricsWaiter);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void lockOrientation_withActivityContext_shouldInitializeOriginalActivityOrientationAndCallActivitySetOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
assertThat(subject.getOriginalActivityOrientation()).isNull();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertThat(subject.getOriginalActivityOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void lockOrientation_subsequentTimes_shouldNotModifyOriginalActivityOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertThat(subject.getOriginalActivityOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
assertThat(subject.getOriginalActivityOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void applyOrientation_withLockedOrientation_withForceOrientationNone_withAllowOrientationChangeTrue_shouldResetOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
subject.handleSetOrientationProperties(true, MraidOrientation.NONE);
subject.applyOrientation();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void applyOrientation_withNoLockedOrientation_withForceOrientationNone_withAllowOrientationChangeTrue_shouldDoNothing() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.handleSetOrientationProperties(true, MraidOrientation.NONE);
subject.applyOrientation();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void applyOrientation_withForcedOrientationTrue_shouldSetRequestedOrientationToForcedOrienation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handleSetOrientationProperties(true, MraidOrientation.LANDSCAPE);
subject.applyOrientation();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void applyOrientation_withForcedOrientationFalse_shouldSetRequestedOrientationToForcedOrienation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
subject.handleSetOrientationProperties(false, MraidOrientation.LANDSCAPE);
subject.applyOrientation();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
@Test
public void unapplyOrientation_withALockedOrientation_shouldReturnToOriginalOrientationAndResetOriginalActivityOrientation() throws MraidCommandException, PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
assertThat(subject.getOriginalActivityOrientation()).isNull();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.lockOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
assertThat(subject.getOriginalActivityOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
subject.unApplyOrientation();
assertThat(subject.getOriginalActivityOrientation()).isNull();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void unapplyOrientation_withoutLockedOrientation_shouldNotChangeRequestedOrientation()
throws PackageManager.NameNotFoundException {
setMockActivityInfo(true, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_SCREEN_SIZE);
assertThat(subject.getOriginalActivityOrientation()).isNull();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
subject.unApplyOrientation();
assertThat(subject.getOriginalActivityOrientation()).isNull();
assertThat(activity.getRequestedOrientation())
.isEqualTo(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Test
public void destroy_shouldCancelLastMetricsRequest_shouldUnregisterBroadcastReceiver_shouldDetachAllBridges() {
subject.destroy();
verify(mockScreenMetricsWaiter).cancelLastRequest();
verify(mockOrientationBroadcastReceiver).unregister();
verify(mockBridge).detach();
verify(mockTwoPartBridge).detach();
}
@Test
public void destroy_withDefaultState_shouldSetMraidWebViewsToNull() {
subject.setViewStateForTesting(ViewState.DEFAULT);
assertThat(subject.getMraidWebView()).isNotNull();
// The two-part WebView is null by default
assertThat(subject.getTwoPartWebView()).isNull();
subject.destroy();
assertThat(subject.getMraidWebView()).isNull();
assertThat(subject.getTwoPartWebView()).isNull();
}
@Test
public void destroy_withExpandedState_shouldSetMraidWebViewsToNull()
throws MraidCommandException {
// Necessary to set up the webview before expanding. Also moves the state to DEFAULT.
subject.handlePageLoad();
assertThat(subject.getViewState()).isEqualTo(ViewState.DEFAULT);
subject.handleExpand(URI.create("http://two-part-url"), false);
assertThat(subject.getMraidWebView()).isNotNull();
assertThat(subject.getTwoPartWebView()).isNotNull();
subject.destroy();
assertThat(subject.getMraidWebView()).isNull();
assertThat(subject.getTwoPartWebView()).isNull();
}
@Test
public void destroy_afterDestroy_shouldNotThrowAnException() {
subject.destroy();
subject.destroy();
assertThat(subject.getMraidWebView()).isNull();
assertThat(subject.getTwoPartWebView()).isNull();
}
@Test
public void destroy_fromExpandedState_shouldRemoveCloseableAdContainerFromContentView()
throws MraidCommandException {
subject.handlePageLoad();
subject.handleExpand(null, false);
assertThat(rootView.getChildCount()).isEqualTo(1);
subject.destroy();
assertThat(rootView.getChildCount()).isEqualTo(0);
}
@Test
public void destroy_fromResizedState_shouldRemoveCloseableAdContainerFromContentView()
throws MraidCommandException {
subject.handlePageLoad();
subject.setRootViewSize(100, 100);
subject.handleResize(100, 100, 0, 0, ClosePosition.TOP_RIGHT, true);
assertThat(rootView.getChildCount()).isEqualTo(1);
subject.destroy();
assertThat(rootView.getChildCount()).isEqualTo(0);
}
private void setMockActivityInfo(final boolean activityInfoFound, int screenOrientation,
int configChanges) throws PackageManager.NameNotFoundException {
final ActivityInfo mockActivityInfo = mock(ActivityInfo.class);
mockActivityInfo.screenOrientation = screenOrientation;
mockActivityInfo.configChanges = configChanges;
final PackageManager mockPackageManager = mock(PackageManager.class);
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
if (!activityInfoFound) {
throw new PackageManager.NameNotFoundException("");
}
return mockActivityInfo;
}
}).when(mockPackageManager).getActivityInfo(any(ComponentName.class), anyInt());
when(activity.getPackageManager()).thenReturn(mockPackageManager);
}
}