package com.mopub.mraid; import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; import android.os.Environment; import android.provider.CalendarContract; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; import com.mopub.common.test.support.SdkTestRunner; import com.mopub.mobileads.test.support.FileUtils; import com.mopub.mobileads.test.support.TestHttpResponseWithHeaders; import com.mopub.mobileads.test.support.ThreadUtils; import com.mopub.mraid.MraidNativeCommandHandler.MraidCommandFailureListener; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowAlertDialog; import org.robolectric.shadows.ShadowEnvironment; import org.robolectric.shadows.ShadowLog; import org.robolectric.shadows.ShadowToast; import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import static android.content.DialogInterface.BUTTON_NEGATIVE; import static android.content.DialogInterface.BUTTON_POSITIVE; import static com.mopub.mraid.MraidNativeCommandHandler.ANDROID_CALENDAR_CONTENT_TYPE; import static java.io.File.separator; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.stub; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Robolectric.shadowOf; @RunWith(SdkTestRunner.class) public class MraidNativeCommandHandlerTest { private static final String IMAGE_URI_VALUE = "file://tmp/expectedFile.jpg"; private static final int TIME_TO_PAUSE_FOR_NETWORK = 300; private static final String FAKE_IMAGE_DATA = "imageFileData"; //XXX: Robolectric or JUNIT doesn't support the correct suffix ZZZZZ in the parse pattern, so replacing xx:xx with xxxx for time. private static final String CALENDAR_START_TIME = "2013-08-14T20:00:00-0000"; @Mock MraidCommandFailureListener mraidCommandFailureListener; private MraidNativeCommandHandler subject; private Context context; private Map<String, String> params; private File expectedFile; private File pictureDirectory; private File fileWithoutExtension; private TestHttpResponseWithHeaders response; @Before public void setUp() throws Exception { subject = new MraidNativeCommandHandler(); context = Robolectric.buildActivity(Activity.class).create().get(); FileUtils.copyFile("etc/expectedFile.jpg", "/tmp/expectedFile.jpg"); expectedFile = new File(Environment.getExternalStorageDirectory(), "Pictures" + separator + "expectedFile.jpg"); pictureDirectory = new File(Environment.getExternalStorageDirectory(), "Pictures"); fileWithoutExtension = new File(pictureDirectory, "file"); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_withActivityContext_shouldDisplayAlertDialog() throws Exception { response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); subject.storePicture(context, IMAGE_URI_VALUE, mraidCommandFailureListener); AlertDialog alertDialog = ShadowAlertDialog.getLatestAlertDialog(); ShadowAlertDialog shadowAlertDialog = shadowOf(alertDialog); assertThat(alertDialog.isShowing()); assertThat(shadowAlertDialog.getTitle()).isEqualTo("Save Image"); assertThat(shadowAlertDialog.getMessage()).isEqualTo("Download image to Picture gallery?"); assertThat(shadowAlertDialog.isCancelable()).isTrue(); assertThat(alertDialog.getButton(BUTTON_POSITIVE).hasOnClickListeners()); assertThat(alertDialog.getButton(BUTTON_NEGATIVE)).isNotNull(); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_whenOkayClicked_shouldDownloadImage() throws Exception { response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); Robolectric.addPendingHttpResponse(response); subject.storePicture(context, IMAGE_URI_VALUE, mraidCommandFailureListener); ShadowAlertDialog.getLatestAlertDialog().getButton(BUTTON_POSITIVE).performClick(); ThreadUtils.pause(TIME_TO_PAUSE_FOR_NETWORK); assertThat(expectedFile.exists()).isTrue(); assertThat(expectedFile.length()).isEqualTo(FAKE_IMAGE_DATA.length()); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_whenCancelClicked_shouldDismissDialog() throws Exception { response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); subject.storePicture(context, IMAGE_URI_VALUE, mraidCommandFailureListener); AlertDialog alertDialog = ShadowAlertDialog.getLatestAlertDialog(); ShadowAlertDialog shadowAlertDialog = shadowOf(alertDialog); alertDialog.getButton(BUTTON_NEGATIVE).performClick(); assertThat(shadowAlertDialog.hasBeenDismissed()).isTrue(); assertThat(expectedFile.exists()).isFalse(); assertThat(expectedFile.length()).isEqualTo(0); } @Ignore("MRAID 2.0") @Test public void showUserDownloadImageAlert_withAppContext_shouldToastAndDownloadImage() throws Exception { response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); Robolectric.addPendingHttpResponse(response); assertThat(ShadowToast.shownToastCount()).isEqualTo(0); subject.storePicture(context.getApplicationContext(), IMAGE_URI_VALUE, mraidCommandFailureListener); ThreadUtils.pause(TIME_TO_PAUSE_FOR_NETWORK); assertThat(ShadowToast.shownToastCount()).isEqualTo(1); assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo("Downloading image to Picture gallery..."); Robolectric.runUiThreadTasks(); assertThat(expectedFile.exists()).isTrue(); assertThat(expectedFile.length()).isEqualTo(FAKE_IMAGE_DATA.length()); } @Ignore("MRAID 2.0") @Test public void showUserDownloadImageAlert_withAppContext_whenDownloadImageFails_shouldDisplayFailureToastAndNotDownloadImage() throws Exception { response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); Robolectric.addPendingHttpResponse(response); assertThat(ShadowToast.shownToastCount()).isEqualTo(0); subject.storePicture(context, "this is an invalid image url and cannot be downloaded", mraidCommandFailureListener); ThreadUtils.pause(TIME_TO_PAUSE_FOR_NETWORK); assertThat(ShadowToast.shownToastCount()).isEqualTo(1); assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo("Downloading image to Picture gallery..."); Robolectric.runUiThreadTasks(); assertThat(ShadowToast.shownToastCount()).isEqualTo(2); assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo("Image failed to download."); assertThat(expectedFile.exists()).isFalse(); assertThat(expectedFile.length()).isEqualTo(0); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_whenStorePictureNotSupported_shouldFireErrorEvent_andNotToastNorAlertDialog() throws Exception { Robolectric.getShadowApplication().denyPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE); subject.storePicture(context, "http://image.jpg", mraidCommandFailureListener); assertThat(ShadowToast.shownToastCount()).isEqualTo(0); assertThat(ShadowAlertDialog.getLatestAlertDialog()).isNull(); verify(mraidCommandFailureListener).onFailure(any(MraidCommandException.class)); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_withMimeTypeAndNoFileExtension_shouldSavePictureWithMimeType() throws Exception { String fileNameWithNoExtension = "https://www.somewhere.com/images/blah/file"; assertThatMimeTypeWasAddedCorrectly( fileNameWithNoExtension, "image/jpg", "file.jpg", ".jpg"); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_withMultipleContentTypesAndNoFileExtension_shouldSavePictureWithMimeType() throws Exception { String fileNameWithNoExtension = "https://www.somewhere.com/images/blah/file"; assertThatMimeTypeWasAddedCorrectly( fileNameWithNoExtension, "text/html; image/png", "file.png", ".png"); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_withMimeTypeAndFileExtension_shouldSavePictureWithFileExtension() throws Exception { String fileNameWithExtension = "https://www.somewhere.com/images/blah/file.extension"; assertThatMimeTypeWasAddedCorrectly( fileNameWithExtension, "image/extension", "file.extension", ".extension"); assertThat((expectedFile.getName()).endsWith(".extension.extension")).isFalse(); } @Ignore("Mraid 2.0") @Test public void showUserDownloadImageAlert_withHttpUri_shouldRequestPictureFromNetwork() throws Exception { response = new TestHttpResponseWithHeaders(200, "OK"); downloadImageForPendingResponse("https://www.google.com/images/srpr/logo4w.png", response); HttpUriRequest latestRequest = (HttpUriRequest) Robolectric.getLatestSentHttpRequest(); assertThat(latestRequest.getURI()).isEqualTo(URI.create("https://www.google.com/images/srpr/logo4w.png")); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withMinimumValidParams_atLeastICS_shouldCreateEventIntent() throws Exception { setupCalendarParams(); subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener, never()).onFailure(any(MraidCommandException.class)); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getType()).isEqualTo(ANDROID_CALENDAR_CONTENT_TYPE); assertThat(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isNotEqualTo(0); assertThat(intent.getStringExtra(CalendarContract.Events.TITLE)).isNotNull(); assertThat(intent.getLongExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, -1)).isNotEqualTo(-1); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withoutSecondsOnStartDate_atLeastICS_shouldCreateEventIntent() throws Exception { setupCalendarParams(); params.put("start", "2012-12-21T00:00-0500"); subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener, never()).onFailure(any(MraidCommandException.class)); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getType()).isEqualTo(ANDROID_CALENDAR_CONTENT_TYPE); assertThat(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isNotEqualTo(0); assertThat(intent.getStringExtra(CalendarContract.Events.TITLE)).isNotNull(); assertThat(intent.getLongExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, -1)).isNotEqualTo(-1); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withDailyRecurrence_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "daily"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getType()).isEqualTo(ANDROID_CALENDAR_CONTENT_TYPE); assertThat(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isNotEqualTo(0); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=DAILY;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withDailyRecurrence_withInterval_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "daily"); params.put("interval", "2"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=DAILY;INTERVAL=2;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withWeeklyRecurrence_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=WEEKLY;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withWeeklyRecurrence_withInterval_withOutWeekday_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); params.put("interval", "7"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=WEEKLY;INTERVAL=7;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withWeeklyRecurrence_onAllWeekDays_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); params.put("daysInWeek", "0,1,2,3,4,5,6"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR,SA;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withWeeklyRecurrence_onDuplicateWeekDays_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); params.put("daysInWeek", "3,2,3,3,7,0"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=WEEKLY;BYDAY=WE,TU,SU;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withWeeklyRecurrence_withInterval_withWeekDay_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); params.put("interval", "1"); params.put("daysInWeek", "1"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=WEEKLY;INTERVAL=1;BYDAY=MO;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withDailyRecurrence_withWeeklyRecurrence_withMonthlyOccurence_shouldCreateDailyCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "daily"); params.put("frequency", "daily"); params.put("frequency", "daily"); params.put("interval", "2"); params.put("daysInWeek", "1"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=DAILY;INTERVAL=2;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withMonthlyRecurrence_withOutInterval_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "monthly"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=MONTHLY;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withMonthlyRecurrence_withInterval_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "monthly"); params.put("interval", "2"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=MONTHLY;INTERVAL=2;"); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withMonthlyRecurrence_withOutInterval_withDaysOfMonth_shouldCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "monthly"); params.put("daysInMonth", "2,-15"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getStringExtra(CalendarContract.Events.RRULE)).isEqualTo("FREQ=MONTHLY;BYMONTHDAY=2,-15;"); } @Ignore("Mraid 2.0") @Test public void createCalendarEvent_withMonthlyRecurrence_withInvalidDaysOfMonth_shouldNotCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "monthly"); params.put("daysInMonth", "55"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent).isNull(); assertThat(ShadowLog.getLogs().size()).isEqualTo(1); } @Ignore("Mraid 2.0") @Test public void createCalendarEvent_withWeeklyRecurrence_withInvalidDaysOfWeek_shouldNotCreateCalendarIntent() throws Exception { setupCalendarParams(); params.put("frequency", "weekly"); params.put("daysInWeek", "-1,20"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent).isNull(); assertThat(ShadowLog.getLogs().size()).isEqualTo(1); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.HONEYCOMB_MR2) @Test public void createCalendarEvent_beforeIcs_shouldFireErrorEvent() throws Exception { subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener).onFailure(any(MraidCommandException.class)); } @Ignore("Mraid 2.0") @Test public void createCalendarEvent_withInvalidDate_shouldFireErrorEvent() throws Exception { params.put("start", "2013-08-14T09:00.-08:00"); params.put("description", "Some Event"); subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener).onFailure(any(MraidCommandException.class)); } @Ignore("Mraid 2.0") @Test public void createCalendarEvent_withMissingParameters_shouldFireErrorEvent() throws Exception { //it needs a start time params.put("description", "Some Event"); subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener).onFailure(any(MraidCommandException.class)); } @Ignore("Mraid 2.0") @Test public void createCalendarEvent_withNullDate_shouldFireErrorEvent() throws Exception { params.put("start", null); params.put("description", "Some Event"); subject.createCalendarEvent(context, params); verify(mraidCommandFailureListener).onFailure(any(MraidCommandException.class)); } @Ignore("Mraid 2.0") @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void createCalendarEvent_withValidParamsAllExceptRecurrence_atLeastICS_shouldCreateEventIntent() throws Exception { setupCalendarParams(); params.put("location", "my house"); params.put("end", "2013-08-14T22:01:01-0000"); params.put("summary", "some description actually"); params.put("transparency", "transparent"); subject.createCalendarEvent(context, params); Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(intent.getType()).isEqualTo(ANDROID_CALENDAR_CONTENT_TYPE); assertThat(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK).isNotEqualTo(0); assertThat(intent.getStringExtra(CalendarContract.Events.TITLE)).isNotNull(); assertThat(intent.getStringExtra(CalendarContract.Events.DESCRIPTION)).isNotNull(); assertThat(intent.getStringExtra(CalendarContract.Events.EVENT_LOCATION)).isNotNull(); assertThat(intent.getLongExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, -1)).isNotEqualTo(-1); assertThat(intent.getLongExtra(CalendarContract.EXTRA_EVENT_END_TIME, -1)).isNotEqualTo(-1); assertThat(intent.getIntExtra(CalendarContract.Events.AVAILABILITY, -1)).isEqualTo(CalendarContract.Events.AVAILABILITY_FREE); } @Test public void isTelAvailable_whenCanAcceptIntent_shouldReturnTrue() throws Exception { context = createMockContextWithSpecificIntentData("tel", null, null, "android.intent.action.DIAL"); assertThat(subject.isTelAvailable(context)).isTrue(); } @Test public void isTelAvailable_whenCanNotAcceptIntent_shouldReturnFalse() throws Exception { context = createMockContextWithSpecificIntentData("", null, null, "android.intent.action.DIAL"); assertThat(subject.isTelAvailable(context)).isFalse(); } @Test public void isSmsAvailable_whenCanAcceptIntent_shouldReturnTrue() throws Exception { context = createMockContextWithSpecificIntentData("sms", null, null, "android.intent.action.VIEW"); assertThat(subject.isSmsAvailable(context)).isTrue(); } @Test public void isSmsAvailable_whenCanNotAcceptIntent_shouldReturnFalse() throws Exception { context = createMockContextWithSpecificIntentData("", null, null, "android.intent.action.VIEW"); assertThat(subject.isSmsAvailable(context)).isFalse(); } @Test public void isStorePictureAvailable_whenPermissionDeclaredAndMediaMounted_shouldReturnTrue() throws Exception { Robolectric.getShadowApplication().grantPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE); ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED); assertThat(subject.isStorePictureSupported(context)).isTrue(); } @Test public void isStorePictureAvailable_whenPermissionDenied_shouldReturnFalse() throws Exception { Robolectric.getShadowApplication().denyPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE); ShadowEnvironment.setExternalStorageState(Environment.MEDIA_MOUNTED); assertThat(subject.isStorePictureSupported(context)).isFalse(); } @Test public void isStorePictureAvailable_whenMediaUnmounted_shouldReturnFalse() throws Exception { Robolectric.getShadowApplication().grantPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE); ShadowEnvironment.setExternalStorageState(Environment.MEDIA_UNMOUNTED); assertThat(subject.isStorePictureSupported(context)).isFalse(); } @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void isCalendarAvailable_atLeastIcs_shouldReturnTrue() throws Exception { context = createMockContextWithSpecificIntentData(null, null, ANDROID_CALENDAR_CONTENT_TYPE, "android.intent.action.INSERT"); assertThat(subject.isCalendarAvailable(context)).isTrue(); } @Config(reportSdk = Build.VERSION_CODES.HONEYCOMB_MR2) @Test public void isCalendarAvailable_beforeIcs_shouldReturnFalse() throws Exception { context = createMockContextWithSpecificIntentData(null, null, ANDROID_CALENDAR_CONTENT_TYPE, "android.intent.action.INSERT"); assertThat(subject.isCalendarAvailable(context)).isFalse(); } @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) @Test public void isCalendarAvailable_atLeastIcs_butCanNotAcceptIntent_shouldReturnFalse() throws Exception { context = createMockContextWithSpecificIntentData(null, null, "vnd.android.cursor.item/NOPE", "android.intent.action.INSERT"); assertThat(subject.isCalendarAvailable(context)).isFalse(); } @TargetApi(11) @Test public void isInlineVideoAvailable_whenViewsAreHardwareAccelerated_whenWindowIsHardwareAccelerated_whenApiLevelIsAtLeastHoneycombMR1_shouldReturnTrue() throws Exception { Activity activity = Robolectric.buildActivity(Activity.class).create().get(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); View mockView = mock(View.class); when(mockView.isHardwareAccelerated()).thenReturn(true); when(mockView.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); assertThat(subject.isInlineVideoAvailable(activity, mockView)).isTrue(); } @TargetApi(11) @Test public void isInlineVideoAvailable_whenViewsAreHardwareAccelerated_whenWindowIsNotHardwareAccelerated_whenApiLevelIsAtLeastHoneycombMR1_shouldReturnFalse() throws Exception { Activity activity = Robolectric.buildActivity(Activity.class).create().get(); View mockView = mock(View.class); when(mockView.isHardwareAccelerated()).thenReturn(true); when(mockView.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); assertThat(subject.isInlineVideoAvailable(activity, mockView)).isFalse(); } @Config(reportSdk = Build.VERSION_CODES.HONEYCOMB) @TargetApi(11) @Test public void isInlineVideoAvailable_whenViewsAreHardwareAccelerated_whenWindowIsHardwareAccelerated_whenApiLevelIsLessThanHoneycombMR1_shouldReturnFalse() throws Exception { Activity activity = Robolectric.buildActivity(Activity.class).create().get(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); View mockView = mock(View.class); when(mockView.isHardwareAccelerated()).thenReturn(true); when(mockView.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); assertThat(subject.isInlineVideoAvailable(activity, mockView)).isFalse(); } @TargetApi(11) @Test public void isInlineVideoAvailable_whenViewsAreNotHardwareAccelerated_whenWindowIsHardwareAccelerated_whenApiLevelIsAtLeastHoneycombMR1_shouldReturnFalse() throws Exception { Activity activity = Robolectric.buildActivity(Activity.class).create().get(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); View mockView = mock(View.class); when(mockView.isHardwareAccelerated()).thenReturn(false); when(mockView.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); assertThat(subject.isInlineVideoAvailable(activity, mockView)).isFalse(); } @TargetApi(11) @Test public void isInlineVideoAvailable_whenViewParentIsNotHardwareAccelerated_whenWindowIsHardwareAccelerated_whenApiLevelIsAtLeastHoneycombMR1_shouldReturnFalse() throws Exception { Activity activity = Robolectric.buildActivity(Activity.class).create().get(); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); // ViewParent LinearLayout mockLinearLayout = mock(LinearLayout.class); when(mockLinearLayout.isHardwareAccelerated()).thenReturn(false); when(mockLinearLayout.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); // View View mockView = mock(View.class); when(mockView.isHardwareAccelerated()).thenReturn(true); when(mockView.getLayerType()).thenReturn(View.LAYER_TYPE_HARDWARE); when(mockView.getParent()).thenReturn(mockLinearLayout); assertThat(subject.isInlineVideoAvailable(activity, mockView)).isFalse(); } private static Context createMockContextWithSpecificIntentData(final String scheme, final String componentName, final String type, final String action) { Context context = mock(Context.class); PackageManager packageManager = mock(PackageManager.class); List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>(); resolveInfos.add(new ResolveInfo()); stub(context.getPackageManager()).toReturn(packageManager); BaseMatcher intentWithSpecificData = new BaseMatcher() { // check that the specific intent has the special data, i.e. "tel:", or a component name, or string type, based on a particular data @Override public boolean matches(Object item) { if (item != null && item instanceof Intent ){ boolean result = action != null || type != null || componentName != null || scheme != null; if (action != null) { if (((Intent) item).getAction() != null) { result = result && action.equals(((Intent) item).getAction()); } } if (type != null) { if (((Intent) item).getType() != null) { result = result && type.equals(((Intent) item).getType()); } } if (componentName != null) { if (((Intent) item).getComponent() != null) { result = result && componentName.equals(((Intent) item).getComponent().getClassName()); } } if (scheme != null) { if (((Intent) item).getData() != null) { result = result && scheme.equals(((Intent) item).getData().getScheme()); } } return result; } return false; } @Override public void describeTo(Description description) { } }; // It is okay to query with specific intent or nothing, because by default, none of the query would normally any resolveInfo anyways stub(packageManager.queryIntentActivities((Intent) argThat(intentWithSpecificData), eq(0))).toReturn(resolveInfos); return context; } private void downloadImageForPendingResponse(String uri, HttpResponse response) throws Exception { Robolectric.addPendingHttpResponse(response); subject.storePicture(context, uri, mraidCommandFailureListener); ThreadUtils.pause(TIME_TO_PAUSE_FOR_NETWORK); } private void assertThatMimeTypeWasAddedCorrectly(String originalFileName, String contentType, String expectedFileName, String expectedExtension) throws Exception { expectedFile = new File(pictureDirectory, expectedFileName); response = new TestHttpResponseWithHeaders(200, FAKE_IMAGE_DATA); response.addHeader(MraidNativeCommandHandler.MIME_TYPE_HEADER, contentType); downloadImageForPendingResponse(originalFileName, response); assertThat(expectedFile.exists()).isTrue(); assertThat(expectedFile.getName()).endsWith(expectedExtension); assertThat(fileWithoutExtension.exists()).isFalse(); } private void setupCalendarParams() { //we need mock Context so that we can validate that isCalendarAvailable() is true Context mockContext = createMockContextWithSpecificIntentData(null, null, ANDROID_CALENDAR_CONTENT_TYPE, "android.intent.action.INSERT"); //but a mock context does't know how to startActivity(), so we stub it to use ShadowContext for starting activity doAnswer(new Answer<Void>() { public Void answer(InvocationOnMock invocation) throws Throwable { if (!(invocation.getArguments()[0] instanceof Intent)) { throw new ClassCastException("For some reason you are not passing the calendar intent properly"); } Context shadowContext = Robolectric.getShadowApplication().getApplicationContext(); shadowContext.startActivity((Intent) invocation.getArguments()[0]); return null; } }).when(mockContext).startActivity(any(Intent.class)); params.put("description", "Some Event"); params.put("start", CALENDAR_START_TIME); } }