diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f514455f..99f1bc285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## Version 3.10.0 (August 3, 2015) + +- VAST UI improvements and bug fixes. + - Pause trackers no longer fire when the ad is skipped. + - Improved retrieval of blurred video frame when there is no companion ad. +- Added com.mopub:mopub-sdk AAR to [jCenter](https://bintray.com/mopub/mopub-android-sdk/mopub-android-sdk/view). +- Bug Fixes: + - Fixed a NullPointerException in CacheService on devices with low storage space. + - Improved redirect loading for in-app browser. + ## Version 3.9.0 (July 1, 2015) - Added **VAST 3.0** standard support for video ads. @@ -8,6 +18,7 @@ - MRAID video interstitials now play automatically when displayed on Jellybean MR1 and newer. - MRAID relative assets are correctly rendered. - MoPubLog no longer duplicates some messages. + - Fixed erroneous output of DeviceUtils.getScreenOrientationFromRotationAndOrientation(). ## Version 3.8.0 (June 1, 2015) diff --git a/README.md b/README.md index fe5be9b57..1514edfa7 100644 --- a/README.md +++ b/README.md @@ -6,42 +6,66 @@ Sign up for an account at [http://app.mopub.com/](http://app.mopub.com/). ## Need Help? -You can find integration documentation on our [wiki](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started) and -additional help documentation on our [developer help site](http://dev.twitter.com/mopub). +You can find integration documentation on our [wiki](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started) and additional help documentation on our [developer help site](http://dev.twitter.com/mopub). To file an issue with our team visit the [MoPub Forum](https://twittercommunity.com/c/fabric/mopub) or email [support@mopub.com](mailto:support@mopub.com). -**Please Note: We no longer accept GitHub Issues** +**Please Note: We no longer accept GitHub Issues.** ## Download -The MoPub SDK is distributed as source code that you can include in your application. MoPub provides two prepackaged archives of source code: - -- **[MoPub Android Full SDK.zip](http://bit.ly/YUdU9v)** - - Includes everything you need to serve HTML and MRAID MoPub advertisiments *and* built-in support for Millennial Media third party ad network - [Millennial Media](http://www.millennialmedia.com/) - including the required third party binaries. - -- **[MoPub Android Base SDK.zip](http://bit.ly/YUdWhH)** - - Includes everything you need to serve HTML and MRAID MoPub advertisements. No third party ad networks are included. - -## Integrate - -Integration instructions are available on the [wiki](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started). - +The MoPub SDK is available via: + +1. **jCenter AAR** + + [ ![Download](https://api.bintray.com/packages/mopub/mopub-android-sdk/mopub-android-sdk/images/download.svg)](https://bintray.com/mopub/mopub-android-sdk/mopub-android-sdk/_latestVersion) + The MoPub SDK is available as an AAR via jCenter; to use it, add the following to your `build.gradle`. + + ``` + repositories { + jcenter() + } + + dependencies { + compile('com.mopub:mopub-sdk:3.10.0@aar') { + transitive = true + } + } + ``` + + **To continue integration using the mopub-sdk AAR, please see the [Getting Started guide](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started#updating-your-android-manifest).** + +2. **Zipped Source** + + The MoPub SDK is also distributed as zipped source code that you can include in your application. MoPub provides two prepackaged archives of source code: + + **[MoPub Android Full SDK.zip](http://bit.ly/YUdU9v)** + _Includes everything you need to serve MoPub ads *and* built-in support for Millennial Media third party ad network - [Millennial Media](http://www.millennialmedia.com/) - including the required third party binaries._ + + **[MoPub Android Base SDK.zip](http://bit.ly/YUdWhH)** + _Includes everything you need to serve MoPub ads. No third party ad networks are included._ + + **For additional integration instructions, please see the [Getting Started guide](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started#requirements-and-dependencies).** + +3. **Cloned GitHub repository** + + Alternatively, you can obtain the MoPub SDK source by cloning the git repository: + + `git clone git://github.com/mopub/mopub-android-sdk.git` + + **For additional integration instructions, please see the [Getting Started guide](https://github.com/mopub/mopub-android-sdk/wiki/Getting-Started#requirements-and-dependencies).** ## New in this Version -Please view the [changelog](https://github.com/mopub/mopub-android-sdk/blob/master/CHANGELOG.md) for details. +Please view the [changelog](https://github.com/mopub/mopub-android-sdk/blob/master/CHANGELOG.md) for a complete list of additions, fixes, and enhancements in the lastest release.. -- Added **VAST 3.0** standard support for video ads. -- Improved **video player UX**. -- Added **RecyclerView** support for native ads. See the [integration guide](https://github.com/mopub/mopub-android-sdk/wiki/Native-Ads-with-Recycler-View). -- Improved **deep link** handling. +- VAST UI improvements and bug fixes. + - Pause trackers no longer fire when the ad is skipped. + - Improved retrieval of blurred video frame when there is no companion ad. +- Added com.mopub:mopub-sdk AAR to [jCenter](https://bintray.com/mopub/mopub-android-sdk/mopub-android-sdk/view). - Bug Fixes: - - MRAID video interstitials now play automatically when displayed on Jellybean MR1 and newer. - - MRAID relative assets are correctly rendered. - - MoPubLog no longer duplicates some messages. + - Fixed a NullPointerException in CacheService on devices with low storage space. + - Improved redirect loading for in-app browser. ## Requirements diff --git a/build.gradle b/build.gradle index bfb46b16f..c62b63412 100644 --- a/build.gradle +++ b/build.gradle @@ -6,10 +6,9 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.2.3' - classpath 'org.robolectric:robolectric-gradle-plugin:1.1.0' } } task wrapper(type: Wrapper) { - gradleVersion = '2.2.1' + gradleVersion = '2.5' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3d0dee6e8..30d399d8d 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cd2daf524..57375a650 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Nov 18 14:15:01 PST 2014 +#Wed Jul 15 14:33:43 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-bin.zip diff --git a/mopub-sample/AndroidManifest.xml b/mopub-sample/AndroidManifest.xml index 944023d6c..36a2f79c4 100644 --- a/mopub-sample/AndroidManifest.xml +++ b/mopub-sample/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="27" + android:versionName="3.10.0"> diff --git a/mopub-sample/build.gradle b/mopub-sample/build.gradle index c91e1a7e5..1e3fca7a2 100644 --- a/mopub-sample/build.gradle +++ b/mopub-sample/build.gradle @@ -5,16 +5,16 @@ repositories { apply plugin: 'com.android.application' group = 'com.mopub' - -description = '''MoPub SDK''' +description = '''MoPub Sample App''' +version = '3.10.0' android { compileSdkVersion 22 buildToolsVersion '22.0.1' defaultConfig { - versionCode 26 - versionName "3.9.0" + versionCode 27 + versionName version minSdkVersion 9 targetSdkVersion 22 } diff --git a/mopub-sdk/build.gradle b/mopub-sdk/build.gradle index ab0f24c96..36769c701 100644 --- a/mopub-sdk/build.gradle +++ b/mopub-sdk/build.gradle @@ -1,23 +1,46 @@ // This buildscript will assemble the MoPub SDK into an AAR. +buildscript { + repositories { + mavenCentral() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' + classpath 'org.robolectric:robolectric-gradle-plugin:1.1.0' + } +} + +plugins { + id "com.jfrog.bintray" version "1.2" +} + repositories { + mavenCentral() jcenter() } apply plugin: 'com.android.library' +apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'org.robolectric' -group = 'com.mopub' +task wrapper(type: Wrapper) { + gradleVersion = '2.5' +} -description = '''MoPub SDK''' +group = 'com.mopub' +description = '''MoPub Android SDK''' +version = '3.10.0' android { compileSdkVersion 22 buildToolsVersion '22.0.1' defaultConfig { - versionCode 26 - versionName "3.9.0" + versionCode 27 + versionName version minSdkVersion 9 targetSdkVersion 22 consumerProguardFiles 'proguard.txt' @@ -82,3 +105,108 @@ dependencies { testCompile 'com.squareup:fest-android:1.0.7' testCompile 'org.mockito:mockito-core:1.9.5' } + +def siteUrl = 'https://github.com/mopub/mopub-android-sdk' +def gitUrl = 'https://github.com/mopub/mopub-android-sdk.git' +// Put your credentials (bintray.user, bintray.apikey) in ~/.gradle/gradle.properties +bintray { + user = project.hasProperty("bintray.user") ? project.getProperty("bintray.user") : "" + key = project.hasProperty("bintray.apikey") ? project.getProperty("bintray.apikey") : "" + + configurations = ['archives'] + publish = true + + pkg { + repo = 'mopub-android-sdk' + name = 'mopub-android-sdk' + + userOrg = 'mopub' + desc = description + + websiteUrl = siteUrl + vcsUrl = gitUrl + licenses = ['Apache-2.0'] + + version { + name = project.version + } + } +} + +install { + repositories.mavenInstaller { + pom { + project { + packaging 'aar' + + name 'MoPub Android SDK' + url siteUrl + + licenses { + license { + name 'MoPub SDK License' + url 'http://www.mopub.com/legal/sdk-license-agreement/' + } + } + developers { + // ID corresponds to GitHub user name + developer { + id 'nathanshayefar' + name 'Nathan Shayefar' + email 'nshayefar@twitter.com' + } + developer { + id 'joeblubaugh' + name 'Joe Blubaugh' + email 'joeblubaugh@twitter.com' + } + developer { + id 'steffanc' + name 'Steffan Chartrand' + email 'schartrand@twitter.com' + } + developer { + id 'aornelas' + name 'Andrés Ornelas' + email 'andres@twitter.com' + } + developer { + id 'bichenwang' + name 'Bichen Wang' + email 'bwang@twitter.com' + } + developer { + id 'nathank33' + name 'Nathan Braun' + email 'nbraun@twitter.com' + } + } + scm { + connection gitUrl + developerConnection gitUrl + url siteUrl + } + } + } + } +} + +task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' +} + +task javadoc(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives javadocJar + archives sourcesJar +} diff --git a/mopub-sdk/gradle/wrapper/gradle-wrapper.jar b/mopub-sdk/gradle/wrapper/gradle-wrapper.jar index 3c7abdf12..30d399d8d 100644 Binary files a/mopub-sdk/gradle/wrapper/gradle-wrapper.jar and b/mopub-sdk/gradle/wrapper/gradle-wrapper.jar differ diff --git a/mopub-sdk/gradle/wrapper/gradle-wrapper.properties b/mopub-sdk/gradle/wrapper/gradle-wrapper.properties index d27e87aec..75f1f3fd7 100644 --- a/mopub-sdk/gradle/wrapper/gradle-wrapper.properties +++ b/mopub-sdk/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Mar 20 15:07:53 PDT 2014 +#Fri Jul 24 16:59:31 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-bin.zip diff --git a/mopub-sdk/src/main/java/com/mopub/common/BrowserWebViewClient.java b/mopub-sdk/src/main/java/com/mopub/common/BrowserWebViewClient.java index b0bb92395..33d94acb6 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/BrowserWebViewClient.java +++ b/mopub-sdk/src/main/java/com/mopub/common/BrowserWebViewClient.java @@ -47,34 +47,32 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } - try { - new UrlHandler.Builder() - .withSupportedUrlActions(SUPPORTED_URL_ACTIONS) - .withoutMoPubBrowser() - .withResultActions(new UrlHandler.ResultActions() { - @Override - public void urlHandlingSucceeded(@NonNull String url, - @NonNull UrlAction urlAction) { - if (urlAction.equals(UrlAction.OPEN_IN_APP_BROWSER)) { - mMoPubBrowser.getWebView().loadUrl(url); - } else { - // UrlAction opened in external app, so close MoPubBrowser - mMoPubBrowser.finish(); - } + UrlHandler urlHandler = new UrlHandler.Builder() + .withSupportedUrlActions(SUPPORTED_URL_ACTIONS) + .withoutMoPubBrowser() + .withResultActions(new UrlHandler.ResultActions() { + @Override + public void urlHandlingSucceeded(@NonNull String url, + @NonNull UrlAction urlAction) { + if (urlAction.equals(UrlAction.OPEN_IN_APP_BROWSER)) { + mMoPubBrowser.getWebView().loadUrl(url); + } else { + // UrlAction opened in external app, so close MoPubBrowser + mMoPubBrowser.finish(); } - - @Override - public void urlHandlingFailed(@NonNull String url, - @NonNull UrlAction lastFailedUrlAction) { } - }) - .build().handleUrl(mMoPubBrowser.getApplicationContext(), url, - true, // = fromUserInteraction - true // = throwExceptionOnFailure - ); - return true; - } catch (IntentNotResolvableException e) { - return false; - } + } + + @Override + public void urlHandlingFailed(@NonNull String url, + @NonNull UrlAction lastFailedUrlAction) { + } + }) + .build(); + + return urlHandler.handleResolvedUrl(mMoPubBrowser.getApplicationContext(), url, + true, // = fromUserInteraction + null // = trackingUrls + ); } @Override diff --git a/mopub-sdk/src/main/java/com/mopub/common/CacheService.java b/mopub-sdk/src/main/java/com/mopub/common/CacheService.java index 81f77af7c..58cd1cf50 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/CacheService.java +++ b/mopub-sdk/src/main/java/com/mopub/common/CacheService.java @@ -1,12 +1,12 @@ package com.mopub.common; import android.content.Context; -import android.graphics.Bitmap; import android.os.AsyncTask; -import android.support.v4.util.LruCache; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; -import com.mopub.common.util.DeviceUtils; import com.mopub.common.logging.MoPubLog; +import com.mopub.common.util.DeviceUtils; import com.mopub.common.util.Streams; import com.mopub.common.util.Utils; @@ -40,6 +40,10 @@ public static boolean initializeDiskCache(final Context context) { if (sDiskLruCache == null) { final File cacheDirectory = getDiskCacheDirectory(context); + if (cacheDirectory == null) { + return false; + } + final long diskCacheSizeBytes = DeviceUtils.diskCacheSizeBytes(cacheDirectory); try { sDiskLruCache = open( @@ -50,6 +54,7 @@ public static boolean initializeDiskCache(final Context context) { ); } catch (IOException e) { MoPubLog.d("Unable to create DiskLruCache", e); + return false; } } return true; @@ -63,8 +68,14 @@ public static String createValidDiskCacheKey(final String key) { return Utils.sha1(key); } - public static File getDiskCacheDirectory(final Context context) { - final String cachePath = context.getCacheDir().getPath(); + @Nullable + public static File getDiskCacheDirectory(@NonNull final Context context) { + final File cacheDir = context.getCacheDir(); + if (cacheDir == null) { + return null; + } + + final String cachePath = cacheDir.getPath(); return new File(cachePath + File.separator + UNIQUE_CACHE_NAME); } diff --git a/mopub-sdk/src/main/java/com/mopub/common/HttpClient.java b/mopub-sdk/src/main/java/com/mopub/common/HttpClient.java index c1161d705..09c167308 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/HttpClient.java +++ b/mopub-sdk/src/main/java/com/mopub/common/HttpClient.java @@ -4,10 +4,9 @@ import android.net.http.AndroidHttpClient; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.TextUtils; -import android.webkit.WebView; import com.mopub.common.logging.MoPubLog; +import com.mopub.network.Networking; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.params.HttpClientParams; @@ -25,11 +24,9 @@ public class HttpClient { private static final int CONNECTION_TIMEOUT = 10000; private static final int SOCKET_TIMEOUT = 10000; - private static final String DEFAULT_USER_AGENT = System.getProperty("http.agent"); - private static String sWebViewUserAgent; public static AndroidHttpClient getHttpClient() { - final String userAgent = getWebViewUserAgent(DEFAULT_USER_AGENT); + final String userAgent = Networking.getCachedUserAgent(); AndroidHttpClient httpClient = AndroidHttpClient.newInstance(userAgent); @@ -58,13 +55,13 @@ public static HttpGet initializeHttpGet(@NonNull String url, @Nullable final Con final HttpGet httpGet = new HttpGet(getUrl); - if (getWebViewUserAgent() == null && context != null) { - // Memoize the user agent since creating WebViews is expensive - setWebViewUserAgent(new WebView(context).getSettings().getUserAgentString()); + final String webViewUserAgent; + if (context != null) { + webViewUserAgent = Networking.getUserAgent(context); + } else { + webViewUserAgent = Networking.getCachedUserAgent(); } - - final String webViewUserAgent = getWebViewUserAgent(); if (webViewUserAgent != null) { httpGet.addHeader(USER_AGENT.getKey(), webViewUserAgent); } @@ -137,26 +134,4 @@ static URI encodeUrl(@NonNull String urlString) throws Exception { } return uri; } - - /** - * @param defaultUserAgent the String to return if the WebView user agent hasn't been generated. - * @return the user agent of an Android WebView, or {@code defaultUserAgent} - */ - public synchronized static String getWebViewUserAgent(String defaultUserAgent) { - if (TextUtils.isEmpty(sWebViewUserAgent)) { - return defaultUserAgent; - } - return sWebViewUserAgent; - } - - /** - * @return the user agent of an Android WebView or {@code null} - */ - public synchronized static String getWebViewUserAgent() { - return getWebViewUserAgent(null); - } - - public synchronized static void setWebViewUserAgent(final String userAgent) { - sWebViewUserAgent = userAgent; - } } diff --git a/mopub-sdk/src/main/java/com/mopub/common/MoPub.java b/mopub-sdk/src/main/java/com/mopub/common/MoPub.java index 302a5170e..f9cca0921 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/MoPub.java +++ b/mopub-sdk/src/main/java/com/mopub/common/MoPub.java @@ -8,7 +8,7 @@ import com.mopub.mobileads.MoPubRewardedVideoManager; public class MoPub { - public static final String SDK_VERSION = "3.9.0"; + public static final String SDK_VERSION = "3.10.0"; public static enum LocationAwareness { NORMAL, TRUNCATED, DISABLED } diff --git a/mopub-sdk/src/main/java/com/mopub/common/UrlAction.java b/mopub-sdk/src/main/java/com/mopub/common/UrlAction.java index 0ecb1ef8b..d2b5a438e 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/UrlAction.java +++ b/mopub-sdk/src/main/java/com/mopub/common/UrlAction.java @@ -254,14 +254,7 @@ protected void performAction( // UrlAction.handleUrl already verified this comes from a user interaction final boolean fromUserInteraction = true; - - // Throw IntentNotResolvableException on failure to signal parent handleUrl to continue - // attempting to match other UrlActions - final boolean throwExceptionOnFailure = true; - - urlHandler.handleUrl(context, fallbackUrl, fromUserInteraction, - throwExceptionOnFailure); - makeTrackingHttpRequest(fallbackTrackingUrls, context, BaseEvent.Name.CLICK_REQUEST); + urlHandler.handleUrl(context, fallbackUrl, true, fallbackTrackingUrls); } }, @@ -311,15 +304,6 @@ public void handleUrl( } } - public static UrlAction fromString(@NonNull final String actionName) { - for (UrlAction action : UrlAction.values()) { - if (actionName.equals(action.toString())) { - return action; - } - } - return NOOP; - } - private final boolean mRequiresUserInteraction; UrlAction(boolean requiresUserInteraction) { diff --git a/mopub-sdk/src/main/java/com/mopub/common/UrlHandler.java b/mopub-sdk/src/main/java/com/mopub/common/UrlHandler.java index d558cf2e0..74abd9460 100644 --- a/mopub-sdk/src/main/java/com/mopub/common/UrlHandler.java +++ b/mopub-sdk/src/main/java/com/mopub/common/UrlHandler.java @@ -6,12 +6,16 @@ import android.support.annotation.Nullable; import android.text.TextUtils; +import com.mopub.common.event.BaseEvent; import com.mopub.common.logging.MoPubLog; import com.mopub.common.util.Intents; import com.mopub.exceptions.IntentNotResolvableException; import java.util.EnumSet; +import static com.mopub.common.UrlResolutionTask.UrlResolutionListener; +import static com.mopub.network.TrackingRequest.makeTrackingHttpRequest; + /** * {@code UrlHandler} facilitates handling user clicks on different URLs, allowing configuration * for which kinds of URLs to handle and then responding accordingly for a given URL. @@ -163,6 +167,7 @@ public void urlHandlingFailed(@NonNull String url, @NonNull UrlAction lastFailed private MoPubSchemeListener mMoPubSchemeListener; private boolean mSkipShowMoPubBrowser; private boolean mAlreadySucceeded; + private boolean mTaskPending; /** * Do not instantiate UrlHandler directly; use {@link Builder} instead. @@ -177,6 +182,7 @@ private UrlHandler( mMoPubSchemeListener = moPubSchemeListener; mSkipShowMoPubBrowser = skipShowMoPubBrowser; mAlreadySucceeded = false; + mTaskPending = false; } @NonNull @@ -206,6 +212,8 @@ boolean shouldSkipShowMoPubBrowser() { * @param destinationUrl The URL to handle. */ public void handleUrl(@NonNull final Context context, @NonNull final String destinationUrl) { + Preconditions.checkNotNull(context); + handleUrl(context, destinationUrl, true); } @@ -219,51 +227,106 @@ public void handleUrl(@NonNull final Context context, @NonNull final String dest */ public void handleUrl(@NonNull final Context context, @NonNull final String destinationUrl, final boolean fromUserInteraction) { - try { - final boolean throwExceptionOnFailure = false; - handleUrl(context, destinationUrl, fromUserInteraction, throwExceptionOnFailure); - } catch (IntentNotResolvableException e) { - // Exception will never be thrown since throwExceptionOnFailure is false - } + Preconditions.checkNotNull(context); + + handleUrl(context, destinationUrl, fromUserInteraction, null); } + /** + * Follows any redirects from {@code destinationUrl} and then handles the URL accordingly. + * + * @param context The activity context. + * @param destinationUrl The URL to handle. + * @param fromUserInteraction Whether this handling was triggered from a user interaction. + * @param trackingUrls Optional tracking URLs to trigger on success + */ public void handleUrl(@NonNull final Context context, @NonNull final String destinationUrl, - final boolean fromUserInteraction, final boolean throwExceptionOnFailure) - throws IntentNotResolvableException { - UrlAction lastFailedUrlAction = UrlAction.NOOP; - final String errorMessage; + final boolean fromUserInteraction, @Nullable final Iterable trackingUrls) { + Preconditions.checkNotNull(context); if (TextUtils.isEmpty(destinationUrl)) { - errorMessage = "Attempted to handle empty url."; - } else { - final Uri destinationUri = Uri.parse(destinationUrl); - for (final UrlAction urlAction : mSupportedUrlActions) { - if (urlAction.shouldTryHandlingUrl(destinationUri)) { - try { - urlAction.handleUrl(this, context, destinationUri, fromUserInteraction); - if (!mAlreadySucceeded - && !UrlAction.IGNORE_ABOUT_SCHEME.equals(urlAction) - && !UrlAction.HANDLE_MOPUB_SCHEME.equals(urlAction)) { - mResultActions.urlHandlingSucceeded(destinationUri.toString(), - urlAction); - mAlreadySucceeded = true; - } - return; - } catch (IntentNotResolvableException e) { - MoPubLog.d(e.getMessage(), e); - lastFailedUrlAction = urlAction; - // continue trying to match... + failUrlHandling(destinationUrl, null, "Attempted to handle empty url.", null); + return; + } + + final UrlResolutionListener urlResolutionListener = new UrlResolutionListener() { + @Override + public void onSuccess(@NonNull final String resolvedUrl) { + mTaskPending = false; + handleResolvedUrl(context, resolvedUrl, fromUserInteraction, trackingUrls); + } + + @Override + public void onFailure(@NonNull final String message, + @Nullable final Throwable throwable) { + mTaskPending = false; + failUrlHandling(destinationUrl, null, message, throwable); + + } + + }; + + UrlResolutionTask.getResolvedUrl(destinationUrl, urlResolutionListener); + mTaskPending = true; + } + + /** + * Performs the actual url handling by verifying that the {@code destinationUrl} is one of + * the configured supported {@link UrlAction}s and then handling it accordingly. + * + * @param context The activity context. + * @param url The URL to handle. + * @param fromUserInteraction Whether this handling was triggered from a user interaction. + * @param trackingUrls Optional tracking URLs to trigger on success + * @return true if the given URL was successfully handled; false otherwise + */ + public boolean handleResolvedUrl(@NonNull final Context context, + @NonNull final String url, final boolean fromUserInteraction, + @Nullable Iterable trackingUrls) { + if (TextUtils.isEmpty(url)) { + failUrlHandling(url, null, "Attempted to handle empty url.", null); + return false; + } + + UrlAction lastFailedUrlAction = UrlAction.NOOP; + final Uri destinationUri = Uri.parse(url); + + for (final UrlAction urlAction : mSupportedUrlActions) { + if (urlAction.shouldTryHandlingUrl(destinationUri)) { + try { + urlAction.handleUrl(UrlHandler.this, context, destinationUri, + fromUserInteraction); + if (!mAlreadySucceeded && !mTaskPending + && !UrlAction.IGNORE_ABOUT_SCHEME.equals(urlAction) + && !UrlAction.HANDLE_MOPUB_SCHEME.equals(urlAction)) { + makeTrackingHttpRequest(trackingUrls, context, + BaseEvent.Name.CLICK_REQUEST); + mResultActions.urlHandlingSucceeded(destinationUri.toString(), + urlAction); + mAlreadySucceeded = true; } + return true; + } catch (IntentNotResolvableException e) { + MoPubLog.d(e.getMessage(), e); + lastFailedUrlAction = urlAction; + // continue trying to match... } } - errorMessage = "Link ignored. Unable to handle url: " + destinationUrl; } + failUrlHandling(url, lastFailedUrlAction, "Link ignored. Unable to handle url: " + url, null); + return false; + } - mResultActions.urlHandlingFailed(destinationUrl, lastFailedUrlAction); + private void failUrlHandling(@Nullable final String url, @Nullable UrlAction urlAction, + @NonNull final String message, @Nullable final Throwable throwable) { + Preconditions.checkNotNull(message); - MoPubLog.d(errorMessage); - if (throwExceptionOnFailure) { - throw new IntentNotResolvableException(errorMessage); + if (urlAction == null) { + urlAction = UrlAction.NOOP; } + + MoPubLog.d(message, throwable); + mResultActions.urlHandlingFailed(url, urlAction); } + } diff --git a/mopub-sdk/src/main/java/com/mopub/nativeads/UrlResolutionTask.java b/mopub-sdk/src/main/java/com/mopub/common/UrlResolutionTask.java similarity index 88% rename from mopub-sdk/src/main/java/com/mopub/nativeads/UrlResolutionTask.java rename to mopub-sdk/src/main/java/com/mopub/common/UrlResolutionTask.java index 369653a84..823f39c22 100644 --- a/mopub-sdk/src/main/java/com/mopub/nativeads/UrlResolutionTask.java +++ b/mopub-sdk/src/main/java/com/mopub/common/UrlResolutionTask.java @@ -1,24 +1,23 @@ -package com.mopub.nativeads; +package com.mopub.common; import android.net.Uri; import android.os.AsyncTask; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.mopub.common.UrlAction; -import com.mopub.common.logging.MoPubLog; import com.mopub.common.util.AsyncTasks; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; -class UrlResolutionTask extends AsyncTask { +@VisibleForTesting +public class UrlResolutionTask extends AsyncTask { private static final int REDIRECT_LIMIT = 10; interface UrlResolutionListener { - void onSuccess(@NonNull String resolvedUrl); - void onFailure(); + void onSuccess(@NonNull final String resolvedUrl); + void onFailure(@NonNull final String message, @Nullable final Throwable throwable); } @NonNull private final UrlResolutionListener mListener; @@ -30,9 +29,7 @@ public static void getResolvedUrl(@NonNull final String urlString, try { AsyncTasks.safeExecuteOnExecutor(urlResolutionTask, urlString); } catch (Exception e) { - MoPubLog.d("Failed to resolve url", e); - - listener.onFailure(); + listener.onFailure("Failed to resolve url", e); } } @@ -109,7 +106,7 @@ protected void onPostExecute(@Nullable final String resolvedUrl) { protected void onCancelled() { super.onCancelled(); - mListener.onFailure(); + mListener.onFailure("Task for resolving url was cancelled", null); } } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoPlayerActivity.java b/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoPlayerActivity.java index 78d348776..226ea8ec1 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoPlayerActivity.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoPlayerActivity.java @@ -9,7 +9,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static com.mopub.common.DataKeys.BROADCAST_IDENTIFIER_KEY; -import static com.mopub.mobileads.VastVideoViewController.VAST_VIDEO_CONFIGURATION; +import static com.mopub.mobileads.VastVideoViewController.VAST_VIDEO_CONFIG; public class BaseVideoPlayerActivity extends Activity { static final String VIDEO_CLASS_EXTRAS_KEY = "video_view_class_name"; @@ -34,9 +34,9 @@ static Intent createIntentMraid(final Context context, } static void startVast(final Context context, - final VastVideoConfiguration vastVideoConfiguration, + final VastVideoConfig vastVideoConfig, final long broadcastIdentifier) { - final Intent intentVideoPlayerActivity = createIntentVast(context, vastVideoConfiguration, broadcastIdentifier); + final Intent intentVideoPlayerActivity = createIntentVast(context, vastVideoConfig, broadcastIdentifier); try { context.startActivity(intentVideoPlayerActivity); } catch (ActivityNotFoundException e) { @@ -45,12 +45,12 @@ static void startVast(final Context context, } static Intent createIntentVast(final Context context, - final VastVideoConfiguration vastVideoConfiguration, + final VastVideoConfig vastVideoConfig, final long broadcastIdentifier) { final Intent intentVideoPlayerActivity = new Intent(context, MraidVideoPlayerActivity.class); intentVideoPlayerActivity.setFlags(FLAG_ACTIVITY_NEW_TASK); intentVideoPlayerActivity.putExtra(VIDEO_CLASS_EXTRAS_KEY, "vast"); - intentVideoPlayerActivity.putExtra(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + intentVideoPlayerActivity.putExtra(VAST_VIDEO_CONFIG, vastVideoConfig); intentVideoPlayerActivity.putExtra(BROADCAST_IDENTIFIER_KEY, broadcastIdentifier); return intentVideoPlayerActivity; } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoViewController.java b/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoViewController.java index 13a603b59..6856f4a97 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoViewController.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/BaseVideoViewController.java @@ -3,6 +3,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -50,6 +51,7 @@ protected void onCreate() { protected abstract void onResume(); protected abstract void onDestroy(); protected abstract void onSaveInstanceState(@NonNull Bundle outState); + protected abstract void onConfigurationChanged(@Nullable Configuration configuration); public boolean backButtonEnabled() { return true; diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/MraidVideoPlayerActivity.java b/mopub-sdk/src/main/java/com/mopub/mobileads/MraidVideoPlayerActivity.java index d44f2f224..9f58f6f95 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/MraidVideoPlayerActivity.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/MraidVideoPlayerActivity.java @@ -3,6 +3,7 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.content.res.Configuration; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -36,7 +37,7 @@ protected void onCreate(Bundle savedInstanceState) { } catch (IllegalStateException e) { // This can happen if the activity was started without valid intent extras. We leave // mBaseVideoController set to null, and finish the activity immediately. - + broadcastAction(this, mBroadcastIdentifier, ACTION_INTERSTITIAL_FAIL); finish(); return; @@ -77,6 +78,14 @@ protected void onSaveInstanceState(@NonNull Bundle outState) { } } + @Override + public void onConfigurationChanged(@Nullable Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (mBaseVideoController != null) { + mBaseVideoController.onConfigurationChanged(newConfig); + } + } + @Override public void onBackPressed() { if (mBaseVideoController != null && mBaseVideoController.backButtonEnabled()) { diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAd.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAdConfig.java similarity index 88% rename from mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAd.java rename to mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAdConfig.java index 159ae7909..6bf820ae2 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAd.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastCompanionAdConfig.java @@ -1,6 +1,7 @@ package com.mopub.mobileads; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -12,6 +13,7 @@ import com.mopub.common.Preconditions; import com.mopub.common.UrlAction; import com.mopub.common.UrlHandler; +import com.mopub.common.logging.MoPubLog; import com.mopub.common.util.Intents; import java.io.Serializable; @@ -19,7 +21,7 @@ import static com.mopub.network.TrackingRequest.makeVastTrackingHttpRequest; -public class VastCompanionAd implements Serializable { +public class VastCompanionAdConfig implements Serializable { private static final long serialVersionUID = 0L; private final int mWidth; @@ -29,7 +31,7 @@ public class VastCompanionAd implements Serializable { @NonNull private final List mClickTrackers; @NonNull private final List mCreativeViewTrackers; - public VastCompanionAd( + public VastCompanionAdConfig( int width, int height, @NonNull VastResource vastResource, @@ -156,9 +158,15 @@ public void urlHandlingSucceeded(@NonNull String url, bundle.putString(MoPubBrowser.DESTINATION_URL_KEY, url); - Intent intent = Intents.getStartActivityIntent( - context, MoPubBrowser.class, bundle); - ((Activity) context).startActivityForResult(intent, requestCode); + final Class clazz = MoPubBrowser.class; + final Intent intent = Intents.getStartActivityIntent( + context, clazz, bundle); + try { + ((Activity) context).startActivityForResult(intent, requestCode); + } catch (ActivityNotFoundException e) { + MoPubLog.d("Activity " + clazz.getName() + " not found. Did you " + + "declare it in your AndroidManifest.xml?"); + } } } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastIcon.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastIconConfig.java similarity index 98% rename from mopub-sdk/src/main/java/com/mopub/mobileads/VastIcon.java rename to mopub-sdk/src/main/java/com/mopub/mobileads/VastIconConfig.java index 37cd3590a..73648a27a 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastIcon.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastIconConfig.java @@ -23,7 +23,7 @@ /** * The data and event handlers for the icon displayed during a VAST 3.0 video. */ -class VastIcon implements Serializable { +class VastIconConfig implements Serializable { private static final long serialVersionUID = 0L; private final int mWidth; @@ -35,7 +35,7 @@ class VastIcon implements Serializable { @Nullable private final String mClickThroughUri; @NonNull private final List mViewTrackingUris; - VastIcon(int width, + VastIconConfig(int width, int height, @Nullable Integer offsetMS, @Nullable Integer durationMS, diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastManager.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastManager.java index ffac9c831..d2e16bc7f 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastManager.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastManager.java @@ -17,7 +17,7 @@ /** * Given a VAST xml document, this class manages the lifecycle of parsing and finding a video and * possibly companion ad. It provides the API for clients to prepare a - * {@link VastVideoConfiguration}. + * {@link VastVideoConfig}. */ public class VastManager implements VastXmlManagerAggregator.VastXmlManagerAggregatorListener { /** @@ -29,17 +29,17 @@ public interface VastManagerListener { * Called when a video is found or if the VAST document is invalid. Passes in {@code null} * when the VAST document is invalid. * - * @param vastVideoConfiguration A configuration that can be used for displaying a VAST + * @param vastVideoConfig A configuration that can be used for displaying a VAST * video or {@code null} if the VAST document is invalid. */ void onVastVideoConfigurationPrepared( - @Nullable final VastVideoConfiguration vastVideoConfiguration); + @Nullable final VastVideoConfig vastVideoConfig); } @Nullable private VastManagerListener mVastManagerListener; @Nullable private VastXmlManagerAggregator mVastXmlManagerAggregator; private double mScreenAspectRatio; - private int mScreenArea; + private int mScreenAreaDp; public VastManager(@NonNull final Context context) { initializeScreenDimensions(context); @@ -60,7 +60,7 @@ public void prepareVastVideoConfiguration(@Nullable final String vastXml, if (mVastXmlManagerAggregator == null) { mVastManagerListener = vastManagerListener; mVastXmlManagerAggregator = new VastXmlManagerAggregator(this, mScreenAspectRatio, - mScreenArea, context.getApplicationContext()); + mScreenAreaDp, context.getApplicationContext()); try { AsyncTasks.safeExecuteOnExecutor(mVastXmlManagerAggregator, vastXml); @@ -82,20 +82,19 @@ public void cancel() { } @Override - public void onAggregationComplete( - @Nullable final VastVideoConfiguration vastVideoConfiguration) { + public void onAggregationComplete(@Nullable final VastVideoConfig vastVideoConfig) { if (mVastManagerListener == null) { throw new IllegalStateException( "mVastManagerListener cannot be null here. Did you call " + "prepareVastVideoConfiguration()?"); } - if (vastVideoConfiguration == null) { + if (vastVideoConfig == null) { mVastManagerListener.onVastVideoConfigurationPrepared(null); return; } - if (updateDiskMediaFileUrl(vastVideoConfiguration)) { - mVastManagerListener.onVastVideoConfigurationPrepared(vastVideoConfiguration); + if (updateDiskMediaFileUrl(vastVideoConfig)) { + mVastManagerListener.onVastVideoConfigurationPrepared(vastVideoConfig); return; } @@ -103,8 +102,8 @@ public void onAggregationComplete( new VastVideoDownloadTaskListener() { @Override public void onComplete(boolean success) { - if (success && updateDiskMediaFileUrl(vastVideoConfiguration)) { - mVastManagerListener.onVastVideoConfigurationPrepared(vastVideoConfiguration); + if (success && updateDiskMediaFileUrl(vastVideoConfig)) { + mVastManagerListener.onVastVideoConfigurationPrepared(vastVideoConfig); } else { mVastManagerListener.onVastVideoConfigurationPrepared(null); } @@ -115,7 +114,7 @@ public void onComplete(boolean success) { try { AsyncTasks.safeExecuteOnExecutor( vastVideoDownloadTask, - vastVideoConfiguration.getNetworkMediaFileUrl() + vastVideoConfig.getNetworkMediaFileUrl() ); } catch (Exception e) { MoPubLog.d("Failed to download vast video", e); @@ -125,20 +124,20 @@ public void onComplete(boolean success) { /** * This method takes the media file http url and checks to see if we have the media file downloaded - * and cached in the Disk LRU cache. If it is cached, then the {@link VastVideoConfiguration} is + * and cached in the Disk LRU cache. If it is cached, then the {@link VastVideoConfig} is * updated with the media file's url on disk. * - * @param vastVideoConfiguration used to store the media file's disk url and web url + * @param vastVideoConfig used to store the media file's disk url and web url * @return true if the media file was already cached locally, otherwise false */ private boolean updateDiskMediaFileUrl( - @NonNull final VastVideoConfiguration vastVideoConfiguration) { - Preconditions.checkNotNull(vastVideoConfiguration, "vastVideoConfiguration cannot be null"); + @NonNull final VastVideoConfig vastVideoConfig) { + Preconditions.checkNotNull(vastVideoConfig, "vastVideoConfig cannot be null"); - final String networkMediaFileUrl = vastVideoConfiguration.getNetworkMediaFileUrl(); + final String networkMediaFileUrl = vastVideoConfig.getNetworkMediaFileUrl(); if (CacheService.containsKeyDiskCache(networkMediaFileUrl)) { final String filePathDiskCache = CacheService.getFilePathDiskCache(networkMediaFileUrl); - vastVideoConfiguration.setDiskMediaFileUrl(filePathDiskCache); + vastVideoConfig.setDiskMediaFileUrl(filePathDiskCache); return true; } return false; @@ -148,20 +147,26 @@ private void initializeScreenDimensions(@NonNull final Context context) { Preconditions.checkNotNull(context, "context cannot be null"); // This currently assumes that all vast videos will be played in landscape final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - int x = display.getWidth(); - int y = display.getHeight(); + final int xPx = display.getWidth(); + final int yPx = display.getHeight(); + // Use the screen density to convert x and y (in pixels) to DP. Also, check the density to + // make sure that this is a valid density and that this is not going to divide by 0. + float density = context.getResources().getDisplayMetrics().density; + if (density <= 0) { + density = 1; + } // For landscape, width is always greater than height - int screenWidth = Math.max(x, y); - int screenHeight = Math.min(x, y); + int screenWidth = Math.max(xPx, yPx); + int screenHeight = Math.min(xPx, yPx); mScreenAspectRatio = (double) screenWidth / screenHeight; - mScreenArea = screenWidth * screenHeight; + mScreenAreaDp = (int) ((screenWidth / density) * (screenHeight / density)); } @VisibleForTesting @Deprecated - int getScreenArea() { - return mScreenArea; + int getScreenAreaDp() { + return mScreenAreaDp; } @VisibleForTesting diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTask.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTask.java new file mode 100644 index 000000000..53e9c9ce6 --- /dev/null +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTask.java @@ -0,0 +1,88 @@ +package com.mopub.mobileads; + +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.os.AsyncTask; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.widget.ImageView; + +import com.mopub.common.VisibleForTesting; +import com.mopub.common.logging.MoPubLog; +import com.mopub.common.util.ImageUtils; +import com.mopub.mobileads.resource.DrawableConstants; + +public class VastVideoBlurLastVideoFrameTask extends AsyncTask { + @NonNull private final MediaMetadataRetriever mMediaMetadataRetriever; + @NonNull private final ImageView mBlurredLastVideoFrameImageView; + private int mVideoDuration; + @Nullable private Bitmap mLastVideoFrame; + @Nullable private Bitmap mBlurredLastVideoFrame; + + public VastVideoBlurLastVideoFrameTask( + @NonNull final MediaMetadataRetriever mediaMetadataRetriever, + @NonNull final ImageView blurredLastVideoFrameImageView, int videoDuration) { + mMediaMetadataRetriever = mediaMetadataRetriever; + mBlurredLastVideoFrameImageView = blurredLastVideoFrameImageView; + mVideoDuration = videoDuration; + } + + @Override + protected Boolean doInBackground(String... videoPaths) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) { + if (videoPaths == null || videoPaths.length == 0 || videoPaths[0] == null) { + return false; + } + + try { + final String videoPath = videoPaths[0]; + + mMediaMetadataRetriever.setDataSource(videoPath); + + mLastVideoFrame = mMediaMetadataRetriever.getFrameAtTime( + mVideoDuration * 1000, MediaMetadataRetriever.OPTION_CLOSEST); + + if (mLastVideoFrame == null) { + return false; + } + + mBlurredLastVideoFrame = ImageUtils.applyFastGaussianBlurToBitmap( + mLastVideoFrame, 4); + + return true; + } catch (Exception e) { + MoPubLog.d("Failed to blur last video frame", e); + return false; + } + } + + return false; + } + + @Override + protected void onPostExecute(final Boolean success) { + if (isCancelled()) { + onCancelled(); + return; + } + + if (success != null && success) { + mBlurredLastVideoFrameImageView.setImageBitmap(mBlurredLastVideoFrame); + ImageUtils.setImageViewAlpha(mBlurredLastVideoFrameImageView, + DrawableConstants.BlurredLastVideoFrame.ALPHA); + } + } + + @Override + protected void onCancelled() { + MoPubLog.d("VastVideoBlurLastVideoFrameTask was cancelled."); + } + + // for testing + @Deprecated + @VisibleForTesting + Bitmap getBlurredLastVideoFrame() { + return mBlurredLastVideoFrame; + } +} diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfig.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfig.java new file mode 100644 index 000000000..913f4bf33 --- /dev/null +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfig.java @@ -0,0 +1,604 @@ +package com.mopub.mobileads; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.mopub.common.MoPubBrowser; +import com.mopub.common.Preconditions; +import com.mopub.common.UrlAction; +import com.mopub.common.UrlHandler; +import com.mopub.common.logging.MoPubLog; +import com.mopub.common.util.DeviceUtils; +import com.mopub.common.util.Intents; +import com.mopub.common.util.Strings; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.mopub.network.TrackingRequest.makeVastTrackingHttpRequest; + +public class VastVideoConfig implements Serializable { + private static final long serialVersionUID = 1L; + + @NonNull private final ArrayList mImpressionTrackers; + @NonNull private final ArrayList mFractionalTrackers; + @NonNull private final ArrayList mAbsoluteTrackers; + @NonNull private final ArrayList mPauseTrackers; + @NonNull private final ArrayList mResumeTrackers; + @NonNull private final ArrayList mCompleteTrackers; + @NonNull private final ArrayList mCloseTrackers; + @NonNull private final ArrayList mSkipTrackers; + @NonNull private final ArrayList mClickTrackers; + @NonNull private final ArrayList mErrorTrackers; + @Nullable private String mClickThroughUrl; + @Nullable private String mNetworkMediaFileUrl; + @Nullable private String mDiskMediaFileUrl; + @Nullable private String mSkipOffset; + @Nullable private VastCompanionAdConfig mLandscapeVastCompanionAdConfig; + @Nullable private VastCompanionAdConfig mPortraitVastCompanionAdConfig; + @Nullable private VastIconConfig mVastIconConfig; + + // Custom extensions + @Nullable private String mCustomCtaText; + @Nullable private String mCustomSkipText; + @Nullable private String mCustomCloseIconUrl; + @NonNull private DeviceUtils.ForceOrientation mCustomForceOrientation = DeviceUtils.ForceOrientation.FORCE_LANDSCAPE; // Default is forcing landscape + + /** + * Flag to indicate if the VAST xml document has explicitly set the orientation as opposed to + * using the default. + */ + private boolean mIsForceOrientationSet; + + public VastVideoConfig() { + mImpressionTrackers = new ArrayList(); + mFractionalTrackers = new ArrayList(); + mAbsoluteTrackers = new ArrayList(); + mPauseTrackers = new ArrayList(); + mResumeTrackers = new ArrayList(); + mCompleteTrackers = new ArrayList(); + mCloseTrackers = new ArrayList(); + mSkipTrackers = new ArrayList(); + mClickTrackers = new ArrayList(); + mErrorTrackers = new ArrayList(); + } + + /** + * Setters + */ + + public void addImpressionTrackers(@NonNull final List impressionTrackers) { + Preconditions.checkNotNull(impressionTrackers, "impressionTrackers cannot be null"); + mImpressionTrackers.addAll(impressionTrackers); + } + + /** + * Add trackers for percentage-based tracking. This includes all quartile trackers and any + * "progress" events with other percentages. + */ + public void addFractionalTrackers(@NonNull final List fractionalTrackers) { + Preconditions.checkNotNull(fractionalTrackers, "fractionalTrackers cannot be null"); + mFractionalTrackers.addAll(fractionalTrackers); + Collections.sort(mFractionalTrackers); + } + + /** + * Add trackers for absolute tracking. This includes start trackers, which have an absolute threshold of 2 seconds. + */ + public void addAbsoluteTrackers(@NonNull final List absoluteTrackers) { + Preconditions.checkNotNull(absoluteTrackers, "absoluteTrackers cannot be null"); + mAbsoluteTrackers.addAll(absoluteTrackers); + Collections.sort(mAbsoluteTrackers); + } + + public void addCompleteTrackers(@NonNull final List completeTrackers) { + Preconditions.checkNotNull(completeTrackers, "completeTrackers cannot be null"); + mCompleteTrackers.addAll(completeTrackers); + } + + /** + * Add trackers for when the video is paused. + * + * @param pauseTrackers List of String URLs to hit + */ + public void addPauseTrackers(@NonNull List pauseTrackers) { + Preconditions.checkNotNull(pauseTrackers, "pauseTrackers cannot be null"); + mPauseTrackers.addAll(pauseTrackers); + } + + /** + * Add trackers for when the video is resumed. + * + * @param resumeTrackers List of String URLs to hit + */ + public void addResumeTrackers(@NonNull List resumeTrackers) { + Preconditions.checkNotNull(resumeTrackers, "resumeTrackers cannot be null"); + mResumeTrackers.addAll(resumeTrackers); + } + + public void addCloseTrackers(@NonNull final List closeTrackers) { + Preconditions.checkNotNull(closeTrackers, "closeTrackers cannot be null"); + mCloseTrackers.addAll(closeTrackers); + } + + public void addSkipTrackers(@NonNull final List skipTrackers) { + Preconditions.checkNotNull(skipTrackers, "skipTrackers cannot be null"); + mSkipTrackers.addAll(skipTrackers); + } + + public void addClickTrackers(@NonNull final List clickTrackers) { + Preconditions.checkNotNull(clickTrackers, "clickTrackers cannot be null"); + mClickTrackers.addAll(clickTrackers); + } + + /** + * Add trackers for errors. + * + * @param errorTrackers A URL to hit when an error happens. + */ + public void addErrorTrackers(@NonNull final List errorTrackers) { + Preconditions.checkNotNull(errorTrackers, "errorTrackers cannot be null"); + mErrorTrackers.addAll(errorTrackers); + } + + public void setClickThroughUrl(@Nullable final String clickThroughUrl) { + mClickThroughUrl = clickThroughUrl; + } + + public void setNetworkMediaFileUrl(@Nullable final String networkMediaFileUrl) { + mNetworkMediaFileUrl = networkMediaFileUrl; + } + + public void setDiskMediaFileUrl(@Nullable final String diskMediaFileUrl) { + mDiskMediaFileUrl = diskMediaFileUrl; + } + + public void setVastCompanionAd(@Nullable final VastCompanionAdConfig landscapeVastCompanionAdConfig, + @Nullable final VastCompanionAdConfig portraitVastCompanionAdConfig) { + mLandscapeVastCompanionAdConfig = landscapeVastCompanionAdConfig; + mPortraitVastCompanionAdConfig = portraitVastCompanionAdConfig; + } + + public void setVastIconConfig(@Nullable final VastIconConfig vastIconConfig) { + mVastIconConfig = vastIconConfig; + } + + public void setCustomCtaText(@Nullable final String customCtaText) { + if (customCtaText != null) { + mCustomCtaText = customCtaText; + } + } + + public void setCustomSkipText(@Nullable final String customSkipText) { + if (customSkipText != null) { + mCustomSkipText = customSkipText; + } + } + + public void setCustomCloseIconUrl(@Nullable final String customCloseIconUrl) { + if (customCloseIconUrl != null) { + mCustomCloseIconUrl = customCloseIconUrl; + } + } + + public void setCustomForceOrientation(@Nullable final DeviceUtils.ForceOrientation customForceOrientation) { + if (customForceOrientation != null && customForceOrientation != DeviceUtils.ForceOrientation.UNDEFINED) { + mCustomForceOrientation = customForceOrientation; + mIsForceOrientationSet = true; + } + } + + public void setSkipOffset(@Nullable final String skipOffset) { + if (skipOffset != null) { + mSkipOffset = skipOffset; + } + } + + /** + * Getters + */ + + @NonNull + public List getImpressionTrackers() { + return mImpressionTrackers; + } + + @NonNull + public ArrayList getAbsoluteTrackers() { + return mAbsoluteTrackers; + } + + @NonNull + public ArrayList getFractionalTrackers() { + return mFractionalTrackers; + } + + @NonNull + public List getPauseTrackers() { + return mPauseTrackers; + } + + @NonNull + public List getResumeTrackers() { + return mResumeTrackers; + } + + @NonNull + public List getCompleteTrackers() { + return mCompleteTrackers; + } + + @NonNull + public List getCloseTrackers() { + return mCloseTrackers; + } + + @NonNull + public List getSkipTrackers() { + return mSkipTrackers; + } + + @NonNull + public List getClickTrackers() { + return mClickTrackers; + } + + /** + * Gets a list of error trackers. + * + * @return List of String URLs. + */ + @NonNull + public List getErrorTrackers() { + return mErrorTrackers; + } + + @Nullable + public String getClickThroughUrl() { + return mClickThroughUrl; + } + + @Nullable + public String getNetworkMediaFileUrl() { + return mNetworkMediaFileUrl; + } + + @Nullable + public String getDiskMediaFileUrl() { + return mDiskMediaFileUrl; + } + + @Nullable + public VastCompanionAdConfig getVastCompanionAd(final int orientation) { + switch (orientation) { + case Configuration.ORIENTATION_PORTRAIT: + return mPortraitVastCompanionAdConfig; + case Configuration.ORIENTATION_LANDSCAPE: + return mLandscapeVastCompanionAdConfig; + default: + return mLandscapeVastCompanionAdConfig; + } + } + + @Nullable + public VastIconConfig getVastIconConfig() { + return mVastIconConfig; + } + + @Nullable + public String getCustomCtaText() { + return mCustomCtaText; + } + + @Nullable + public String getCustomSkipText() { + return mCustomSkipText; + } + + @Nullable + public String getCustomCloseIconUrl() { + return mCustomCloseIconUrl; + } + + public boolean isCustomForceOrientationSet() { + return mIsForceOrientationSet; + } + + /** + * Returns whether or not there is a companion ad set. There must be both a landscape and a + * portrait companion ad set for this to be true. + * + * @return true if both the landscape and portrait companion ads are set, false otherwise. + */ + public boolean hasCompanionAd() { + return mLandscapeVastCompanionAdConfig != null && mPortraitVastCompanionAdConfig != null; + } + + /** + * Get custom force orientation + * @return ForceOrientation enum (default is FORCE_LANDSCAPE) + */ + @NonNull + public DeviceUtils.ForceOrientation getCustomForceOrientation() { + return mCustomForceOrientation; + } + + /** + * Gets the String specified in the VAST document regarding the skip offset. This should be in + * the form HH:MM:SS[.mmm] or n%. (e.g. 00:00:12, 00:00:12.345, 42%). + * + * @return String representation of the skip offset or {@code null} if not set. + */ + @Nullable + public String getSkipOffsetString() { + return mSkipOffset; + } + + /** + * Called when the video starts playing. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time. + */ + public void handleImpression(@NonNull final Context context, int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mImpressionTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Called when the video is clicked. Handles forwarding the user to the specified click through + * url. + * + * @param activity This has to be an activity to call startActivityForResult. + * @param contentPlayHead Current video playback time when clicked. + * @param requestCode The code that identifies what kind of activity request is going to be + * made + */ + public void handleClick(@NonNull final Activity activity, final int contentPlayHead, + final int requestCode) { + Preconditions.checkNotNull(activity, "activity cannot be null"); + + makeVastTrackingHttpRequest( + mClickTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + activity + ); + + if (TextUtils.isEmpty(mClickThroughUrl)) { + return; + } + + new UrlHandler.Builder() + .withSupportedUrlActions( + UrlAction.IGNORE_ABOUT_SCHEME, + UrlAction.OPEN_APP_MARKET, + UrlAction.OPEN_NATIVE_BROWSER, + UrlAction.OPEN_IN_APP_BROWSER, + UrlAction.HANDLE_SHARE_TWEET, + UrlAction.FOLLOW_DEEP_LINK_WITH_FALLBACK, + UrlAction.FOLLOW_DEEP_LINK) + .withResultActions(new UrlHandler.ResultActions() { + @Override + public void urlHandlingSucceeded(@NonNull String url, + @NonNull UrlAction urlAction) { + if (urlAction == UrlAction.OPEN_IN_APP_BROWSER) { + Bundle bundle = new Bundle(); + bundle.putString(MoPubBrowser.DESTINATION_URL_KEY, url); + + final Class clazz = MoPubBrowser.class; + final Intent intent = Intents.getStartActivityIntent( + activity, clazz, bundle); + try { + activity.startActivityForResult(intent, requestCode); + } catch (ActivityNotFoundException e) { + MoPubLog.d("Activity " + clazz.getName() + " not found. Did you " + + "declare it in your AndroidManifest.xml?"); + } + } + } + + @Override + public void urlHandlingFailed(@NonNull String url, + @NonNull UrlAction lastFailedUrlAction) { + } + }) + .withoutMoPubBrowser() + .build().handleUrl(activity, mClickThroughUrl); + } + + /** + * Called when the video is not finished and is resumed from the middle of the video. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time. + */ + public void handleResume(@NonNull final Context context, int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mResumeTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Called when the video is not finished and is paused. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time. + */ + public void handlePause(@NonNull final Context context, int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mPauseTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Called when the video is closed or skipped. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time. + */ + public void handleClose(@NonNull Context context, int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mCloseTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + + makeVastTrackingHttpRequest( + mSkipTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Called when the video is played completely without skipping. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time (should be duration of video). + */ + public void handleComplete(@NonNull Context context, int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mCompleteTrackers, + null, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Called when there is a problem with the video. Refer to the possible {@link VastErrorCode}s + * for a list of problems. + * + * @param context The context. Can be application or activity context. + * @param contentPlayHead Current video playback time. + */ + public void handleError(@NonNull Context context, @NonNull VastErrorCode errorCode, + int contentPlayHead) { + Preconditions.checkNotNull(context, "context cannot be null"); + makeVastTrackingHttpRequest( + mErrorTrackers, + errorCode, + contentPlayHead, + mNetworkMediaFileUrl, + context + ); + } + + /** + * Returns untriggered VAST progress trackers with a progress before the provided position. + * + * @param currentPositionMillis the current video position in milliseconds. + * @param videoLengthMillis the total video length. + */ + @NonNull + public List getUntriggeredTrackersBefore(int currentPositionMillis, int videoLengthMillis) { + if (Preconditions.NoThrow.checkArgument(videoLengthMillis > 0)) { + float progressFraction = currentPositionMillis / (float) (videoLengthMillis); + List untriggeredTrackers = new ArrayList(); + + VastAbsoluteProgressTracker absoluteTest = new VastAbsoluteProgressTracker("", currentPositionMillis); + int absoluteTrackerCount = mAbsoluteTrackers.size(); + for (int i = 0; i < absoluteTrackerCount; i++) { + VastAbsoluteProgressTracker tracker = mAbsoluteTrackers.get(i); + if (tracker.compareTo(absoluteTest) > 0) { + break; + } + if (!tracker.isTracked()) { + untriggeredTrackers.add(tracker); + } + } + + final VastFractionalProgressTracker fractionalTest = new VastFractionalProgressTracker("", progressFraction); + int fractionalTrackerCount = mFractionalTrackers.size(); + for (int i = 0; i < fractionalTrackerCount; i++) { + VastFractionalProgressTracker tracker = mFractionalTrackers.get(i); + if (tracker.compareTo(fractionalTest) > 0) { + break; + } + if (!tracker.isTracked()) { + untriggeredTrackers.add(tracker); + } + } + + return untriggeredTrackers; + } else { + return Collections.emptyList(); + } + } + + /** + * Returns the number of untriggered progress trackers. + * + * @return Integer count >= 0 of the remaining progress trackers. + */ + public int getRemainingProgressTrackerCount() { + return getUntriggeredTrackersBefore(Integer.MAX_VALUE, Integer.MAX_VALUE).size(); + } + + /** + * Gets the skip offset in milliseconds. If the skip offset would be past the video duration, + * this returns null. If an error occurs, this returns null. + * + * @param videoDuration Used to calculate percentage based offsets. + * @return The skip offset in milliseconds. Can return null. + */ + @Nullable + public Integer getSkipOffsetMillis(final int videoDuration) { + if (mSkipOffset != null) { + try { + if (Strings.isAbsoluteTracker(mSkipOffset)) { + Integer skipOffsetMilliseconds = Strings.parseAbsoluteOffset(mSkipOffset); + if (skipOffsetMilliseconds != null && skipOffsetMilliseconds < videoDuration) { + return skipOffsetMilliseconds; + } + } else if (Strings.isPercentageTracker(mSkipOffset)) { + float percentage = Float.parseFloat(mSkipOffset.replace("%", "")) / 100f; + int skipOffsetMillisecondsRounded = Math.round(videoDuration * percentage); + if (skipOffsetMillisecondsRounded < videoDuration) { + return skipOffsetMillisecondsRounded; + } + } else { + MoPubLog.d( + String.format("Invalid VAST skipoffset format: %s", mSkipOffset)); + } + } catch (NumberFormatException e) { + MoPubLog.d(String.format("Failed to parse skipoffset %s", mSkipOffset)); + } + } + return null; + } +} diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfiguration.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfiguration.java deleted file mode 100644 index 27c53a8ac..000000000 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoConfiguration.java +++ /dev/null @@ -1,304 +0,0 @@ -package com.mopub.mobileads; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.mopub.common.Preconditions; -import com.mopub.common.util.DeviceUtils; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class VastVideoConfiguration implements Serializable { - private static final long serialVersionUID = 1L; - - @NonNull private final ArrayList mImpressionTrackers; - @NonNull private final ArrayList mFractionalTrackers; - @NonNull private final ArrayList mAbsoluteTrackers; - @NonNull private final ArrayList mPauseTrackers; - @NonNull private final ArrayList mResumeTrackers; - @NonNull private final ArrayList mCompleteTrackers; - @NonNull private final ArrayList mCloseTrackers; - @NonNull private final ArrayList mSkipTrackers; - @NonNull private final ArrayList mClickTrackers; - @NonNull private final ArrayList mErrorTrackers; - @Nullable private String mClickThroughUrl; - @Nullable private String mNetworkMediaFileUrl; - @Nullable private String mDiskMediaFileUrl; - @Nullable private String mSkipOffset; - @Nullable private VastCompanionAd mVastCompanionAd; - @Nullable private VastIcon mVastIcon; - - // Custom extensions - @Nullable private String mCustomCtaText; - @Nullable private String mCustomSkipText; - @Nullable private String mCustomCloseIconUrl; - @NonNull private DeviceUtils.ForceOrientation mCustomForceOrientation = DeviceUtils.ForceOrientation.FORCE_LANDSCAPE; // Default is forcing landscape - - /** - * Flag to indicate if the VAST xml document has explicitly set the orientation as opposed to - * using the default. - */ - private boolean mIsForceOrientationSet; - - public VastVideoConfiguration() { - mImpressionTrackers = new ArrayList(); - mFractionalTrackers = new ArrayList(); - mAbsoluteTrackers = new ArrayList(); - mPauseTrackers = new ArrayList(); - mResumeTrackers = new ArrayList(); - mCompleteTrackers = new ArrayList(); - mCloseTrackers = new ArrayList(); - mSkipTrackers = new ArrayList(); - mClickTrackers = new ArrayList(); - mErrorTrackers = new ArrayList(); - } - - /** - * Setters - */ - - public void addImpressionTrackers(@NonNull final List impressionTrackers) { - Preconditions.checkNotNull(impressionTrackers, "impressionTrackers cannot be null"); - mImpressionTrackers.addAll(impressionTrackers); - } - - /** - * Add trackers for percentage-based tracking. This includes all quartile trackers and any - * "progress" events with other percentages. - */ - public void addFractionalTrackers(@NonNull final List fractionalTrackers) { - Preconditions.checkNotNull(fractionalTrackers, "fractionalTrackers cannot be null"); - mFractionalTrackers.addAll(fractionalTrackers); - Collections.sort(mFractionalTrackers); - } - - /** - * Add trackers for absolute tracking. This includes start trackers, which have an absolute threshold of 2 seconds. - */ - public void addAbsoluteTrackers(@NonNull final List absoluteTrackers) { - Preconditions.checkNotNull(absoluteTrackers, "absoluteTrackers cannot be null"); - mAbsoluteTrackers.addAll(absoluteTrackers); - Collections.sort(mAbsoluteTrackers); - } - - public void addCompleteTrackers(@NonNull final List completeTrackers) { - Preconditions.checkNotNull(completeTrackers, "completeTrackers cannot be null"); - mCompleteTrackers.addAll(completeTrackers); - } - - /** - * Add trackers for when the video is paused. - * - * @param pauseTrackers List of String URLs to hit - */ - public void addPauseTrackers(@NonNull List pauseTrackers) { - Preconditions.checkNotNull(pauseTrackers, "pauseTrackers cannot be null"); - mPauseTrackers.addAll(pauseTrackers); - } - - /** - * Add trackers for when the video is resumed. - * - * @param resumeTrackers List of String URLs to hit - */ - public void addResumeTrackers(@NonNull List resumeTrackers) { - Preconditions.checkNotNull(resumeTrackers, "resumeTrackers cannot be null"); - mResumeTrackers.addAll(resumeTrackers); - } - - public void addCloseTrackers(@NonNull final List closeTrackers) { - Preconditions.checkNotNull(closeTrackers, "closeTrackers cannot be null"); - mCloseTrackers.addAll(closeTrackers); - } - - public void addSkipTrackers(@NonNull final List skipTrackers) { - Preconditions.checkNotNull(skipTrackers, "skipTrackers cannot be null"); - mSkipTrackers.addAll(skipTrackers); - } - - public void addClickTrackers(@NonNull final List clickTrackers) { - Preconditions.checkNotNull(clickTrackers, "clickTrackers cannot be null"); - mClickTrackers.addAll(clickTrackers); - } - - /** - * Add trackers for errors. - * - * @param errorTrackers A URL to hit when an error happens. - */ - public void addErrorTrackers(@NonNull final List errorTrackers) { - Preconditions.checkNotNull(errorTrackers, "errorTrackers cannot be null"); - mErrorTrackers.addAll(errorTrackers); - } - - public void setClickThroughUrl(@Nullable final String clickThroughUrl) { - mClickThroughUrl = clickThroughUrl; - } - - public void setNetworkMediaFileUrl(@Nullable final String networkMediaFileUrl) { - mNetworkMediaFileUrl = networkMediaFileUrl; - } - - public void setDiskMediaFileUrl(@Nullable final String diskMediaFileUrl) { - mDiskMediaFileUrl = diskMediaFileUrl; - } - - public void setVastCompanionAd(@Nullable final VastCompanionAd vastCompanionAd) { - mVastCompanionAd = vastCompanionAd; - } - - public void setVastIcon(@Nullable final VastIcon vastIcon) { - mVastIcon = vastIcon; - } - - public void setCustomCtaText(@Nullable final String customCtaText) { - if (customCtaText != null) { - mCustomCtaText = customCtaText; - } - } - - public void setCustomSkipText(@Nullable final String customSkipText) { - if (customSkipText != null) { - mCustomSkipText = customSkipText; - } - } - - public void setCustomCloseIconUrl(@Nullable final String customCloseIconUrl) { - if (customCloseIconUrl != null) { - mCustomCloseIconUrl = customCloseIconUrl; - } - } - - public void setCustomForceOrientation(@Nullable final DeviceUtils.ForceOrientation customForceOrientation) { - if (customForceOrientation != null && customForceOrientation != DeviceUtils.ForceOrientation.UNDEFINED) { - mCustomForceOrientation = customForceOrientation; - mIsForceOrientationSet = true; - } - } - - public void setSkipOffset(@Nullable final String skipOffset) { - if (skipOffset != null) { - mSkipOffset = skipOffset; - } - } - - /** - * Getters - */ - - @NonNull - public List getImpressionTrackers() { - return mImpressionTrackers; - } - - @NonNull - public ArrayList getAbsoluteTrackers() { - return mAbsoluteTrackers; - } - - @NonNull - public ArrayList getFractionalTrackers() { - return mFractionalTrackers; - } - - @NonNull - public List getPauseTrackers() { - return mPauseTrackers; - } - - @NonNull - public List getResumeTrackers() { - return mResumeTrackers; - } - - @NonNull - public List getCompleteTrackers() { - return mCompleteTrackers; - } - - @NonNull - public List getCloseTrackers() { - return mCloseTrackers; - } - - @NonNull - public List getSkipTrackers() { - return mSkipTrackers; - } - - @NonNull - public List getClickTrackers() { - return mClickTrackers; - } - - /** - * Gets a list of error trackers. - * - * @return List of String URLs. - */ - @NonNull - public List getErrorTrackers() { - return mErrorTrackers; - } - - @Nullable - public String getClickThroughUrl() { - return mClickThroughUrl; - } - - @Nullable - public String getNetworkMediaFileUrl() { - return mNetworkMediaFileUrl; - } - - @Nullable - public String getDiskMediaFileUrl() { - return mDiskMediaFileUrl; - } - - @Nullable - public VastCompanionAd getVastCompanionAd() { - return mVastCompanionAd; - } - - @Nullable - public VastIcon getVastIcon() { - return mVastIcon; - } - - @Nullable - public String getCustomCtaText() { - return mCustomCtaText; - } - - @Nullable - public String getCustomSkipText() { - return mCustomSkipText; - } - - @Nullable - public String getCustomCloseIconUrl() { - return mCustomCloseIconUrl; - } - - public boolean isCustomForceOrientationSet() { - return mIsForceOrientationSet; - } - - /** - * Get custom force orientation - * @return ForceOrientation enum (default is FORCE_LANDSCAPE) - */ - @NonNull - public DeviceUtils.ForceOrientation getCustomForceOrientation() { - return mCustomForceOrientation; - } - - @Nullable - public String getSkipOffset() { - return mSkipOffset; - } -} diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoCtaButtonWidget.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoCtaButtonWidget.java index 86e243a5b..0ca1a1ff2 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoCtaButtonWidget.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoCtaButtonWidget.java @@ -22,12 +22,14 @@ public class VastVideoCtaButtonWidget extends ImageView { private boolean mIsVideoSkippable; private boolean mIsVideoComplete; private boolean mHasCompanionAd; + private boolean mHasClickthroughUrl; public VastVideoCtaButtonWidget(@NonNull final Context context, final int videoViewId, - final boolean hasCompanionAd) { + final boolean hasCompanionAd, final boolean hasClickthroughUrl) { super(context); mHasCompanionAd = hasCompanionAd; + mHasClickthroughUrl = hasClickthroughUrl; setId((int) Utils.generateUniqueId()); @@ -76,8 +78,21 @@ void notifyVideoComplete() { } private void updateLayoutAndVisibility() { + // If the video does not have a clickthrough url, never show the CTA button + if (!mHasClickthroughUrl) { + setVisibility(View.GONE); + return; + } + // If video is not skippable yet, do not show CTA button if (!mIsVideoSkippable) { + setVisibility(View.INVISIBLE); + return; + } + + // If video has finished playing and there's a companion ad, do not show CTA button + if (mIsVideoComplete && mHasCompanionAd) { + setVisibility(View.GONE); return; } @@ -85,16 +100,8 @@ private void updateLayoutAndVisibility() { switch (currentOrientation) { case Configuration.ORIENTATION_LANDSCAPE: - // Do not show CTA button if ALL these conditions are satisfied: - // 1. device in landscape mode - // 2. video has finished playing - // 3. there is a companion ad - if (mIsVideoComplete && mHasCompanionAd) { - setVisibility(View.GONE); - } else { - setVisibility(View.VISIBLE); - setLayoutParams(mLandscapeLayoutParams); - } + setVisibility(View.VISIBLE); + setLayoutParams(mLandscapeLayoutParams); break; case Configuration.ORIENTATION_PORTRAIT: setVisibility(View.VISIBLE); diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoDownloadTask.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoDownloadTask.java index 9077525aa..910b59d21 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoDownloadTask.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoDownloadTask.java @@ -29,7 +29,7 @@ public VastVideoDownloadTask(final VastVideoDownloadTaskListener listener) { @Override protected Boolean doInBackground(final String... params) { - if (params == null || params[0] == null) { + if (params == null || params.length == 0 || params[0] == null) { return false; } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoGradientStripWidget.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoGradientStripWidget.java index d72141a65..bbc19b9bd 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoGradientStripWidget.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoGradientStripWidget.java @@ -1,21 +1,35 @@ package com.mopub.mobileads; import android.content.Context; -import android.graphics.Color; +import android.content.res.Configuration; import android.graphics.drawable.GradientDrawable; import android.support.annotation.NonNull; +import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; +import com.mopub.common.logging.MoPubLog; +import com.mopub.common.util.DeviceUtils; import com.mopub.common.util.Dips; import com.mopub.mobileads.resource.DrawableConstants; public class VastVideoGradientStripWidget extends ImageView { + @NonNull DeviceUtils.ForceOrientation mForceOrientation; + private int mVisibilityForCompanionAd; + private boolean mHasCompanionAd; + private boolean mIsVideoComplete; + public VastVideoGradientStripWidget(@NonNull final Context context, - @NonNull final GradientDrawable.Orientation gradientOrientation, final int layoutVerb, + @NonNull final GradientDrawable.Orientation gradientOrientation, + @NonNull final DeviceUtils.ForceOrientation forceOrientation, + final boolean hasCompanionAd, final int visibilityForCompanionAd, final int layoutVerb, final int layoutAnchor) { super(context); + mForceOrientation = forceOrientation; + mVisibilityForCompanionAd = visibilityForCompanionAd; + mHasCompanionAd = hasCompanionAd; + final GradientDrawable gradientDrawable = new GradientDrawable(gradientOrientation, new int[] {DrawableConstants.GradientStrip.START_COLOR, DrawableConstants.GradientStrip.END_COLOR}); @@ -27,5 +41,60 @@ public VastVideoGradientStripWidget(@NonNull final Context context, context)); layoutParams.addRule(layoutVerb, layoutAnchor); setLayoutParams(layoutParams); + + updateVisibility(); + } + + void notifyVideoComplete() { + mIsVideoComplete = true; + updateVisibility(); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + updateVisibility(); + } + + private void updateVisibility() { + if (mIsVideoComplete) { + if (mHasCompanionAd) { + setVisibility(mVisibilityForCompanionAd); + } else { + setVisibility(View.GONE); + } + + return; + } + + if (mForceOrientation == DeviceUtils.ForceOrientation.FORCE_PORTRAIT) { + setVisibility(View.INVISIBLE); + } else if (mForceOrientation == DeviceUtils.ForceOrientation.FORCE_LANDSCAPE) { + setVisibility(View.VISIBLE); + } else { + final int currentOrientation = getResources().getConfiguration().orientation; + + switch (currentOrientation) { + case Configuration.ORIENTATION_LANDSCAPE: + setVisibility(View.VISIBLE); + break; + case Configuration.ORIENTATION_PORTRAIT: + setVisibility(View.INVISIBLE); + break; + case Configuration.ORIENTATION_UNDEFINED: + MoPubLog.d("Screen orientation undefined: do not show gradient strip widget"); + setVisibility(View.INVISIBLE); + break; + case Configuration.ORIENTATION_SQUARE: + MoPubLog.d("Screen orientation is deprecated ORIENTATION_SQUARE: do not show gradient strip widget"); + setVisibility(View.INVISIBLE); + break; + default: + MoPubLog.d("Unrecognized screen orientation: do not show gradient strip widget"); + setVisibility(View.INVISIBLE); + break; + } + } } } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoInterstitial.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoInterstitial.java index 28093fc4f..a3a14cd99 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoInterstitial.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoInterstitial.java @@ -10,7 +10,7 @@ class VastVideoInterstitial extends ResponseBodyInterstitial implements VastMana private CustomEventInterstitialListener mCustomEventInterstitialListener; private String mVastResponse; private VastManager mVastManager; - private VastVideoConfiguration mVastVideoConfiguration; + private VastVideoConfig mVastVideoConfig; @Override protected void extractExtras(Map serverExtras) { @@ -32,7 +32,7 @@ protected void preRenderHtml(CustomEventInterstitialListener customEventIntersti @Override public void showInterstitial() { - MraidVideoPlayerActivity.startVast(mContext, mVastVideoConfiguration, mBroadcastIdentifier); + MraidVideoPlayerActivity.startVast(mContext, mVastVideoConfig, mBroadcastIdentifier); } @Override @@ -49,13 +49,13 @@ public void onInvalidate() { */ @Override - public void onVastVideoConfigurationPrepared(final VastVideoConfiguration vastVideoConfiguration) { - if (vastVideoConfiguration == null) { + public void onVastVideoConfigurationPrepared(final VastVideoConfig vastVideoConfig) { + if (vastVideoConfig == null) { mCustomEventInterstitialListener.onInterstitialFailed(MoPubErrorCode.VIDEO_DOWNLOAD_ERROR); return; } - mVastVideoConfiguration = vastVideoConfiguration; + mVastVideoConfig = vastVideoConfig; mCustomEventInterstitialListener.onInterstitialLoaded(); } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoView.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoView.java new file mode 100644 index 000000000..32904efbe --- /dev/null +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoView.java @@ -0,0 +1,162 @@ +package com.mopub.mobileads; + +import android.content.Context; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.os.AsyncTask; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.widget.ImageView; +import android.widget.VideoView; + +import com.mopub.common.Preconditions; +import com.mopub.common.VisibleForTesting; +import com.mopub.common.logging.MoPubLog; +import com.mopub.common.util.AsyncTasks; +import com.mopub.common.util.Streams; + +import java.io.File; +import java.io.FileInputStream; + +/** + * Custom VideoView dedicated for VAST videos. This primarily deals with the blurring of the last + * frame when there's no companion ad and retrying the video. + */ +public class VastVideoView extends VideoView { + + private static final int MAX_VIDEO_RETRIES = 1; + private static final int VIDEO_VIEW_FILE_PERMISSION_ERROR = Integer.MIN_VALUE; + + @Nullable private VastVideoBlurLastVideoFrameTask mBlurLastVideoFrameTask; + @Nullable private MediaMetadataRetriever mMediaMetadataRetriever; + private int mVideoRetries; + + public VastVideoView(@NonNull final Context context) { + super(context); + Preconditions.checkNotNull(context, "context cannot be null"); + mMediaMetadataRetriever = createMediaMetadataRetriever(); + } + + /** + * Launches an async task to blur the last frame of the video. If the API of the device is not + * high enough, this does nothing. + * + * @param blurredLastVideoFrameImageView The view will get populated with the image when the + * async task is finished. + */ + public void prepareBlurredLastVideoFrame( + @NonNull final ImageView blurredLastVideoFrameImageView, + @NonNull final String diskMediaFileUrl) { + if (mMediaMetadataRetriever != null) { + mBlurLastVideoFrameTask = new VastVideoBlurLastVideoFrameTask(mMediaMetadataRetriever, + blurredLastVideoFrameImageView, getDuration()); + + try { + AsyncTasks.safeExecuteOnExecutor( + mBlurLastVideoFrameTask, + diskMediaFileUrl + ); + } catch (Exception e) { + MoPubLog.d("Failed to blur last video frame", e); + } + } + } + + /** + * Called when the activity enclosing this view is destroyed. We do not want to continue this + * task when the activity expecting the result no longer exists. + */ + public void onDestroy() { + if (mBlurLastVideoFrameTask != null && + mBlurLastVideoFrameTask.getStatus() != AsyncTask.Status.FINISHED) { + mBlurLastVideoFrameTask.cancel(true); + } + } + + boolean retryMediaPlayer(final MediaPlayer mediaPlayer, final int what, final int extra, + @NonNull final String diskMediaFileUrl) { + // XXX + // VideoView has a bug in versions lower than Jelly Bean, Api Level 16, Android 4.1 + // For api < 16, VideoView is not able to read files written to disk since it reads them in + // a Context different from the Application and therefore does not have correct permission. + // To solve this problem we obtain the video file descriptor ourselves with valid permissions + // and pass it to the underlying MediaPlayer in VideoView. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN + && what == MediaPlayer.MEDIA_ERROR_UNKNOWN + && extra == VIDEO_VIEW_FILE_PERMISSION_ERROR + && mVideoRetries < MAX_VIDEO_RETRIES) { + + FileInputStream inputStream = null; + try { + mediaPlayer.reset(); + final File file = new File(diskMediaFileUrl); + inputStream = new FileInputStream(file); + mediaPlayer.setDataSource(inputStream.getFD()); + + // XXX + // VideoView has a callback registered with the MediaPlayer to set a flag when the + // media file has been prepared. Start also sets a flag in VideoView indicating the + // desired state is to play the video. Therefore, whichever method finishes last + // will check both flags and begin playing the video. + mediaPlayer.prepareAsync(); + start(); + return true; + } catch (Exception e) { + return false; + } finally { + Streams.closeStream(inputStream); + mVideoRetries++; + } + } + return false; + } + + /** + * Called when the activity enclosing this view is resumed. + */ + public void onResume() { + // When resuming, VideoView needs to reinitialize its MediaPlayer with the video path + // and therefore reset the count to zero, to let it retry on error + mVideoRetries = 0; + } + + @VisibleForTesting + @Nullable + MediaMetadataRetriever createMediaMetadataRetriever() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) { + return new MediaMetadataRetriever(); + } + + return null; + } + + // for testing + @Deprecated + @VisibleForTesting + void setMediaMetadataRetriever(@NonNull MediaMetadataRetriever mediaMetadataRetriever) { + mMediaMetadataRetriever = mediaMetadataRetriever; + } + + // for testing + @Deprecated + @VisibleForTesting + @Nullable + VastVideoBlurLastVideoFrameTask getBlurLastVideoFrameTask() { + return mBlurLastVideoFrameTask; + } + + // for testing + @Deprecated + @VisibleForTesting + void setBlurLastVideoFrameTask(@NonNull VastVideoBlurLastVideoFrameTask blurLastVideoFrameTask) { + mBlurLastVideoFrameTask = blurLastVideoFrameTask; + } + + // for testing + @Deprecated + @VisibleForTesting + int getVideoRetries() { + return mVideoRetries; + } +} diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewController.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewController.java index 7bef8ed83..77f9ceced 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewController.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewController.java @@ -3,12 +3,10 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.drawable.GradientDrawable; -import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -24,26 +22,12 @@ import android.widget.RelativeLayout; import android.widget.VideoView; -import com.mopub.common.MoPubBrowser; import com.mopub.common.Preconditions; -import com.mopub.common.UrlAction; -import com.mopub.common.UrlHandler; import com.mopub.common.VisibleForTesting; -import com.mopub.common.logging.MoPubLog; import com.mopub.common.util.Dips; -import com.mopub.common.util.ImageUtils; -import com.mopub.common.util.Streams; -import com.mopub.common.util.Strings; import com.mopub.common.util.Utils; -import com.mopub.common.util.VersionCode; -import com.mopub.mobileads.resource.DrawableConstants; -import java.io.File; -import java.io.FileInputStream; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; @@ -53,15 +37,13 @@ import static com.mopub.network.TrackingRequest.makeVastTrackingHttpRequest; public class VastVideoViewController extends BaseVideoViewController { - static final String VAST_VIDEO_CONFIGURATION = "vast_video_configuration"; + static final String VAST_VIDEO_CONFIG = "vast_video_config"; static final String CURRENT_POSITION = "current_position"; - static final String RESUMED_VAST_CONFIGURATION = "resumed_vast_configuration"; + static final String RESUMED_VAST_CONFIG = "resumed_vast_config"; private static final long VIDEO_PROGRESS_TIMER_CHECKER_DELAY = 50; private static final long VIDEO_COUNTDOWN_UPDATE_INTERVAL = 250; private static final int MOPUB_BROWSER_REQUEST_CODE = 1; - private static final int MAX_VIDEO_RETRIES = 1; - private static final int VIDEO_VIEW_FILE_PERMISSION_ERROR = Integer.MIN_VALUE; private static final int SEEKER_POSITION_NOT_INITIALIZED = -1; /** @@ -75,9 +57,9 @@ public class VastVideoViewController extends BaseVideoViewController { static final int DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON = 5 * 1000; static final int MAX_VIDEO_DURATION_FOR_CLOSE_BUTTON = 16 * 1000; - private final VastVideoConfiguration mVastVideoConfiguration; + private final VastVideoConfig mVastVideoConfig; - @NonNull private final VideoView mVideoView; + @NonNull private final VastVideoView mVideoView; @NonNull private VastVideoGradientStripWidget mTopGradientStripWidget; @NonNull private VastVideoGradientStripWidget mBottomGradientStripWidget; @NonNull private ImageView mBlurredLastVideoFrameImageView; @@ -87,74 +69,73 @@ public class VastVideoViewController extends BaseVideoViewController { @NonNull private VastVideoCtaButtonWidget mCtaButtonWidget; @NonNull private VastVideoCloseButtonWidget mCloseButtonWidget; - @Nullable private final VastCompanionAd mVastCompanionAd; - @NonNull private final View mCompanionAdView; - @Nullable private final VastIcon mVastIcon; + @Nullable private VastCompanionAdConfig mVastCompanionAdConfig; + @NonNull private final View mLandscapeCompanionAdView; + @NonNull private final View mPortraitCompanionAdView; + @Nullable private final VastIconConfig mVastIconConfig; @NonNull private final View mIconView; @NonNull private final VastVideoViewProgressRunnable mProgressCheckerRunnable; @NonNull private final VastVideoViewCountdownRunnable mCountdownRunnable; @NonNull private final View.OnTouchListener mClickThroughListener; - @Nullable private MediaMetadataRetriever mMediaMetadataRetriever; - private int mShowCloseButtonDelay = DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON; private boolean mShowCloseButtonEventFired; private int mSeekerPositionOnPause; private boolean mIsVideoFinishedPlaying; - private int mVideoRetries; private boolean mVideoError; private boolean mHasSkipOffset = false; private boolean mIsCalibrationDone = false; private int mDuration; - VastVideoViewController(final Context context, + /** + * For when the video is closing. + */ + private boolean mIsClosing = false; + + VastVideoViewController(final Activity activity, final Bundle intentExtras, @Nullable final Bundle savedInstanceState, final long broadcastIdentifier, final BaseVideoViewControllerListener baseVideoViewControllerListener) throws IllegalStateException { - super(context, broadcastIdentifier, baseVideoViewControllerListener); + super(activity, broadcastIdentifier, baseVideoViewControllerListener); mSeekerPositionOnPause = SEEKER_POSITION_NOT_INITIALIZED; Serializable resumedVastConfiguration = null; if (savedInstanceState != null) { resumedVastConfiguration = - savedInstanceState.getSerializable(RESUMED_VAST_CONFIGURATION); + savedInstanceState.getSerializable(RESUMED_VAST_CONFIG); } - Serializable serializable = intentExtras.getSerializable(VAST_VIDEO_CONFIGURATION); + Serializable serializable = intentExtras.getSerializable(VAST_VIDEO_CONFIG); if (resumedVastConfiguration != null - && resumedVastConfiguration instanceof VastVideoConfiguration) { - mVastVideoConfiguration = (VastVideoConfiguration) resumedVastConfiguration; + && resumedVastConfiguration instanceof VastVideoConfig) { + mVastVideoConfig = (VastVideoConfig) resumedVastConfiguration; mSeekerPositionOnPause = savedInstanceState.getInt(CURRENT_POSITION, SEEKER_POSITION_NOT_INITIALIZED); - } else if (serializable != null && serializable instanceof VastVideoConfiguration) { - mVastVideoConfiguration = (VastVideoConfiguration) serializable; + } else if (serializable != null && serializable instanceof VastVideoConfig) { + mVastVideoConfig = (VastVideoConfig) serializable; } else { - throw new IllegalStateException("VastVideoConfiguration is invalid"); + throw new IllegalStateException("VastVideoConfig is invalid"); } - if (mVastVideoConfiguration.getDiskMediaFileUrl() == null) { - throw new IllegalStateException("VastVideoConfiguration does not have a video disk path"); + if (mVastVideoConfig.getDiskMediaFileUrl() == null) { + throw new IllegalStateException("VastVideoConfig does not have a video disk path"); } - mVastCompanionAd = mVastVideoConfiguration.getVastCompanionAd(); - mVastIcon = mVastVideoConfiguration.getVastIcon(); - - mMediaMetadataRetriever = createMediaMetadataRetriever(); + mVastCompanionAdConfig = mVastVideoConfig.getVastCompanionAd( + activity.getResources().getConfiguration().orientation); + mVastIconConfig = mVastVideoConfig.getVastIconConfig(); mClickThroughListener = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_UP && shouldAllowClickThrough()) { - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getClickTrackers(), - null, + mIsClosing = true; + broadcastAction(ACTION_INTERSTITIAL_CLICK); + mVastVideoConfig.handleClick(activity, mIsVideoFinishedPlaying ? mDuration : getCurrentPosition(), - getNetworkMediaFileUrl(), - getContext() - ); - handleClick(mVastVideoConfiguration.getClickThroughUrl()); + MOPUB_BROWSER_REQUEST_CODE); } return true; } @@ -167,38 +148,45 @@ public boolean onTouch(View view, MotionEvent motionEvent) { getLayout().setBackgroundColor(Color.BLACK); // Video view - mVideoView = createVideoView(context, View.VISIBLE); + mVideoView = createVideoView(activity, View.VISIBLE); mVideoView.requestFocus(); + // Companion ad view, set to invisible initially to have it be drawn to calculate size + mLandscapeCompanionAdView = createCompanionAdView(activity, + mVastVideoConfig.getVastCompanionAd(Configuration.ORIENTATION_LANDSCAPE), + View.INVISIBLE); + mPortraitCompanionAdView = createCompanionAdView(activity, + mVastVideoConfig.getVastCompanionAd(Configuration.ORIENTATION_PORTRAIT), + View.INVISIBLE); + // Top transparent gradient strip overlaying top of screen - addTopGradientStripWidget(context, View.VISIBLE); + addTopGradientStripWidget(activity); // Progress bar overlaying bottom of video view - addProgressBarWidget(context, View.INVISIBLE); + addProgressBarWidget(activity, View.INVISIBLE); // Bottom transparent gradient strip above progress bar - addBottomGradientStripWidget(context, View.VISIBLE); + addBottomGradientStripWidget(activity); // Radial countdown timer snapped to top-right corner of screen - addRadialCountdownWidget(context, View.INVISIBLE); - - // Companion ad view, set to invisible initially to have it be drawn to calculate size - mCompanionAdView = createCompanionAdView(context, mVastCompanionAd, View.INVISIBLE); + addRadialCountdownWidget(activity, View.INVISIBLE); // Icon view - mIconView = createIconView(context, mVastIcon, View.INVISIBLE); + mIconView = createIconView(activity, mVastIconConfig, View.INVISIBLE); // Blurred last frame - addBlurredLastVideoFrameImageView(context, View.INVISIBLE); + addBlurredLastVideoFrameImageView(activity, View.INVISIBLE); - // Close button snapped to top-right corner of screen - addCloseButtonWidget(context, View.GONE); + // CTA button + addCtaButtonWidget(activity); + // Close button snapped to top-right corner of screen // Always add last to layout since it must be visible above all other views - addCtaButtonWidget(context, View.INVISIBLE); + addCloseButtonWidget(activity, View.GONE); Handler mainHandler = new Handler(Looper.getMainLooper()); - mProgressCheckerRunnable = new VastVideoViewProgressRunnable(this, mainHandler); + mProgressCheckerRunnable = new VastVideoViewProgressRunnable(this, mVastVideoConfig, + mainHandler); mCountdownRunnable = new VastVideoViewCountdownRunnable(this, mainHandler); } @@ -211,7 +199,7 @@ protected VideoView getVideoView() { protected void onCreate() { super.onCreate(); - switch (mVastVideoConfiguration.getCustomForceOrientation()) { + switch (mVastVideoConfig.getCustomForceOrientation()) { case FORCE_PORTRAIT: getBaseVideoViewControllerListener().onSetRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); break; @@ -226,21 +214,12 @@ protected void onCreate() { break; } - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getImpressionTrackers(), - null, - getCurrentPosition(), - getNetworkMediaFileUrl(), - getContext() - ); + mVastVideoConfig.handleImpression(getContext(), getCurrentPosition()); broadcastAction(ACTION_INTERSTITIAL_SHOW); } @Override protected void onResume() { - // When resuming, VideoView needs to reinitialize its MediaPlayer with the video path - // and therefore reset the count to zero, to let it retry on error - mVideoRetries = 0; startRunnables(); if (mSeekerPositionOnPause > 0) { @@ -250,13 +229,7 @@ protected void onResume() { mVideoView.start(); } if (mSeekerPositionOnPause != SEEKER_POSITION_NOT_INITIALIZED) { - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getResumeTrackers(), - null, - mSeekerPositionOnPause, - mVastVideoConfiguration.getNetworkMediaFileUrl(), - getContext() - ); + mVastVideoConfig.handleResume(getContext(), mSeekerPositionOnPause); } } @@ -265,14 +238,8 @@ protected void onPause() { stopRunnables(); mSeekerPositionOnPause = getCurrentPosition(); mVideoView.pause(); - if (!mIsVideoFinishedPlaying) { - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getPauseTrackers(), - null, - getCurrentPosition(), - mVastVideoConfiguration.getNetworkMediaFileUrl(), - getContext() - ); + if (!mIsVideoFinishedPlaying && !mIsClosing) { + mVastVideoConfig.handlePause(getContext(), mSeekerPositionOnPause); } } @@ -280,12 +247,33 @@ protected void onPause() { protected void onDestroy() { stopRunnables(); broadcastAction(ACTION_INTERSTITIAL_DISMISS); + + mVideoView.onDestroy(); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { outState.putInt(CURRENT_POSITION, mSeekerPositionOnPause); - outState.putSerializable(RESUMED_VAST_CONFIGURATION, mVastVideoConfiguration); + outState.putSerializable(RESUMED_VAST_CONFIG, mVastVideoConfig); + } + + @Override + protected void onConfigurationChanged(@Nullable final Configuration newConfig) { + final int orientation = getContext().getResources().getConfiguration().orientation; + mVastCompanionAdConfig = mVastVideoConfig.getVastCompanionAd(orientation); + if (mLandscapeCompanionAdView.getVisibility() == View.VISIBLE || + mPortraitCompanionAdView.getVisibility() == View.VISIBLE) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + mLandscapeCompanionAdView.setVisibility(View.INVISIBLE); + mPortraitCompanionAdView.setVisibility(View.VISIBLE); + } else { + mPortraitCompanionAdView.setVisibility(View.INVISIBLE); + mLandscapeCompanionAdView.setVisibility(View.VISIBLE); + } + if (mVastCompanionAdConfig != null) { + mVastCompanionAdConfig.handleImpression(getContext(), mDuration); + } + } } // Enable the device's back button when the video close button has been displayed @@ -310,113 +298,18 @@ private void adjustSkipOffset() { } // Override if skipoffset attribute is specified in VAST - String skipOffsetString = mVastVideoConfiguration.getSkipOffset(); - if (skipOffsetString != null) { - try { - if (Strings.isAbsoluteTracker(skipOffsetString)) { - Integer skipOffsetMilliseconds = Strings.parseAbsoluteOffset(skipOffsetString); - if (skipOffsetMilliseconds != null && skipOffsetMilliseconds < videoDuration) { - mShowCloseButtonDelay = skipOffsetMilliseconds; - mHasSkipOffset = true; - } - } else if (Strings.isPercentageTracker(skipOffsetString)) { - float percentage = Float.parseFloat(skipOffsetString.replace("%", "")) / 100f; - int skipOffsetMillisecondsRounded = Math.round(videoDuration * percentage); - if (skipOffsetMillisecondsRounded < videoDuration) { - mShowCloseButtonDelay = skipOffsetMillisecondsRounded; - mHasSkipOffset = true; - } - } else { - MoPubLog.d(String.format("Invalid VAST skipoffset format: %s", skipOffsetString)); - } - } catch (NumberFormatException e) { - MoPubLog.d(String.format("Failed to parse skipoffset %s", skipOffsetString)); - } - } - } - - private void prepareBlurredLastVideoFrame() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) { - if (mVastCompanionAd == null && mMediaMetadataRetriever != null) { - - try { - mMediaMetadataRetriever.setDataSource(mVastVideoConfiguration.getDiskMediaFileUrl()); - } catch (RuntimeException e) { - // XXX - // MediaMetadataRetriever.setDataSource() might throw RuntimeException, - // possibly due to decoding issues for certain video formats. - // http://stackoverflow.com/questions/9657280/mediaplayer-setdatasource-causes-ioexception-for-valid-file - if (e.getMessage().contains("0x80000000")) { - MoPubLog.d("MediaMetadataRetriever.setDataSource() failed: status = 0x80000000"); - return; - } else { - throw e; - } - } - - Bitmap lastVideoFrame = mMediaMetadataRetriever.getFrameAtTime( - getDuration() * 1000, MediaMetadataRetriever.OPTION_CLOSEST); - - Bitmap blurredLastVideoFrame = ImageUtils.applyFastGaussianBlurToBitmap( - lastVideoFrame, 4); - - mBlurredLastVideoFrameImageView.setImageBitmap(blurredLastVideoFrame); - ImageUtils.setImageViewAlpha(mBlurredLastVideoFrameImageView, - DrawableConstants.BlurredLastVideoFrame.ALPHA); - } + final Integer skipOffsetMillis = mVastVideoConfig.getSkipOffsetMillis(videoDuration); + if (skipOffsetMillis != null) { + mShowCloseButtonDelay = skipOffsetMillis; + mHasSkipOffset = true; } } - /** - * Returns untriggered VAST progress trackers with a progress before the provided position. - * - * @param currentPositionMillis the current video position in milliseconds. - * @param videoLengthMillis the total video length. - */ - @NonNull - List getUntriggeredTrackersBefore(int currentPositionMillis, int videoLengthMillis) { - if (Preconditions.NoThrow.checkArgument(videoLengthMillis > 0)) { - float progressFraction = currentPositionMillis / (float) (videoLengthMillis); - List untriggeredTrackers = new ArrayList(); - - final ArrayList absoluteTrackers = mVastVideoConfiguration.getAbsoluteTrackers(); - VastAbsoluteProgressTracker absoluteTest = new VastAbsoluteProgressTracker("", currentPositionMillis); - int absoluteTrackerCount = absoluteTrackers.size(); - for (int i = 0; i < absoluteTrackerCount; i++) { - VastAbsoluteProgressTracker tracker = absoluteTrackers.get(i); - if (tracker.compareTo(absoluteTest) > 0) { - break; - } - if (!tracker.isTracked()) { - untriggeredTrackers.add(tracker); - } - } - - final ArrayList fractionalTrackers = mVastVideoConfiguration.getFractionalTrackers(); - final VastFractionalProgressTracker fractionalTest = new VastFractionalProgressTracker("", progressFraction); - int fractionalTrackerCount = fractionalTrackers.size(); - for (int i = 0; i < fractionalTrackerCount; i++) { - VastFractionalProgressTracker tracker = fractionalTrackers.get(i); - if (tracker.compareTo(fractionalTest) > 0) { - break; - } - if (!tracker.isTracked()) { - untriggeredTrackers.add(tracker); - } - } - - return untriggeredTrackers; - } else { - return Collections.emptyList(); + private VastVideoView createVideoView(@NonNull final Context context, int initialVisibility) { + if (mVastVideoConfig.getDiskMediaFileUrl() == null) { + throw new IllegalStateException("VastVideoConfig does not have a video disk path"); } - } - - private int remainingProgressTrackerCount() { - return getUntriggeredTrackersBefore(Integer.MAX_VALUE, Integer.MAX_VALUE).size(); - } - - private VideoView createVideoView(@NonNull final Context context, int initialVisibility) { - final VideoView videoView = new VideoView(context); + final VastVideoView videoView = new VastVideoView(context); videoView.setId((int) Utils.generateUniqueId()); @@ -428,7 +321,10 @@ public void onPrepared(MediaPlayer mp) { // Therefore set it here so that we have access to it at all times mDuration = mVideoView.getDuration(); adjustSkipOffset(); - prepareBlurredLastVideoFrame(); + if (mVastCompanionAdConfig == null) { + videoView.prepareBlurredLastVideoFrame(mBlurredLastVideoFrameImageView, + mVastVideoConfig.getDiskMediaFileUrl()); + } mProgressBarWidget.calibrateAndMakeVisible(getDuration(), mShowCloseButtonDelay); mRadialCountdownWidget.calibrateAndMakeVisible(mShowCloseButtonDelay); mIsCalibrationDone = true; @@ -447,29 +343,28 @@ public void onCompletion(MediaPlayer mp) { // Only fire the completion tracker if we hit all the progress marks. Some Android implementations // fire the completion event even if the whole video isn't watched. - if (!mVideoError && remainingProgressTrackerCount() == 0) { - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getCompleteTrackers(), - null, - getCurrentPosition(), - getNetworkMediaFileUrl(), - getContext() - ); + if (!mVideoError && mVastVideoConfig.getRemainingProgressTrackerCount() == 0) { + mVastVideoConfig.handleComplete(getContext(), getCurrentPosition()); } videoView.setVisibility(View.INVISIBLE); mProgressBarWidget.setVisibility(View.GONE); - mTopGradientStripWidget.setVisibility(View.GONE); - mBottomGradientStripWidget.setVisibility(View.GONE); mIconView.setVisibility(View.GONE); + mTopGradientStripWidget.notifyVideoComplete(); + mBottomGradientStripWidget.notifyVideoComplete(); mCtaButtonWidget.notifyVideoComplete(); // Show companion ad if available - if (mVastCompanionAd != null) { - mCompanionAdView.setVisibility(View.VISIBLE); - mVastCompanionAd.handleImpression(context, mDuration); + if (mVastCompanionAdConfig != null) { + final int orientation = context.getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + mPortraitCompanionAdView.setVisibility(View.VISIBLE); + } else { + mLandscapeCompanionAdView.setVisibility(View.VISIBLE); + } + mVastCompanionAdConfig.handleImpression(context, mDuration); } else if (mBlurredLastVideoFrameImageView.getDrawable() != null) { // If there is no companion ad, show blurred last video frame with dark overlay mBlurredLastVideoFrameImageView.setVisibility(View.VISIBLE); @@ -480,7 +375,8 @@ public void onCompletion(MediaPlayer mp) { videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(final MediaPlayer mediaPlayer, final int what, final int extra) { - if (retryMediaPlayer(mediaPlayer, what, extra)) { + if (videoView.retryMediaPlayer(mediaPlayer, what, extra, + mVastVideoConfig.getDiskMediaFileUrl())) { return true; } else { stopRunnables(); @@ -488,40 +384,43 @@ public boolean onError(final MediaPlayer mediaPlayer, final int what, final int videoError(false); mVideoError = true; - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getErrorTrackers(), - VastErrorCode.GENERAL_LINEAR_AD_ERROR, - getCurrentPosition(), - getNetworkMediaFileUrl(), - getContext() - ); + mVastVideoConfig.handleError(getContext(), + VastErrorCode.GENERAL_LINEAR_AD_ERROR, getCurrentPosition()); return false; } } }); - videoView.setVideoPath(mVastVideoConfiguration.getDiskMediaFileUrl()); + videoView.setVideoPath(mVastVideoConfig.getDiskMediaFileUrl()); videoView.setVisibility(initialVisibility); return videoView; } - private void addTopGradientStripWidget(@NonNull final Context context, int initialVisibility) { + private void addTopGradientStripWidget(@NonNull final Context context) { + boolean hasCompanionAd = (mVastCompanionAdConfig != null); + mTopGradientStripWidget = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + mVastVideoConfig.getCustomForceOrientation(), + hasCompanionAd, + View.VISIBLE, RelativeLayout.ALIGN_TOP, - mVideoView.getId()); - mTopGradientStripWidget.setVisibility(initialVisibility); + getLayout().getId()); getLayout().addView(mTopGradientStripWidget); } - private void addBottomGradientStripWidget(@NonNull final Context context, int initialVisibility) { + private void addBottomGradientStripWidget(@NonNull final Context context) { + boolean hasCompanionAd = (mVastCompanionAdConfig != null); + mBottomGradientStripWidget = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.BOTTOM_TOP, + mVastVideoConfig.getCustomForceOrientation(), + hasCompanionAd, + View.GONE, RelativeLayout.ABOVE, mProgressBarWidget.getId()); - mBottomGradientStripWidget.setVisibility(initialVisibility); getLayout().addView(mBottomGradientStripWidget); } @@ -537,19 +436,20 @@ private void addRadialCountdownWidget(@NonNull final Context context, int initia getLayout().addView(mRadialCountdownWidget); } - private void addCtaButtonWidget(@NonNull final Context context, int initialVisibility) { - boolean hasCompanionAd = (mVastCompanionAd != null); + private void addCtaButtonWidget(@NonNull final Context context) { + boolean hasCompanionAd = (mVastCompanionAdConfig != null); + boolean hasClickthroughUrl = !TextUtils.isEmpty( + mVastVideoConfig.getClickThroughUrl()); - mCtaButtonWidget = new VastVideoCtaButtonWidget(context, mVideoView.getId(), hasCompanionAd); - - mCtaButtonWidget.setVisibility(initialVisibility); + mCtaButtonWidget = new VastVideoCtaButtonWidget(context, mVideoView.getId(), hasCompanionAd, + hasClickthroughUrl); getLayout().addView(mCtaButtonWidget); mCtaButtonWidget.setOnTouchListener(mClickThroughListener); // Update custom CTA text if specified in VAST extension - String customCtaText = mVastVideoConfiguration.getCustomCtaText(); + String customCtaText = mVastVideoConfig.getCustomCtaText(); if (customCtaText != null) { mCtaButtonWidget.updateCtaText(customCtaText); } @@ -571,20 +471,8 @@ public boolean onTouch(View view, MotionEvent motionEvent) { currentPosition = getCurrentPosition(); } if (motionEvent.getAction() == MotionEvent.ACTION_UP) { - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getCloseTrackers(), - null, - currentPosition, - getNetworkMediaFileUrl(), - getContext() - ); - makeVastTrackingHttpRequest( - mVastVideoConfiguration.getSkipTrackers(), - null, - currentPosition, - getNetworkMediaFileUrl(), - getContext() - ); + mIsClosing = true; + mVastVideoConfig.handleClose(getContext(), currentPosition); getBaseVideoViewControllerListener().onFinish(); } return true; @@ -594,27 +482,18 @@ public boolean onTouch(View view, MotionEvent motionEvent) { mCloseButtonWidget.setOnTouchListenerToContent(closeOnTouchListener); // Update custom skip text if specified in VAST extensions - final String customSkipText = mVastVideoConfiguration.getCustomSkipText(); + final String customSkipText = mVastVideoConfig.getCustomSkipText(); if (customSkipText != null) { mCloseButtonWidget.updateCloseButtonText(customSkipText); } // Update custom close icon if specified in VAST extensions - final String customCloseIconUrl = mVastVideoConfiguration.getCustomCloseIconUrl(); + final String customCloseIconUrl = mVastVideoConfig.getCustomCloseIconUrl(); if (customCloseIconUrl != null) { mCloseButtonWidget.updateCloseButtonIcon(customCloseIconUrl); } } - @Nullable - private MediaMetadataRetriever createMediaMetadataRetriever() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) { - return new MediaMetadataRetriever(); - } - - return null; - } - private void addBlurredLastVideoFrameImageView(@NonNull final Context context, int initialVisibility) { @@ -627,101 +506,21 @@ private void addBlurredLastVideoFrameImageView(@NonNull final Context context, getLayout().addView(mBlurredLastVideoFrameImageView, layoutParams); } - boolean retryMediaPlayer(final MediaPlayer mediaPlayer, final int what, final int extra) { - // XXX - // VideoView has a bug in versions lower than Jelly Bean, Api Level 16, Android 4.1 - // For api < 16, VideoView is not able to read files written to disk since it reads them in - // a Context different from the Application and therefore does not have correct permission. - // To solve this problem we obtain the video file descriptor ourselves with valid permissions - // and pass it to the underlying MediaPlayer in VideoView. - if (VersionCode.currentApiLevel().isBelow(VersionCode.JELLY_BEAN) - && what == MediaPlayer.MEDIA_ERROR_UNKNOWN - && extra == VIDEO_VIEW_FILE_PERMISSION_ERROR - && mVideoRetries < MAX_VIDEO_RETRIES) { - - FileInputStream inputStream = null; - try { - mediaPlayer.reset(); - final File file = new File(mVastVideoConfiguration.getDiskMediaFileUrl()); - inputStream = new FileInputStream(file); - mediaPlayer.setDataSource(inputStream.getFD()); - - // XXX - // VideoView has a callback registered with the MediaPlayer to set a flag when the - // media file has been prepared. Start also sets a flag in VideoView indicating the - // desired state is to play the video. Therefore, whichever method finishes last - // will check both flags and begin playing the video. - mediaPlayer.prepareAsync(); - mVideoView.start(); - return true; - } catch (Exception e) { - return false; - } finally { - Streams.closeStream(inputStream); - mVideoRetries++; - } - } - return false; - } - - /** - * Called upon user click. Attempts open mopubnativebrowser links in the device browser and all - * other links in the MoPub in-app browser. - */ - @VisibleForTesting - void handleClick(final String clickThroughUrl) { - if (TextUtils.isEmpty(clickThroughUrl)) { - return; - } - - broadcastAction(ACTION_INTERSTITIAL_CLICK); - - new UrlHandler.Builder() - .withSupportedUrlActions( - UrlAction.IGNORE_ABOUT_SCHEME, - UrlAction.OPEN_APP_MARKET, - UrlAction.OPEN_NATIVE_BROWSER, - UrlAction.OPEN_IN_APP_BROWSER, - UrlAction.HANDLE_SHARE_TWEET, - UrlAction.FOLLOW_DEEP_LINK_WITH_FALLBACK, - UrlAction.FOLLOW_DEEP_LINK) - .withResultActions(new UrlHandler.ResultActions() { - @Override - public void urlHandlingSucceeded(@NonNull String url, - @NonNull UrlAction urlAction) { - if (urlAction == UrlAction.OPEN_IN_APP_BROWSER) { - Bundle bundle = new Bundle(); - bundle.putString(MoPubBrowser.DESTINATION_URL_KEY, url); - - getBaseVideoViewControllerListener().onStartActivityForResult( - MoPubBrowser.class, MOPUB_BROWSER_REQUEST_CODE, bundle); - } - } - - @Override - public void urlHandlingFailed(@NonNull String url, - @NonNull UrlAction lastFailedUrlAction) { - } - }) - .withoutMoPubBrowser() - .build().handleUrl(getContext(), clickThroughUrl); - } - /** * Creates and lays out the webview used to display the companion ad. * * @param context The context. - * @param vastCompanionAd The data used to populate the view. + * @param vastCompanionAdConfig The data used to populate the view. * @return the populated webview */ @NonNull @VisibleForTesting View createCompanionAdView(@NonNull final Context context, - @Nullable final VastCompanionAd vastCompanionAd, + @Nullable final VastCompanionAdConfig vastCompanionAdConfig, int initialVisibility) { Preconditions.checkNotNull(context); - if (vastCompanionAd == null) { + if (vastCompanionAdConfig == null) { final View emptyView = new View(context); emptyView.setVisibility(View.INVISIBLE); return emptyView; @@ -736,25 +535,31 @@ View createCompanionAdView(@NonNull final Context context, getLayout().addView(relativeLayout, layoutParams); VastWebView companionView = VastWebView.createView(context, - vastCompanionAd.getVastResource()); + vastCompanionAdConfig.getVastResource()); + + // For javascript, HTML, and IFrames, ignore the traditional clickthrough url and open all + // new urls in the MoPub Browser. For static images, use the clickthrough url specified in + // the VAST document. These two handleClicks make it so that the correct behavior happens + // in these special cases. onVastWebViewClick is called in both circumstances to fire the + // click trackers. companionView.setVastWebViewClickListener(new VastWebView.VastWebViewClickListener() { @Override public void onVastWebViewClick() { broadcastAction(ACTION_INTERSTITIAL_CLICK); makeVastTrackingHttpRequest( - vastCompanionAd.getClickTrackers(), + vastCompanionAdConfig.getClickTrackers(), null, mDuration, null, context ); - vastCompanionAd.handleClick(context, MOPUB_BROWSER_REQUEST_CODE, null); + vastCompanionAdConfig.handleClick(context, MOPUB_BROWSER_REQUEST_CODE, null); } }); companionView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - vastCompanionAd.handleClick(context, MOPUB_BROWSER_REQUEST_CODE, url); + vastCompanionAdConfig.handleClick(context, MOPUB_BROWSER_REQUEST_CODE, url); return true; } }); @@ -762,8 +567,8 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { companionView.setVisibility(initialVisibility); final RelativeLayout.LayoutParams companionAdLayout = new RelativeLayout.LayoutParams( - Dips.dipsToIntPixels(vastCompanionAd.getWidth() + WEBVIEW_PADDING, context), - Dips.dipsToIntPixels(vastCompanionAd.getHeight() + WEBVIEW_PADDING, context) + Dips.dipsToIntPixels(vastCompanionAdConfig.getWidth() + WEBVIEW_PADDING, context), + Dips.dipsToIntPixels(vastCompanionAdConfig.getHeight() + WEBVIEW_PADDING, context) ); companionAdLayout.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); @@ -775,36 +580,36 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { * Creates and lays out the webview used to display the icon. * * @param context the context. - * @param vastIcon the data used to populate the view. + * @param vastIconConfig the data used to populate the view. * @return the populated webview. */ @NonNull @VisibleForTesting - View createIconView(@NonNull final Context context, @Nullable final VastIcon vastIcon, int initialVisibility) { + View createIconView(@NonNull final Context context, @Nullable final VastIconConfig vastIconConfig, int initialVisibility) { Preconditions.checkNotNull(context); - if (vastIcon == null) { + if (vastIconConfig == null) { return new View(context); } - VastWebView iconView = VastWebView.createView(context, vastIcon.getVastResource()); + VastWebView iconView = VastWebView.createView(context, vastIconConfig.getVastResource()); iconView.setVastWebViewClickListener(new VastWebView.VastWebViewClickListener() { @Override public void onVastWebViewClick() { makeVastTrackingHttpRequest( - vastIcon.getClickTrackingUris(), + vastIconConfig.getClickTrackingUris(), null, getCurrentPosition(), getNetworkMediaFileUrl(), context ); - vastIcon.handleClick(getContext(), null); + vastIconConfig.handleClick(getContext(), null); } }); iconView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - vastIcon.handleClick(getContext(), url); + vastIconConfig.handleClick(getContext(), url); return true; } }); @@ -813,8 +618,8 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { // Add extra room for the WebView to account for the natural padding in Android WebViews. RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( - Dips.asIntPixels(vastIcon.getWidth() + WEBVIEW_PADDING, context), - Dips.asIntPixels(vastIcon.getHeight() + WEBVIEW_PADDING, context)); + Dips.asIntPixels(vastIconConfig.getWidth() + WEBVIEW_PADDING, context), + Dips.asIntPixels(vastIconConfig.getHeight() + WEBVIEW_PADDING, context)); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); @@ -855,10 +660,10 @@ void updateProgressBar() { } String getNetworkMediaFileUrl() { - if (mVastVideoConfiguration == null) { + if (mVastVideoConfig == null) { return null; } - return mVastVideoConfiguration.getNetworkMediaFileUrl(); + return mVastVideoConfig.getNetworkMediaFileUrl(); } /** @@ -869,18 +674,18 @@ String getNetworkMediaFileUrl() { * @param currentPosition the current position of the video in milliseconds. */ void handleIconDisplay(int currentPosition) { - if (mVastIcon == null || currentPosition < mVastIcon.getOffsetMS()) { + if (mVastIconConfig == null || currentPosition < mVastIconConfig.getOffsetMS()) { return; } mIconView.setVisibility(View.VISIBLE); - mVastIcon.handleImpression(getContext(), currentPosition, getNetworkMediaFileUrl()); + mVastIconConfig.handleImpression(getContext(), currentPosition, getNetworkMediaFileUrl()); - if (mVastIcon.getDurationMS() == null) { + if (mVastIconConfig.getDurationMS() == null) { return; } - if (currentPosition >= mVastIcon.getOffsetMS() + mVastIcon.getDurationMS()) { + if (currentPosition >= mVastIconConfig.getOffsetMS() + mVastIconConfig.getDurationMS()) { mIconView.setVisibility(View.GONE); } } @@ -912,13 +717,6 @@ VastVideoViewCountdownRunnable getCountdownRunnable() { return mCountdownRunnable; } - // for testing - @Deprecated - @VisibleForTesting - int getVideoRetries() { - return mVideoRetries; - } - // for testing @Deprecated @VisibleForTesting @@ -964,15 +762,15 @@ boolean isCalibrationDone() { // for testing @Deprecated @VisibleForTesting - View getCompanionAdView() { - return mCompanionAdView; + View getLandscapeCompanionAdView() { + return mLandscapeCompanionAdView; } // for testing @Deprecated @VisibleForTesting - void setVideoError() { - mVideoError = true; + View getPortraitCompanionAdView() { + return mPortraitCompanionAdView; } // for testing @@ -982,6 +780,13 @@ boolean getVideoError() { return mVideoError; } + // for testing + @Deprecated + @VisibleForTesting + void setVideoError() { + mVideoError = true; + } + // for testing @Deprecated @VisibleForTesting @@ -1000,7 +805,7 @@ VastVideoGradientStripWidget getTopGradientStripWidget() { @Deprecated @VisibleForTesting VastVideoGradientStripWidget getBottomGradientStripWidget() { - return mTopGradientStripWidget; + return mBottomGradientStripWidget; } // for testing @@ -1010,6 +815,13 @@ VastVideoProgressBarWidget getProgressBarWidget() { return mProgressBarWidget; } + // for testing + @Deprecated + @VisibleForTesting + void setProgressBarWidget(@NonNull VastVideoProgressBarWidget progressBarWidget) { + mProgressBarWidget = progressBarWidget; + } + // for testing @Deprecated @VisibleForTesting @@ -1017,6 +829,13 @@ VastVideoRadialCountdownWidget getRadialCountdownWidget() { return mRadialCountdownWidget; } + // for testing + @Deprecated + @VisibleForTesting + void setRadialCountdownWidget(@NonNull VastVideoRadialCountdownWidget radialCountdownWidget) { + mRadialCountdownWidget = radialCountdownWidget; + } + // for testing @Deprecated @VisibleForTesting @@ -1041,21 +860,13 @@ ImageView getBlurredLastVideoFrameImageView() { // for testing @Deprecated @VisibleForTesting - void setMediaMetadataRetriever(@NonNull MediaMetadataRetriever mediaMetadataRetriever) { - mMediaMetadataRetriever = mediaMetadataRetriever; - } - - // for testing - @Deprecated - @VisibleForTesting - void setRadialCountdownWidget(@NonNull VastVideoRadialCountdownWidget radialCountdownWidget) { - mRadialCountdownWidget = radialCountdownWidget; + VastVideoView getVastVideoView() { + return mVideoView; } - // for testing @Deprecated @VisibleForTesting - void setProgressBarWidget(@NonNull VastVideoProgressBarWidget progressBarWidget) { - mProgressBarWidget = progressBarWidget; + void setIsClosing(boolean isClosing) { + mIsClosing = isClosing; } } diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewProgressRunnable.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewProgressRunnable.java index fdb31fa0c..d7abf6c32 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewProgressRunnable.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastVideoViewProgressRunnable.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import com.mopub.common.Preconditions; -import com.mopub.common.logging.MoPubLog; import com.mopub.network.TrackingRequest; import java.util.ArrayList; @@ -17,12 +16,17 @@ public class VastVideoViewProgressRunnable extends RepeatingHandlerRunnable { @NonNull private final VastVideoViewController mVideoViewController; + @NonNull private final VastVideoConfig mVastVideoConfig; + public VastVideoViewProgressRunnable(@NonNull VastVideoViewController videoViewController, + @NonNull final VastVideoConfig vastVideoConfig, @NonNull Handler handler) { super(handler); Preconditions.checkNotNull(videoViewController); + Preconditions.checkNotNull(vastVideoConfig); mVideoViewController = videoViewController; + mVastVideoConfig = vastVideoConfig; } @Override @@ -34,7 +38,7 @@ public void doWork() { if (videoLength > 0) { final List trackersToTrack = - mVideoViewController.getUntriggeredTrackersBefore(currentPosition, videoLength); + mVastVideoConfig.getUntriggeredTrackersBefore(currentPosition, videoLength); if (!trackersToTrack.isEmpty()) { final List trackUrls = new ArrayList(); for (VastTracker tracker : trackersToTrack) { diff --git a/mopub-sdk/src/main/java/com/mopub/mobileads/VastXmlManagerAggregator.java b/mopub-sdk/src/main/java/com/mopub/mobileads/VastXmlManagerAggregator.java index 5cc832382..09c5d7b7d 100644 --- a/mopub-sdk/src/main/java/com/mopub/mobileads/VastXmlManagerAggregator.java +++ b/mopub-sdk/src/main/java/com/mopub/mobileads/VastXmlManagerAggregator.java @@ -1,6 +1,7 @@ package com.mopub.mobileads; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Point; import android.net.http.AndroidHttpClient; import android.os.AsyncTask; @@ -16,6 +17,7 @@ import com.mopub.common.logging.MoPubLog; import com.mopub.common.util.Dips; import com.mopub.common.util.Strings; +import com.mopub.network.Networking; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -33,10 +35,10 @@ /** * AsyncTask that reads in VAST xml and resolves redirects. This returns a - * fully formed {@link VastVideoConfiguration} so that the video can be + * fully formed {@link VastVideoConfig} so that the video can be * displayed with the settings and trackers set in the configuration. */ -public class VastXmlManagerAggregator extends AsyncTask { +public class VastXmlManagerAggregator extends AsyncTask { /** * Listener for when the xml parsing is done. @@ -45,22 +47,32 @@ interface VastXmlManagerAggregatorListener { /** * When all the wrappers have resolved and aggregation is done, this passes in * a video configuration or null if one is not found. - * @param vastVideoConfiguration The video configuration found or null if + * @param vastVideoConfig The video configuration found or null if * no video was found. */ - void onAggregationComplete(final @Nullable VastVideoConfiguration vastVideoConfiguration); + void onAggregationComplete(final @Nullable VastVideoConfig vastVideoConfig); + } + + /** + * Flag for companion ad orientation during xml parsing. + */ + enum CompanionOrientation { + LANDSCAPE, + PORTRAIT } // More than reasonable number of nested VAST urls to follow static final int MAX_TIMES_TO_FOLLOW_VAST_REDIRECT = 10; - private static final double ASPECT_RATIO_WEIGHT = 40; - private static final double AREA_WEIGHT = 60; + private static final double ASPECT_RATIO_WEIGHT = 70; + private static final double AREA_WEIGHT = 30; private static final List VIDEO_MIME_TYPES = Arrays.asList("video/mp4", "video/3gpp"); + private static final int MINIMUM_COMPANION_AD_WIDTH = 300; + private static final int MINIMUM_COMPANION_AD_HEIGHT = 250; @NonNull private final WeakReference mVastXmlManagerAggregatorListener; private final double mScreenAspectRatio; - private final int mScreenArea; + private final int mScreenAreaDp; @NonNull private final Context mContext; /** @@ -71,7 +83,7 @@ interface VastXmlManagerAggregatorListener { VastXmlManagerAggregator(@NonNull final VastXmlManagerAggregatorListener vastXmlManagerAggregatorListener, final double screenAspectRatio, - final int screenArea, + final int screenAreaDp, @NonNull final Context context) { super(); @@ -80,12 +92,19 @@ interface VastXmlManagerAggregatorListener { mVastXmlManagerAggregatorListener = new WeakReference(vastXmlManagerAggregatorListener); mScreenAspectRatio = screenAspectRatio; - mScreenArea = screenArea; + mScreenAreaDp = screenAreaDp; mContext = context.getApplicationContext(); } @Override - protected VastVideoConfiguration doInBackground(@Nullable String... strings) { + protected void onPreExecute() { + // This is to set the WebView user agent in case it was not already set by some other + // element (such as the request queue). + Networking.getUserAgent(mContext); + } + + @Override + protected VastVideoConfig doInBackground(@Nullable String... strings) { AndroidHttpClient httpClient = null; try { httpClient = HttpClient.getHttpClient(); @@ -108,10 +127,10 @@ protected VastVideoConfiguration doInBackground(@Nullable String... strings) { } @Override - protected void onPostExecute(final @Nullable VastVideoConfiguration vastVideoConfiguration) { + protected void onPostExecute(final @Nullable VastVideoConfig vastVideoConfig) { final VastXmlManagerAggregatorListener listener = mVastXmlManagerAggregatorListener.get(); if (listener != null) { - listener.onAggregationComplete(vastVideoConfiguration); + listener.onAggregationComplete(vastVideoConfig); } } @@ -139,12 +158,12 @@ protected void onCancelled() { * @param androidHttpClient This is used to follow redirects * @param errorTrackers This is the current list of error tracker URLs to hit if something * goes wrong. - * @return {@link VastVideoConfiguration} with all available fields set or null if the xml is + * @return {@link VastVideoConfig} with all available fields set or null if the xml is * invalid or null. */ @VisibleForTesting @Nullable - VastVideoConfiguration evaluateVastXmlManager(@NonNull final String vastXml, + VastVideoConfig evaluateVastXmlManager(@NonNull final String vastXml, @NonNull final AndroidHttpClient androidHttpClient, @NonNull final List errorTrackers) { Preconditions.checkNotNull(vastXml, "vastXml cannot be null"); @@ -177,12 +196,12 @@ VastVideoConfiguration evaluateVastXmlManager(@NonNull final String vastXml, // InLine evaluation VastInLineXmlManager vastInLineXmlManager = vastAdXmlManager.getInLineXmlManager(); if (vastInLineXmlManager != null) { - VastVideoConfiguration vastVideoConfiguration = evaluateInLineXmlManager( + VastVideoConfig vastVideoConfig = evaluateInLineXmlManager( vastInLineXmlManager, errorTrackers); - // If the vastVideoConfiguration is non null, it means we found a valid media file - if (vastVideoConfiguration != null) { - populateMoPubCustomElements(xmlManager, vastVideoConfiguration); - return vastVideoConfiguration; + // If the vastVideoConfig is non null, it means we found a valid media file + if (vastVideoConfig != null) { + populateMoPubCustomElements(xmlManager, vastVideoConfig); + return vastVideoConfig; } } @@ -197,7 +216,7 @@ VastVideoConfiguration evaluateVastXmlManager(@NonNull final String vastXml, continue; } - VastVideoConfiguration vastVideoConfiguration = evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = evaluateVastXmlManager( vastRedirectXml, androidHttpClient, wrapperErrorTrackers); @@ -205,40 +224,53 @@ VastVideoConfiguration evaluateVastXmlManager(@NonNull final String vastXml, // look at the next Ad element // NOTE: Wrapper elements will never contain media files according to the VAST // 3.0 spec - if (vastVideoConfiguration == null) { + if (vastVideoConfig == null) { continue; } - // If we have a vastVideoConfiguration it means that we found a valid media file + // If we have a vastVideoConfig it means that we found a valid media file // in one of Wrapper redirects. Therefore, aggregate all trackers in the wrapper - vastVideoConfiguration.addImpressionTrackers( + vastVideoConfig.addImpressionTrackers( vastWrapperXmlManager.getImpressionTrackers()); List linearXmlManagers = vastWrapperXmlManager.getLinearXmlManagers(); for (VastLinearXmlManager linearXmlManager : linearXmlManagers) { - populateLinearTrackersAndIcon(linearXmlManager, vastVideoConfiguration); + populateLinearTrackersAndIcon(linearXmlManager, vastVideoConfig); } // Only populate a companion ad if we don't already have one from one of the // redirects - final VastCompanionAd companionAd = vastVideoConfiguration.getVastCompanionAd(); - if (companionAd == null) { - vastVideoConfiguration.setVastCompanionAd( - getBestCompanionAd(vastWrapperXmlManager.getCompanionAdXmlManagers())); + if (!vastVideoConfig.hasCompanionAd()) { + vastVideoConfig.setVastCompanionAd( + getBestCompanionAd(vastWrapperXmlManager.getCompanionAdXmlManagers(), + CompanionOrientation.LANDSCAPE), + getBestCompanionAd(vastWrapperXmlManager.getCompanionAdXmlManagers(), + CompanionOrientation.PORTRAIT)); } else { // Otherwise append the companion trackers if it doesn't have resources - for (final VastCompanionAdXmlManager companionAdXmlManager : vastWrapperXmlManager.getCompanionAdXmlManagers()) { - if (!companionAdXmlManager.hasResources()) { - companionAd.addClickTrackers(companionAdXmlManager.getClickTrackers()); - companionAd.addCreativeViewTrackers( - companionAdXmlManager.getCompanionCreativeViewTrackers()); + final VastCompanionAdConfig landscapeCompanionAd = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_LANDSCAPE); + final VastCompanionAdConfig portraitCompanionAd = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_PORTRAIT); + if (landscapeCompanionAd != null && portraitCompanionAd != null) { + for (final VastCompanionAdXmlManager companionAdXmlManager : vastWrapperXmlManager.getCompanionAdXmlManagers()) { + if (!companionAdXmlManager.hasResources()) { + landscapeCompanionAd.addClickTrackers( + companionAdXmlManager.getClickTrackers()); + landscapeCompanionAd.addCreativeViewTrackers( + companionAdXmlManager.getCompanionCreativeViewTrackers()); + portraitCompanionAd.addClickTrackers( + companionAdXmlManager.getClickTrackers()); + portraitCompanionAd.addCreativeViewTrackers( + companionAdXmlManager.getCompanionCreativeViewTrackers()); + } } } } - populateMoPubCustomElements(xmlManager, vastVideoConfiguration); + populateMoPubCustomElements(xmlManager, vastVideoConfig); - return vastVideoConfiguration; + return vastVideoConfig; } } @@ -248,16 +280,16 @@ VastVideoConfiguration evaluateVastXmlManager(@NonNull final String vastXml, /** * Parses and evaluates an InLine element looking for a valid media file. InLine elements are * evaluated in order and the first valid media file found is used. If a media file is - * found, a {@link VastVideoConfiguration} is created and trackers are aggregated. If a + * found, a {@link VastVideoConfig} is created and trackers are aggregated. If a * valid companion ad is found, it is also added to the configuration. * * @param vastInLineXmlManager used to extract the media file, clickthrough link, trackers, and * companion ad * @param errorTrackers The error trackers from previous wrappers - * @return a {@link VastVideoConfiguration} or null if a valid media file was not found + * @return a {@link VastVideoConfig} or null if a valid media file was not found */ @Nullable - private VastVideoConfiguration evaluateInLineXmlManager( + private VastVideoConfig evaluateInLineXmlManager( @NonNull final VastInLineXmlManager vastInLineXmlManager, @NonNull final List errorTrackers) { Preconditions.checkNotNull(vastInLineXmlManager); @@ -267,21 +299,24 @@ private VastVideoConfiguration evaluateInLineXmlManager( String bestMediaFileUrl = getBestMediaFileUrl(linearXmlManager.getMediaXmlManagers()); if (bestMediaFileUrl != null) { // Create vast video configuration and populate initial trackers - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.addImpressionTrackers(vastInLineXmlManager.getImpressionTrackers()); - populateLinearTrackersAndIcon(linearXmlManager, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.addImpressionTrackers(vastInLineXmlManager.getImpressionTrackers()); + populateLinearTrackersAndIcon(linearXmlManager, vastVideoConfig); // Linear nodes will only have a click through url and network media file when they // are under an InLine element. They will not have these assets when they are under // a Wrapper element. - vastVideoConfiguration.setClickThroughUrl(linearXmlManager.getClickThroughUrl()); - vastVideoConfiguration.setNetworkMediaFileUrl(bestMediaFileUrl); - - vastVideoConfiguration.setVastCompanionAd(getBestCompanionAd(vastInLineXmlManager - .getCompanionAdXmlManagers())); + vastVideoConfig.setClickThroughUrl(linearXmlManager.getClickThroughUrl()); + vastVideoConfig.setNetworkMediaFileUrl(bestMediaFileUrl); + + vastVideoConfig.setVastCompanionAd( + getBestCompanionAd(vastInLineXmlManager.getCompanionAdXmlManagers(), + CompanionOrientation.LANDSCAPE), + getBestCompanionAd(vastInLineXmlManager.getCompanionAdXmlManagers(), + CompanionOrientation.PORTRAIT)); errorTrackers.addAll(vastInLineXmlManager.getErrorTrackers()); - vastVideoConfiguration.addErrorTrackers(errorTrackers); - return vastVideoConfiguration; + vastVideoConfig.addErrorTrackers(errorTrackers); + return vastVideoConfig; } } @@ -321,65 +356,65 @@ private String evaluateWrapperRedirect(@NonNull VastWrapperXmlManager vastWrappe /** * This method aggregates all trackers found in the linearXmlManager and adds them to the - * {@link VastVideoConfiguration}. This method also populates the skip offset and icon if they + * {@link VastVideoConfig}. This method also populates the skip offset and icon if they * have not already been populated in one of the wrapper redirects. * * @param linearXmlManager used to retrieve trackers, and assets - * @param vastVideoConfiguration modified in this method to store trackers and assets + * @param vastVideoConfig modified in this method to store trackers and assets */ private void populateLinearTrackersAndIcon(@NonNull final VastLinearXmlManager linearXmlManager, - @NonNull final VastVideoConfiguration vastVideoConfiguration) { + @NonNull final VastVideoConfig vastVideoConfig) { Preconditions.checkNotNull(linearXmlManager, "linearXmlManager cannot be null"); - Preconditions.checkNotNull(vastVideoConfiguration, "vastVideoConfiguration cannot be null"); + Preconditions.checkNotNull(vastVideoConfig, "vastVideoConfig cannot be null"); - vastVideoConfiguration.addAbsoluteTrackers(linearXmlManager.getAbsoluteProgressTrackers()); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addAbsoluteTrackers(linearXmlManager.getAbsoluteProgressTrackers()); + vastVideoConfig.addFractionalTrackers( linearXmlManager.getFractionalProgressTrackers()); - vastVideoConfiguration.addPauseTrackers(linearXmlManager.getPauseTrackers()); - vastVideoConfiguration.addResumeTrackers(linearXmlManager.getResumeTrackers()); - vastVideoConfiguration.addCompleteTrackers(linearXmlManager.getVideoCompleteTrackers()); - vastVideoConfiguration.addCloseTrackers(linearXmlManager.getVideoCloseTrackers()); - vastVideoConfiguration.addSkipTrackers(linearXmlManager.getVideoSkipTrackers()); - vastVideoConfiguration.addClickTrackers(linearXmlManager.getClickTrackers()); + vastVideoConfig.addPauseTrackers(linearXmlManager.getPauseTrackers()); + vastVideoConfig.addResumeTrackers(linearXmlManager.getResumeTrackers()); + vastVideoConfig.addCompleteTrackers(linearXmlManager.getVideoCompleteTrackers()); + vastVideoConfig.addCloseTrackers(linearXmlManager.getVideoCloseTrackers()); + vastVideoConfig.addSkipTrackers(linearXmlManager.getVideoSkipTrackers()); + vastVideoConfig.addClickTrackers(linearXmlManager.getClickTrackers()); // Only set the skip offset if we haven't set it already in one of the redirects - if (vastVideoConfiguration.getSkipOffset() == null) { - vastVideoConfiguration.setSkipOffset(linearXmlManager.getSkipOffset()); + if (vastVideoConfig.getSkipOffsetString() == null) { + vastVideoConfig.setSkipOffset(linearXmlManager.getSkipOffset()); } // Only set the icon if we haven't set it already in one of the redirects - if (vastVideoConfiguration.getVastIcon() == null) { - vastVideoConfiguration.setVastIcon(getBestIcon(linearXmlManager.getIconXmlManagers())); + if (vastVideoConfig.getVastIconConfig() == null) { + vastVideoConfig.setVastIconConfig(getBestIcon(linearXmlManager.getIconXmlManagers())); } } /** * Parses all custom MoPub specific custom extensions and impression trackers - * and populates them in the {@link VastVideoConfiguration}. These extensions are not part + * and populates them in the {@link VastVideoConfig}. These extensions are not part * of the Vast 3.0 spec and are appended to the root of the xml document. * * @param xmlManager used to retrieve the custom extensions and impression trackers - * @param vastVideoConfiguration modified in this method to store custom extensions and + * @param vastVideoConfig modified in this method to store custom extensions and * impression trackers */ private void populateMoPubCustomElements(@NonNull final VastXmlManager xmlManager, - @NonNull final VastVideoConfiguration vastVideoConfiguration) { + @NonNull final VastVideoConfig vastVideoConfig) { Preconditions.checkNotNull(xmlManager, "xmlManager cannot be null"); - Preconditions.checkNotNull(vastVideoConfiguration, "vastVideoConfiguration cannot be null"); + Preconditions.checkNotNull(vastVideoConfig, "vastVideoConfig cannot be null"); - vastVideoConfiguration.addImpressionTrackers(xmlManager.getMoPubImpressionTrackers()); + vastVideoConfig.addImpressionTrackers(xmlManager.getMoPubImpressionTrackers()); - if (vastVideoConfiguration.getCustomCtaText() == null) { - vastVideoConfiguration.setCustomCtaText(xmlManager.getCustomCtaText()); + if (vastVideoConfig.getCustomCtaText() == null) { + vastVideoConfig.setCustomCtaText(xmlManager.getCustomCtaText()); } - if (vastVideoConfiguration.getCustomSkipText() == null) { - vastVideoConfiguration.setCustomSkipText(xmlManager.getCustomSkipText()); + if (vastVideoConfig.getCustomSkipText() == null) { + vastVideoConfig.setCustomSkipText(xmlManager.getCustomSkipText()); } - if (vastVideoConfiguration.getCustomCloseIconUrl() == null) { - vastVideoConfiguration.setCustomCloseIconUrl(xmlManager.getCustomCloseIconUrl()); + if (vastVideoConfig.getCustomCloseIconUrl() == null) { + vastVideoConfig.setCustomCloseIconUrl(xmlManager.getCustomCloseIconUrl()); } - if (!vastVideoConfiguration.isCustomForceOrientationSet()) { - vastVideoConfiguration.setCustomForceOrientation(xmlManager.getCustomForceOrientation()); + if (!vastVideoConfig.isCustomForceOrientationSet()) { + vastVideoConfig.setCustomForceOrientation(xmlManager.getCustomForceOrientation()); } } @@ -450,9 +485,12 @@ String getBestMediaFileUrl(@NonNull final List managers) { @VisibleForTesting @Nullable - VastCompanionAd getBestCompanionAd( - @NonNull final List managers) { + VastCompanionAdConfig getBestCompanionAd( + @NonNull final List managers, + @NonNull final CompanionOrientation orientation) { Preconditions.checkNotNull(managers, "managers cannot be null"); + Preconditions.checkNotNull(orientation, "orientation cannot be null"); + final List companionXmlManagers = new ArrayList(managers); double bestCompanionFitness = Double.POSITIVE_INFINITY; @@ -469,8 +507,8 @@ VastCompanionAd getBestCompanionAd( final Integer width = companionXmlManager.getWidth(); final Integer height = companionXmlManager.getHeight(); - if (width == null || width <= 0 || - height == null || height <= 0) { + if (width == null || width < MINIMUM_COMPANION_AD_WIDTH || + height == null || height < MINIMUM_COMPANION_AD_HEIGHT) { continue; } @@ -482,7 +520,12 @@ VastCompanionAd getBestCompanionAd( continue; } - final double companionFitness = calculateFitness(width, height); + final double companionFitness; + if (CompanionOrientation.PORTRAIT == orientation) { + companionFitness = calculateFitness(height, width); + } else { + companionFitness = calculateFitness(width, height); + } if (companionFitness < bestCompanionFitness) { bestCompanionFitness = companionFitness; bestCompanionXmlManager = companionXmlManager; @@ -496,7 +539,7 @@ VastCompanionAd getBestCompanionAd( } if (bestCompanionXmlManager != null) { - return new VastCompanionAd( + return new VastCompanionAdConfig( bestVastScaledDimensions.x, bestVastScaledDimensions.y, bestVastResource, @@ -561,7 +604,7 @@ Point getScaledDimensions(int widthDp, int heightDp) { @VisibleForTesting @Nullable - VastIcon getBestIcon(@NonNull final List managers) { + VastIconConfig getBestIcon(@NonNull final List managers) { Preconditions.checkNotNull(managers, "managers cannot be null"); final List iconXmlManagers = new ArrayList(managers); @@ -587,7 +630,7 @@ VastIcon getBestIcon(@NonNull final List managers) { continue; } - return new VastIcon( + return new VastIconConfig( iconXmlManager.getWidth(), iconXmlManager.getHeight(), iconXmlManager.getOffsetMS(), @@ -607,15 +650,15 @@ VastIcon getBestIcon(@NonNull final List managers) { * area to those of the device. The closer to 0 the score, the better. The fitness function * weighs aspect ratios and areas differently. * - * @param width the width of the media file or companion ad - * @param height the height of th media file or companion ad + * @param widthDp the width of the media file or companion ad + * @param heightDp the height of th media file or companion ad * @return the fitness score. The closer to 0, the better. */ - private double calculateFitness(final int width, final int height) { - final double mediaAspectRatio = (double) width / height; - final int mediaArea = width * height; + private double calculateFitness(final int widthDp, final int heightDp) { + final double mediaAspectRatio = (double) widthDp / heightDp; + final int mediaAreaDp = widthDp * heightDp; final double aspectRatioRatio = mediaAspectRatio / mScreenAspectRatio; - final double areaRatio = (double) mediaArea / mScreenArea; + final double areaRatio = (double) mediaAreaDp / mScreenAreaDp; return ASPECT_RATIO_WEIGHT * Math.abs(Math.log(aspectRatioRatio)) + AREA_WEIGHT * Math.abs(Math.log(areaRatio)); } diff --git a/mopub-sdk/src/main/java/com/mopub/mraid/MraidVideoViewController.java b/mopub-sdk/src/main/java/com/mopub/mraid/MraidVideoViewController.java index a02b1ad41..8aea4da9b 100644 --- a/mopub-sdk/src/main/java/com/mopub/mraid/MraidVideoViewController.java +++ b/mopub-sdk/src/main/java/com/mopub/mraid/MraidVideoViewController.java @@ -1,10 +1,12 @@ package com.mopub.mraid; import android.content.Context; +import android.content.res.Configuration; import android.graphics.drawable.StateListDrawable; import android.media.MediaPlayer; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.View; import android.widget.ImageButton; import android.widget.RelativeLayout; @@ -85,6 +87,10 @@ protected void onResume() {} @Override protected void onSaveInstanceState(@NonNull Bundle outState) {} + @Override + protected void onConfigurationChanged(@Nullable Configuration newConfig) { + } + private void createInterstitialCloseButton() { mCloseButton = new ImageButton(getContext()); StateListDrawable states = new StateListDrawable(); diff --git a/mopub-sdk/src/main/java/com/mopub/nativeads/ClickDestinationResolutionListener.java b/mopub-sdk/src/main/java/com/mopub/nativeads/ClickDestinationResolutionListener.java deleted file mode 100644 index 5c545e5a0..000000000 --- a/mopub-sdk/src/main/java/com/mopub/nativeads/ClickDestinationResolutionListener.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.mopub.nativeads; - -import android.content.Context; -import android.support.annotation.NonNull; - -import com.mopub.common.UrlHandler; -import com.mopub.common.UrlAction; -import com.mopub.common.logging.MoPubLog; - -import java.lang.ref.WeakReference; -import java.util.Iterator; - -class ClickDestinationResolutionListener implements UrlResolutionTask.UrlResolutionListener { - private final Context mContext; - private final Iterator mUrlIterator; - private final WeakReference mSpinningProgressView; - - public ClickDestinationResolutionListener(@NonNull final Context context, - @NonNull final Iterator urlIterator, - @NonNull final SpinningProgressView spinningProgressView) { - mContext = context.getApplicationContext(); - mUrlIterator = urlIterator; - mSpinningProgressView = new WeakReference(spinningProgressView); - } - - /** - * Called upon user click, after the corresponding UrlResolutionTask has followed all redirects - * successfully. Attempts to open mopubnativebrowser links in the device browser, deep-links in - * the corresponding application, and all other links in the MoPub in-app browser. In the first - * two cases, malformed URLs will try to fallback to the next entry in mUrlIterator, and failing - * that, will no-op. - */ - @Override - public void onSuccess(@NonNull final String resolvedUrl) { - new UrlHandler.Builder() - .withSupportedUrlActions( - UrlAction.IGNORE_ABOUT_SCHEME, - UrlAction.OPEN_NATIVE_BROWSER, - UrlAction.OPEN_APP_MARKET, - UrlAction.OPEN_IN_APP_BROWSER, - UrlAction.HANDLE_SHARE_TWEET, - UrlAction.FOLLOW_DEEP_LINK_WITH_FALLBACK, - UrlAction.FOLLOW_DEEP_LINK) - .withResultActions(new UrlHandler.ResultActions() { - @Override - public void urlHandlingSucceeded(@NonNull String url, - @NonNull UrlAction urlAction) { - } - - @Override - public void urlHandlingFailed(@NonNull String url, - @NonNull UrlAction lastFailedUrlAction) { - if (mUrlIterator.hasNext()) { - UrlResolutionTask.getResolvedUrl(mUrlIterator.next(), - ClickDestinationResolutionListener.this); - } - } - }) - .build().handleUrl(mContext, resolvedUrl); - removeSpinningProgressView(); - } - - @Override - public void onFailure() { - MoPubLog.d("Failed to resolve URL for click."); - removeSpinningProgressView(); - } - - private void removeSpinningProgressView() { - final SpinningProgressView spinningProgressView = mSpinningProgressView.get(); - if (spinningProgressView != null) { - spinningProgressView.removeFromRoot(); - } - } -} diff --git a/mopub-sdk/src/main/java/com/mopub/nativeads/NativeResponse.java b/mopub-sdk/src/main/java/com/mopub/nativeads/NativeResponse.java index e332c6cf5..9191d3548 100644 --- a/mopub-sdk/src/main/java/com/mopub/nativeads/NativeResponse.java +++ b/mopub-sdk/src/main/java/com/mopub/nativeads/NativeResponse.java @@ -7,6 +7,9 @@ import android.view.ViewGroup; import android.widget.ImageView; +import com.mopub.common.Preconditions; +import com.mopub.common.UrlAction; +import com.mopub.common.UrlHandler; import com.mopub.common.VisibleForTesting; import com.mopub.common.event.BaseEvent; import com.mopub.common.logging.MoPubLog; @@ -17,9 +20,7 @@ import com.mopub.volley.toolbox.ImageLoader; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -255,6 +256,14 @@ public void recordImpression(@Nullable final View view) { } public void handleClick(@Nullable final View view) { + handleClick(view, new SpinningProgressView(mContext)); + } + + @VisibleForTesting + void handleClick(@Nullable final View view, + @NonNull final SpinningProgressView spinningProgressView) { + Preconditions.checkNotNull(spinningProgressView); + if (isDestroyed()) { return; } @@ -264,7 +273,7 @@ public void handleClick(@Nullable final View view) { mMoPubClickTracker, mContext, BaseEvent.Name.CLICK_REQUEST); } - openClickDestinationUrl(view); + openClickDestinationUrl(view, spinningProgressView); mNativeAd.handleClick(view); mIsClicked = true; @@ -344,21 +353,47 @@ public void onErrorResponse(final VolleyError volleyError) { } } - private void openClickDestinationUrl(@Nullable final View view) { + private void openClickDestinationUrl(@Nullable final View view, + @NonNull final SpinningProgressView spinningProgressView) { + Preconditions.checkNotNull(spinningProgressView); + if (getClickDestinationUrl() == null) { return; } - SpinningProgressView spinningProgressView = null; if (view != null) { - spinningProgressView = new SpinningProgressView(mContext); spinningProgressView.addToRoot(view); } - final Iterator urlIterator = Arrays.asList(getClickDestinationUrl()).iterator(); - final ClickDestinationResolutionListener urlResolutionListener = - new ClickDestinationResolutionListener(mContext, urlIterator, spinningProgressView); - UrlResolutionTask.getResolvedUrl(urlIterator.next(), urlResolutionListener); + new UrlHandler.Builder() + .withSupportedUrlActions( + UrlAction.IGNORE_ABOUT_SCHEME, + UrlAction.OPEN_NATIVE_BROWSER, + UrlAction.OPEN_APP_MARKET, + UrlAction.OPEN_IN_APP_BROWSER, + UrlAction.HANDLE_SHARE_TWEET, + UrlAction.FOLLOW_DEEP_LINK_WITH_FALLBACK, + UrlAction.FOLLOW_DEEP_LINK) + .withResultActions(new UrlHandler.ResultActions() { + @Override + public void urlHandlingSucceeded(@NonNull String url, + @NonNull UrlAction urlAction) { + removeSpinningProgressView(); + } + + @Override + public void urlHandlingFailed(@NonNull String url, + @NonNull UrlAction lastFailedUrlAction) { + removeSpinningProgressView(); + } + + private void removeSpinningProgressView() { + if (view != null) { + spinningProgressView.removeFromRoot(); + } + } + }) + .build().handleUrl(mContext, getClickDestinationUrl()); } private void setOnClickListener(@NonNull final View view, diff --git a/mopub-sdk/src/main/java/com/mopub/network/Networking.java b/mopub-sdk/src/main/java/com/mopub/network/Networking.java index ed087c690..e820a0a56 100644 --- a/mopub-sdk/src/main/java/com/mopub/network/Networking.java +++ b/mopub-sdk/src/main/java/com/mopub/network/Networking.java @@ -29,7 +29,7 @@ public class Networking { @VisibleForTesting static final String CACHE_DIRECTORY_NAME = "mopub-volley-cache"; - + private static final String DEFAULT_USER_AGENT = System.getProperty("http.agent"); // These are volatile so that double-checked locking works. // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java @@ -133,7 +133,7 @@ public static String getUserAgent(@NonNull Context context) { } else { // In the exceptional case where we can't access the WebView user agent, // fall back to the System-specific user agent. - userAgent = System.getProperty("http.agent"); + userAgent = DEFAULT_USER_AGENT; } sUserAgent = userAgent; } @@ -143,6 +143,21 @@ public static String getUserAgent(@NonNull Context context) { return userAgent; } + /** + * Gets the previously cached WebView user agent. This returns the default userAgent if the + * WebView user agent has not been initialized yet. + * + * @return Best-effort String WebView user agent. + */ + @NonNull + public static String getCachedUserAgent() { + final String userAgent = sUserAgent; + if (userAgent == null) { + return DEFAULT_USER_AGENT; + } + return userAgent; + } + @VisibleForTesting public static synchronized void clearForTesting() { sRequestQueue = null; diff --git a/mopub-sdk/src/test/java/com/mopub/common/BrowserWebViewClientTest.java b/mopub-sdk/src/test/java/com/mopub/common/BrowserWebViewClientTest.java index bc18e40ab..08917adb2 100644 --- a/mopub-sdk/src/test/java/com/mopub/common/BrowserWebViewClientTest.java +++ b/mopub-sdk/src/test/java/com/mopub/common/BrowserWebViewClientTest.java @@ -91,7 +91,7 @@ public void shouldOverrideUrlLoading_withDeeplinkPlusUrl_withSuccessfulPrimaryUr @Test public void shouldOverrideUrlLoading_withDeeplinkPlusUrl_withFailedPrimaryUrl_withHTTPFallbackUrl_shouldReturnTrue_shouldLoadFallbackUrl_shouldNotFinish() { final String primaryUrl = "missingApp://somePath"; - final String fallbackUrl = "http://twitter.com"; + final String fallbackUrl = "https://twitter.com/"; final String url = "deeplink+://navigate?primaryUrl=" + Uri.encode(primaryUrl) + "&fallbackUrl=" + Uri.encode(fallbackUrl); diff --git a/mopub-sdk/src/test/java/com/mopub/common/CacheServiceTest.java b/mopub-sdk/src/test/java/com/mopub/common/CacheServiceTest.java index 16b35e0ee..ce7282a36 100644 --- a/mopub-sdk/src/test/java/com/mopub/common/CacheServiceTest.java +++ b/mopub-sdk/src/test/java/com/mopub/common/CacheServiceTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; @RunWith(SdkTestRunner.class) public class CacheServiceTest { @@ -55,6 +56,14 @@ public Object answer(InvocationOnMock invocationOnMock) throws Throwable { }).when(diskCacheGetListener).onComplete(anyString(), any(byte[].class)); } + @Test + public void initializeDiskCache_withNullCacheDirectory_shouldNotThrowNpe_shouldReturnFalse() { + Activity mockContext = mock(Activity.class); + when(mockContext.getCacheDir()).thenReturn(null); + + assertThat(CacheService.initializeDiskCache(mockContext)).isFalse(); + } + @Test public void initializeCache_withValidContext_shouldCreateNewCachesIdempotently() throws Exception { assertThat(CacheService.getDiskLruCache()).isNull(); diff --git a/mopub-sdk/src/test/java/com/mopub/common/HttpClientTest.java b/mopub-sdk/src/test/java/com/mopub/common/HttpClientTest.java index c00f14fbd..497bbbbbc 100644 --- a/mopub-sdk/src/test/java/com/mopub/common/HttpClientTest.java +++ b/mopub-sdk/src/test/java/com/mopub/common/HttpClientTest.java @@ -4,6 +4,7 @@ import android.webkit.WebView; import com.mopub.common.util.ResponseHeader; +import com.mopub.network.Networking; import org.apache.http.HttpRequest; import org.apache.http.client.methods.HttpGet; @@ -16,7 +17,6 @@ import org.robolectric.tester.org.apache.http.RequestMatcher; import org.robolectric.tester.org.apache.http.TestHttpResponse; -import static com.mopub.common.HttpClient.getWebViewUserAgent; import static com.mopub.common.HttpClient.initializeHttpGet; import static com.mopub.common.HttpClient.urlEncode; import static org.fest.assertions.api.Assertions.assertThat; @@ -39,39 +39,32 @@ public boolean matches(HttpRequest request) { } }, new TestHttpResponse(200, "body")); - HttpClient.setWebViewUserAgent(null); Robolectric.getBackgroundScheduler().pause(); Robolectric.clearPendingHttpResponses(); } @After public void tearDown() throws Exception { - HttpClient.setWebViewUserAgent(null); Robolectric.getBackgroundScheduler().reset(); Robolectric.clearPendingHttpResponses(); } @Test public void initializeHttpGet_shouldReturnHttpGetWithWebViewUserAgent() throws Exception { + Networking.setUserAgentForTesting(null); HttpGet httpGet = initializeHttpGet(url, context); assertThat(httpGet.getURI().toURL().toString()).isEqualTo(url); - assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey()).getValue()).isEqualTo(userAgent); + assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey()).getValue()).isEqualTo( + userAgent); } @Test - public void initializeHttpGet_shouldPopulateStaticWebViewUserAgent() throws Exception { - assertThat(HttpClient.getWebViewUserAgent()).isNull(); - - HttpGet httpGet = initializeHttpGet(url, context); - - assertThat(HttpClient.getWebViewUserAgent()).isEqualTo(userAgent); - } - - @Test - public void initializeHttpGet_withNullContext_shouldNotSetUserAgent() throws Exception { + public void initializeHttpGet_withNullContext_shouldUseCachedUserAgent() throws Exception { + Networking.setUserAgentForTesting("cached"); HttpGet httpGet = initializeHttpGet("http://www.mopub.com/"); - assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey())).isNull(); + assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey()).getValue()).isEqualTo( + "cached"); } @Test @@ -113,7 +106,8 @@ public void urlEncode_withProperlyEncodedUrl_shouldReturnUrlWithSameEncoding() t .isEqualTo("http://user:passwrd@host:80/doc%7Csearch?q=green%20robots#over%206%22"); assertThat(urlEncode("https://www.mywebsite.com%2Fd+ocs%2Fenglish%2Fsite%2Fmybook.do%3Fkey%3Dvalue%3B%23fragment")) - .isEqualTo("https://www.mywebsite.com%2Fd+ocs%2Fenglish%2Fsite%2Fmybook.do%3Fkey%3Dvalue%3B%23fragment"); + .isEqualTo( + "https://www.mywebsite.com%2Fd+ocs%2Fenglish%2Fsite%2Fmybook.do%3Fkey%3Dvalue%3B%23fragment"); } @Test(expected = Exception.class) @@ -134,21 +128,18 @@ public void urlEncode_withMalformedUrl_shouldThrowException() throws Exception { urlEncode("derp://www.mopub.com/"); } - @Test - public void getWebViewUserAgent_whenUserAgentNotSet_shouldReturnDefault() { - assertThat(getWebViewUserAgent("test")).isEqualTo("test"); - } - @Test(expected = NullPointerException.class) public void initializeHttpGet_withNullUrl_shouldThrowNullPointerException() throws Exception { initializeHttpGet(null, context); } @Test - public void initializeHttpGet_withNullContext_shouldNotPopulateUserAgentHeader() throws Exception { + public void initializeHttpGet_withNullContext_shouldPopulateUserAgentHeaderWithCachedValue() throws Exception { + Networking.setUserAgentForTesting("cached"); HttpGet httpGet = initializeHttpGet(url, null); assertThat(httpGet.getURI().toURL().toString()).isEqualTo(url); - assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey())).isNull(); + assertThat(httpGet.getFirstHeader(ResponseHeader.USER_AGENT.getKey()).getValue()).isEqualTo( + "cached"); } } diff --git a/mopub-sdk/src/test/java/com/mopub/common/UrlHandlerTest.java b/mopub-sdk/src/test/java/com/mopub/common/UrlHandlerTest.java index 962cd8c36..d70faa576 100644 --- a/mopub-sdk/src/test/java/com/mopub/common/UrlHandlerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/common/UrlHandlerTest.java @@ -48,14 +48,14 @@ public void setUp() throws Exception { @Test public void urlHandler_withoutMoPubBrowser_shouldCallOnClickSuccessButNotStartActivity() { - final String url = "http://some_url"; + final String url = "http://www.mopub.com/"; new UrlHandler.Builder() .withSupportedUrlActions(OPEN_IN_APP_BROWSER) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) .withoutMoPubBrowser() - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, OPEN_IN_APP_BROWSER); verifyNoMoreCallbacks(); @@ -70,7 +70,7 @@ public void urlHandler_withMatchingMoPubSchemeFinishLoad_shouldCallOnFinishLoad( .withSupportedUrlActions(HANDLE_MOPUB_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockMoPubSchemeListener).onFinishLoad(); verifyNoMoreCallbacks(); @@ -83,7 +83,7 @@ public void urlHandler_withMatchingMoPubSchemeClose_shouldCallOnClose() { .withSupportedUrlActions(HANDLE_MOPUB_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockMoPubSchemeListener).onClose(); verifyNoMoreCallbacks(); @@ -96,7 +96,7 @@ public void urlHandler_withMatchingMoPubSchemeFailLoad_shouldCallOnFailLoad() { .withSupportedUrlActions(HANDLE_MOPUB_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockMoPubSchemeListener).onFailLoad(); verifyNoMoreCallbacks(); @@ -112,7 +112,7 @@ public void urlHandler_withMatchingAboutSchemeUrl_shouldIgnoreClick() { HANDLE_PHONE_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verifyNoMoreCallbacks(); verifyNoStartedActivity(); @@ -157,7 +157,7 @@ public void urlHandler_withMatchingPhoneSchemeUrl_shouldStartActivity() { OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); final Intent startedActivity = Robolectric.getShadowApplication().peekNextStartedActivity(); assertThat(startedActivity.getAction()).isEqualTo(Intent.ACTION_VIEW); @@ -166,7 +166,7 @@ public void urlHandler_withMatchingPhoneSchemeUrl_shouldStartActivity() { @Test public void urlHandler_withValidNativeBrowserUrl_shouldCallOnClickSuccess_shouldStartActivity() { - final String urlToLoad = "some_url"; + final String urlToLoad = "http://www.mopub.com/"; final String url = "mopubnativebrowser://navigate?url=" + urlToLoad; new UrlHandler.Builder() @@ -174,7 +174,7 @@ public void urlHandler_withValidNativeBrowserUrl_shouldCallOnClickSuccess_should OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, OPEN_NATIVE_BROWSER); verifyNoMoreCallbacks(); @@ -192,7 +192,7 @@ public void urlHandler_withMatchingInAppBrowserHttpUrl_shouldCallOnClickSuccess_ OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, OPEN_IN_APP_BROWSER); verifyNoMoreCallbacks(); @@ -204,14 +204,14 @@ public void urlHandler_withMatchingInAppBrowserHttpUrl_shouldCallOnClickSuccess_ @Test public void urlHandler_withMatchingInAppBrowserHttpsUrl_shouldCallOnClickSuccess_shouldStartActivity() { - final String url = "https://some_url"; + final String url = "https://www.mopub.com/"; new UrlHandler.Builder() .withSupportedUrlActions(IGNORE_ABOUT_SCHEME, HANDLE_MOPUB_SCHEME, FOLLOW_DEEP_LINK, OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, OPEN_IN_APP_BROWSER); verifyNoMoreCallbacks(); @@ -228,7 +228,7 @@ public void urlHandler_withMatchingShareUrl_shouldCallOnClickSuccess_shouldStart new UrlHandler.Builder() .withSupportedUrlActions(HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) - .build().handleUrl(context, shareTweetUrl); + .build().handleResolvedUrl(context, shareTweetUrl, true, null); verify(mockResultActions).urlHandlingSucceeded(shareTweetUrl, HANDLE_SHARE_TWEET); verifyNoMoreCallbacks(); @@ -245,7 +245,7 @@ public void urlHandler_withMatchingDeepLinkUrl_shouldCallOnClickSuccess_shouldSt .withSupportedUrlActions(FOLLOW_DEEP_LINK) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, deepLinkUrl); + .build().handleResolvedUrl(context, deepLinkUrl, true, null); verify(mockResultActions).urlHandlingSucceeded(deepLinkUrl, FOLLOW_DEEP_LINK); verifyNoMoreCallbacks(); @@ -263,7 +263,7 @@ public void urlHandler_withMatchingDeeplinkPlus_shouldCallOnClickSuccess_shouldS new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, deeplinkPlusUrl); + .build().handleResolvedUrl(context, deeplinkPlusUrl, true, null); verify(mockResultActions).urlHandlingSucceeded(deeplinkPlusUrl, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -273,9 +273,10 @@ public void urlHandler_withMatchingDeeplinkPlus_shouldCallOnClickSuccess_shouldS } @Test - public void urlHandler_withMatchingUnresolvableDeeplinkPlus_withResolvableFallback_shouldCallOnClickSuccess_shouldStartActivity() { + public void urlHandler_withMatchingUnresolvableDeeplinkPlus_withResolvableFallback_shouldResolveRedirects_shouldCallOnClickSuccess_shouldStartActivity() { final String primaryUrl = "missingApp://somePath"; - final String fallbackUrl = "http://twitter.com"; + final String fallbackUrl = "http://www.twitter.com"; + final String fallbackUrlAfterRedirects = "https://twitter.com/"; final String deeplinkPlusUrl = "deeplink+://navigate?primaryUrl=" + Uri.encode(primaryUrl) + "&fallbackUrl=" + Uri.encode(fallbackUrl); @@ -284,32 +285,30 @@ public void urlHandler_withMatchingUnresolvableDeeplinkPlus_withResolvableFallba .withResultActions(mockResultActions) .build().handleUrl(context, deeplinkPlusUrl); - verify(mockResultActions).urlHandlingSucceeded(fallbackUrl, OPEN_IN_APP_BROWSER); + Robolectric.runBackgroundTasks(); + verify(mockResultActions).urlHandlingSucceeded(fallbackUrlAfterRedirects, + OPEN_IN_APP_BROWSER); verifyNoMoreCallbacks(); final Intent startedActivity = Robolectric.getShadowApplication().peekNextStartedActivity(); assertThat(startedActivity.getComponent().getClassName()) .isEqualTo(MoPubBrowser.class.getName()); assertThat(startedActivity.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)) - .isEqualTo(fallbackUrl); + .isEqualTo(fallbackUrlAfterRedirects); } @Test - public void urlHandler_withMatchingUnresolvableDeeplinkPlus_withUnresolvableFallback_shouldAttemptAsDeeplink() { + public void urlHandler_withMatchingUnresolvableDeeplinkPlus_withUnresolvableFallback_shouldDoNothing() { final String primaryUrl = "missingApp://somePath"; final String fallbackUrl = "unresolvableUrl"; final String deeplinkPlusUrl = "deeplink+://navigate?primaryUrl=" + Uri.encode(primaryUrl) + "&fallbackUrl=" + Uri.encode(fallbackUrl); - makeDeeplinkResolvable(deeplinkPlusUrl); new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK, FOLLOW_DEEP_LINK) .withResultActions(mockResultActions) - .build().handleUrl(context, deeplinkPlusUrl); + .build().handleResolvedUrl(context, deeplinkPlusUrl, true, null); - // There should really be only one of these fired at a time, but this is such an edge-case - // that we're not fixing at the moment (see ADF-1700). verify(mockResultActions).urlHandlingFailed(fallbackUrl, NOOP); - verify(mockResultActions).urlHandlingSucceeded(deeplinkPlusUrl, FOLLOW_DEEP_LINK); verifyNoMoreCallbacks(); } @@ -329,7 +328,7 @@ public void urlHandler_withDeeplinkPlus_shouldTriggerPrimaryTracker() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockRequestQueue).add(argThat(isUrl(primaryTracker))); verify(mockRequestQueue, never()).add(argThat(isUrl(fallbackTracker))); @@ -348,7 +347,7 @@ public void urlHandler_withDeeplinkPlus_shouldTriggerMultiplePrimaryTrackers() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockRequestQueue).add(argThat(isUrl(primaryTracker1))); verify(mockRequestQueue).add(argThat(isUrl(primaryTracker2))); @@ -369,7 +368,7 @@ public void urlHandler_withDeeplinkPlus_withResolvableFallback_shouldTriggerFall new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK, OPEN_IN_APP_BROWSER) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockRequestQueue).add(argThat(isUrl(fallbackTracker))); verify(mockRequestQueue, never()).add(argThat(isUrl(primaryTracker))); @@ -389,7 +388,7 @@ public void urlHandler_withDeeplinkPlus_withResolvableFallback_shouldTriggerMult new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK, OPEN_IN_APP_BROWSER) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockRequestQueue).add(argThat(isUrl(fallbackTracker1))); verify(mockRequestQueue).add(argThat(isUrl(fallbackTracker2))); @@ -404,7 +403,7 @@ public void urlHandler_withUppercasedDeeplinkPlus_shouldBeHandled() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); } @@ -418,7 +417,7 @@ public void urlHandler_withdDeeplinkPlus_withUppercasedNavigate_shouldBeHandled( new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); } @@ -430,7 +429,7 @@ public void urlHandler_withoutMatchingDeeplinkPlus_shouldDoNothing() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, NOOP); verifyNoMoreCallbacks(); @@ -444,7 +443,7 @@ public void urlHandler_withDeeplinkPlus_withoutNavigate_shouldDoNothing() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -459,7 +458,7 @@ public void urlHandler_withNestedDeeplinkPlus_shouldDoNothing() { new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -475,7 +474,7 @@ public void urlHandler_withDeeplinkPlus_withDeeplinkPlusAsFallback_shouldDoNothi new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -489,7 +488,7 @@ public void urlHandler_withDeeplinkPlus_withInvalidPrimaryUrl_shouldDoNothing() new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -503,7 +502,7 @@ public void urlHandler_withDeeplinkPlus_withDecodedPrimaryUrl_shouldDoNothing() new UrlHandler.Builder() .withSupportedUrlActions(FOLLOW_DEEP_LINK_WITH_FALLBACK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK_WITH_FALLBACK); verifyNoMoreCallbacks(); @@ -518,7 +517,7 @@ public void urlHandler_withDualMatchingUnresolvableUrlActions_shouldCallOnClickF .withSupportedUrlActions(HANDLE_MOPUB_SCHEME, FOLLOW_DEEP_LINK) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK); verifyNoMoreCallbacks(); @@ -531,7 +530,7 @@ public void urlHandler_withShareTweetAndDeepLink_shouldCallOnClickFailOnLastMatc new UrlHandler.Builder() .withSupportedUrlActions(HANDLE_SHARE_TWEET, FOLLOW_DEEP_LINK) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, FOLLOW_DEEP_LINK); verifyNoMoreCallbacks(); @@ -539,7 +538,7 @@ public void urlHandler_withShareTweetAndDeepLink_shouldCallOnClickFailOnLastMatc @Test public void urlHandler_withNoConfiguration_shouldDoNothing() { - new UrlHandler.Builder().build().handleUrl(context, ""); + new UrlHandler.Builder().build().handleResolvedUrl(context, "", true, null); verifyNoMoreCallbacks(); } @@ -550,7 +549,7 @@ public void urlHandler_withoutDestinationUrl_shouldNotError() { .withSupportedUrlActions(IGNORE_ABOUT_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, ""); + .build().handleResolvedUrl(context, "", true, null); verify(mockResultActions).urlHandlingFailed("", NOOP); verifyNoMoreCallbacks(); @@ -561,7 +560,7 @@ public void urlHandler_withoutSupportedUrlActions_shouldNotError() { new UrlHandler.Builder() .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, "about:blank"); + .build().handleResolvedUrl(context, "about:blank", true, null); verify(mockResultActions).urlHandlingFailed("about:blank", NOOP); verifyNoMoreCallbacks(); @@ -572,7 +571,7 @@ public void urlHandler_withoutClickListener_shouldNotError() { new UrlHandler.Builder() .withSupportedUrlActions(IGNORE_ABOUT_SCHEME) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, "about:blank"); + .build().handleResolvedUrl(context, "about:blank", true, null); verifyNoMoreCallbacks(); } @@ -582,7 +581,7 @@ public void urlHandler_withoutMoPubSchemeListener_shouldNotError() { new UrlHandler.Builder() .withSupportedUrlActions(IGNORE_ABOUT_SCHEME) .withResultActions(mockResultActions) - .build().handleUrl(context, "about:blank"); + .build().handleResolvedUrl(context, "about:blank", true, null); verifyNoMoreCallbacks(); } @@ -594,7 +593,7 @@ public void urlHandler_withoutMoPubBrowser_shouldNotError() { .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) .withoutMoPubBrowser() - .build().handleUrl(context, "about:blank"); + .build().handleResolvedUrl(context, "about:blank", true, null); verifyNoMoreCallbacks(); } @@ -695,7 +694,7 @@ public void urlHandler_withNullDestinationURL_shouldDoNothing() { OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, nullUrl); + .build().handleResolvedUrl(context, nullUrl, true, null); verify(mockResultActions).urlHandlingFailed(nullUrl, NOOP); verifyNoMoreCallbacks(); @@ -710,7 +709,7 @@ public void urlHandler_withEmptyDestinationURL_shouldDoNothing() { OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, emptyUrl); + .build().handleResolvedUrl(context, emptyUrl, true, null); verify(mockResultActions).urlHandlingFailed(emptyUrl, NOOP); verifyNoMoreCallbacks(); @@ -726,7 +725,7 @@ public void urlHandler_withInvalidDestinationURL_shouldDoNothing() { OPEN_IN_APP_BROWSER, HANDLE_PHONE_SCHEME, OPEN_NATIVE_BROWSER, HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, invalidUrl); + .build().handleResolvedUrl(context, invalidUrl, true, null); verify(mockResultActions).urlHandlingFailed(invalidUrl, NOOP); verifyNoMoreCallbacks(); @@ -739,7 +738,7 @@ public void urlHandler_withMatchingMoPubSchemeWithoutMoPubSchemeListener_shouldD new UrlHandler.Builder() .withSupportedUrlActions(HANDLE_MOPUB_SCHEME) .withResultActions(mockResultActions) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verifyNoMoreCallbacks(); } @@ -751,7 +750,7 @@ public void urlHandler_withInvalidMoPubSchemeCustom_shouldNotError() { .withSupportedUrlActions(HANDLE_MOPUB_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, HANDLE_MOPUB_SCHEME); verifyNoMoreCallbacks(); @@ -765,7 +764,7 @@ public void urlHandler_withInvalidNativeBrowserUrl_shouldCallUrlHandlingFailed() .withSupportedUrlActions(OPEN_NATIVE_BROWSER) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, OPEN_NATIVE_BROWSER); verifyNoMoreCallbacks(); @@ -780,7 +779,7 @@ public void urlHandler_withInvalidHostInShareTweetUrl_shouldCallUrlHandlingFaile .withSupportedUrlActions(HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, NOOP); verifyNoMoreCallbacks(); @@ -795,7 +794,7 @@ public void urlHandler_withMissingQueryParametersInShareTweetUrl_shouldCallUrlHa .withSupportedUrlActions(HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, HANDLE_SHARE_TWEET); verifyNoMoreCallbacks(); @@ -810,7 +809,7 @@ public void urlHandler_withEmptyQueryParametersInShareTweetUrl_shouldCallUrlHand .withSupportedUrlActions(HANDLE_SHARE_TWEET) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, HANDLE_SHARE_TWEET); verifyNoMoreCallbacks(); @@ -828,7 +827,7 @@ public void urlHandler_withMatchingUnresolvableDeepLinkUrl_shouldCallUrlHandling .withSupportedUrlActions(FOLLOW_DEEP_LINK) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, deepLinkUrl); + .build().handleResolvedUrl(context, deepLinkUrl, true, null); verify(mockResultActions).urlHandlingFailed(deepLinkUrl, FOLLOW_DEEP_LINK); verifyNoMoreCallbacks(); @@ -840,7 +839,7 @@ private void assertPhoneSchemeCallback(@NonNull final String url) { .withSupportedUrlActions(HANDLE_PHONE_SCHEME) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingSucceeded(url, HANDLE_PHONE_SCHEME); verifyNoMoreCallbacks(); @@ -858,7 +857,7 @@ private void assertCallbackWithoutMatchingUrl(@NonNull final UrlAction urlAction .withSupportedUrlActions(urlAction) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, expectedFailUrlAction); verifyNoMoreCallbacks(); } @@ -869,7 +868,7 @@ private void assertCallbackWithoutMatchingSupportedUrlAction(@NonNull final Stri .withSupportedUrlActions(NOOP, otherTypes) .withResultActions(mockResultActions) .withMoPubSchemeListener(mockMoPubSchemeListener) - .build().handleUrl(context, url); + .build().handleResolvedUrl(context, url, true, null); verify(mockResultActions).urlHandlingFailed(url, NOOP); verifyNoMoreCallbacks(); } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/BaseVideoPlayerActivityTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/BaseVideoPlayerActivityTest.java index cc8db4393..940f9f07d 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/BaseVideoPlayerActivityTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/BaseVideoPlayerActivityTest.java @@ -24,11 +24,11 @@ public class BaseVideoPlayerActivityTest { private static final String MRAID_VIDEO_URL = "http://mraidVideo"; private long testBroadcastIdentifier; - private VastVideoConfiguration vastVideoConfiguration; + private VastVideoConfig mVastVideoConfig; @Before public void setup() throws Exception { - vastVideoConfiguration = mock(VastVideoConfiguration.class, withSettings().serializable()); + mVastVideoConfig = mock(VastVideoConfig.class, withSettings().serializable()); testBroadcastIdentifier = 1234; } @@ -40,19 +40,19 @@ public void startMraid_shouldStartMraidVideoPlayerActivity() throws Exception { @Test public void startVast_shouldStartMraidVideoPlayerActivity() throws Exception { - startVast(Robolectric.buildActivity(Activity.class).create().get(), vastVideoConfiguration, testBroadcastIdentifier); - assertVastVideoPlayerActivityStarted(MraidVideoPlayerActivity.class, vastVideoConfiguration, testBroadcastIdentifier); + startVast(Robolectric.buildActivity(Activity.class).create().get(), mVastVideoConfig, testBroadcastIdentifier); + assertVastVideoPlayerActivityStarted(MraidVideoPlayerActivity.class, mVastVideoConfig, testBroadcastIdentifier); } static void assertVastVideoPlayerActivityStarted(final Class clazz, - final VastVideoConfiguration vastVideoConfiguration, + final VastVideoConfig vastVideoConfig, final long broadcastIdentifier) { final Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); assertIntentAndBroadcastIdentifierAreCorrect(intent, clazz, broadcastIdentifier); - final VastVideoConfiguration expectedVastVideoConfiguration = - (VastVideoConfiguration) intent.getSerializableExtra(VastVideoViewController.VAST_VIDEO_CONFIGURATION); - assertThat(expectedVastVideoConfiguration).isEqualsToByComparingFields(vastVideoConfiguration); + final VastVideoConfig expectedVastVideoConfig = + (VastVideoConfig) intent.getSerializableExtra(VastVideoViewController.VAST_VIDEO_CONFIG); + assertThat(expectedVastVideoConfig).isEqualsToByComparingFields(vastVideoConfig); } public static void assertMraidVideoPlayerActivityStarted(final Class clazz, final String url) { diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/MraidVideoPlayerActivityTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/MraidVideoPlayerActivityTest.java index e7577ce8a..9a3e30909 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/MraidVideoPlayerActivityTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/MraidVideoPlayerActivityTest.java @@ -176,9 +176,9 @@ private void initializeSubjectForMraid() { private void initializeSubjectForVast() { intent.putExtra(BaseVideoPlayerActivity.VIDEO_CLASS_EXTRAS_KEY, "vast"); - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("video_path"); - intent.putExtra(VastVideoViewController.VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("video_path"); + intent.putExtra(VastVideoViewController.VAST_VIDEO_CONFIG, vastVideoConfig); subject = Robolectric.buildActivity(MraidVideoPlayerActivity.class) .withIntent(intent) diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigTest.java similarity index 94% rename from mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdTest.java rename to mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigTest.java index 1292ad5e6..ffbe32f0b 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigTest.java @@ -24,20 +24,20 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @RunWith(SdkTestRunner.class) -public class VastCompanionAdTest { +public class VastCompanionAdConfigTest { - private static final String RESOLVED_CLICKTHROUGH_URL = "http://clickthrough_url"; + private static final String RESOLVED_CLICKTHROUGH_URL = "http://www.mopub.com/"; private static final String CLICKTHROUGH_URL = "deeplink+://navigate?" + "&primaryUrl=bogus%3A%2F%2Furl" + "&fallbackUrl=" + Uri.encode(RESOLVED_CLICKTHROUGH_URL); - private VastCompanionAd subject; + private VastCompanionAdConfig subject; private Context context; @Mock private MoPubRequestQueue mockRequestQueue; @Before public void setup() { - subject = new VastCompanionAd(123, 456, + subject = new VastCompanionAdConfig(123, 456, new VastResource("resource", VastResource.Type.STATIC_RESOURCE, VastResource .CreativeType.IMAGE, 123, 456), CLICKTHROUGH_URL, @@ -83,6 +83,7 @@ public void handleClick_shouldNotTrackClick() throws Exception { public void handleClick_shouldOpenMoPubBrowser() throws Exception { subject.handleClick(context, 1, null); + Robolectric.runBackgroundTasks(); Intent startedActivity = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(startedActivity.getComponent().getClassName()) .isEqualTo("com.mopub.common.MoPubBrowser"); diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdXmlManagerTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigXmlManagerTest.java similarity index 98% rename from mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdXmlManagerTest.java rename to mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigXmlManagerTest.java index 440f49652..a199dbf9a 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdXmlManagerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastCompanionAdConfigXmlManagerTest.java @@ -12,7 +12,7 @@ import static org.fest.assertions.api.Assertions.assertThat; @RunWith(SdkTestRunner.class) -public class VastCompanionAdXmlManagerTest { +public class VastCompanionAdConfigXmlManagerTest { private VastCompanionAdXmlManager subject; private Node companionNode; diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigTest.java similarity index 91% rename from mopub-sdk/src/test/java/com/mopub/mobileads/VastIconTest.java rename to mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigTest.java index ba750c6d5..7833472d6 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigTest.java @@ -23,19 +23,19 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @RunWith(SdkTestRunner.class) -public class VastIconTest { +public class VastIconConfigTest { - private VastIcon subject; + private VastIconConfig subject; private Context context; @Mock private MoPubRequestQueue mockRequestQueue; @Before public void setup() { - subject = new VastIcon(123, 456, 789, 101, + subject = new VastIconConfig(123, 456, 789, 101, new VastResource("resource", VastResource.Type.STATIC_RESOURCE, VastResource .CreativeType.IMAGE, 123, 456), VastUtils.stringsToVastTrackers("clickTrackerOne", "clickTrackerTwo"), - "http://clickThroughUri", + "http://www.mopub.com/", VastUtils.stringsToVastTrackers("viewTrackerOne", "viewTrackerTwo") ); context = Robolectric.buildActivity(Activity.class).create().get(); @@ -54,14 +54,14 @@ public void constructor_shouldSetParamsCorrectly() throws Exception { .isEqualTo(VastResource.CreativeType.IMAGE); assertThat(VastUtils.vastTrackersToStrings(subject.getClickTrackingUris())) .containsOnly("clickTrackerOne", "clickTrackerTwo"); - assertThat(subject.getClickThroughUri()).isEqualTo("http://clickThroughUri"); + assertThat(subject.getClickThroughUri()).isEqualTo("http://www.mopub.com/"); assertThat(VastUtils.vastTrackersToStrings(subject.getViewTrackingUris())) .containsOnly("viewTrackerOne", "viewTrackerTwo"); } @Test public void constructor_withNullOffset_shouldSetOffsetTo0() throws Exception { - subject = new VastIcon(123, 456, null, 101, + subject = new VastIconConfig(123, 456, null, 101, new VastResource("resource", VastResource.Type.STATIC_RESOURCE, VastResource .CreativeType.IMAGE, 123, 456), VastUtils.stringsToVastTrackers("clickTrackerOne", "clickTrackerTwo"), @@ -92,11 +92,12 @@ public void handleClick_shouldNotTrackClick() throws Exception { public void handleClick_shouldOpenMoPubBrowser() throws Exception { subject.handleClick(context, null); + Robolectric.runBackgroundTasks(); Intent startedActivity = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(startedActivity.getComponent().getClassName()) .isEqualTo("com.mopub.common.MoPubBrowser"); assertThat(startedActivity.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)) - .isEqualTo("http://clickThroughUri"); + .isEqualTo("http://www.mopub.com/"); assertThat(startedActivity.getData()).isNull(); } } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconXmlManagerTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigXmlManagerTest.java similarity index 99% rename from mopub-sdk/src/test/java/com/mopub/mobileads/VastIconXmlManagerTest.java rename to mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigXmlManagerTest.java index aa9da8671..e0e501ab6 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconXmlManagerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastIconConfigXmlManagerTest.java @@ -12,7 +12,7 @@ import static org.fest.assertions.api.Assertions.assertThat; @RunWith(SdkTestRunner.class) -public class VastIconXmlManagerTest { +public class VastIconConfigXmlManagerTest { private VastIconXmlManager subject; private Node iconNode; @@ -47,7 +47,7 @@ public void setup() throws Exception { iconNode = createNode(iconXml); subject = new VastIconXmlManager(iconNode); } - + @Test public void getWidth_shouldReturnWidth() throws Exception { assertThat(subject.getWidth()).isEqualTo(123); @@ -211,4 +211,4 @@ public void getViewTrackingUris_withNoViewTrackingUris_shouldReturnEmptyList() t subject = new VastIconXmlManager(iconNode); assertThat(subject.getViewTrackingUris()).isEmpty(); } -} \ No newline at end of file +} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastManagerTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastManagerTest.java index 02875e92e..357e0ec79 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastManagerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastManagerTest.java @@ -35,7 +35,7 @@ public class VastManagerTest { private FakeHttpLayer mFakeHttpLayer; private VastManagerListener vastManagerListener; private Activity context; - private VastVideoConfiguration vastVideoConfiguration; + private VastVideoConfig mVastVideoConfig; private Semaphore semaphore; @Before @@ -51,11 +51,11 @@ public void setup() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Object[] args = invocationOnMock.getArguments(); - VastManagerTest.this.vastVideoConfiguration = (VastVideoConfiguration) args[0]; + VastManagerTest.this.mVastVideoConfig = (VastVideoConfig) args[0]; semaphore.release(); return null; } - }).when(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + }).when(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); } private void prepareVastVideoConfiguration() { @@ -74,51 +74,52 @@ public void prepareVastVideoConfiguration_shouldNotifyTheListenerAndContainTheCo prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo("https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); + assertThat(mVastVideoConfig.getNetworkMediaFileUrl()).isEqualTo("https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); - final String expectedFilePathDiskCache = CacheService.getFilePathDiskCache(vastVideoConfiguration.getNetworkMediaFileUrl()); - assertThat(vastVideoConfiguration.getDiskMediaFileUrl()).isEqualTo(expectedFilePathDiskCache); + final String expectedFilePathDiskCache = CacheService.getFilePathDiskCache(mVastVideoConfig.getNetworkMediaFileUrl()); + assertThat(mVastVideoConfig.getDiskMediaFileUrl()).isEqualTo(expectedFilePathDiskCache); - assertThat(vastVideoConfiguration.getClickThroughUrl()).isEqualTo("http://rtb-test.dev.tapad.com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); - assertThat(vastVideoConfiguration.getImpressionTrackers().size()).isEqualTo(5); + assertThat(mVastVideoConfig.getClickThroughUrl()).isEqualTo("http://rtb-test.dev.tapad.com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); + assertThat(mVastVideoConfig.getImpressionTrackers().size()).isEqualTo(5); // Verify quartile trackers - assertThat(vastVideoConfiguration.getFractionalTrackers().size()).isEqualTo(3); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(0).trackingFraction()).isEqualTo(0.25f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(1).trackingFraction()).isEqualTo(0.5f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(2).trackingFraction()).isEqualTo(0.75f); + assertThat(mVastVideoConfig.getFractionalTrackers().size()).isEqualTo(3); + assertThat(mVastVideoConfig.getFractionalTrackers().get(0).trackingFraction()).isEqualTo(0.25f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(1).trackingFraction()).isEqualTo(0.5f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(2).trackingFraction()).isEqualTo(0.75f); // Verify start tracker. - assertThat(vastVideoConfiguration.getAbsoluteTrackers().size()).isEqualTo(3); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(0).getTrackingMilliseconds()) + assertThat(mVastVideoConfig.getAbsoluteTrackers().size()).isEqualTo(3); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(0).getTrackingMilliseconds()) .isEqualTo(0); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(1).getTrackingMilliseconds()) + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(1).getTrackingMilliseconds()) .isEqualTo(2000); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(2).getTrackingMilliseconds()) + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(2).getTrackingMilliseconds()) .isEqualTo(3100); - assertThat(vastVideoConfiguration.getCompleteTrackers().size()).isEqualTo(1); + assertThat(mVastVideoConfig.getCompleteTrackers().size()).isEqualTo(1); // We specifically added a close tracker and a skip tracker to the nested vast test case as well, // therefore there are two expected trackers total for each type. - assertThat(vastVideoConfiguration.getCloseTrackers().size()).isEqualTo(2); - assertThat(vastVideoConfiguration.getSkipTrackers().size()).isEqualTo(2); - assertThat(vastVideoConfiguration.getClickTrackers().size()).isEqualTo(1); - - final VastCompanionAd vastCompanionAd = vastVideoConfiguration.getVastCompanionAd(); - assertThat(vastCompanionAd.getWidth()).isEqualTo(300); - assertThat(vastCompanionAd.getHeight()).isEqualTo(250); - assertThat(vastCompanionAd.getVastResource().getResource()) + assertThat(mVastVideoConfig.getCloseTrackers().size()).isEqualTo(2); + assertThat(mVastVideoConfig.getSkipTrackers().size()).isEqualTo(2); + assertThat(mVastVideoConfig.getClickTrackers().size()).isEqualTo(1); + + final VastCompanionAdConfig vastCompanionAdConfig = mVastVideoConfig.getVastCompanionAd( + context.getResources().getConfiguration().orientation); + assertThat(vastCompanionAdConfig.getWidth()).isEqualTo(300); + assertThat(vastCompanionAdConfig.getHeight()).isEqualTo(250); + assertThat(vastCompanionAdConfig.getVastResource().getResource()) .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); - assertThat(vastCompanionAd.getVastResource().getType()) + assertThat(vastCompanionAdConfig.getVastResource().getType()) .isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(vastCompanionAd.getVastResource().getCreativeType()) + assertThat(vastCompanionAdConfig.getVastResource().getCreativeType()) .isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(vastCompanionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); + assertThat(vastCompanionAdConfig.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); - assertThat(VastUtils.vastTrackersToStrings(vastCompanionAd.getClickTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastCompanionAdConfig.getClickTrackers())) .containsOnly("http://companionClickTracking1", "http://companionClickTracking2"); } @@ -134,57 +135,58 @@ public void prepareVastVideoConfiguration_shouldHandleMultipleRedirects() throws prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig .class)); // at this point it should have 3 sets of data from TEST_VAST_XML_STRING and one set from TEST_NESTED_VAST_XML_STRING - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo("https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); - final String expectedFilePathDiskCache = CacheService.getFilePathDiskCache(vastVideoConfiguration.getNetworkMediaFileUrl()); - assertThat(vastVideoConfiguration.getDiskMediaFileUrl()).isEqualTo(expectedFilePathDiskCache); - - assertThat(vastVideoConfiguration.getClickThroughUrl()).isEqualTo("http://rtb-test.dev.tapad.com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); - assertThat(vastVideoConfiguration.getImpressionTrackers().size()).isEqualTo(13); - - assertThat(vastVideoConfiguration.getAbsoluteTrackers().size()).isEqualTo(9); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(0).getTrackingMilliseconds()).isEqualTo(0); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(1).getTrackingMilliseconds()).isEqualTo(0); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(2).getTrackingMilliseconds()).isEqualTo(0); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(3).getTrackingMilliseconds()).isEqualTo(2000); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(4).getTrackingMilliseconds()).isEqualTo(2000); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(5).getTrackingMilliseconds()).isEqualTo(2000); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(6).getTrackingMilliseconds()).isEqualTo(3100); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(7).getTrackingMilliseconds()).isEqualTo(3100); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(8).getTrackingMilliseconds()).isEqualTo(3100); - - - assertThat(vastVideoConfiguration.getFractionalTrackers().size()).isEqualTo(9); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(0).trackingFraction()).isEqualTo(0.25f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(1).trackingFraction()).isEqualTo(0.25f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(2).trackingFraction()).isEqualTo(0.25f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(3).trackingFraction()).isEqualTo(0.5f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(4).trackingFraction()).isEqualTo(0.5f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(5).trackingFraction()).isEqualTo(0.5f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(6).trackingFraction()).isEqualTo(0.75f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(7).trackingFraction()).isEqualTo(0.75f); - assertThat(vastVideoConfiguration.getFractionalTrackers().get(8).trackingFraction()).isEqualTo(0.75f); - - assertThat(vastVideoConfiguration.getCompleteTrackers().size()).isEqualTo(3); - assertThat(vastVideoConfiguration.getCloseTrackers().size()).isEqualTo(4); - assertThat(vastVideoConfiguration.getSkipTrackers().size()).isEqualTo(4); - assertThat(vastVideoConfiguration.getClickTrackers().size()).isEqualTo(3); - assertThat(vastVideoConfiguration.getErrorTrackers().size()).isEqualTo(4); - - final VastCompanionAd vastCompanionAd = vastVideoConfiguration.getVastCompanionAd(); - assertThat(vastCompanionAd.getWidth()).isEqualTo(300); - assertThat(vastCompanionAd.getHeight()).isEqualTo(250); - assertThat(vastCompanionAd.getVastResource().getResource()) + assertThat(mVastVideoConfig.getNetworkMediaFileUrl()).isEqualTo("https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); + final String expectedFilePathDiskCache = CacheService.getFilePathDiskCache(mVastVideoConfig.getNetworkMediaFileUrl()); + assertThat(mVastVideoConfig.getDiskMediaFileUrl()).isEqualTo(expectedFilePathDiskCache); + + assertThat(mVastVideoConfig.getClickThroughUrl()).isEqualTo("http://rtb-test.dev.tapad.com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); + assertThat(mVastVideoConfig.getImpressionTrackers().size()).isEqualTo(13); + + assertThat(mVastVideoConfig.getAbsoluteTrackers().size()).isEqualTo(9); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(0).getTrackingMilliseconds()).isEqualTo(0); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(1).getTrackingMilliseconds()).isEqualTo(0); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(2).getTrackingMilliseconds()).isEqualTo(0); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(3).getTrackingMilliseconds()).isEqualTo(2000); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(4).getTrackingMilliseconds()).isEqualTo(2000); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(5).getTrackingMilliseconds()).isEqualTo(2000); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(6).getTrackingMilliseconds()).isEqualTo(3100); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(7).getTrackingMilliseconds()).isEqualTo(3100); + assertThat(mVastVideoConfig.getAbsoluteTrackers().get(8).getTrackingMilliseconds()).isEqualTo(3100); + + + assertThat(mVastVideoConfig.getFractionalTrackers().size()).isEqualTo(9); + assertThat(mVastVideoConfig.getFractionalTrackers().get(0).trackingFraction()).isEqualTo(0.25f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(1).trackingFraction()).isEqualTo(0.25f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(2).trackingFraction()).isEqualTo(0.25f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(3).trackingFraction()).isEqualTo(0.5f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(4).trackingFraction()).isEqualTo(0.5f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(5).trackingFraction()).isEqualTo(0.5f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(6).trackingFraction()).isEqualTo(0.75f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(7).trackingFraction()).isEqualTo(0.75f); + assertThat(mVastVideoConfig.getFractionalTrackers().get(8).trackingFraction()).isEqualTo(0.75f); + + assertThat(mVastVideoConfig.getCompleteTrackers().size()).isEqualTo(3); + assertThat(mVastVideoConfig.getCloseTrackers().size()).isEqualTo(4); + assertThat(mVastVideoConfig.getSkipTrackers().size()).isEqualTo(4); + assertThat(mVastVideoConfig.getClickTrackers().size()).isEqualTo(3); + assertThat(mVastVideoConfig.getErrorTrackers().size()).isEqualTo(4); + + final VastCompanionAdConfig vastCompanionAdConfig = mVastVideoConfig.getVastCompanionAd( + context.getResources().getConfiguration().orientation); + assertThat(vastCompanionAdConfig.getWidth()).isEqualTo(300); + assertThat(vastCompanionAdConfig.getHeight()).isEqualTo(250); + assertThat(vastCompanionAdConfig.getVastResource().getResource()) .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); - assertThat(vastCompanionAd.getVastResource().getType()) + assertThat(vastCompanionAdConfig.getVastResource().getType()) .isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(vastCompanionAd.getVastResource().getCreativeType()) + assertThat(vastCompanionAdConfig.getVastResource().getCreativeType()) .isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(vastCompanionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); - assertThat(VastUtils.vastTrackersToStrings(vastCompanionAd.getClickTrackers())) + assertThat(vastCompanionAdConfig.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); + assertThat(VastUtils.vastTrackersToStrings(vastCompanionAdConfig.getClickTrackers())) .containsOnly("http://companionClickTracking1", "http://companionClickTracking2"); } @@ -198,9 +200,9 @@ public void prepareVastVideoConfiguration_shouldReturnCorrectVastValuesWhenAVast prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration).isNull(); + assertThat(mVastVideoConfig).isNull(); } @Test @@ -212,12 +214,12 @@ public void prepareVastVideoConfiguration_withNoExtensions_shouldContainTheCorre prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getCustomCtaText()).isNull(); - assertThat(vastVideoConfiguration.getCustomSkipText()).isNull(); - assertThat(vastVideoConfiguration.getCustomCloseIconUrl()).isNull(); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); + assertThat(mVastVideoConfig.getCustomCtaText()).isNull(); + assertThat(mVastVideoConfig.getCustomSkipText()).isNull(); + assertThat(mVastVideoConfig.getCustomCloseIconUrl()).isNull(); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); } @Test @@ -244,13 +246,13 @@ public void prepareVastVideoConfiguration_withExtensionsUnderWrapper_shouldConta Robolectric.runBackgroundTasks(); Robolectric.runUiThreadTasks(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); // Verify custom extensions - assertThat(vastVideoConfiguration.getCustomCtaText()).isEqualTo("custom CTA text"); - assertThat(vastVideoConfiguration.getCustomSkipText()).isEqualTo("skip"); - assertThat(vastVideoConfiguration.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x.png"); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.DEVICE_ORIENTATION); + assertThat(mVastVideoConfig.getCustomCtaText()).isEqualTo("custom CTA text"); + assertThat(mVastVideoConfig.getCustomSkipText()).isEqualTo("skip"); + assertThat(mVastVideoConfig.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x.png"); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.DEVICE_ORIENTATION); } @Test @@ -272,13 +274,13 @@ public void prepareVastVideoConfiguration_withExtensionsUnderInline_shouldContai prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); // Verify custom extensions - assertThat(vastVideoConfiguration.getCustomCtaText()).isEqualTo("custom CTA text"); - assertThat(vastVideoConfiguration.getCustomSkipText()).isEqualTo("skip"); - assertThat(vastVideoConfiguration.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x.png"); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.DEVICE_ORIENTATION); + assertThat(mVastVideoConfig.getCustomCtaText()).isEqualTo("custom CTA text"); + assertThat(mVastVideoConfig.getCustomSkipText()).isEqualTo("skip"); + assertThat(mVastVideoConfig.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x.png"); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.DEVICE_ORIENTATION); } @Test @@ -315,13 +317,13 @@ public void prepareVastVideoConfiguration_withExtensionsUnderBothWrapperAndInlin Robolectric.runUiThreadTasks(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); // Verify custom extension values are the ones last parsed in TEST_NESTED_VAST_XML_STRING - assertThat(vastVideoConfiguration.getCustomCtaText()).isEqualTo("CTA 2"); - assertThat(vastVideoConfiguration.getCustomSkipText()).isEqualTo("skip 2"); - assertThat(vastVideoConfiguration.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x_2.png"); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); + assertThat(mVastVideoConfig.getCustomCtaText()).isEqualTo("CTA 2"); + assertThat(mVastVideoConfig.getCustomSkipText()).isEqualTo("skip 2"); + assertThat(mVastVideoConfig.getCustomCloseIconUrl()).isEqualTo("http://ton.twitter.com/exchange-media/images/v4/star_icon_3x_2.png"); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); } @Test @@ -340,8 +342,8 @@ public void prepareVastVideoConfiguration_withCustomCtaTextAsSingleSpace_shouldR prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getCustomCtaText()).isEmpty(); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getCustomCtaText()).isEmpty(); } @Test @@ -360,8 +362,8 @@ public void prepareVastVideoConfiguration_withCustomCtaTextLongerThan15Chars_sho prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getCustomCtaText()).isNull(); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getCustomCtaText()).isNull(); } @Test @@ -380,8 +382,8 @@ public void prepareVastVideoConfiguration_withCustomSkipTextLongerThan8Chars_sho prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getCustomSkipText()).isNull(); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getCustomSkipText()).isNull(); } @Test @@ -400,8 +402,8 @@ public void prepareVastVideoConfiguration_withInvalidCustomForceOrientation_shou prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_LANDSCAPE); } @Test @@ -420,8 +422,8 @@ public void prepareVastVideoConfiguration_withCustomForceOrientationInMixedCaseA prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_PORTRAIT); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getCustomForceOrientation()).isEqualTo(DeviceUtils.ForceOrientation.FORCE_PORTRAIT); } @Test @@ -434,9 +436,9 @@ public void prepareVastVideoConfiguration_withValidPercentSkipOffset_shouldRetur prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getSkipOffset()).isEqualTo("25%"); + assertThat(mVastVideoConfig.getSkipOffsetString()).isEqualTo("25%"); } @@ -450,9 +452,9 @@ public void prepareVastVideoConfiguration_withValidAbsoluteSkipOffset_shouldRetu prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getSkipOffset()).isEqualTo("00:03:14"); + assertThat(mVastVideoConfig.getSkipOffsetString()).isEqualTo("00:03:14"); } @Test @@ -465,9 +467,9 @@ public void prepareVastVideoConfiguration_withValidAbsoluteSkipOffsetWithExtraSp prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getSkipOffset()).isEqualTo("00:03:14.159"); + assertThat(mVastVideoConfig.getSkipOffsetString()).isEqualTo("00:03:14.159"); } @Test @@ -487,10 +489,10 @@ public void prepareVastVideoConfiguration_withSkipOffsets_shouldReturnLastParsed Robolectric.runUiThreadTasks(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); // Verify that the last parsed skipoffset value is returned - assertThat(vastVideoConfiguration.getSkipOffset()).isEqualTo("25%"); + assertThat(mVastVideoConfig.getSkipOffsetString()).isEqualTo("25%"); } @Test @@ -503,9 +505,9 @@ public void prepareVastVideoConfiguration_withEmptySkipOffset_shouldReturnNull() prepareVastVideoConfiguration(); semaphore.acquire(); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); - assertThat(vastVideoConfiguration.getSkipOffset()).isNull(); + assertThat(mVastVideoConfig.getSkipOffsetString()).isNull(); } @Test @@ -518,7 +520,7 @@ public void prepareVastVideoConfiguration_withNoMediaUrlInXml_shouldReturnNull() semaphore.acquire(); verify(vastManagerListener).onVastVideoConfigurationPrepared(null); - assertThat(vastVideoConfiguration).isEqualTo(null); + assertThat(mVastVideoConfig).isEqualTo(null); } @Test @@ -530,7 +532,7 @@ public void prepareVastVideoConfiguration_withNullXml_shouldReturnNull() throws semaphore.acquire(); verify(vastManagerListener).onVastVideoConfigurationPrepared(null); - assertThat(vastVideoConfiguration).isEqualTo(null); + assertThat(mVastVideoConfig).isEqualTo(null); } @Test @@ -542,7 +544,7 @@ public void prepareVastVideoConfiguration_withEmptyXml_shouldReturnNull() throws semaphore.acquire(); verify(vastManagerListener).onVastVideoConfigurationPrepared(null); - assertThat(vastVideoConfiguration).isEqualTo(null); + assertThat(mVastVideoConfig).isEqualTo(null); } @Test @@ -555,8 +557,8 @@ public void prepareVastVideoConfiguration_withVideoInDiskCache_shouldNotDownload semaphore.acquire(); assertThat(mFakeHttpLayer.getSentHttpRequestInfos().size()).isEqualTo(1); - verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfiguration.class)); - assertThat(vastVideoConfiguration.getDiskMediaFileUrl()) + verify(vastManagerListener).onVastVideoConfigurationPrepared(any(VastVideoConfig.class)); + assertThat(mVastVideoConfig.getDiskMediaFileUrl()) .isEqualTo(CacheService.getFilePathDiskCache("https://s3.amazonaws.com/mopub-vast/tapad-video.mp4")); } @@ -568,7 +570,7 @@ public void prepareVastVideoConfiguration_withUninitializedDiskCache_shouldRetur semaphore.acquire(); verify(vastManagerListener).onVastVideoConfigurationPrepared(null); - assertThat(vastVideoConfiguration).isEqualTo(null); + assertThat(mVastVideoConfig).isEqualTo(null); } @Test @@ -586,6 +588,6 @@ public void cancel_shouldCancelBackgroundProcessingAndNotNotifyListenerWithNull( semaphore.acquire(); verify(vastManagerListener).onVastVideoConfigurationPrepared(null); - assertThat(vastVideoConfiguration).isEqualTo(null); + assertThat(mVastVideoConfig).isEqualTo(null); } } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTaskTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTaskTest.java new file mode 100644 index 000000000..b711a3de1 --- /dev/null +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoBlurLastVideoFrameTaskTest.java @@ -0,0 +1,140 @@ +package com.mopub.mobileads; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.os.Build; +import android.widget.ImageView; + +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.annotation.Config; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(SdkTestRunner.class) +public class VastVideoBlurLastVideoFrameTaskTest { + @Mock private MediaMetadataRetriever mockMediaMetadataRetriever; + @Mock private ImageView mockBlurredLastVideoFrameImageView; + @Mock private Bitmap mockBitmap; + + private VastVideoBlurLastVideoFrameTask subject; + private String videoPath; + private int videoDuration; + + @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) + @Before + public void setUp() throws Exception { + videoPath = "disk_video_path"; + videoDuration = 10000; + + when(mockMediaMetadataRetriever.getFrameAtTime(anyLong(), anyInt())).thenReturn(mockBitmap); + + subject = new VastVideoBlurLastVideoFrameTask(mockMediaMetadataRetriever, + mockBlurredLastVideoFrameImageView, videoDuration); + } + + @Config(reportSdk = Build.VERSION_CODES.GINGERBREAD) + @Test + public void doInBackground_beforeGingerbreadMr1_shouldReturnFalse() throws Exception { + assertThat(subject.doInBackground(videoPath)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Config(reportSdk = Build.VERSION_CODES.GINGERBREAD_MR1) + @Test + public void doInBackground_atLeastGingerbreadMr1_shouldReturnTrue() throws Exception { + assertThat(subject.doInBackground(videoPath)).isTrue(); + assertThat(subject.getBlurredLastVideoFrame()).isEqualTo(mockBitmap); + } + + @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) + @Test + public void doInBackground_whenSetDataSourceThrowsRuntimeException_shouldCatchExceptionAndReturnFalse() throws Exception { + doThrow(new RuntimeException()).when(mockMediaMetadataRetriever).setDataSource(anyString()); + + assertThat(subject.doInBackground(videoPath)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) + @Test + public void doInBackground_whenGetLastFrameReturnsNull_shouldReturnFalse() throws Exception { + when(mockMediaMetadataRetriever.getFrameAtTime(anyLong(), anyInt())).thenReturn(null); + + assertThat(subject.doInBackground(videoPath)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Test + public void doInBackground_whenVideoPathIsNull_shouldReturnFalse() throws Exception { + assertThat(subject.doInBackground((String) null)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Test + public void doInBackground_whenVideoPathsArrayIsNull_shouldReturnFalse() throws Exception { + assertThat(subject.doInBackground((String[]) null)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Test + public void doInBackground_whenVideoPathsArrayIsEmpty_shouldReturnFalse() throws Exception { + assertThat(subject.doInBackground(new String[0])).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Test + public void doInBackground_whenVideoPathsArrayHasMultipleElements_shouldParseFirstElement() throws Exception { + assertThat(subject.doInBackground(videoPath, null)).isTrue(); + assertThat(subject.getBlurredLastVideoFrame()).isEqualTo(mockBitmap); + } + + @Test + public void doInBackground_whenFirstElementOfVideoPathsArrayIsNull_shouldReturnFalse() throws Exception { + assertThat(subject.doInBackground(null, videoPath)).isFalse(); + assertThat(subject.getBlurredLastVideoFrame()).isNull(); + } + + @Test + public void onPostExecute_whenBlurringSucceeded_shouldSetImageBitmap() throws Exception { + subject.onPostExecute(true); + + verify(mockBlurredLastVideoFrameImageView).setImageBitmap(subject.getBlurredLastVideoFrame()); + } + + @Test + public void onPostExecute_whenBlurringFailed_shouldNotSetImageBitmap() throws Exception { + subject.onPostExecute(false); + + verify(mockBlurredLastVideoFrameImageView, never()).setImageBitmap(any(Bitmap.class)); + } + + @Test + public void onPostExecute_whenResultIsNull_shouldNotSetImageBitmap() throws Exception { + subject.onPostExecute(null); + + verify(mockBlurredLastVideoFrameImageView, never()).setImageBitmap(any(Bitmap.class)); + } + + @Test + public void onPostExecute_whenTaskIsAlreadyCancelled_shouldNotSetImageBitmap() throws Exception { + subject.cancel(true); + + subject.onPostExecute(true); + + verify(mockBlurredLastVideoFrameImageView, never()).setImageBitmap(any(Bitmap.class)); + } +} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigTest.java new file mode 100644 index 000000000..b41ec0475 --- /dev/null +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigTest.java @@ -0,0 +1,193 @@ +package com.mopub.mobileads; + +import android.app.Activity; +import android.content.Intent; + +import com.mopub.common.test.support.SdkTestRunner; +import com.mopub.network.MoPubRequestQueue; +import com.mopub.network.Networking; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.robolectric.Robolectric; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static com.mopub.common.VolleyRequestMatcher.isUrl; +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +@RunWith(SdkTestRunner.class) +public class VastVideoConfigTest { + + @Mock MoPubRequestQueue mockRequestQueue; + private Activity activity; + private VastVideoConfig subject; + + @Before + public void setup() { + activity = spy(Robolectric.buildActivity(Activity.class).create().get()); + Networking.setRequestQueueForTesting(mockRequestQueue); + subject = new VastVideoConfig(); + subject.setNetworkMediaFileUrl("video_url"); + } + + @Test + public void addFractionalTrackers_multipleTimes_shouldBeSorted() throws Exception { + ArrayList testSet1 = new ArrayList(); + testSet1.add(new VastFractionalProgressTracker("test1a", 0.24f)); + testSet1.add(new VastFractionalProgressTracker("test1b", 0.5f)); + testSet1.add(new VastFractionalProgressTracker("test1c", 0.91f)); + + ArrayList testSet2 = new ArrayList(); + testSet2.add(new VastFractionalProgressTracker("test2a", 0.14f)); + testSet2.add(new VastFractionalProgressTracker("test2b", 0.6f)); + testSet2.add(new VastFractionalProgressTracker("test2c", 0.71f)); + + VastVideoConfig subject = new VastVideoConfig(); + + subject.addFractionalTrackers(testSet1); + subject.addFractionalTrackers(testSet2); + + assertThat(subject.getFractionalTrackers()).isSorted(); + } + + @Test + public void addAbsoluteTrackers_multipleTimes_shouldBesSorted() throws Exception { + ArrayList testSet1 = new ArrayList(); + testSet1.add(new VastAbsoluteProgressTracker("test1a", 1000)); + testSet1.add(new VastAbsoluteProgressTracker("test1b", 10000)); + testSet1.add(new VastAbsoluteProgressTracker("test1c", 50000)); + + ArrayList testSet2 = new ArrayList(); + testSet2.add(new VastAbsoluteProgressTracker("test2a", 1100)); + testSet2.add(new VastAbsoluteProgressTracker("test2b", 9000)); + testSet2.add(new VastAbsoluteProgressTracker("test2c", 62000)); + + VastVideoConfig subject = new VastVideoConfig(); + + subject.addAbsoluteTrackers(testSet1); + subject.addAbsoluteTrackers(testSet2); + + assertThat(subject.getAbsoluteTrackers()).isSorted(); + } + + + @Test + public void getUntriggeredTrackersBefore_withTriggeredTrackers_shouldNotReturnTriggered() throws Exception { + VastVideoConfig subject = new VastVideoConfig(); + subject.setDiskMediaFileUrl("disk_video_path"); + subject.addFractionalTrackers( + Arrays.asList(new VastFractionalProgressTracker("first", 0.25f), + new VastFractionalProgressTracker("second", 0.5f), + new VastFractionalProgressTracker("third", 0.75f))); + subject.addAbsoluteTrackers( + Arrays.asList(new VastAbsoluteProgressTracker("5secs", 5000), + new VastAbsoluteProgressTracker("10secs", 10000))); + + final List untriggeredTrackers = subject.getUntriggeredTrackersBefore(11000, + 11000); + assertThat(untriggeredTrackers).hasSize(5); + untriggeredTrackers.get(0).setTracked(); + + final List secondTrackersList = subject.getUntriggeredTrackersBefore(11000, + 11000); + assertThat(secondTrackersList).hasSize(4); + } + + @Test + public void getUntriggeredTrackersBefore_shouldReturnAllTrackersSorted() throws Exception { + VastVideoConfig subject = new VastVideoConfig(); + subject.setDiskMediaFileUrl("disk_video_path"); + subject.addFractionalTrackers( + Arrays.asList(new VastFractionalProgressTracker("first", 0.25f), + new VastFractionalProgressTracker("second", 0.5f), + new VastFractionalProgressTracker("third", 0.75f))); + subject.addAbsoluteTrackers( + Arrays.asList(new VastAbsoluteProgressTracker("1secs", 1000), + new VastAbsoluteProgressTracker("10secs", 10000))); + + final List untriggeredTrackers = subject.getUntriggeredTrackersBefore(11000, + 11000); + assertThat(untriggeredTrackers).hasSize(5); + + // Sorted absolute trackers, followed by sorted fractional trackers + final VastTracker tracker0 = untriggeredTrackers.get(0); + assertThat(tracker0).isExactlyInstanceOf(VastAbsoluteProgressTracker.class); + assertThat(((VastAbsoluteProgressTracker) tracker0).getTrackingMilliseconds()).isEqualTo( + 1000); + + final VastTracker tracker1 = untriggeredTrackers.get(1); + assertThat(tracker1).isExactlyInstanceOf(VastAbsoluteProgressTracker.class); + assertThat(((VastAbsoluteProgressTracker) tracker1).getTrackingMilliseconds()).isEqualTo( + 10000); + + + final VastTracker tracker2 = untriggeredTrackers.get(2); + assertThat(tracker2).isExactlyInstanceOf(VastFractionalProgressTracker.class); + assertThat(((VastFractionalProgressTracker) tracker2).trackingFraction()).isEqualTo(0.25f); + + final VastTracker tracker3 = untriggeredTrackers.get(3); + assertThat(tracker3).isExactlyInstanceOf(VastFractionalProgressTracker.class); + assertThat(((VastFractionalProgressTracker) tracker3).trackingFraction()).isEqualTo(0.5f); + + final VastTracker tracker4 = untriggeredTrackers.get(4); + assertThat(tracker4).isExactlyInstanceOf(VastFractionalProgressTracker.class); + assertThat(((VastFractionalProgressTracker) tracker4).trackingFraction()).isEqualTo(0.75f); + } + + @Test + public void handleClick_withNullClickThroughUrl_shouldNotOpenNewActivity() throws Exception { + subject.handleClick(activity, 1234, 1); + + Robolectric.getUiThreadScheduler().unPause(); + assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); + } + + @Test + public void handleClick_withMoPubNativeBrowserClickThroughUrl_shouldOpenExternalBrowser_shouldMakeTrackingHttpRequest() throws Exception { + subject.setClickThroughUrl( + "mopubnativebrowser://navigate?url=http%3A%2F%2Fwww.mopub.com%2F"); + subject.addClickTrackers( + Arrays.asList(new VastTracker("http://trackerone+content=[CONTENTPLAYHEAD]"), + new VastTracker("http://trackertwo+error=[ERRORCODE]&asset=[ASSETURI]"))); + + subject.handleClick(activity, 2345, 1234); + + Robolectric.getUiThreadScheduler().unPause(); + Robolectric.runBackgroundTasks(); + Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); + assertThat(intent.getDataString()).isEqualTo("http://www.mopub.com/"); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW); + verify(mockRequestQueue).add(argThat(isUrl("http://trackerone+content=00:00:02.345"))); + verify(mockRequestQueue).add(argThat(isUrl("http://trackertwo+error=&asset=video_url"))); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void handleClick_withMalformedMoPubNativeBrowserClickThroughUrl_shouldNotOpenANewActivity() throws Exception { + // url2 is an invalid query parameter + subject.setClickThroughUrl( + "mopubnativebrowser://navigate?url2=http%3A%2F%2Fwww.mopub.com%2F"); + + subject.handleClick(activity, 3456, 1); + + assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); + } + + @Test + public void handleClick_withAboutBlankClickThroughUrl_shouldFailSilently() throws Exception { + subject.setClickThroughUrl("about:blank"); + + subject.handleClick(activity, 4567, 1); + + assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); + } +} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigurationTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigurationTest.java deleted file mode 100644 index 75d69ca7b..000000000 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoConfigurationTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.mopub.mobileads; - -import org.junit.Test; - -import java.util.ArrayList; - -import static org.fest.assertions.api.Assertions.assertThat; - -public class VastVideoConfigurationTest { - - @Test - public void testAddFractionalTrackers_multipleTimes_shouldBeSorted() throws Exception { - ArrayList testSet1 = new ArrayList(); - testSet1.add(new VastFractionalProgressTracker("test1a", 0.24f)); - testSet1.add(new VastFractionalProgressTracker("test1b", 0.5f)); - testSet1.add(new VastFractionalProgressTracker("test1c", 0.91f)); - - ArrayList testSet2 = new ArrayList(); - testSet2.add(new VastFractionalProgressTracker("test2a", 0.14f)); - testSet2.add(new VastFractionalProgressTracker("test2b", 0.6f)); - testSet2.add(new VastFractionalProgressTracker("test2c", 0.71f)); - - VastVideoConfiguration subject = new VastVideoConfiguration(); - - subject.addFractionalTrackers(testSet1); - subject.addFractionalTrackers(testSet2); - - assertThat(subject.getFractionalTrackers()).isSorted(); - } - - @Test - public void testAddAbsoluteTrackers_multipleTimes_shouldBesSorted() throws Exception { - ArrayList testSet1 = new ArrayList(); - testSet1.add(new VastAbsoluteProgressTracker("test1a", 1000)); - testSet1.add(new VastAbsoluteProgressTracker("test1b", 10000)); - testSet1.add(new VastAbsoluteProgressTracker("test1c", 50000)); - - ArrayList testSet2 = new ArrayList(); - testSet2.add(new VastAbsoluteProgressTracker("test2a", 1100)); - testSet2.add(new VastAbsoluteProgressTracker("test2b", 9000)); - testSet2.add(new VastAbsoluteProgressTracker("test2c", 62000)); - - VastVideoConfiguration subject = new VastVideoConfiguration(); - - subject.addAbsoluteTrackers(testSet1); - subject.addAbsoluteTrackers(testSet2); - - assertThat(subject.getAbsoluteTrackers()).isSorted(); - } -} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoCtaButtonWidgetTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoCtaButtonWidgetTest.java index 0da12e67e..988d36b14 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoCtaButtonWidgetTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoCtaButtonWidgetTest.java @@ -25,28 +25,43 @@ public void setUp() throws Exception { } @Test - public void constructor_withCompanionAd_shouldNotSetLayoutParams() throws Exception { - subject = new VastVideoCtaButtonWidget(context, 0, true); + public void constructor_withCompanionAd_shouldBeInvisibleAndNotSetLayoutParams() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, true, true); + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); assertThat(subject.getLayoutParams()).isNull(); - assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); } @Test - public void constructor_withoutCompanionAd_shouldNotSetLayoutParams() throws Exception { - subject = new VastVideoCtaButtonWidget(context, 0, false); + public void constructor_withoutCompanionAd_shouldBeInvisibleAndNotSetLayoutParams() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, false, true); + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getLayoutParams()).isNull(); + } + + @Test + public void constructor_withCompanionAd_withNoClickthroughUrl_shouldBeGoneAndNotSetLayoutParams() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, true, false); + + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + assertThat(subject.getLayoutParams()).isNull(); + } + + @Test + public void constructor_withoutCompanionAd_withNoClickthroughUrl_shouldBeGoneAndNotSetLayoutParams() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, false, false); + + assertThat(subject.getVisibility()).isEqualTo(View.GONE); assertThat(subject.getLayoutParams()).isNull(); - assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); } - // Video is skippable, has companion ad, CTA button initially invisible + // Video is skippable, has companion ad, has clickthrough url, CTA button initially invisible @Test public void notifyVideoSkippable_withCompanionAdAndInPortrait_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; - subject = new VastVideoCtaButtonWidget(context, 0, true); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.notifyVideoSkippable(); @@ -57,8 +72,7 @@ public void notifyVideoSkippable_withCompanionAdAndInPortrait_shouldBeVisibleAnd @Test public void notifyVideoSkippable_withCompanionAdAndInLandscape_shouldBeVisibleAndSetLandscapeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; - subject = new VastVideoCtaButtonWidget(context, 0, true); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.notifyVideoSkippable(); @@ -69,8 +83,7 @@ public void notifyVideoSkippable_withCompanionAdAndInLandscape_shouldBeVisibleAn @Test public void notifyVideoSkippable_withCompanionAdAndOrientationUndefined_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; - subject = new VastVideoCtaButtonWidget(context, 0, true); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.notifyVideoSkippable(); @@ -78,13 +91,12 @@ public void notifyVideoSkippable_withCompanionAdAndOrientationUndefined_shouldBe assertThat(subject.hasPortraitLayoutParams()).isTrue(); } - // Video is skippable, no companion ad, CTA button initially invisible + // Video is skippable, no companion ad, has clickthrough url, CTA button initially invisible @Test public void notifyVideoSkippable_withoutCompanionAdAndInPortrait_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; - subject = new VastVideoCtaButtonWidget(context, 0, false); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.notifyVideoSkippable(); @@ -95,8 +107,7 @@ public void notifyVideoSkippable_withoutCompanionAdAndInPortrait_shouldBeVisible @Test public void notifyVideoSkippable_withoutCompanionAdAndInLandscape_shouldBeVisibleAndSetLandscapeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; - subject = new VastVideoCtaButtonWidget(context, 0, false); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.notifyVideoSkippable(); @@ -107,8 +118,7 @@ public void notifyVideoSkippable_withoutCompanionAdAndInLandscape_shouldBeVisibl @Test public void notifyVideoSkippable_withoutCompanionAdAndOrientationUndefined_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; - subject = new VastVideoCtaButtonWidget(context, 0, false); - subject.setVisibility(View.INVISIBLE); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.notifyVideoSkippable(); @@ -119,21 +129,21 @@ public void notifyVideoSkippable_withoutCompanionAdAndOrientationUndefined_shoul // Video is complete, has companion ad, CTA button already visible @Test - public void notifyVideoComplete_withCompanionAdAndInPortrait_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { + public void notifyVideoComplete_withCompanionAdAndInPortrait_shouldBeGoneAndNotChangeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; - subject = new VastVideoCtaButtonWidget(context, 0, true); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); - assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(subject.hasPortraitLayoutParams()).isTrue(); + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + assertThat(subject.getLayoutParams()).isNull(); } @Test public void notifyVideoComplete_withCompanionAdAndInLandscape_shouldBeGoneAndNotChangeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; - subject = new VastVideoCtaButtonWidget(context, 0, true); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); @@ -143,23 +153,23 @@ public void notifyVideoComplete_withCompanionAdAndInLandscape_shouldBeGoneAndNot } @Test - public void notifyVideoComplete_withCompanionAdAndOrientationUndefined_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { + public void notifyVideoComplete_withCompanionAdAndOrientationUndefined_shouldBeGoneAndNotChangeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; - subject = new VastVideoCtaButtonWidget(context, 0, true); + subject = new VastVideoCtaButtonWidget(context, 0, true, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); - assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); - assertThat(subject.hasPortraitLayoutParams()).isTrue(); + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + assertThat(subject.getLayoutParams()).isNull(); } - // Video is complete, no companion ad, CTA button already visible + // Video is complete, no companion ad, has clickthrough url, CTA button already visible @Test public void notifyVideoComplete_withoutCompanionAdAndInPortrait_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; - subject = new VastVideoCtaButtonWidget(context, 0, false); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); @@ -171,7 +181,7 @@ public void notifyVideoComplete_withoutCompanionAdAndInPortrait_shouldBeVisibleA @Test public void notifyVideoComplete_withoutCompanionAdAndInLandscape_shouldBeVisibleAndSetLandscapeLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; - subject = new VastVideoCtaButtonWidget(context, 0, false); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); @@ -183,7 +193,7 @@ public void notifyVideoComplete_withoutCompanionAdAndInLandscape_shouldBeVisible @Test public void notifyVideoComplete_withoutCompanionAdAndOrientationUndefined_shouldBeVisibleAndSetPortraitLayoutParams() throws Exception { context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; - subject = new VastVideoCtaButtonWidget(context, 0, false); + subject = new VastVideoCtaButtonWidget(context, 0, false, true); subject.setVisibility(View.VISIBLE); subject.notifyVideoComplete(); @@ -191,4 +201,26 @@ public void notifyVideoComplete_withoutCompanionAdAndOrientationUndefined_should assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); assertThat(subject.hasPortraitLayoutParams()).isTrue(); } + + // No clickthrough url means never show cta button + + @Test + public void notifyVideoSkippable_withoutClickthroughUrl_shouldBeGone() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, true, false); + subject.setVisibility(View.VISIBLE); + + subject.notifyVideoSkippable(); + + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void notifyVideoComplete_withoutClickthroughUrl_shouldBeGone() throws Exception { + subject = new VastVideoCtaButtonWidget(context, 0, true, false); + subject.setVisibility(View.VISIBLE); + + subject.notifyVideoComplete(); + + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + } } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoDownloadTaskTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoDownloadTaskTest.java index dd69502f6..9fdafe8d4 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoDownloadTaskTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoDownloadTaskTest.java @@ -7,7 +7,6 @@ import com.mopub.common.test.support.SdkTestRunner; import com.mopub.mobileads.test.support.TestHttpResponseWithHeaders; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -86,6 +85,14 @@ public void execute_whenUrlArrayIsNull_shouldSignalDownloadFailed() throws Excep verify(mVastVideoDownloadTaskListener).onComplete(false); } + @Test + public void execute_whenUrlArrayIsEmpty_shouldSignalDownloadFailed() throws Exception { + subject.execute(new String[0]); + + semaphore.acquire(); + verify(mVastVideoDownloadTaskListener).onComplete(false); + } + @Test public void execute_whenFirstElementOfUrlArrayIsNull_shouldSignalDownloadFailed() throws Exception { subject.execute(null, "ignored"); diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoGradientStripWidgetTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoGradientStripWidgetTest.java new file mode 100644 index 000000000..f4b3c2403 --- /dev/null +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoGradientStripWidgetTest.java @@ -0,0 +1,247 @@ +package com.mopub.mobileads; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.widget.RelativeLayout; + +import com.mopub.common.test.support.SdkTestRunner; +import com.mopub.common.util.DeviceUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; + +import static org.fest.assertions.api.Assertions.assertThat; + +@RunWith(SdkTestRunner.class) +public class VastVideoGradientStripWidgetTest { + private Context context; + private VastVideoGradientStripWidget subject; + + @Before + public void setUp() throws Exception { + context = Robolectric.buildActivity(Activity.class).create().get(); + } + + @Test + public void constructor_whenForcePortrait_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void constructor_whenForceLandscape_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_LANDSCAPE, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void constructor_whenUseDeviceOrientation_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.DEVICE_ORIENTATION, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + + // If not forcing orientation, visibility depends on device orientation, + // which is initially ORIENTATION_UNDEFINED in tests + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void constructor_whenForceOrientationUndefined_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.UNDEFINED, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + + // If force orientation undefined, visibility depends on device orientation, + // which is initially ORIENTATION_UNDEFINED in tests + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + // Video is still playing, forcing portrait orientation + + @Test + public void onConfigurationChanged_whenForcePortraitAndDeviceInPortrait_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void onConfigurationChanged_whenForcePortraitAndDeviceInLandscape_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void onConfigurationChanged_whenForcePortraitAndDeviceOrientationUndefined_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + // Video is still playing, forcing landscape orientation + + @Test + public void onConfigurationChanged_whenForceLandscapeAndDeviceInPortrait_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_LANDSCAPE, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onConfigurationChanged_whenForceLandscapeAndDeviceInLandscape_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_LANDSCAPE, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onConfigurationChanged_whenForceLandscapeAndDeviceOrientationUndefined_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_LANDSCAPE, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + // Video is still playing, use device orientation + + @Test + public void onConfigurationChanged_whenUseDeviceOrientationAndDeviceInPortrait_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.DEVICE_ORIENTATION, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void onConfigurationChanged_whenUseDeviceOrientationAndDeviceInLandscape_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.DEVICE_ORIENTATION, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onConfigurationChanged_whenUseDeviceOrientationAndDeviceOrientationUndefined_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.DEVICE_ORIENTATION, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + // Video is still playing, force orientation undefined + + @Test + public void onConfigurationChanged_whenForceOrientationUndefinedAndDeviceInPortrait_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.UNDEFINED, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + @Test + public void onConfigurationChanged_whenForceOrientationUndefinedAndDeviceInLandscape_shouldBeVisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.UNDEFINED, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onConfigurationChanged_whenForceOrientationUndefinedAndDeviceOrientationUndefined_shouldBeInvisible() throws Exception { + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.UNDEFINED, true, View.VISIBLE, + RelativeLayout.ALIGN_TOP, 0); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_UNDEFINED; + + subject.onConfigurationChanged(context.getResources().getConfiguration()); + + assertThat(subject.getVisibility()).isEqualTo(View.INVISIBLE); + } + + // Video is complete + + @Test + public void notifyVideoComplete_withCompanionAd_shouldSetVisibilityForCompanionAd() throws Exception { + final int visibilityForCompanionAd = View.VISIBLE; + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, true, visibilityForCompanionAd, + RelativeLayout.ALIGN_TOP, 0); + + subject.notifyVideoComplete(); + + assertThat(subject.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void notifyVideoComplete_withoutCompanionAd_shouldBeGone() throws Exception { + final int visibilityForCompanionAd = View.VISIBLE; + subject = new VastVideoGradientStripWidget(context, GradientDrawable.Orientation.TOP_BOTTOM, + DeviceUtils.ForceOrientation.FORCE_PORTRAIT, false, visibilityForCompanionAd, + RelativeLayout.ALIGN_TOP, 0); + + subject.notifyVideoComplete(); + + assertThat(subject.getVisibility()).isEqualTo(View.GONE); + } +} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoInterstitialTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoInterstitialTest.java index 21b54edaa..4a17ff8cc 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoInterstitialTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoInterstitialTest.java @@ -144,28 +144,28 @@ public void loadInterstitial_shouldConnectListenerToBroadcastReceiver() throws E @Test public void showInterstitial_shouldStartVideoPlayerActivityWithAllValidTrackers() throws Exception { - VastCompanionAd vastCompanionAd = mock(VastCompanionAd.class, withSettings().serializable()); - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl(videoUrl); - vastVideoConfiguration.addAbsoluteTrackers(Arrays.asList(new VastAbsoluteProgressTracker + VastCompanionAdConfig vastCompanionAdConfig = mock(VastCompanionAdConfig.class, withSettings().serializable()); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl(videoUrl); + vastVideoConfig.addAbsoluteTrackers(Arrays.asList(new VastAbsoluteProgressTracker ("start", 2000))); - vastVideoConfiguration.addFractionalTrackers(Arrays.asList(new + vastVideoConfig.addFractionalTrackers(Arrays.asList(new VastFractionalProgressTracker("first", 0.25f), new VastFractionalProgressTracker("mid", 0.5f), new VastFractionalProgressTracker("third", 0.75f))); - vastVideoConfiguration.addCompleteTrackers(VastUtils.stringsToVastTrackers("complete")); - vastVideoConfiguration.addImpressionTrackers(VastUtils.stringsToVastTrackers("imp")); - vastVideoConfiguration.setClickThroughUrl("clickThrough"); - vastVideoConfiguration.addClickTrackers(VastUtils.stringsToVastTrackers("click")); - vastVideoConfiguration.setVastCompanionAd(vastCompanionAd); + vastVideoConfig.addCompleteTrackers(VastUtils.stringsToVastTrackers("complete")); + vastVideoConfig.addImpressionTrackers(VastUtils.stringsToVastTrackers("imp")); + vastVideoConfig.setClickThroughUrl("clickThrough"); + vastVideoConfig.addClickTrackers(VastUtils.stringsToVastTrackers("click")); + vastVideoConfig.setVastCompanionAd(vastCompanionAdConfig, vastCompanionAdConfig); subject.loadInterstitial(context, customEventInterstitialListener, localExtras, serverExtras); - ((VastVideoInterstitial) subject).onVastVideoConfigurationPrepared(vastVideoConfiguration); + ((VastVideoInterstitial) subject).onVastVideoConfigurationPrepared(vastVideoConfig); subject.showInterstitial(); BaseVideoPlayerActivityTest.assertVastVideoPlayerActivityStarted( MraidVideoPlayerActivity.class, - vastVideoConfiguration, + vastVideoConfig, broadcastIdentifier ); } @@ -209,7 +209,7 @@ public void onInvalidate_shouldDisconnectListenerToBroadcastReceiver() throws Ex @Test public void onVastVideoConfigurationPrepared_withVastVideoConfiguration_shouldSignalOnInterstitialLoaded() throws Exception { subject.loadInterstitial(context, customEventInterstitialListener, localExtras, serverExtras); - ((VastVideoInterstitial) subject).onVastVideoConfigurationPrepared(mock(VastVideoConfiguration.class)); + ((VastVideoInterstitial) subject).onVastVideoConfigurationPrepared(mock(VastVideoConfig.class)); verify(customEventInterstitialListener).onInterstitialLoaded(); } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewControllerTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewControllerTest.java index ed77778e4..773e6e1bf 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewControllerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewControllerTest.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; @@ -12,6 +13,7 @@ import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.view.View; @@ -24,6 +26,7 @@ import com.mopub.common.util.DeviceUtils.ForceOrientation; import com.mopub.mobileads.resource.CloseButtonDrawable; import com.mopub.mobileads.test.support.GestureUtils; +import com.mopub.mobileads.test.support.ShadowVastVideoView; import com.mopub.mobileads.test.support.VastUtils; import com.mopub.network.MaxWidthImageLoader; import com.mopub.network.MoPubRequestQueue; @@ -35,7 +38,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.robolectric.Robolectric; import org.robolectric.annotation.Config; @@ -50,15 +52,12 @@ import java.io.File; import java.util.Arrays; import java.util.Collections; -import java.util.List; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; -import static com.mopub.common.MoPubBrowser.DESTINATION_URL_KEY; import static com.mopub.common.VolleyRequestMatcher.isUrl; import static com.mopub.common.util.ResponseHeader.USER_AGENT; import static com.mopub.mobileads.BaseVideoViewController.BaseVideoViewControllerListener; -import static com.mopub.mobileads.EventForwardingBroadcastReceiver.ACTION_INTERSTITIAL_CLICK; import static com.mopub.mobileads.EventForwardingBroadcastReceiver.ACTION_INTERSTITIAL_DISMISS; import static com.mopub.mobileads.EventForwardingBroadcastReceiver.ACTION_INTERSTITIAL_FAIL; import static com.mopub.mobileads.EventForwardingBroadcastReceiver.ACTION_INTERSTITIAL_SHOW; @@ -67,12 +66,13 @@ import static com.mopub.mobileads.VastVideoViewController.CURRENT_POSITION; import static com.mopub.mobileads.VastVideoViewController.DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON; import static com.mopub.mobileads.VastVideoViewController.MAX_VIDEO_DURATION_FOR_CLOSE_BUTTON; -import static com.mopub.mobileads.VastVideoViewController.RESUMED_VAST_CONFIGURATION; -import static com.mopub.mobileads.VastVideoViewController.VAST_VIDEO_CONFIGURATION; +import static com.mopub.mobileads.VastVideoViewController.RESUMED_VAST_CONFIG; +import static com.mopub.mobileads.VastVideoViewController.VAST_VIDEO_CONFIG; import static com.mopub.volley.toolbox.ImageLoader.ImageListener; import static org.fest.assertions.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; @@ -87,18 +87,22 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Robolectric.shadowOf; +import static org.robolectric.Robolectric.shadowOf_; @RunWith(SdkTestRunner.class) +@Config(shadows = {ShadowVastVideoView.class}) public class VastVideoViewControllerTest { public static final int NETWORK_DELAY = 100; private static final String COMPANION_IMAGE_URL = "companion_image_url"; private static final String COMPANION_CLICK_TRACKING_URL_1 = "companion_click_tracking_url_1"; private static final String COMPANION_CLICK_TRACKING_URL_2 = "companion_click_tracking_url_2"; + private static final String COMPANION_CLICK_TRACKING_URL_3 = "companion_click_tracking_url_3"; private static final String COMPANION_CLICK_DESTINATION_URL = "http://companion_click_destination_url"; private static final String COMPANION_CREATIVE_VIEW_URL_1 = "companion_creative_view_url_1"; private static final String COMPANION_CREATIVE_VIEW_URL_2 = "companion_creative_view_url_2"; - private static final String RESOLVED_CLICKTHROUGH_URL = "http://clickthrough_url"; + private static final String COMPANION_CREATIVE_VIEW_URL_3 = "companion_creative_view_url_3"; + private static final String RESOLVED_CLICKTHROUGH_URL = "http://www.mopub.com/"; private static final String CLICKTHROUGH_URL = "deeplink+://navigate?" + "&primaryUrl=bogus%3A%2F%2Furl" + "&fallbackUrl=" + Uri.encode(RESOLVED_CLICKTHROUGH_URL); @@ -120,7 +124,7 @@ public class VastVideoViewControllerTest { @Mock private EventForwardingBroadcastReceiver broadcastReceiver; @Mock MoPubRequestQueue mockRequestQueue; @Mock MaxWidthImageLoader mockImageLoader; - @Mock private VastIcon mockVastIcon; + @Mock private VastIconConfig mMockVastIconConfig; @Mock private MediaMetadataRetriever mockMediaMetadataRetriever; @Mock private Bitmap mockBitmap; @@ -133,38 +137,38 @@ public class VastVideoViewControllerTest { public void setUp() throws Exception { Networking.setRequestQueueForTesting(mockRequestQueue); Networking.setImageLoaderForTesting(mockImageLoader); - context = Robolectric.buildActivity(Activity.class).create().get(); + context = spy(Robolectric.buildActivity(Activity.class).create().get()); bundle = new Bundle(); savedInstanceState = new Bundle(); testBroadcastIdentifier = 1111; - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addAbsoluteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addAbsoluteTrackers( Arrays.asList(new VastAbsoluteProgressTracker("start" + MACRO_TAGS, 2000))); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f), new VastFractionalProgressTracker("mid" + MACRO_TAGS, 0.5f), new VastFractionalProgressTracker("third" + MACRO_TAGS, 0.75f))); - vastVideoConfiguration.addPauseTrackers( + vastVideoConfig.addPauseTrackers( Arrays.asList(new VastTracker("pause" + MACRO_TAGS, true))); - vastVideoConfiguration.addResumeTrackers( + vastVideoConfig.addResumeTrackers( Arrays.asList(new VastTracker("resume" + MACRO_TAGS, true))); - vastVideoConfiguration.addCompleteTrackers( + vastVideoConfig.addCompleteTrackers( VastUtils.stringsToVastTrackers("complete" + MACRO_TAGS)); - vastVideoConfiguration.addCloseTrackers( + vastVideoConfig.addCloseTrackers( VastUtils.stringsToVastTrackers("close" + MACRO_TAGS)); - vastVideoConfiguration.addSkipTrackers(VastUtils.stringsToVastTrackers("skip" + MACRO_TAGS)); - vastVideoConfiguration.addImpressionTrackers( + vastVideoConfig.addSkipTrackers(VastUtils.stringsToVastTrackers("skip" + MACRO_TAGS)); + vastVideoConfig.addImpressionTrackers( VastUtils.stringsToVastTrackers("imp" + MACRO_TAGS)); - vastVideoConfiguration.addErrorTrackers( + vastVideoConfig.addErrorTrackers( Collections.singletonList(new VastTracker("error" + MACRO_TAGS))); - vastVideoConfiguration.setClickThroughUrl(CLICKTHROUGH_URL); - vastVideoConfiguration.addClickTrackers( + vastVideoConfig.setClickThroughUrl(CLICKTHROUGH_URL); + vastVideoConfig.addClickTrackers( VastUtils.stringsToVastTrackers("click_1" + MACRO_TAGS, "click_2" + MACRO_TAGS)); - VastCompanionAd vastCompanionAd = new VastCompanionAd( + VastCompanionAdConfig landscapeVastCompanionAdConfig = new VastCompanionAdConfig( 300, 250, new VastResource(COMPANION_IMAGE_URL, @@ -174,20 +178,31 @@ public void setUp() throws Exception { VastUtils.stringsToVastTrackers(COMPANION_CLICK_TRACKING_URL_1, COMPANION_CLICK_TRACKING_URL_2), VastUtils.stringsToVastTrackers(COMPANION_CREATIVE_VIEW_URL_1, COMPANION_CREATIVE_VIEW_URL_2) ); - vastVideoConfiguration.setVastCompanionAd(vastCompanionAd); + VastCompanionAdConfig portraitVastCompanionAdConfig = new VastCompanionAdConfig( + 250, + 300, + new VastResource(COMPANION_IMAGE_URL, + VastResource.Type.STATIC_RESOURCE, + VastResource.CreativeType.IMAGE, 250, 300), + COMPANION_CLICK_DESTINATION_URL, + VastUtils.stringsToVastTrackers(COMPANION_CLICK_TRACKING_URL_3), + VastUtils.stringsToVastTrackers(COMPANION_CREATIVE_VIEW_URL_3) + ); + vastVideoConfig.setVastCompanionAd(landscapeVastCompanionAdConfig, + portraitVastCompanionAdConfig); - when(mockVastIcon.getWidth()).thenReturn(40); - when(mockVastIcon.getHeight()).thenReturn(40); + when(mMockVastIconConfig.getWidth()).thenReturn(40); + when(mMockVastIconConfig.getHeight()).thenReturn(40); VastResource vastResource = mock(VastResource.class); when(vastResource.getType()).thenReturn(VastResource.Type.STATIC_RESOURCE); when(vastResource.getResource()).thenReturn("static"); when(vastResource.getCreativeType()).thenReturn(VastResource.CreativeType.IMAGE); - when(mockVastIcon.getVastResource()).thenReturn(vastResource); - vastVideoConfiguration.setVastIcon(mockVastIcon); + when(mMockVastIconConfig.getVastResource()).thenReturn(vastResource); + vastVideoConfig.setVastIconConfig(mMockVastIconConfig); when(mockMediaMetadataRetriever.getFrameAtTime(anyLong(), anyInt())).thenReturn(mockBitmap); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); expectedBrowserRequestCode = 1; @@ -225,7 +240,8 @@ public void constructor_shouldAddCtaButtonWidgetToLayoutAndSetInvisibleWithOnTou assertThat(ctaButtonWidget.getVisibility()).isEqualTo(View.INVISIBLE); ShadowImageView ctaButtonWidgetShadow = shadowOf(ctaButtonWidget); assertThat(ctaButtonWidgetShadow.getOnTouchListener()).isNotNull(); - assertThat(ctaButtonWidgetShadow.getOnTouchListener()).isEqualTo(getShadowVideoView().getOnTouchListener()); + assertThat(ctaButtonWidgetShadow.getOnTouchListener()).isEqualTo( + getShadowVideoView().getOnTouchListener()); } @Test @@ -269,23 +285,23 @@ public void constructor_shouldAddCloseButtonWidgetToLayoutAndSetToGoneWithOnTouc } @Test - public void constructor_shouldAddTopGradientWidgetToLayoutAndSetVisibleWithNoListeners() throws Exception { + public void constructor_shouldAddTopGradientStripWidgetToLayoutWithNoListeners() throws Exception { initializeSubject(); VastVideoGradientStripWidget topGradientStripWidget = subject.getTopGradientStripWidget(); assertThat(topGradientStripWidget.getParent()).isEqualTo(subject.getLayout()); - assertThat(topGradientStripWidget.getVisibility()).isEqualTo(View.VISIBLE); + ShadowImageView topGradientStripWidgetShadow = shadowOf(topGradientStripWidget); assertThat(topGradientStripWidgetShadow.getOnTouchListener()).isNull(); } @Test - public void constructor_shouldAddBottomGradientWidgetToLayoutAndSetVisibleWithNoListeners() throws Exception { + public void constructor_shouldAddBottomGradientStripWidgetToLayoutWithNoListeners() throws Exception { initializeSubject(); VastVideoGradientStripWidget bottomGradientStripWidget = subject.getBottomGradientStripWidget(); assertThat(bottomGradientStripWidget.getParent()).isEqualTo(subject.getLayout()); - assertThat(bottomGradientStripWidget.getVisibility()).isEqualTo(View.VISIBLE); + ShadowImageView bottomGradientStripWidgetShadow = shadowOf(bottomGradientStripWidget); assertThat(bottomGradientStripWidgetShadow.getOnTouchListener()).isNull(); } @@ -345,7 +361,7 @@ public void constructor_withMissingVastVideoConfiguration_shouldThrowIllegalStat @Test public void constructor_withNullVastVideoConfigurationDiskMediaFileUrl_shouldThrowIllegalStateException() throws Exception { - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, new VastVideoConfiguration()); + bundle.putSerializable(VAST_VIDEO_CONFIG, new VastVideoConfig()); try { initializeSubject(); fail("VastVideoViewController didn't throw IllegalStateException"); @@ -356,9 +372,9 @@ public void constructor_withNullVastVideoConfigurationDiskMediaFileUrl_shouldThr @Test public void constructor_whenCustomCtaTextNotSpecified_shouldUseDefaultCtaText() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -368,10 +384,10 @@ public void constructor_whenCustomCtaTextNotSpecified_shouldUseDefaultCtaText() @Test public void constructor_whenCustomCtaTextSpecified_shouldUseCustomCtaText() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomCtaText("custom CTA text"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomCtaText("custom CTA text"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -381,9 +397,9 @@ public void constructor_whenCustomCtaTextSpecified_shouldUseCustomCtaText() thro @Test public void constructor_whenCustomSkipTextNotSpecified_shouldUseDefaultSkipText() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -393,10 +409,10 @@ public void constructor_whenCustomSkipTextNotSpecified_shouldUseDefaultSkipText( @Test public void constructor_whenCustomSkipTextSpecified_shouldUseCustomSkipText() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomSkipText("custom skip text"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomSkipText("custom skip text"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -406,9 +422,9 @@ public void constructor_whenCustomSkipTextSpecified_shouldUseCustomSkipText() th @Test public void constructor_whenCustomCloseIconNotSpecified_shouldUseDefaultCloseIcon() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -420,11 +436,11 @@ public void constructor_whenCustomCloseIconNotSpecified_shouldUseDefaultCloseIco @Test public void constructor_whenCustomCloseIconSpecified_shouldUseCustomCloseIcon() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomCloseIconUrl( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomCloseIconUrl( "http://ton.twitter.com/exchange-media/images/v4/star_icon_3x_1.png"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -435,10 +451,10 @@ public void constructor_whenCustomCloseIconSpecified_shouldUseCustomCloseIcon() @Test public void constructor_withVastConfigurationInSavedInstanceState_shouldUseThatVastConfiguration() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setNetworkMediaFileUrl("resumed_network_media_url"); - savedInstanceState.putSerializable(RESUMED_VAST_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setNetworkMediaFileUrl("resumed_network_media_url"); + savedInstanceState.putSerializable(RESUMED_VAST_CONFIG, vastVideoConfig); initializeSubject(); @@ -447,10 +463,10 @@ public void constructor_withVastConfigurationInSavedInstanceState_shouldUseThatV @Test public void constructor_withSavedVastConfiguration_shouldUseThatVastConfiguration() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setNetworkMediaFileUrl("resumed_network_media_url"); - savedInstanceState.putSerializable(RESUMED_VAST_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setNetworkMediaFileUrl("resumed_network_media_url"); + savedInstanceState.putSerializable(RESUMED_VAST_CONFIG, vastVideoConfig); initializeSubject(); @@ -459,10 +475,10 @@ public void constructor_withSavedVastConfiguration_shouldUseThatVastConfiguratio @Test public void constructor_withSavedVastConfiguration_withCurrentPositionSet_shouldResumeVideoFromCurrentPosition() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setNetworkMediaFileUrl("resumed_network_media_url"); - savedInstanceState.putSerializable(RESUMED_VAST_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setNetworkMediaFileUrl("resumed_network_media_url"); + savedInstanceState.putSerializable(RESUMED_VAST_CONFIG, vastVideoConfig); savedInstanceState.putInt(CURRENT_POSITION, 123); initializeSubject(); @@ -495,9 +511,9 @@ public void onCreate_shouldBroadcastInterstitialShow() throws Exception { @Test public void onCreate_whenCustomForceOrientationNotSpecified_shouldForceLandscapeOrientation() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.onCreate(); @@ -508,10 +524,10 @@ public void onCreate_whenCustomForceOrientationNotSpecified_shouldForceLandscape @Test public void onCreate_whenCustomForceOrientationIsDeviceOrientation_shouldNotForceLandscapeOrientation() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomForceOrientation(ForceOrientation.DEVICE_ORIENTATION); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomForceOrientation(ForceOrientation.DEVICE_ORIENTATION); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.onCreate(); @@ -521,10 +537,10 @@ public void onCreate_whenCustomForceOrientationIsDeviceOrientation_shouldNotForc @Test public void onCreate_whenCustomForceOrientationIsPortraitOrientation_shouldForcePortraitOrientation() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomForceOrientation(ForceOrientation.FORCE_PORTRAIT); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomForceOrientation(ForceOrientation.FORCE_PORTRAIT); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.onCreate(); @@ -535,10 +551,10 @@ public void onCreate_whenCustomForceOrientationIsPortraitOrientation_shouldForce @Test public void onCreate_whenCustomForceOrientationIsLandscapeOrientation_shouldForceLandscapeOrientation() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setCustomForceOrientation(ForceOrientation.FORCE_LANDSCAPE); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setCustomForceOrientation(ForceOrientation.FORCE_LANDSCAPE); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.onCreate(); @@ -551,33 +567,35 @@ public void onCreate_whenCustomForceOrientationIsLandscapeOrientation_shouldForc public void VastWebView_onVastWebViewClick_shouldCallVastCompanionAdHandleClick() throws Exception { initializeSubject(); - VastCompanionAd vastCompanionAd = mock(VastCompanionAd.class); - when(vastCompanionAd.getWidth()).thenReturn(300); - when(vastCompanionAd.getHeight()).thenReturn(240); + VastCompanionAdConfig vastCompanionAdConfig = mock(VastCompanionAdConfig.class); + when(vastCompanionAdConfig.getWidth()).thenReturn(300); + when(vastCompanionAdConfig.getHeight()).thenReturn(240); VastResource vastResource = mock(VastResource.class); when(vastResource.getType()).thenReturn(VastResource.Type.STATIC_RESOURCE); when(vastResource.getResource()).thenReturn("static"); - when(vastCompanionAd.getVastResource()).thenReturn(vastResource); + when(vastCompanionAdConfig.getVastResource()).thenReturn(vastResource); - VastWebView view = (VastWebView) subject.createCompanionAdView(context, vastCompanionAd, View.INVISIBLE); + VastWebView view = (VastWebView) subject.createCompanionAdView(context, + vastCompanionAdConfig, View.INVISIBLE); view.getVastWebViewClickListener().onVastWebViewClick(); - verify(vastCompanionAd).handleClick(any(Context.class), eq(1), anyString()); + verify(vastCompanionAdConfig).handleClick(any(Context.class), eq(1), anyString()); } @Test public void createCompanionAdView_shouldLayoutAndReturnInvisibleVastIconView() throws Exception { initializeSubject(); - VastCompanionAd vastCompanionAd = mock(VastCompanionAd.class); - when(vastCompanionAd.getWidth()).thenReturn(300); - when(vastCompanionAd.getHeight()).thenReturn(240); + VastCompanionAdConfig vastCompanionAdConfig = mock(VastCompanionAdConfig.class); + when(vastCompanionAdConfig.getWidth()).thenReturn(300); + when(vastCompanionAdConfig.getHeight()).thenReturn(240); VastResource vastResource = mock(VastResource.class); when(vastResource.getType()).thenReturn(VastResource.Type.STATIC_RESOURCE); when(vastResource.getResource()).thenReturn("static"); - when(vastCompanionAd.getVastResource()).thenReturn(vastResource); + when(vastCompanionAdConfig.getVastResource()).thenReturn(vastResource); - VastWebView view = (VastWebView) subject.createCompanionAdView(context, vastCompanionAd, View.INVISIBLE); + VastWebView view = (VastWebView) subject.createCompanionAdView(context, + vastCompanionAdConfig, View.INVISIBLE); assertThat(view).isNotNull(); assertThat(view.getVisibility()).isEqualTo(View.INVISIBLE); @@ -594,7 +612,8 @@ public void createCompanionAdView_withNullCompanionAd_shouldReturnEmptyView() th @Test public void onDestroy_shouldBroadcastInterstitialDismiss() throws Exception { - Intent expectedIntent = getIntentForActionAndIdentifier(ACTION_INTERSTITIAL_DISMISS, testBroadcastIdentifier); + Intent expectedIntent = getIntentForActionAndIdentifier(ACTION_INTERSTITIAL_DISMISS, + testBroadcastIdentifier); initializeSubject(); @@ -604,6 +623,45 @@ public void onDestroy_shouldBroadcastInterstitialDismiss() throws Exception { verify(broadcastReceiver).onReceive(any(Context.class), eq(expectedIntent)); } + @Test + public void onDestroy_withBlurLastVideoFrameTaskStillRunning_shouldCancelTask() throws Exception { + initializeSubject(); + + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock(VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.RUNNING); + subject.getVastVideoView().setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask).cancel(true); + } + + @Test + public void onDestroy_withBlurLastVideoFrameTaskStillPending_shouldCancelTask() throws Exception { + initializeSubject(); + + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock(VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.PENDING); + subject.getVastVideoView().setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask).cancel(true); + } + + @Test + public void onDestroy_withBlurLastVideoFrameTaskFinished_shouldNotCancelTask() throws Exception { + initializeSubject(); + + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock(VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.FINISHED); + subject.getVastVideoView().setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask, never()).cancel(anyBoolean()); + } + @Test public void onSaveInstanceState_shouldSetCurrentPosition_shouldSetVastConfiguration() throws Exception { initializeSubject(); @@ -612,7 +670,7 @@ public void onSaveInstanceState_shouldSetCurrentPosition_shouldSetVastConfigurat subject.onSaveInstanceState(bundle); verify(bundle).putInt(eq(CURRENT_POSITION), anyInt()); - verify(bundle).putSerializable(eq(RESUMED_VAST_CONFIGURATION), any(VastVideoConfiguration + verify(bundle).putSerializable(eq(RESUMED_VAST_CONFIG), any(VastVideoConfig .class)); } @@ -679,15 +737,14 @@ public void onTouch_withTouchUp_whenVideoLessThan16Seconds_andClickAfterEnd_shou getShadowVideoView().getOnTouchListener().onTouch(null, GestureUtils.createActionUp(0, 0)); - ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); - verify(baseVideoViewControllerListener).onStartActivityForResult( - eq(MoPubBrowser.class), - eq(expectedBrowserRequestCode), - bundleCaptor.capture() - ); - - assertThat(bundleCaptor.getValue().get(DESTINATION_URL_KEY)) - .isEqualTo(RESOLVED_CLICKTHROUGH_URL); + Robolectric.runBackgroundTasks(); + final Intent startedActivity = Robolectric.getShadowApplication().peekNextStartedActivity(); + assertThat(startedActivity.getComponent().getClassName()) + .isEqualTo(MoPubBrowser.class.getName()); + assertThat(startedActivity.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)).isEqualTo( + RESOLVED_CLICKTHROUGH_URL); + verify((Activity) context).startActivityForResult(any(Intent.class), + eq(expectedBrowserRequestCode)); } @Test @@ -720,25 +777,24 @@ public void onTouch_withTouchUp_whenVideoLongerThan16Seconds_andClickAfter5Secon getShadowVideoView().getOnTouchListener().onTouch(null, GestureUtils.createActionUp(0, 0)); - ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); - verify(baseVideoViewControllerListener).onStartActivityForResult( - eq(MoPubBrowser.class), - eq(expectedBrowserRequestCode), - bundleCaptor.capture() - ); - - assertThat(bundleCaptor.getValue().get(DESTINATION_URL_KEY)) - .isEqualTo(RESOLVED_CLICKTHROUGH_URL); + Robolectric.runBackgroundTasks(); + final Intent startedActivity = Robolectric.getShadowApplication().peekNextStartedActivity(); + assertThat(startedActivity.getComponent().getClassName()) + .isEqualTo(MoPubBrowser.class.getName()); + assertThat(startedActivity.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)).isEqualTo( + RESOLVED_CLICKTHROUGH_URL); + verify((Activity) context).startActivityForResult(any(Intent.class), + eq(expectedBrowserRequestCode)); } @Test public void onTouch_whenCloseButtonVisible_shouldPingClickThroughTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addClickTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addClickTrackers( VastUtils.stringsToVastTrackers("click_1" + MACRO_TAGS, "click_2" + MACRO_TAGS)); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -758,11 +814,11 @@ public void onTouch_whenCloseButtonVisible_shouldPingClickThroughTrackers() thro @Test public void onTouch_whenCloseButtonNotVisible_shouldNotPingClickThroughTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addClickTrackers(VastUtils.stringsToVastTrackers("click_1", + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addClickTrackers(VastUtils.stringsToVastTrackers("click_1", "click_2")); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -774,7 +830,8 @@ public void onTouch_whenCloseButtonNotVisible_shouldNotPingClickThroughTrackers( @Test public void onTouch_withNullBaseVideoViewListener_andActionTouchUp_shouldReturnTrueAndNotBlowUp() throws Exception { - subject = new VastVideoViewController(context, bundle, null, testBroadcastIdentifier, null); + subject = new VastVideoViewController((Activity) context, bundle, null, + testBroadcastIdentifier, null); boolean result = getShadowVideoView().getOnTouchListener().onTouch(null, GestureUtils.createActionUp( 0, 0)); @@ -819,10 +876,10 @@ public void onPrepared_whenDurationIsGreaterThanMaxVideoDurationForCloseButton_s @Test public void onPrepared_whenPercentSkipOffsetSpecified_shouldSetShowCloseButtonDelayToSkipOffset() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("25%"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("25%"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -836,10 +893,10 @@ public void onPrepared_whenPercentSkipOffsetSpecified_shouldSetShowCloseButtonDe @Test public void onPrepared_whenAbsoluteSkipOffsetSpecified_shouldSetShowCloseButtonDelayToSkipOffset() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:03"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:03"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -853,10 +910,10 @@ public void onPrepared_whenAbsoluteSkipOffsetSpecified_shouldSetShowCloseButtonD @Test public void onPrepared_whenAbsoluteSkipOffsetWithMillisecondsSpecified_shouldSetShowCloseButtonDelayToSkipOffset() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:03.141"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:03.141"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -870,10 +927,10 @@ public void onPrepared_whenAbsoluteSkipOffsetWithMillisecondsSpecified_shouldSet @Test public void onPrepared_whenSkipOffsetIsNull_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset(null); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset(null); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -881,16 +938,17 @@ public void onPrepared_whenSkipOffsetIsNull_shouldNotSetShowCloseButtonDelay() t getShadowVideoView().getOnPreparedListener().onPrepared(null); - assertThat(subject.getShowCloseButtonDelay()).isEqualTo(DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); + assertThat(subject.getShowCloseButtonDelay()).isEqualTo( + DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); assertThat(subject.getHasSkipOffset()).isFalse(); } @Test public void onPrepared_whenSkipOffsetHasInvalidAbsoluteFormat_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("123:4:56.7"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("123:4:56.7"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -898,16 +956,17 @@ public void onPrepared_whenSkipOffsetHasInvalidAbsoluteFormat_shouldNotSetShowCl getShadowVideoView().getOnPreparedListener().onPrepared(null); - assertThat(subject.getShowCloseButtonDelay()).isEqualTo(DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); + assertThat(subject.getShowCloseButtonDelay()).isEqualTo( + DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); assertThat(subject.getHasSkipOffset()).isFalse(); } @Test public void onPrepared_whenSkipOffsetHasInvalidPercentFormat_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("101%"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("101%"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -915,16 +974,17 @@ public void onPrepared_whenSkipOffsetHasInvalidPercentFormat_shouldNotSetShowClo getShadowVideoView().getOnPreparedListener().onPrepared(null); - assertThat(subject.getShowCloseButtonDelay()).isEqualTo(DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); + assertThat(subject.getShowCloseButtonDelay()).isEqualTo( + DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); assertThat(subject.getHasSkipOffset()).isFalse(); } @Test public void onPrepared_whenSkipOffsetHasInvalidFractionalPercentFormat_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("3.14%"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("3.14%"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -932,16 +992,17 @@ public void onPrepared_whenSkipOffsetHasInvalidFractionalPercentFormat_shouldNot getShadowVideoView().getOnPreparedListener().onPrepared(null); - assertThat(subject.getShowCloseButtonDelay()).isEqualTo(DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); + assertThat(subject.getShowCloseButtonDelay()).isEqualTo( + DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); assertThat(subject.getHasSkipOffset()).isFalse(); } @Test public void onPrepared_whenSkipOffsetIsNegative_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("-00:00:03"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("-00:00:03"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -949,16 +1010,17 @@ public void onPrepared_whenSkipOffsetIsNegative_shouldNotSetShowCloseButtonDelay getShadowVideoView().getOnPreparedListener().onPrepared(null); - assertThat(subject.getShowCloseButtonDelay()).isEqualTo(DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); + assertThat(subject.getShowCloseButtonDelay()).isEqualTo( + DEFAULT_VIDEO_DURATION_FOR_CLOSE_BUTTON); assertThat(subject.getHasSkipOffset()).isFalse(); } @Test public void onPrepared_whenSkipOffsetIsZero_shouldSetShowCloseButtonDelayToZero() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:00"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:00"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -972,10 +1034,10 @@ public void onPrepared_whenSkipOffsetIsZero_shouldSetShowCloseButtonDelayToZero( @Test public void onPrepared_whenSkipOffsetIsLongerThanDurationForShortVideo_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:11"); // 11s - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:11"); // 11s + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -989,10 +1051,10 @@ public void onPrepared_whenSkipOffsetIsLongerThanDurationForShortVideo_shouldNot @Test public void onPrepared_whenSkipOffsetIsLongerThanDurationForLongVideo_shouldNotSetShowCloseButtonDelay() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:21"); // 21s - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:21"); // 21s + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1007,10 +1069,10 @@ public void onPrepared_whenSkipOffsetIsLongerThanDurationForLongVideo_shouldNotS @Test public void onPrepared_shouldCalibrateAndMakeVisibleRadialCountdownWidget() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:05"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:05"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); setVideoViewParams(0, 10000); @@ -1030,10 +1092,10 @@ public void onPrepared_shouldCalibrateAndMakeVisibleRadialCountdownWidget() thro @Test public void onPrepared_shouldCalibrateAndMakeVisibleProgressBarWidget() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:05"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:05"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); setVideoViewParams(0, 10000); @@ -1054,13 +1116,16 @@ public void onPrepared_shouldCalibrateAndMakeVisibleProgressBarWidget() throws E @Config(reportSdk = VERSION_CODES.GINGERBREAD) @Test public void onPrepared_beforeGingerbreadMr1_shouldNotSetBlurredLastVideoFrame() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); assertThat(subject.getBlurredLastVideoFrameImageView().getDrawable()).isNull(); @@ -1071,17 +1136,21 @@ public void onPrepared_beforeGingerbreadMr1_shouldNotSetBlurredLastVideoFrame() @Config(reportSdk = VERSION_CODES.GINGERBREAD_MR1) @Test public void onPrepared_atLeastGingerbreadMr1_shouldSetBlurredLastVideoFrame() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); final ImageView blurredLastVideoFrameImageView = subject.getBlurredLastVideoFrameImageView(); assertThat(blurredLastVideoFrameImageView.getDrawable()).isInstanceOf(BitmapDrawable.class); - assertThat(((BitmapDrawable) blurredLastVideoFrameImageView.getDrawable()).getBitmap()).isNotNull(); + assertThat( + ((BitmapDrawable) blurredLastVideoFrameImageView.getDrawable()).getBitmap()).isNotNull(); ShadowImageView imageView = shadowOf(subject.getBlurredLastVideoFrameImageView()); assertThat(imageView.getOnTouchListener()).isNull(); @@ -1098,16 +1167,16 @@ public void onCompletion_shouldMarkVideoAsFinished() throws Exception { @Test public void onCompletion_whenAllTrackersTracked_whenNoPlaybackErrors_shouldPingCompletionTrackersOnlyOnce() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); VastAbsoluteProgressTracker testTracker = new VastAbsoluteProgressTracker( "testUrl" + MACRO_TAGS, 123); - vastVideoConfiguration.addAbsoluteTrackers(Arrays.asList(testTracker)); - vastVideoConfiguration.addCompleteTrackers( + vastVideoConfig.addAbsoluteTrackers(Arrays.asList(testTracker)); + vastVideoConfig.addCompleteTrackers( VastUtils.stringsToVastTrackers("complete_1" + MACRO_TAGS, "complete_2" + MACRO_TAGS)); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); testTracker.setTracked(); @@ -1130,16 +1199,16 @@ public void onCompletion_whenAllTrackersTracked_whenNoPlaybackErrors_shouldPingC @Test public void onCompletion_whenSomeTrackersRemain_shouldNotPingCompletionTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addCompleteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addCompleteTrackers( VastUtils.stringsToVastTrackers("complete_1", "complete_2")); VastAbsoluteProgressTracker testTracker = new VastAbsoluteProgressTracker( "testUrl" + MACRO_TAGS, 123); // Never track the testTracker, so completion trackers should not be fired. - vastVideoConfiguration.addAbsoluteTrackers(Arrays.asList(testTracker)); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + vastVideoConfig.addAbsoluteTrackers(Arrays.asList(testTracker)); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); @@ -1150,12 +1219,12 @@ public void onCompletion_whenSomeTrackersRemain_shouldNotPingCompletionTrackers( @Test public void onCompletion_whenPlaybackError_shouldNotPingCompletionTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addCompleteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addCompleteTrackers( VastUtils.stringsToVastTrackers("complete_1", "complete_2")); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.setVideoError(); @@ -1195,7 +1264,7 @@ public void onCompletion_shouldStopProgressCheckerAndCountdown() throws Exceptio public void onCompletion_whenCompanionAdAvailable_shouldShowCompanionAdAndHideBlurredLastVideoFrame() throws Exception { initializeSubject(); - final View companionView = subject.getCompanionAdView(); + final View companionView = subject.getLandscapeCompanionAdView(); final ImageView blurredLastVideoFrameImageView = subject.getBlurredLastVideoFrameImageView(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.VISIBLE); @@ -1203,23 +1272,46 @@ public void onCompletion_whenCompanionAdAvailable_shouldShowCompanionAdAndHideBl assertThat(blurredLastVideoFrameImageView.getVisibility()).isEqualTo(View.INVISIBLE); getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); + getShadowVideoView().getOnCompletionListener().onCompletion(null); + assertThat(subject.getVastVideoView().getBlurLastVideoFrameTask()).isNull(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.INVISIBLE); assertThat(companionView.getVisibility()).isEqualTo(View.VISIBLE); assertThat(blurredLastVideoFrameImageView.getVisibility()).isEqualTo(View.INVISIBLE); } + @Test + public void onCompletion_whenCompanionAdAvailable_shouldOnlyShowTopGradientStripWidget() throws Exception { + initializeSubject(); + + final VastVideoGradientStripWidget topGradientStripWidget = subject.getTopGradientStripWidget(); + final VastVideoGradientStripWidget bottomGradientStripWidget = subject.getBottomGradientStripWidget(); + + getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); + + getShadowVideoView().getOnCompletionListener().onCompletion(null); + + assertThat(topGradientStripWidget.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(bottomGradientStripWidget.getVisibility()).isEqualTo(View.GONE); + } + @Test public void onCompletion_whenCompanionAdNotAvailable_shouldHideCompanionAdAndShowBlurredLastVideoFrame() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setVastCompanionAd(null); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setVastCompanionAd(null, null); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); - final View companionView = subject.getCompanionAdView(); + final View companionView = subject.getLandscapeCompanionAdView(); final ImageView blurredLastVideoFrameImageView = subject.getBlurredLastVideoFrameImageView(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.VISIBLE); @@ -1227,26 +1319,55 @@ public void onCompletion_whenCompanionAdNotAvailable_shouldHideCompanionAdAndSho assertThat(blurredLastVideoFrameImageView.getVisibility()).isEqualTo(View.INVISIBLE); getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); + getShadowVideoView().getOnCompletionListener().onCompletion(null); + assertThat(subject.getVastVideoView().getBlurLastVideoFrameTask()).isNotNull(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.INVISIBLE); assertThat(companionView.getVisibility()).isEqualTo(View.INVISIBLE); assertThat(blurredLastVideoFrameImageView.getVisibility()).isEqualTo(View.VISIBLE); assertThat(blurredLastVideoFrameImageView.getDrawable()).isInstanceOf(BitmapDrawable.class); - assertThat(((BitmapDrawable) blurredLastVideoFrameImageView.getDrawable()).getBitmap()).isNotNull(); + assertThat( + ((BitmapDrawable) blurredLastVideoFrameImageView.getDrawable()).getBitmap()).isNotNull(); + } + + @Test + public void onCompletion_whenCompanionAdNotAvailable_shouldHideBothGradientStripWidgets() throws Exception { + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setVastCompanionAd(null, null); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); + + initializeSubject(); + + final VastVideoGradientStripWidget topGradientStripWidget = subject.getTopGradientStripWidget(); + final VastVideoGradientStripWidget bottomGradientStripWidget = subject.getBottomGradientStripWidget(); + + getShadowVideoView().getOnPreparedListener().onPrepared(null); + Robolectric.getBackgroundScheduler().unPause(); + Robolectric.getUiThreadScheduler().unPause(); + Thread.sleep(NETWORK_DELAY); + + getShadowVideoView().getOnCompletionListener().onCompletion(null); + + assertThat(topGradientStripWidget.getVisibility()).isEqualTo(View.GONE); + assertThat(bottomGradientStripWidget.getVisibility()).isEqualTo(View.GONE); } @TargetApi(VERSION_CODES.HONEYCOMB) @Test public void onCompletion_whenCompanionAdNotAvailableAndBlurredLastVideoFrameNotPrepared_shouldShowBlackBackground() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setVastCompanionAd(null); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setVastCompanionAd(null, null); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); - final View companionView = subject.getCompanionAdView(); + final View companionView = subject.getLandscapeCompanionAdView(); final ImageView blurredLastVideoFrameImageView = subject.getBlurredLastVideoFrameImageView(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.VISIBLE); @@ -1255,6 +1376,7 @@ public void onCompletion_whenCompanionAdNotAvailableAndBlurredLastVideoFrameNotP getShadowVideoView().getOnCompletionListener().onCompletion(null); + assertThat(subject.getVastVideoView().getBlurLastVideoFrameTask()).isNull(); assertThat(subject.getVideoView().getVisibility()).isEqualTo(View.INVISIBLE); assertThat(companionView.getVisibility()).isEqualTo(View.INVISIBLE); assertThat(blurredLastVideoFrameImageView.getVisibility()).isEqualTo(View.INVISIBLE); @@ -1263,6 +1385,24 @@ public void onCompletion_whenCompanionAdNotAvailableAndBlurredLastVideoFrameNotP assertThat(((ColorDrawable) background).getColor()).isEqualTo(Color.BLACK); } + @Test + public void onCompletion_whenCompanionAdNotAvailableAndBlurredLastVideoFrameNotPrepared_shouldHideBothGradientStripWidgets() throws Exception { + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setVastCompanionAd(null, null); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); + + initializeSubject(); + + final VastVideoGradientStripWidget topGradientStripWidget = subject.getTopGradientStripWidget(); + final VastVideoGradientStripWidget bottomGradientStripWidget = subject.getBottomGradientStripWidget(); + + getShadowVideoView().getOnCompletionListener().onCompletion(null); + + assertThat(topGradientStripWidget.getVisibility()).isEqualTo(View.GONE); + assertThat(bottomGradientStripWidget.getVisibility()).isEqualTo(View.GONE); + } + @Test public void onError_shouldFireVideoErrorAndReturnFalse() throws Exception { initializeSubject(); @@ -1301,25 +1441,25 @@ public void onError_withVideoFilePermissionErrorBelowJellyBean_shouldRetryPlayin assertThat(getShadowVideoView().getCurrentVideoState()).isEqualTo(-1); - assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.getVastVideoView().getVideoRetries()).isEqualTo(0); getShadowVideoView().getOnErrorListener().onError(new MediaPlayer(), 1, Integer.MIN_VALUE); assertThat(getShadowVideoView().isPlaying()).isTrue(); - assertThat(subject.getVideoRetries()).isEqualTo(1); + assertThat(subject.getVastVideoView().getVideoRetries()).isEqualTo(1); file.delete(); } @Test public void onError_shouldFireErrorTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addCompleteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addCompleteTrackers( VastUtils.stringsToVastTrackers("complete_1", "complete_2")); - vastVideoConfiguration.addErrorTrackers( + vastVideoConfig.addErrorTrackers( Collections.singletonList(new VastTracker("error" + MACRO_TAGS))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.setVideoError(); @@ -1335,12 +1475,12 @@ public void onError_shouldFireErrorTrackers() throws Exception { @Test public void onError_withMultipleCalls_shouldRepeatedlyFireErrorTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addErrorTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addErrorTrackers( Collections.singletonList(new VastTracker("error" + MACRO_TAGS))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); subject.setVideoError(); @@ -1355,137 +1495,17 @@ public void onError_withMultipleCalls_shouldRepeatedlyFireErrorTrackers() throws verifyNoMoreInteractions(mockRequestQueue); } - @Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - @Test - public void retryMediaPlayer_withVideoFilePermissionErrorAndBelowJellyBean_shouldReturnTrue() throws Exception { - File file = new File("disk_video_path"); - file.createNewFile(); - - initializeSubject(); - - assertThat(subject.getVideoRetries()).isEqualTo(0); - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isTrue(); - assertThat(subject.getVideoRetries()).isEqualTo(1); - - file.delete(); - } - - @Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - @Test - public void retryMediaPlayer_shouldNotRunMoreThanOnce() throws Exception { - File file = new File("disk_video_path"); - file.createNewFile(); - - initializeSubject(); - - assertThat(subject.getVideoRetries()).isEqualTo(0); - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isTrue(); - assertThat(subject.getVideoRetries()).isEqualTo(1); - - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isFalse(); - assertThat(subject.getVideoRetries()).isEqualTo(1); - - file.delete(); - } - - @Config(reportSdk = VERSION_CODES.JELLY_BEAN) - @Test - public void retryMediaPlayer_withAndroidVersionAboveJellyBean_shouldReturnFalse() throws Exception { - File file = new File("disk_video_path"); - file.createNewFile(); - - initializeSubject(); - - assertThat(subject.getVideoRetries()).isEqualTo(0); - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isFalse(); - assertThat(subject.getVideoRetries()).isEqualTo(0); - - file.delete(); - } - - @Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH) - @Test - public void retryMediaPlayer_withOtherVideoError_shouldReturnFalse() throws Exception { - File file = new File("disk_video_path"); - file.createNewFile(); - - initializeSubject(); - - assertThat(subject.getVideoRetries()).isEqualTo(0); - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 2, Integer.MIN_VALUE)).isFalse(); - assertThat(subject.getVideoRetries()).isEqualTo(0); - - file.delete(); - } - - @Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH) - @Test - public void retryMediaPlayer_withExceptionThrown_shouldReturnFalseAndIncrementRetryCount() throws Exception { - File file = new File("disk_video_path"); - if (file.exists()) { - assertThat(file.delete()).isTrue(); - } - - initializeSubject(); - - assertThat(subject.getVideoRetries()).isEqualTo(0); - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isFalse(); - assertThat(subject.getVideoRetries()).isEqualTo(1); - } - - @Test - public void handleClick_withNullClickThroughUrl_shouldNotBroadcastClickOrOpenNewActivity() throws Exception { - Intent expectedIntent = getIntentForActionAndIdentifier(ACTION_INTERSTITIAL_CLICK, testBroadcastIdentifier); - - initializeSubject(); - subject.handleClick(null); - - Robolectric.getUiThreadScheduler().unPause(); - verify(broadcastReceiver, never()).onReceive(any(Context.class), eq(expectedIntent)); - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - } - - @Test - public void handleClick_withMoPubNativeBrowserClickThroughUrl_shouldOpenExternalBrowser() throws Exception { - initializeSubject(); - - subject.handleClick("mopubnativebrowser://navigate?url=http%3A%2F%2Fwww.mopub.com"); - - Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); - assertThat(intent.getDataString()).isEqualTo("http://www.mopub.com"); - assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW); - } - - @Test - public void handleClick_withMalformedMoPubNativeBrowserClickThroughUrl_shouldNotOpenANewActivity() throws Exception { - initializeSubject(); - - // url2 is an invalid query parameter - subject.handleClick("mopubnativebrowser://navigate?url2=http%3A%2F%2Fwww.mopub.com"); - - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - } - - @Test - public void handleClick_withAboutBlankClickThroughUrl_shouldFailSilently() throws Exception { - initializeSubject(); - - subject.handleClick("about:blank"); - - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - } - @Test public void videoRunnablesRun_shouldFireOffAllProgressTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f), new VastFractionalProgressTracker("second" + MACRO_TAGS, 0.5f), new VastFractionalProgressTracker("third" + MACRO_TAGS, 0.75f))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1503,79 +1523,11 @@ public void videoRunnablesRun_shouldFireOffAllProgressTrackers() throws Exceptio argThat(isUrl("third?errorcode=&asseturi=video_url&contentplayhead=00:00:09.002"))); } - @Test - public void getUntriggeredTrackersBefore_endOfVideo_shouldReturnAllTrackers() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( - Arrays.asList(new VastFractionalProgressTracker("first", 0.25f), - new VastFractionalProgressTracker("second", 0.5f), - new VastFractionalProgressTracker("third", 0.75f))); - vastVideoConfiguration.addAbsoluteTrackers( - Arrays.asList(new VastAbsoluteProgressTracker("1secs", 1000), - new VastAbsoluteProgressTracker("10secs", 10000))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); - - initializeSubject(); - spyOnVideoView(); - setVideoViewParams(11000, 11000); - - final List untriggeredTrackers = subject.getUntriggeredTrackersBefore(11000, 11000); - assertThat(untriggeredTrackers).hasSize(5); - - // Sorted absolute trackers, followed by sorted fractional trackers - final VastTracker tracker0 = untriggeredTrackers.get(0); - assertThat(tracker0).isExactlyInstanceOf(VastAbsoluteProgressTracker.class); - assertThat(((VastAbsoluteProgressTracker) tracker0).getTrackingMilliseconds()).isEqualTo(1000); - - final VastTracker tracker1 = untriggeredTrackers.get(1); - assertThat(tracker1).isExactlyInstanceOf(VastAbsoluteProgressTracker.class); - assertThat(((VastAbsoluteProgressTracker) tracker1).getTrackingMilliseconds()).isEqualTo(10000); - - - final VastTracker tracker2 = untriggeredTrackers.get(2); - assertThat(tracker2).isExactlyInstanceOf(VastFractionalProgressTracker.class); - assertThat(((VastFractionalProgressTracker) tracker2).trackingFraction()).isEqualTo(0.25f); - - final VastTracker tracker3 = untriggeredTrackers.get(3); - assertThat(tracker3).isExactlyInstanceOf(VastFractionalProgressTracker.class); - assertThat(((VastFractionalProgressTracker) tracker3).trackingFraction()).isEqualTo(0.5f); - - final VastTracker tracker4 = untriggeredTrackers.get(4); - assertThat(tracker4).isExactlyInstanceOf(VastFractionalProgressTracker.class); - assertThat(((VastFractionalProgressTracker) tracker4).trackingFraction()).isEqualTo(0.75f); - } - - @Test - public void getUntriggeredTrackersBefore_withTriggeredTrackers_shouldNotReturnTriggered() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( - Arrays.asList(new VastFractionalProgressTracker("first", 0.25f), - new VastFractionalProgressTracker("second", 0.5f), - new VastFractionalProgressTracker("third", 0.75f))); - vastVideoConfiguration.addAbsoluteTrackers( - Arrays.asList(new VastAbsoluteProgressTracker("5secs", 5000), - new VastAbsoluteProgressTracker("10secs", 10000))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); - - initializeSubject(); - spyOnVideoView(); - setVideoViewParams(11000, 11000); - - final List untriggeredTrackers = subject.getUntriggeredTrackersBefore(11000, 11000); - assertThat(untriggeredTrackers).hasSize(5); - untriggeredTrackers.get(0).setTracked(); - - final List secondTrackersList = subject.getUntriggeredTrackersBefore(11000, 11000); - assertThat(secondTrackersList).hasSize(4); - } - @Test public void videoRunnablesRun_whenDurationIsInvalid_shouldNotMakeAnyNetworkCalls() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1592,11 +1544,11 @@ public void videoRunnablesRun_whenDurationIsInvalid_shouldNotMakeAnyNetworkCalls @Test public void videoRunnablesRun_whenCurrentTimeLessThanTwoSeconds_shouldNotFireStartTracker() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addAbsoluteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addAbsoluteTrackers( Arrays.asList(new VastAbsoluteProgressTracker("start", 2000))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1621,14 +1573,14 @@ public void videoRunnablesRun_whenCurrentTimeLessThanTwoSeconds_shouldNotFireSta @Test public void videoRunnablesRun_whenCurrentTimeGreaterThanTwoSeconds_shouldFireStartTracker() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addAbsoluteTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addAbsoluteTrackers( Arrays.asList(new VastAbsoluteProgressTracker("start" + MACRO_TAGS, 2000))); - vastVideoConfiguration.addAbsoluteTrackers( + vastVideoConfig.addAbsoluteTrackers( Arrays.asList(new VastAbsoluteProgressTracker("later" + MACRO_TAGS, 3000))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1650,14 +1602,14 @@ public void videoRunnablesRun_whenCurrentTimeGreaterThanTwoSeconds_shouldFireSta @Test public void videoRunnablesRun_whenProgressIsPastFirstQuartile_shouldOnlyPingFirstQuartileTrackersOnce() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f))); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("don't call" + MACRO_TAGS, 0.28f))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1680,14 +1632,14 @@ public void videoRunnablesRun_whenProgressIsPastFirstQuartile_shouldOnlyPingFirs @Test public void videoRunnablesRun_whenProgressIsPastMidQuartile_shouldPingFirstQuartileTrackers_andMidQuartileTrackersBothOnlyOnce() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f))); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("second" + MACRO_TAGS, 0.5f))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1710,16 +1662,16 @@ public void videoRunnablesRun_whenProgressIsPastMidQuartile_shouldPingFirstQuart @Test public void videoRunnablesRun_whenProgressIsPastThirdQuartile_shouldPingFirstQuartileTrackers_andMidQuartileTrackers_andThirdQuartileTrackersAllOnlyOnce() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f))); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("second" + MACRO_TAGS, 0.5f))); - vastVideoConfiguration.addFractionalTrackers( + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("third" + MACRO_TAGS, 0.75f))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1746,14 +1698,14 @@ public void videoRunnablesRun_whenProgressIsPastThirdQuartile_shouldPingFirstQua public void videoRunnablesRun_asVideoPlays_shouldPingAllThreeTrackersIndividuallyOnce() throws Exception { //stub(mockMediaPlayer.getDuration()).toReturn(100); - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setNetworkMediaFileUrl("video_url"); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.addFractionalTrackers( + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setNetworkMediaFileUrl("video_url"); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.addFractionalTrackers( Arrays.asList(new VastFractionalProgressTracker("first" + MACRO_TAGS, 0.25f))); - vastVideoConfiguration.addFractionalTrackers(Arrays.asList(new VastFractionalProgressTracker("second" + MACRO_TAGS, 0.5f))); - vastVideoConfiguration.addFractionalTrackers(Arrays.asList(new VastFractionalProgressTracker("third" + MACRO_TAGS, 0.75f))); - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + vastVideoConfig.addFractionalTrackers(Arrays.asList(new VastFractionalProgressTracker("second" + MACRO_TAGS, 0.5f))); + vastVideoConfig.addFractionalTrackers(Arrays.asList(new VastFractionalProgressTracker("third" + MACRO_TAGS, 0.75f))); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1812,10 +1764,10 @@ public void videoRunnablesRun_whenCurrentPositionIsGreaterThanShowCloseButtonDel @Test public void videoRunnablesRun_whenCurrentPositionIsGreaterThanSkipOffset_shouldShowCloseButton() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("25%"); // skipoffset is at 2.5s - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("25%"); // skipoffset is at 2.5s + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1836,10 +1788,10 @@ public void videoRunnablesRun_whenCurrentPositionIsGreaterThanSkipOffset_shouldS @Test public void videoRunnablesRun_whenCurrentPositionIsLessThanSkipOffset_shouldNotShowCloseButton() throws Exception { - VastVideoConfiguration vastVideoConfiguration = new VastVideoConfiguration(); - vastVideoConfiguration.setDiskMediaFileUrl("disk_video_path"); - vastVideoConfiguration.setSkipOffset("00:00:03"); // skipoffset is at 3s - bundle.putSerializable(VAST_VIDEO_CONFIGURATION, vastVideoConfiguration); + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setSkipOffset("00:00:03"); // skipoffset is at 3s + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); initializeSubject(); spyOnVideoView(); @@ -1879,6 +1831,15 @@ public void onPause_shouldFirePauseTrackers() throws Exception { argThat(isUrl("pause?errorcode=&asseturi=video_url&contentplayhead=00:00:00.000"))); } + @Test + public void onPause_withIsClosingFlagSet_shouldNotFirePauseTrackers() throws Exception { + initializeSubject(); + subject.setIsClosing(true); + + subject.onPause(); + verifyNoMoreInteractions(mockRequestQueue); + } + @Test public void onResume_shouldStartRunnables() throws Exception { initializeSubject(); @@ -1902,23 +1863,6 @@ public void onResume_shouldSetVideoViewStateToStarted() throws Exception { assertThat(getShadowVideoView().getPrevVideoState()).isNotEqualTo(ShadowVideoView.START); } - @Config(reportSdk = VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - @Test - public void onResume_shouldResetVideoRetryCountToZero() throws Exception { - File file = new File("disk_video_path"); - file.createNewFile(); - - initializeSubject(); - - assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE)).isTrue(); - assertThat(subject.getVideoRetries()).isEqualTo(1); - - subject.onResume(); - assertThat(subject.getVideoRetries()).isEqualTo(0); - - file.delete(); - } - @Test public void onResume_shouldSeekToPrePausedPosition() throws Exception { initializeSubject(); @@ -1946,13 +1890,107 @@ public void onResume_multipleTimes_shouldFirePauseResumeTrackersMultipleTimes() verify(mockRequestQueue).add(argThat(isUrl ("pause?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); - verify(mockRequestQueue).add(argThat(isUrl("resume?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); + verify(mockRequestQueue).add( + argThat(isUrl("resume?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); subject.onPause(); subject.onResume(); - verify(mockRequestQueue).add(argThat(isUrl("pause?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); - verify(mockRequestQueue).add(argThat(isUrl("resume?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); + verify(mockRequestQueue).add( + argThat(isUrl("pause?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); + verify(mockRequestQueue).add( + argThat(isUrl("resume?errorcode=&asseturi=video_url&contentplayhead=00:00:07.000"))); + } + + @Test + public void onConfigurationChanged_withPortraitCompanionAdVisible_withDeviceLandscape_shouldMakeLandscapeCompanionAdVisible() throws Exception { + initializeSubject(); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + subject.getPortraitCompanionAdView().setVisibility(View.VISIBLE); + + subject.onConfigurationChanged(null); + + assertThat(subject.getPortraitCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getLandscapeCompanionAdView().getVisibility()).isEqualTo(View.VISIBLE); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_1))); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_2))); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void onConfigurationChanged_withLandscapeCompanionAdVisible_withDevicePortrait_shouldMakePortraitCompanionAdVisible() throws Exception { + initializeSubject(); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + subject.getLandscapeCompanionAdView().setVisibility(View.VISIBLE); + + subject.onConfigurationChanged(null); + + assertThat(subject.getLandscapeCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getPortraitCompanionAdView().getVisibility()).isEqualTo(View.VISIBLE); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_3))); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void onConfigurationChanged_withPortraitCompanionAdVisible_withDevicePortrait_shouldKeepPortraitCompanionAdVisible() throws Exception { + initializeSubject(); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + subject.getPortraitCompanionAdView().setVisibility(View.VISIBLE); + + subject.onConfigurationChanged(null); + + assertThat(subject.getPortraitCompanionAdView().getVisibility()).isEqualTo(View.VISIBLE); + assertThat(subject.getLandscapeCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_3))); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void onConfigurationChanged_withNoCompanionAdVisible_shouldDoNothing() throws Exception { + initializeSubject(); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + + subject.onConfigurationChanged(null); + + assertThat(subject.getPortraitCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getLandscapeCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void onConfigurationChanged_whenCalledMultipleTimes_shouldOnlyEverFireEachCreativeViewTrackerOnce() throws Exception { + initializeSubject(); + subject.getPortraitCompanionAdView().setVisibility(View.VISIBLE); + + for(int i = 0; i < 10; i++) { + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; + subject.onConfigurationChanged(null); + context.getResources().getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT; + subject.onConfigurationChanged(null); + } + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_1))); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_2))); + verify(mockRequestQueue).add(argThat(isUrl(COMPANION_CREATIVE_VIEW_URL_3))); + verifyNoMoreInteractions(mockRequestQueue); + } + + @Test + public void onConfigurationChanged_withNoCompanionAd_shouldDoNothing() throws Exception { + VastVideoConfig vastVideoConfig = new VastVideoConfig(); + vastVideoConfig.setDiskMediaFileUrl("disk_video_path"); + vastVideoConfig.setNetworkMediaFileUrl("media_url"); + bundle.putSerializable(VAST_VIDEO_CONFIG, vastVideoConfig); + initializeSubject(); + + subject.onConfigurationChanged(null); + + verifyNoMoreInteractions(mockRequestQueue); + assertThat(subject.getLandscapeCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getLandscapeCompanionAdView().getWidth()).isEqualTo(0); + assertThat(subject.getLandscapeCompanionAdView().getHeight()).isEqualTo(0); + assertThat(subject.getPortraitCompanionAdView().getVisibility()).isEqualTo(View.INVISIBLE); + assertThat(subject.getPortraitCompanionAdView().getWidth()).isEqualTo(0); + assertThat(subject.getPortraitCompanionAdView().getHeight()).isEqualTo(0); } @Test @@ -2021,15 +2059,15 @@ public void onClickCloseButtonTextView_whenCloseButtonIsVisible_shouldFireCloseT public void createIconView_shouldLayoutAndReturnInvisibleVastIconView() throws Exception { initializeSubject(); - VastIcon vastIcon = mock(VastIcon.class); - when(vastIcon.getWidth()).thenReturn(40); - when(vastIcon.getHeight()).thenReturn(40); + VastIconConfig vastIconConfig = mock(VastIconConfig.class); + when(vastIconConfig.getWidth()).thenReturn(40); + when(vastIconConfig.getHeight()).thenReturn(40); VastResource vastResource = mock(VastResource.class); when(vastResource.getType()).thenReturn(VastResource.Type.STATIC_RESOURCE); when(vastResource.getResource()).thenReturn("static"); - when(vastIcon.getVastResource()).thenReturn(vastResource); + when(vastIconConfig.getVastResource()).thenReturn(vastResource); - VastWebView view = (VastWebView) subject.createIconView(context, vastIcon, View.INVISIBLE); + VastWebView view = (VastWebView) subject.createIconView(context, vastIconConfig, View.INVISIBLE); assertThat(view).isNotNull(); assertThat(view.getVisibility()).isEqualTo(View.INVISIBLE); @@ -2048,51 +2086,52 @@ public void createIconView_withNullVastIcon_shouldReturnEmptyView() throws Excep public void VastWebView_onVastWebViewClick_shouldCallVastIconHandleClick() throws Exception { initializeSubject(); - VastIcon vastIcon = mock(VastIcon.class); - when(vastIcon.getWidth()).thenReturn(40); - when(vastIcon.getHeight()).thenReturn(40); + VastIconConfig vastIconConfig = mock(VastIconConfig.class); + when(vastIconConfig.getWidth()).thenReturn(40); + when(vastIconConfig.getHeight()).thenReturn(40); VastResource vastResource = mock(VastResource.class); when(vastResource.getType()).thenReturn(VastResource.Type.STATIC_RESOURCE); when(vastResource.getResource()).thenReturn("static"); - when(vastIcon.getVastResource()).thenReturn(vastResource); + when(vastIconConfig.getVastResource()).thenReturn(vastResource); - VastWebView view = (VastWebView) subject.createIconView(context, vastIcon, View.INVISIBLE); + VastWebView view = (VastWebView) subject.createIconView(context, vastIconConfig, View.INVISIBLE); view.getVastWebViewClickListener().onVastWebViewClick(); - verify(vastIcon).handleClick(any(Context.class), anyString()); + verify(vastIconConfig).handleClick(any(Context.class), anyString()); } @Test public void handleIconDisplay_withCurrentPositionGreaterThanOffset_shouldSetIconToVisible_shouldCallHandleImpression() throws Exception { initializeSubject(); - when(mockVastIcon.getOffsetMS()).thenReturn(0); - when(mockVastIcon.getDurationMS()).thenReturn(1); + when(mMockVastIconConfig.getOffsetMS()).thenReturn(0); + when(mMockVastIconConfig.getDurationMS()).thenReturn(1); subject.handleIconDisplay(0); assertThat(subject.getIconView().getVisibility()).isEqualTo(View.VISIBLE); - verify(mockVastIcon).handleImpression(any(Context.class), eq(0), eq("video_url")); + verify(mMockVastIconConfig).handleImpression(any(Context.class), eq(0), eq("video_url")); } @Test public void handleIconDisplay_withCurrentPositionLessThanOffset_shouldReturn() throws Exception { initializeSubject(); - when(mockVastIcon.getOffsetMS()).thenReturn(1); + when(mMockVastIconConfig.getOffsetMS()).thenReturn(1); subject.handleIconDisplay(0); assertThat(subject.getIconView().getVisibility()).isEqualTo(View.INVISIBLE); - verify(mockVastIcon, never()).handleImpression(any(Context.class), eq(0), eq("video_url")); + verify(mMockVastIconConfig, never()).handleImpression(any(Context.class), eq(0), + eq("video_url")); } @Test public void handleIconDisplay_withCurrentPositionGreaterThanOffsetPlusDuration_shouldSetIconToGone() throws Exception { initializeSubject(); - when(mockVastIcon.getOffsetMS()).thenReturn(0); - when(mockVastIcon.getDurationMS()).thenReturn(1); + when(mMockVastIconConfig.getOffsetMS()).thenReturn(0); + when(mMockVastIconConfig.getDurationMS()).thenReturn(1); subject.handleIconDisplay(2); @@ -2110,8 +2149,9 @@ public void makeInteractable_shouldHideCountdownWidgetAndShowCtaAndCloseButtonWi } private void initializeSubject() throws IllegalAccessException { - subject = new VastVideoViewController(context, bundle, savedInstanceState, testBroadcastIdentifier, baseVideoViewControllerListener); - subject.setMediaMetadataRetriever(mockMediaMetadataRetriever); + subject = new VastVideoViewController((Activity) context, bundle, savedInstanceState, + testBroadcastIdentifier, baseVideoViewControllerListener); + subject.getVastVideoView().setMediaMetadataRetriever(mockMediaMetadataRetriever); spyOnRunnables(); } @@ -2136,8 +2176,8 @@ private void setVideoViewParams(int currentPosition, int duration) throws Illega when(spyVideoView.getDuration()).thenReturn(duration); } - private ShadowVideoView getShadowVideoView() { - return shadowOf(subject.getVideoView()); + private ShadowVastVideoView getShadowVideoView() { + return (ShadowVastVideoView) shadowOf_(subject.getVastVideoView()); } public static void assertHttpRequestsMade(final String userAgent, final String... urls) { diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewProgressRunnableTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewProgressRunnableTest.java index 8ba508247..1f5eabdb6 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewProgressRunnableTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewProgressRunnableTest.java @@ -31,12 +31,14 @@ public class VastVideoViewProgressRunnableTest { @Mock Context mockContext; @Mock Handler mockHandler; @Mock MoPubRequestQueue mockRequestQueue; + @Mock VastVideoConfig mockVideoConfig; @Captor ArgumentCaptor requestCaptor; VastVideoViewProgressRunnable subject; @Before public void setup() { - subject = new VastVideoViewProgressRunnable(mockVastVideoViewController, mockHandler); + subject = new VastVideoViewProgressRunnable(mockVastVideoViewController, mockVideoConfig, + mockHandler); // Request Queue needed to verify tracking requests made. Networking.setRequestQueueForTesting(mockRequestQueue); @@ -48,7 +50,7 @@ public void doWork_whenTrackersReturned_shouldMakeTrackingRequests() { testTrackers.add(new VastAbsoluteProgressTracker("http://example.com/", 1999)); testTrackers.add(new VastAbsoluteProgressTracker("http://example1.com/", 2000)); - when(mockVastVideoViewController.getUntriggeredTrackersBefore(eq(3000), eq(4000))) + when(mockVideoConfig.getUntriggeredTrackersBefore(eq(3000), eq(4000))) .thenReturn(testTrackers); when(mockVastVideoViewController.getCurrentPosition()).thenReturn(3000); when(mockVastVideoViewController.getDuration()).thenReturn(4000); @@ -56,7 +58,7 @@ public void doWork_whenTrackersReturned_shouldMakeTrackingRequests() { subject.doWork(); - verify(mockVastVideoViewController).getUntriggeredTrackersBefore(eq(3000), eq(4000)); + verify(mockVideoConfig).getUntriggeredTrackersBefore(eq(3000), eq(4000)); verify(mockVastVideoViewController).getCurrentPosition(); verify(mockVastVideoViewController).getDuration(); verify(mockVastVideoViewController).getContext(); @@ -78,7 +80,7 @@ public void doWork_whenTrackersReturned_shouldMakeTrackingRequests() { public void doWork_whenNoTrackersReturned_shouldNotMakeTrackingRequests() { List testTrackers = new ArrayList(); - when(mockVastVideoViewController.getUntriggeredTrackersBefore(eq(3000), eq(4000))) + when(mockVideoConfig.getUntriggeredTrackersBefore(eq(3000), eq(4000))) .thenReturn(testTrackers); when(mockVastVideoViewController.getCurrentPosition()).thenReturn(3000); when(mockVastVideoViewController.getDuration()).thenReturn(4000); @@ -86,7 +88,7 @@ public void doWork_whenNoTrackersReturned_shouldNotMakeTrackingRequests() { subject.doWork(); - verify(mockVastVideoViewController).getUntriggeredTrackersBefore(eq(3000), eq(4000)); + verify(mockVideoConfig).getUntriggeredTrackersBefore(eq(3000), eq(4000)); verify(mockVastVideoViewController).getCurrentPosition(); verify(mockVastVideoViewController).getDuration(); verify(mockVastVideoViewController).handleIconDisplay(eq(3000)); diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewTest.java new file mode 100644 index 000000000..064b8b787 --- /dev/null +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastVideoViewTest.java @@ -0,0 +1,194 @@ +package com.mopub.mobileads; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.os.AsyncTask; +import android.os.Build; + +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 org.robolectric.annotation.Config; + +import java.io.File; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(SdkTestRunner.class) +public class VastVideoViewTest { + + @Mock private MediaMetadataRetriever mockMediaMetadataRetriever; + @Mock private Bitmap mockBitmap; + + private Context context; + private VastVideoView subject; + + @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) + @Before + public void setUp() throws Exception { + context = Robolectric.buildActivity(Activity.class).create().get(); + subject = new VastVideoView(context); + subject.setMediaMetadataRetriever(mockMediaMetadataRetriever); + when(mockMediaMetadataRetriever.getFrameAtTime(anyLong(), anyInt())).thenReturn( + mockBitmap); + } + + @Test + public void onDestroy_withBlurLastVideoFrameTaskStillRunning_shouldCancelTask() throws Exception { + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock( + VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.RUNNING); + subject.setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask).cancel(true); + } + + @Test + public void onDestroy_withBlurLastVideoFrameTaskStillPending_shouldCancelTask() throws Exception { + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock( + VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.PENDING); + subject.setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask).cancel(true); + } + + @Test + public void onDestroy_withBlurLastVideoFrameTaskFinished_shouldNotCancelTask() throws Exception { + VastVideoBlurLastVideoFrameTask mockBlurLastVideoFrameTask = mock( + VastVideoBlurLastVideoFrameTask.class); + when(mockBlurLastVideoFrameTask.getStatus()).thenReturn(AsyncTask.Status.FINISHED); + subject.setBlurLastVideoFrameTask(mockBlurLastVideoFrameTask); + + subject.onDestroy(); + + verify(mockBlurLastVideoFrameTask, never()).cancel(anyBoolean()); + } + + + @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) + @Test + public void retryMediaPlayer_withVideoFilePermissionErrorAndBelowJellyBean_shouldReturnTrue() throws Exception { + File file = new File("disk_video_path"); + file.createNewFile(); + + assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, + Integer.MIN_VALUE, "disk_video_path")).isTrue(); + assertThat(subject.getVideoRetries()).isEqualTo(1); + + file.delete(); + } + + @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) + @Test + public void retryMediaPlayer_shouldNotRunMoreThanOnce() throws Exception { + File file = new File("disk_video_path"); + file.createNewFile(); + + assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, + Integer.MIN_VALUE, "disk_video_path")).isTrue(); + assertThat(subject.getVideoRetries()).isEqualTo(1); + + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, + Integer.MIN_VALUE, "disk_video_path")).isFalse(); + assertThat(subject.getVideoRetries()).isEqualTo(1); + + file.delete(); + } + + @Config(reportSdk = Build.VERSION_CODES.JELLY_BEAN) + @Test + public void retryMediaPlayer_withAndroidVersionAboveJellyBean_shouldReturnFalse() throws Exception { + File file = new File("disk_video_path"); + file.createNewFile(); + + assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE, + "disk_video_path")).isFalse(); + assertThat(subject.getVideoRetries()).isEqualTo(0); + + file.delete(); + } + + @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Test + public void retryMediaPlayer_withOtherVideoError_shouldReturnFalse() throws Exception { + File file = new File("disk_video_path"); + file.createNewFile(); + + assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 2, Integer.MIN_VALUE, + "disk_video_path")).isFalse(); + assertThat(subject.getVideoRetries()).isEqualTo(0); + + file.delete(); + } + + @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Test + public void retryMediaPlayer_withExceptionThrown_shouldReturnFalseAndIncrementRetryCount() throws Exception { + File file = new File("disk_video_path"); + if (file.exists()) { + assertThat(file.delete()).isTrue(); + } + + assertThat(subject.getVideoRetries()).isEqualTo(0); + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE, + "disk_video_path")).isFalse(); + assertThat(subject.getVideoRetries()).isEqualTo(1); + } + + @Config(reportSdk = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) + @Test + public void onResume_shouldResetVideoRetryCountToZero() throws Exception { + File file = new File("disk_video_path"); + file.createNewFile(); + + assertThat(subject.retryMediaPlayer(new MediaPlayer(), 1, Integer.MIN_VALUE, + "disk_video_path")).isTrue(); + assertThat(subject.getVideoRetries()).isEqualTo(1); + + subject.onResume(); + assertThat(subject.getVideoRetries()).isEqualTo(0); + + file.delete(); + } + + @Config(reportSdk = Build.VERSION_CODES.GINGERBREAD) + @Test + public void createMediaMetadataRetriever_beforeGingerbreadMr1_shouldReturnNull() throws Exception { + MediaMetadataRetriever mediaMetadataRetriever = subject.createMediaMetadataRetriever(); + + assertThat(mediaMetadataRetriever).isNull(); + } + + @Config(reportSdk = Build.VERSION_CODES.GINGERBREAD_MR1) + @Test + public void createMediaMetadataRetriever_atLeastGingerbreadMr1_shouldReturnNewMediaMetadataRetriever() throws Exception { + MediaMetadataRetriever mediaMetadataRetriever = subject.createMediaMetadataRetriever(); + + assertThat(mediaMetadataRetriever).isNotNull(); + assertThat(mediaMetadataRetriever).isInstanceOf(MediaMetadataRetriever.class); + } +} diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastWebViewTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastWebViewTest.java index 76a615091..3ee435f11 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastWebViewTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastWebViewTest.java @@ -106,14 +106,14 @@ public void VastWebViewOnTouchListener_withActionDown_withActionUp_shouldCallOnV @Test public void createView_shouldInitializeAndReturnView() throws Exception { - VastIcon vastIcon = new VastIcon(123, 456, 789, 101, + VastIconConfig vastIconConfig = new VastIconConfig(123, 456, 789, 101, mockResource, VastUtils.stringsToVastTrackers("clickTrackerOne", "clickTrackerTwo"), "clickThroughUri", VastUtils.stringsToVastTrackers("viewTrackerOne", "viewTrackerTwo") ); - WebView webView = subject.createView(context, vastIcon.getVastResource()); + WebView webView = subject.createView(context, vastIconConfig.getVastResource()); assertThat(webView).isNotNull(); verify(mockResource).initializeWebView(any(VastWebView.class)); } diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/VastXmlManagerAggregatorTest.java b/mopub-sdk/src/test/java/com/mopub/mobileads/VastXmlManagerAggregatorTest.java index 204871212..e74a94ccf 100644 --- a/mopub-sdk/src/test/java/com/mopub/mobileads/VastXmlManagerAggregatorTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/VastXmlManagerAggregatorTest.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Point; import android.view.Display; import android.view.WindowManager; @@ -88,7 +89,7 @@ public class VastXmlManagerAggregatorTest { " " + " " + " " + - " " + + " " + " " + " http://wrapperCompanionAdStaticResource" + " " + @@ -99,7 +100,7 @@ public class VastXmlManagerAggregatorTest { " http://wrapperCompanionClickThrough" + " " + " " + - " " + + " " + " " + " http://firstNoResourceWrapperCompanionCreativeView" + " http://secondNoResourceWrapperCompanionCreativeView" + @@ -270,7 +271,7 @@ public class VastXmlManagerAggregatorTest { private Semaphore semaphore; private VastXmlManagerAggregatorListener vastXmlManagerAggregatorListener; private VastXmlManagerAggregator subject; - private VastVideoConfiguration vastVideoConfiguration; + private VastVideoConfig mVastVideoConfig; @Mock MoPubRequestQueue mockRequestQueue; @@ -288,11 +289,11 @@ public void setup() { @Override public Object answer(InvocationOnMock invocationOnMock) throws Throwable { Object[] args = invocationOnMock.getArguments(); - VastXmlManagerAggregatorTest.this.vastVideoConfiguration = (VastVideoConfiguration) args[0]; + VastXmlManagerAggregatorTest.this.mVastVideoConfig = (VastVideoConfig) args[0]; semaphore.release(); return null; } - }).when(vastXmlManagerAggregatorListener).onAggregationComplete(any(VastVideoConfiguration.class)); + }).when(vastXmlManagerAggregatorListener).onAggregationComplete(any(VastVideoConfig.class)); // Always assume landscape (where width > height) since videos will always be played in this orientation int screenWidth = 800; @@ -316,7 +317,7 @@ public void doInBackground_shouldNotFollowRedirectsOnceTheLimitHasBeenReached() subject.execute(TEST_VAST_XML_STRING); semaphore.acquire(); - assertThat(vastVideoConfiguration).isNull(); + assertThat(mVastVideoConfig).isNull(); } @Test @@ -329,9 +330,9 @@ public void doInBackground_shouldFollowMaxRedirectsMinusOne() throws Exception { subject.execute(TEST_VAST_XML_STRING); semaphore.acquire(); - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo("https://s3" + + assertThat(mVastVideoConfig.getNetworkMediaFileUrl()).isEqualTo("https://s3" + ".amazonaws.com/mopub-vast/tapad-video.mp4"); - assertThat(vastVideoConfiguration.getClickThroughUrl()).isEqualTo("http://rtb-test.dev" + + assertThat(mVastVideoConfig.getClickThroughUrl()).isEqualTo("http://rtb-test.dev" + ".tapad.com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMj" + "AwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTN" + "BMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxh" + @@ -342,9 +343,9 @@ public void doInBackground_shouldFollowMaxRedirectsMinusOne() throws Exception { "PUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3" + "D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad." + "com"); - assertThat(vastVideoConfiguration.getImpressionTrackers().size()).isEqualTo(4 * + assertThat(mVastVideoConfig.getImpressionTrackers().size()).isEqualTo(4 * VastXmlManagerAggregator.MAX_TIMES_TO_FOLLOW_VAST_REDIRECT + 1); - assertThat(vastVideoConfiguration.getFractionalTrackers().size()).isEqualTo(3 * + assertThat(mVastVideoConfig.getFractionalTrackers().size()).isEqualTo(3 * VastXmlManagerAggregator.MAX_TIMES_TO_FOLLOW_VAST_REDIRECT); } @@ -431,9 +432,11 @@ public void getBestMediaFileUrl_withSameAspectRatios_shouldReturnUrlWithAreaClos // Triple screen size final VastMediaXmlManager mediaXmlManager1 = initializeMediaXmlManagerMock(2400, 1440, "video/mp4", "video_url1"); // Half screen size - final VastMediaXmlManager mediaXmlManager2 = initializeMediaXmlManagerMock(400, 240, "video/mp4", "video_url2"); + final VastMediaXmlManager mediaXmlManager2 = initializeMediaXmlManagerMock(400, 240, + "video/mp4", "video_url2"); - String bestMediaFileUrl = subject.getBestMediaFileUrl(Arrays.asList(mediaXmlManager1, mediaXmlManager2)); + String bestMediaFileUrl = subject.getBestMediaFileUrl( + Arrays.asList(mediaXmlManager1, mediaXmlManager2)); assertThat(bestMediaFileUrl).isEqualTo("video_url2"); } @@ -451,7 +454,8 @@ public void getBestMediaFileUrl_withSameArea_shouldReturnUrlWithAspectRatioClose final VastMediaXmlManager mediaXmlManager2 = initializeMediaXmlManagerMock(240, 400, "video/mp4", "video_url2"); - String bestMediaFileUrl = subject.getBestMediaFileUrl(Arrays.asList(mediaXmlManager1, mediaXmlManager2)); + String bestMediaFileUrl = subject.getBestMediaFileUrl( + Arrays.asList(mediaXmlManager1, mediaXmlManager2)); assertThat(bestMediaFileUrl).isEqualTo("video_url1"); } @@ -465,9 +469,11 @@ public void getBestMediaFileUrl_withInvalidMediaTypeAndNullDimension_shouldRetur // Invalid media type final VastMediaXmlManager mediaXmlManager1 = initializeMediaXmlManagerMock(800, 480, "video/invalid", "video_url1"); // Null dimension - final VastMediaXmlManager mediaXmlManager2 = initializeMediaXmlManagerMock(null, null, "video/mp4", "video_url2"); + final VastMediaXmlManager mediaXmlManager2 = initializeMediaXmlManagerMock(null, null, + "video/mp4", "video_url2"); - String bestMediaFileUrl = subject.getBestMediaFileUrl(Arrays.asList(mediaXmlManager1, mediaXmlManager2)); + String bestMediaFileUrl = subject.getBestMediaFileUrl( + Arrays.asList(mediaXmlManager1, mediaXmlManager2)); assertThat(bestMediaFileUrl).isNull(); } @@ -492,8 +498,9 @@ public void getBestCompanionAd_shouldReturnCompanionAd() throws Exception { final VastCompanionAdXmlManager companionXmlManager = initializeCompanionXmlManagerMock( 300, 250, "image_url", "image/jpeg", null, null); - final VastCompanionAd bestCompanionAd = - subject.getBestCompanionAd(Arrays.asList(companionXmlManager)); + final VastCompanionAdConfig bestCompanionAd = + subject.getBestCompanionAd(Arrays.asList(companionXmlManager), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertCompanionAdsAreEqual(companionXmlManager, bestCompanionAd); } @@ -502,8 +509,9 @@ public void getBestCompanionAd_withInvalidVastResource_shouldReturnNull() throws final VastCompanionAdXmlManager companionXmlManager = initializeCompanionXmlManagerMock( 300, 250, "image_url", "image/INVALID", null, null); - final VastCompanionAd bestCompanionAd = - subject.getBestCompanionAd(Arrays.asList(companionXmlManager)); + final VastCompanionAdConfig bestCompanionAd = + subject.getBestCompanionAd(Arrays.asList(companionXmlManager), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd).isNull(); } @@ -512,25 +520,31 @@ public void getBestCompanionAd_withNullDimension_shouldReturnNull() throws Excep final VastCompanionAdXmlManager companionXmlManager = initializeCompanionXmlManagerMock(null, 250, "image_url", "image/png", null, null); - final VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager)); + final VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd).isNull(); } @Test - public void getBestCompanionAd_withZeroDimension_shouldReturnNull() throws Exception { + public void getBestCompanionAd_withWidthTooSmall_shouldReturnNull() throws Exception { final VastCompanionAdXmlManager companionXmlManager = - initializeCompanionXmlManagerMock(0, 250, "image_url", "image/png", null, null); + initializeCompanionXmlManagerMock(299, 250, "image_url", "image/png", null, null); - final VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager)); + final VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd).isNull(); } @Test - public void getBestCompanionAd_withNegativeDimension_shouldReturnNull() throws Exception { + public void getBestCompanionAd_withHeightTooSmall_shouldReturnNull() throws Exception { final VastCompanionAdXmlManager companionXmlManager = - initializeCompanionXmlManagerMock(-300, 250, "image_url", "image/png", null, null); + initializeCompanionXmlManagerMock(300, 249, "image_url", "image/png", null, null); - final VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager)); + final VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd).isNull(); } @@ -548,7 +562,9 @@ public void getBestCompanionAd_withSameAspectRatios_shouldReturnCompanionAdWithA final VastCompanionAdXmlManager companionXmlManager2 = initializeCompanionXmlManagerMock(1600, 960, "image_url2", "image/bmp", null, null); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager1, companionXmlManager2)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager1, companionXmlManager2), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("image_url2"); } @@ -564,14 +580,16 @@ public void getBestCompanionAd_withSameAspectRatios_shouldReturnCompanionAdWithA initializeCompanionXmlManagerMock(2400, 1440, "image_url1", "image/png", null, null); // Half screen size final VastCompanionAdXmlManager companionXmlManager2 = - initializeCompanionXmlManagerMock(400, 240, "image_url2", "image/bmp", null, null); + initializeCompanionXmlManagerMock(400, 250, "image_url2", "image/bmp", null, null); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager1, companionXmlManager2)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager1, companionXmlManager2), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("image_url2"); } @Test - public void getBestCompanionAd_withSameArea_shouldReturnCompanionAdWithAspectRatioCloserToScreenAspectRatio() throws Exception { + public void getBestCompanionAd_withSameArea_shouldReturnLandscapeCompanionAdWithAspectRatioCloserToScreenAspectRatio() throws Exception { // Default screen width is 480, height is 800 final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); assertThat(display.getWidth()).isEqualTo(480); @@ -579,29 +597,53 @@ public void getBestCompanionAd_withSameArea_shouldReturnCompanionAdWithAspectRat // Landscape final VastCompanionAdXmlManager companionXmlManager1 = - initializeCompanionXmlManagerMock(400, 240, "image_url1", "image/png", null, null); + initializeCompanionXmlManagerMock(400, 250, "image_url1", "image/png", null, null); // Portrait final VastCompanionAdXmlManager companionXmlManager2 = - initializeCompanionXmlManagerMock(240, 400, "image_url2", "image/bmp", null, null); + initializeCompanionXmlManagerMock(250, 400, "image_url2", "image/bmp", null, null); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd(Arrays.asList(companionXmlManager1, companionXmlManager2)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager1, companionXmlManager2), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("image_url1"); } + @Test + public void getBestCompanionAd_withSameArea_shouldReturnPortraitCompanionAdWithAspectRatioCloserToScreenAspectRatio() throws Exception { + // Default screen width is 480, height is 800 + final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + assertThat(display.getWidth()).isEqualTo(480); + assertThat(display.getHeight()).isEqualTo(800); + + // Landscape + final VastCompanionAdXmlManager companionXmlManager1 = + initializeCompanionXmlManagerMock(400, 300, "image_url1", "image/png", null, null); + // Portrait + final VastCompanionAdXmlManager companionXmlManager2 = + initializeCompanionXmlManagerMock(300, 400, "image_url2", "image/bmp", null, null); + + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager1, companionXmlManager2), + VastXmlManagerAggregator.CompanionOrientation.PORTRAIT); + assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("image_url2"); + } + @Test public void getBestCompanionAd_withAllThreeResourceTypes_shouldReturnStaticResourceType() throws Exception { // Static Resource final VastCompanionAdXmlManager companionXmlManager1 = - initializeCompanionXmlManagerMock(400, 240, "StaticResource", "image/png", null, null); + initializeCompanionXmlManagerMock(400, 250, "StaticResource", "image/png", null, + null); // HTML Resource final VastCompanionAdXmlManager companionXmlManager2 = - initializeCompanionXmlManagerMock(240, 400, null, null, null, "HTMLResource"); + initializeCompanionXmlManagerMock(250, 400, null, null, null, "HTMLResource"); // IFrame Resource final VastCompanionAdXmlManager companionXmlManager3 = - initializeCompanionXmlManagerMock(240, 400, null, null, "IFrameResource", null); + initializeCompanionXmlManagerMock(250, 400, null, null, "IFrameResource", null); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd( - Arrays.asList(companionXmlManager3, companionXmlManager2, companionXmlManager1)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager3, companionXmlManager2, companionXmlManager1), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("StaticResource"); } @@ -609,29 +651,51 @@ public void getBestCompanionAd_withAllThreeResourceTypes_shouldReturnStaticResou public void getBestCompanionAd_withHTMLAndStaticResourceTypes_shouldReturnStaticResourceType() throws Exception { // Static Resource final VastCompanionAdXmlManager companionXmlManager1 = - initializeCompanionXmlManagerMock(400, 240, "StaticResource", "image/png", null, null); + initializeCompanionXmlManagerMock(400, 250, "StaticResource", "image/png", null, null); // HTML Resource final VastCompanionAdXmlManager companionXmlManager2 = - initializeCompanionXmlManagerMock(240, 400, null, null, null, "HTMLResource"); + initializeCompanionXmlManagerMock(250, 400, null, null, null, "HTMLResource"); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd( - Arrays.asList(companionXmlManager2, companionXmlManager1)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager2, companionXmlManager1), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("StaticResource"); } @Test public void getBestCompanionAd_withInvalidStaticResource_withValidHtmlResource_shouldReturnHtmlResource() throws Exception { final VastCompanionAdXmlManager companionXmlManager1 = - initializeCompanionXmlManagerMock(400, 240, "StaticResource", "INVALID", + initializeCompanionXmlManagerMock(400, 250, "StaticResource", "INVALID", "IFrameResource", null); final VastCompanionAdXmlManager companionXmlManager2 = - initializeCompanionXmlManagerMock(240, 400, null, null, null, "HTMLResource"); + initializeCompanionXmlManagerMock(300, 400, null, null, null, "HTMLResource"); - VastCompanionAd bestCompanionAd = subject.getBestCompanionAd( - Arrays.asList(companionXmlManager2, companionXmlManager1)); + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager2, companionXmlManager1), + VastXmlManagerAggregator.CompanionOrientation.LANDSCAPE); assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("HTMLResource"); } + @Test + public void getBestCompanionAd_withCompanionAdTooSmall_shouldReturnCompanionAdWithAtLeastMinimumSize() throws Exception { + // Default screen width is 480, height is 800 + final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + assertThat(display.getWidth()).isEqualTo(480); + assertThat(display.getHeight()).isEqualTo(800); + + // 305 x 305 is both fewer pixels (screen area) and a worse aspect ratio. It still should be + // chosen because 240 is not wide enough to be considered for a companion ad + final VastCompanionAdXmlManager companionXmlManager1 = + initializeCompanionXmlManagerMock(305, 305, "image_url1", "image/png", null, null); + final VastCompanionAdXmlManager companionXmlManager2 = + initializeCompanionXmlManagerMock(240, 400, "image_url2", "image/bmp", null, null); + + VastCompanionAdConfig bestCompanionAd = subject.getBestCompanionAd( + Arrays.asList(companionXmlManager1, companionXmlManager2), + VastXmlManagerAggregator.CompanionOrientation.PORTRAIT); + assertThat(bestCompanionAd.getVastResource().getResource()).isEqualTo("image_url1"); + } + @Test public void getScaledDimensions_withWidthLargerThanScreen_shouldScaleWidthAndHeight() throws Exception { // Default screen width is 480, height is 800 @@ -713,7 +777,7 @@ public void getBestIcon_shouldReturnBestIcon() throws Exception { initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getWidth()).isEqualTo(40); assertThat(bestIcon.getHeight()).isEqualTo(50); assertThat(bestIcon.getOffsetMS()).isEqualTo(123); @@ -740,7 +804,7 @@ public void getBestIcon_withMissingWidth_shouldNotSelectThatIcon() throws Except null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -753,7 +817,7 @@ public void getBestIcon_withNegativeWidth_shouldNotSelectThatIcon() throws Excep initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -766,7 +830,7 @@ public void getBestIcon_withWidthGreaterThan300dp_shouldNotSelectThatIcon() thro initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -779,7 +843,7 @@ public void getBestIcon_withMissingHeight_shouldNotSelectThatIcon() throws Excep initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -792,7 +856,7 @@ public void getBestIcon_withNegativeHeight_shouldNotSelectThatIcon() throws Exce initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -805,7 +869,7 @@ public void getBestIcon_withHeightGreaterThan300dp_shouldNotSelectThatIcon() thr initializeIconXmlManagerMock(40, 40, null, null, "staticResource2", "image/png", null, null, new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager1, iconXmlManager2)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("staticResource2"); } @@ -821,7 +885,7 @@ public void getBestIcon_withAllThreeResourceTypes_shouldReturnStaticResourceType initializeIconXmlManagerMock(40, 40, null, null, null, null, null, "HTMLResource", new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager3, iconXmlManager2, + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager3, iconXmlManager2, iconXmlManager1)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("StaticResource"); } @@ -835,7 +899,7 @@ public void getBestIcon_withHTMLAndStaticResourceTypes_shouldReturnStaticResourc initializeIconXmlManagerMock(40, 40, null, null, null, null, null, "HTMLResource", new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager2, iconXmlManager1)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager2, iconXmlManager1)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("StaticResource"); } @@ -848,75 +912,81 @@ public void getBestIcon_withInvalidStaticResource_withValidHtmlResource_shouldRe initializeIconXmlManagerMock(40, 40, null, null, null, null, null, "HTMLResource", new ArrayList(), null, new ArrayList()); - VastIcon bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager2, iconXmlManager1)); + VastIconConfig bestIcon = subject.getBestIcon(Arrays.asList(iconXmlManager2, iconXmlManager1)); assertThat(bestIcon.getVastResource().getResource()).isEqualTo("HTMLResource"); } @Test public void evaluateVastXmlManager_withStandardInline_shouldReturnValidVastVideoConfiguration() { - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_NESTED_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getImpressionTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getImpressionTrackers())) .containsOnly("http://rtb-test.dev.tapad.com:8080/creative/imp" + ".png?ts=1374099035457&svid=1&creative_id=30731&ctx_type=InApp&ta_pinfo" + "=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&liverail_cp=1"); - assertThat(vastVideoConfiguration.getFractionalTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getAbsoluteTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getPauseTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getResumeTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getCompleteTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getCloseTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getSkipTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getClickTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getClickThroughUrl()).isEqualTo( + assertThat(vastVideoConfig.getFractionalTrackers()).isEmpty(); + assertThat(vastVideoConfig.getAbsoluteTrackers()).isEmpty(); + assertThat(vastVideoConfig.getPauseTrackers()).isEmpty(); + assertThat(vastVideoConfig.getResumeTrackers()).isEmpty(); + assertThat(vastVideoConfig.getCompleteTrackers()).isEmpty(); + assertThat(vastVideoConfig.getCloseTrackers()).isEmpty(); + assertThat(vastVideoConfig.getSkipTrackers()).isEmpty(); + assertThat(vastVideoConfig.getClickTrackers()).isEmpty(); + assertThat(vastVideoConfig.getClickThroughUrl()).isEqualTo( "http://rtb-test.dev.tapad" + ".com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo( + assertThat(vastVideoConfig.getNetworkMediaFileUrl()).isEqualTo( "https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); - assertThat(vastVideoConfiguration.getSkipOffset()).isNull(); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getErrorTrackers())) + assertThat(vastVideoConfig.getSkipOffsetString()).isNull(); + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getErrorTrackers())) .containsOnly("http://nestedInLineErrorOne", "http://nestedInLineErrorTwo"); - VastCompanionAd companionAd = vastVideoConfiguration.getVastCompanionAd(); - assertThat(companionAd.getWidth()).isEqualTo(300); - assertThat(companionAd.getHeight()).isEqualTo(250); - assertThat(companionAd.getVastResource().getResource()) - .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); - assertThat(companionAd.getVastResource().getType()) - .isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(companionAd.getVastResource().getCreativeType()) - .isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(companionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) - .containsOnly("http://companionClickTracking1", - "http://companionClickTracking2"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) - .containsExactly("http://myTrackingURL/firstCompanionCreativeView", - "http://myTrackingURL/secondCompanionCreativeView"); - - VastIcon vastIcon = vastVideoConfiguration.getVastIcon(); - assertThat(vastIcon.getWidth()).isEqualTo(123); - assertThat(vastIcon.getHeight()).isEqualTo(234); - assertThat(vastIcon.getDurationMS()).isEqualTo(3723456); - assertThat(vastIcon.getOffsetMS()).isEqualTo(3723000); - assertThat(vastIcon.getVastResource().getResource()).isEqualTo("imageJpeg"); - assertThat(vastIcon.getVastResource().getType()).isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(vastIcon.getVastResource().getCreativeType()).isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(VastUtils.vastTrackersToStrings(vastIcon.getClickTrackingUris())) + VastCompanionAdConfig[] companionAds = new VastCompanionAdConfig[2]; + companionAds[0] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_LANDSCAPE); + companionAds[1] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_PORTRAIT); + for (VastCompanionAdConfig companionAd : companionAds) { + assertThat(companionAd.getWidth()).isEqualTo(300); + assertThat(companionAd.getHeight()).isEqualTo(250); + assertThat(companionAd.getVastResource().getResource()) + .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); + assertThat(companionAd.getVastResource().getType()) + .isEqualTo(VastResource.Type.STATIC_RESOURCE); + assertThat(companionAd.getVastResource().getCreativeType()) + .isEqualTo(VastResource.CreativeType.IMAGE); + assertThat(companionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) + .containsOnly("http://companionClickTracking1", + "http://companionClickTracking2"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) + .containsExactly("http://myTrackingURL/firstCompanionCreativeView", + "http://myTrackingURL/secondCompanionCreativeView"); + } + + VastIconConfig vastIconConfig = vastVideoConfig.getVastIconConfig(); + assertThat(vastIconConfig.getWidth()).isEqualTo(123); + assertThat(vastIconConfig.getHeight()).isEqualTo(234); + assertThat(vastIconConfig.getDurationMS()).isEqualTo(3723456); + assertThat(vastIconConfig.getOffsetMS()).isEqualTo(3723000); + assertThat(vastIconConfig.getVastResource().getResource()).isEqualTo("imageJpeg"); + assertThat(vastIconConfig.getVastResource().getType()).isEqualTo(VastResource.Type.STATIC_RESOURCE); + assertThat(vastIconConfig.getVastResource().getCreativeType()).isEqualTo(VastResource.CreativeType.IMAGE); + assertThat(VastUtils.vastTrackersToStrings(vastIconConfig.getClickTrackingUris())) .containsOnly("clickTrackingUri1", "clickTrackingUri2"); - assertThat(vastIcon.getClickThroughUri()).isEqualTo("clickThroughUri"); - assertThat(VastUtils.vastTrackersToStrings(vastIcon.getViewTrackingUris())) + assertThat(vastIconConfig.getClickThroughUri()).isEqualTo("clickThroughUri"); + assertThat(VastUtils.vastTrackersToStrings(vastIconConfig.getViewTrackingUris())) .containsOnly("viewTrackingUri1", "viewTrackingUri2"); } @Test public void evaluateVastXmlManager_withAWrapperToAnInline_shouldReturnValidVastVideoConfiguration() { mFakeHttpLayer.addPendingHttpResponse(200, TEST_NESTED_VAST_XML_STRING); - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getImpressionTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getImpressionTrackers())) .containsOnly( "http://rtb-test.dev.tapad.com:8080/creative/imp" + ".png?ts=1374099035457&svid=1&creative_id=30731&ctx_type=InApp" + @@ -927,124 +997,137 @@ public void evaluateVastXmlManager_withAWrapperToAnInline_shouldReturnValidVastV "http://www.mopub.com/imp1", "http://www.mopub.com/imp2"); - assertThat(vastVideoConfiguration.getFractionalTrackers()).hasSize(3); + assertThat(vastVideoConfig.getFractionalTrackers()).hasSize(3); assertThat( - vastVideoConfiguration.getFractionalTrackers().get(0)).isEqualsToByComparingFields( + vastVideoConfig.getFractionalTrackers().get(0)).isEqualsToByComparingFields( new VastFractionalProgressTracker("http://myTrackingURL/wrapper/firstQuartile", 0.25f)); assertThat( - vastVideoConfiguration.getFractionalTrackers().get(1)).isEqualsToByComparingFields( + vastVideoConfig.getFractionalTrackers().get(1)).isEqualsToByComparingFields( new VastFractionalProgressTracker("http://myTrackingURL/wrapper/midpoint", 0.5f)); assertThat( - vastVideoConfiguration.getFractionalTrackers().get(2)).isEqualsToByComparingFields( + vastVideoConfig.getFractionalTrackers().get(2)).isEqualsToByComparingFields( new VastFractionalProgressTracker("http://myTrackingURL/wrapper/thirdQuartile", 0.75f)); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().size()).isEqualTo(2); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(0)).isEqualsToByComparingFields( + assertThat(vastVideoConfig.getAbsoluteTrackers().size()).isEqualTo(2); + assertThat(vastVideoConfig.getAbsoluteTrackers().get(0)).isEqualsToByComparingFields( new VastAbsoluteProgressTracker("http://myTrackingURL/wrapper/creativeView", 0)); - assertThat(vastVideoConfiguration.getAbsoluteTrackers().get(1)).isEqualsToByComparingFields( + assertThat(vastVideoConfig.getAbsoluteTrackers().get(1)).isEqualsToByComparingFields( new VastAbsoluteProgressTracker("http://myTrackingURL/wrapper/start", 2000)); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getPauseTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getPauseTrackers())) .containsOnly("http://myTrackingURL/wrapper/pause"); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getResumeTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getResumeTrackers())) .containsOnly("http://myTrackingURL/wrapper/resume"); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getCompleteTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getCompleteTrackers())) .containsOnly("http://myTrackingURL/wrapper/complete"); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getErrorTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getErrorTrackers())) .containsExactly( "http://wrapperErrorOne?errorcode=[ERRORCODE]", "http://wrapperErrorTwo?errorcode=[ERRORCODE]", "http://nestedInLineErrorOne", "http://nestedInLineErrorTwo"); - assertThat(vastVideoConfiguration.getCloseTrackers()).isEmpty(); - assertThat(vastVideoConfiguration.getSkipTrackers()).isEmpty(); + assertThat(vastVideoConfig.getCloseTrackers()).isEmpty(); + assertThat(vastVideoConfig.getSkipTrackers()).isEmpty(); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getClickTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getClickTrackers())) .containsOnly("http://myTrackingURL/wrapper/click"); - assertThat(vastVideoConfiguration.getClickThroughUrl()).isEqualTo( + assertThat(vastVideoConfig.getClickThroughUrl()).isEqualTo( "http://rtb-test.dev.tapad" + ".com:8080/click?ta_pinfo=JnRhX2JpZD1iNDczNTQwMS1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmaXA9OTguMTE2LjEyLjk0JnNzcD1MSVZFUkFJTCZ0YV9iaWRkZXJfaWQ9NTEzJTNBMzA1NSZjdHg9MTMzMSZ0YV9jYW1wYWlnbl9pZD01MTMmZGM9MTAwMjAwMzAyOSZ1YT1Nb3ppbGxhJTJGNS4wKyUyOE1hY2ludG9zaCUzQitJbnRlbCtNYWMrT1MrWCsxMF84XzMlMjkrQXBwbGVXZWJLaXQlMkY1MzcuMzYrJTI4S0hUTUwlMkMrbGlrZStHZWNrbyUyOStDaHJvbWUlMkYyNy4wLjE0NTMuMTE2K1NhZmFyaSUyRjUzNy4zNiZjcHQ9VkFTVCZkaWQ9ZDgyNWZjZDZlNzM0YTQ3ZTE0NWM4ZTkyNzMwMjYwNDY3YjY1NjllMSZpZD1iNDczNTQwMC1lZjJkLTExZTItYTNkNS0yMjAwMGE4YzEwOWQmcGlkPUNPTVBVVEVSJnN2aWQ9MSZicD0zNS4wMCZjdHhfdHlwZT1BJnRpZD0zMDU1JmNyaWQ9MzA3MzE%3D&crid=30731&ta_action_id=click&ts=1374099035458&redirect=http%3A%2F%2Ftapad.com"); - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo( + assertThat(vastVideoConfig.getNetworkMediaFileUrl()).isEqualTo( "https://s3.amazonaws.com/mopub-vast/tapad-video.mp4"); - assertThat(vastVideoConfiguration.getSkipOffset()).isNull(); - - VastCompanionAd companionAd = vastVideoConfiguration.getVastCompanionAd(); - assertThat(companionAd.getWidth()).isEqualTo(300); - assertThat(companionAd.getHeight()).isEqualTo(250); - assertThat(companionAd.getVastResource().getResource()) - .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); - assertThat(companionAd.getVastResource().getType()) - .isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(companionAd.getVastResource().getCreativeType()) - .isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(companionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) - .containsOnly("http://companionClickTracking1", - "http://companionClickTracking2", - "http://noResourceWrapperCompanionClickTracking1"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) - .containsExactly("http://myTrackingURL/firstCompanionCreativeView", - "http://myTrackingURL/secondCompanionCreativeView", - "http://firstNoResourceWrapperCompanionCreativeView", - "http://secondNoResourceWrapperCompanionCreativeView"); - - VastIcon vastIcon = vastVideoConfiguration.getVastIcon(); - assertThat(vastIcon.getWidth()).isEqualTo(123); - assertThat(vastIcon.getHeight()).isEqualTo(234); - assertThat(vastIcon.getDurationMS()).isEqualTo(3723456); - assertThat(vastIcon.getOffsetMS()).isEqualTo(3723000); - assertThat(vastIcon.getVastResource().getResource()).isEqualTo("imageJpeg"); - assertThat(vastIcon.getVastResource().getType()).isEqualTo(VastResource.Type.STATIC_RESOURCE); - assertThat(vastIcon.getVastResource().getCreativeType()).isEqualTo(VastResource.CreativeType.IMAGE); - assertThat(VastUtils.vastTrackersToStrings(vastIcon.getClickTrackingUris())) + assertThat(vastVideoConfig.getSkipOffsetString()).isNull(); + + VastCompanionAdConfig[] companionAds = new VastCompanionAdConfig[2]; + companionAds[0] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_LANDSCAPE); + companionAds[1] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_PORTRAIT); + for (VastCompanionAdConfig companionAd : companionAds) { + assertThat(companionAd.getWidth()).isEqualTo(300); + assertThat(companionAd.getHeight()).isEqualTo(250); + assertThat(companionAd.getVastResource().getResource()) + .isEqualTo("http://demo.tremormedia.com/proddev/vast/Blistex1.jpg"); + assertThat(companionAd.getVastResource().getType()) + .isEqualTo(VastResource.Type.STATIC_RESOURCE); + assertThat(companionAd.getVastResource().getCreativeType()) + .isEqualTo(VastResource.CreativeType.IMAGE); + assertThat(companionAd.getClickThroughUrl()).isEqualTo("http://www.tremormedia.com"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) + .containsOnly("http://companionClickTracking1", + "http://companionClickTracking2", + "http://noResourceWrapperCompanionClickTracking1"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) + .containsExactly("http://myTrackingURL/firstCompanionCreativeView", + "http://myTrackingURL/secondCompanionCreativeView", + "http://firstNoResourceWrapperCompanionCreativeView", + "http://secondNoResourceWrapperCompanionCreativeView"); + } + + VastIconConfig vastIconConfig = vastVideoConfig.getVastIconConfig(); + assertThat(vastIconConfig.getWidth()).isEqualTo(123); + assertThat(vastIconConfig.getHeight()).isEqualTo(234); + assertThat(vastIconConfig.getDurationMS()).isEqualTo(3723456); + assertThat(vastIconConfig.getOffsetMS()).isEqualTo(3723000); + assertThat(vastIconConfig.getVastResource().getResource()).isEqualTo("imageJpeg"); + assertThat(vastIconConfig.getVastResource().getType()).isEqualTo(VastResource.Type.STATIC_RESOURCE); + assertThat(vastIconConfig.getVastResource().getCreativeType()).isEqualTo(VastResource.CreativeType.IMAGE); + assertThat(VastUtils.vastTrackersToStrings(vastIconConfig.getClickTrackingUris())) .containsOnly("clickTrackingUri1", "clickTrackingUri2"); - assertThat(vastIcon.getClickThroughUri()).isEqualTo("clickThroughUri"); - assertThat(VastUtils.vastTrackersToStrings(vastIcon.getViewTrackingUris())) + assertThat(vastIconConfig.getClickThroughUri()).isEqualTo("clickThroughUri"); + assertThat(VastUtils.vastTrackersToStrings(vastIconConfig.getViewTrackingUris())) .containsOnly("viewTrackingUri1", "viewTrackingUri2"); } @Test public void evaluateVastXmlManager_withInvalidXml_shouldReturnNullVastVideoConfiguration() { - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_BAD_NEST_URL_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); } @Test public void evaluateVastXmlManager_withRedirectHavingNoCompanionAd_shouldReturnVastVideoConfigurationWithCompanionAdOfWrapper() { mFakeHttpLayer.addPendingHttpResponse(200, TEST_NESTED_NO_COMPANION_VAST_XML_STRING); - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - VastCompanionAd companionAd = vastVideoConfiguration.getVastCompanionAd(); - assertThat(companionAd.getWidth()).isEqualTo(456); - assertThat(companionAd.getHeight()).isEqualTo(123); - assertThat(companionAd.getVastResource().getResource()).isEqualTo("http" + - "://wrapperCompanionAdStaticResource"); - assertThat(companionAd.getClickThroughUrl()).isEqualTo("http://wrapperCompanionClickThrough"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) - .containsOnly("http://wrapperCompanionClickTracking"); - assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) - .containsExactly("http://firstWrapperCompanionCreativeView", - "http://secondWrapperCompanionCreativeView"); + VastCompanionAdConfig[] companionAds = new VastCompanionAdConfig[2]; + companionAds[0] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_LANDSCAPE); + companionAds[1] = vastVideoConfig.getVastCompanionAd( + Configuration.ORIENTATION_PORTRAIT); + for (VastCompanionAdConfig companionAd : companionAds) { + assertThat(companionAd.getWidth()).isEqualTo(456); + assertThat(companionAd.getHeight()).isEqualTo(250); + assertThat(companionAd.getVastResource().getResource()).isEqualTo("http" + + "://wrapperCompanionAdStaticResource"); + assertThat(companionAd.getClickThroughUrl()).isEqualTo( + "http://wrapperCompanionClickThrough"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getClickTrackers())) + .containsOnly("http://wrapperCompanionClickTracking"); + assertThat(VastUtils.vastTrackersToStrings(companionAd.getCreativeViewTrackers())) + .containsExactly("http://firstWrapperCompanionCreativeView", + "http://secondWrapperCompanionCreativeView"); + } } @Test public void evaluateVastXmlManager_withSequenceNumbers_shouldReturnVastVideoConfigurationWithNegativeSequenceNumber() { - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_WITH_NEGATIVE_SEQUENCE_NUMBER_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration.getNetworkMediaFileUrl()).isEqualTo( + assertThat(vastVideoConfig.getNetworkMediaFileUrl()).isEqualTo( "http://negativeSequence"); - assertThat(VastUtils.vastTrackersToStrings(vastVideoConfiguration.getImpressionTrackers())) + assertThat(VastUtils.vastTrackersToStrings(vastVideoConfig.getImpressionTrackers())) .containsOnly("http://negativeSequence"); } @@ -1090,11 +1173,11 @@ public void isValidSequenceNumber_withTwo_shouldReturnFalse() { @Test public void evaluateVastXmlManager_withJustError_shouldReturnNullVastVideoConfiguration_shouldFireErrorTracker() { - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_JUST_ERROR_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); verify(mockRequestQueue).add(argThat(isUrl("http://justErrorTracking?errorcode=900"))); verifyNoMoreInteractions(mockRequestQueue); } @@ -1102,10 +1185,10 @@ public void evaluateVastXmlManager_withJustError_shouldReturnNullVastVideoConfig @Test public void evaluateVastXmlManager_withWrapperToJustError_shouldReturnNullVastVideoConfiguration_shouldFireErrorTrackers() { mFakeHttpLayer.addPendingHttpResponse(200, TEST_JUST_ERROR_XML_STRING); - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); verify(mockRequestQueue).add(argThat(isUrl("http://justErrorTracking?errorcode=303"))); verifyNoMoreInteractions(mockRequestQueue); } @@ -1113,20 +1196,20 @@ public void evaluateVastXmlManager_withWrapperToJustError_shouldReturnNullVastVi @Test public void evaluateVastXmlManager_withWrapperToVastXmlError_shouldReturnNullVastVideoConfiguration_shouldFireErrorTracker() { mFakeHttpLayer.addPendingHttpResponse(200, TEST_INVALID_VAST_XML_STRING); - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); verifyNoMoreInteractions(mockRequestQueue); } @Test public void evaluateVastXmlManager_withWrapperToInvalidXml_shouldReturnNullVastVideoConfiguration_shouldFireErrorTracker() { mFakeHttpLayer.addPendingHttpResponse(200, TEST_INVALID_XML_STRING); - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); verify(mockRequestQueue).add(argThat(isUrl("http://wrapperErrorOne?errorcode=100"))); verify(mockRequestQueue).add(argThat(isUrl("http://wrapperErrorTwo?errorcode=100"))); verifyNoMoreInteractions(mockRequestQueue); @@ -1134,10 +1217,10 @@ public void evaluateVastXmlManager_withWrapperToInvalidXml_shouldReturnNullVastV @Test public void evaluateVastXmlManager_withWrapperToNoHttpResponse_shouldReturnNullVastVideoConfiguration_shouldFireErrorTracker() { - VastVideoConfiguration vastVideoConfiguration = subject.evaluateVastXmlManager( + VastVideoConfig vastVideoConfig = subject.evaluateVastXmlManager( TEST_VAST_XML_STRING, HttpClient.getHttpClient(), new ArrayList()); - assertThat(vastVideoConfiguration).isNull(); + assertThat(vastVideoConfig).isNull(); verify(mockRequestQueue).add(argThat(isUrl("http://wrapperErrorOne?errorcode=301"))); verify(mockRequestQueue).add(argThat(isUrl("http://wrapperErrorTwo?errorcode=301"))); verifyNoMoreInteractions(mockRequestQueue); @@ -1180,8 +1263,8 @@ private VastCompanionAdXmlManager initializeCompanionXmlManagerMock( private void assertCompanionAdsAreEqual( final VastCompanionAdXmlManager companionAdXmlManager, - final VastCompanionAd companionAd) { - final VastCompanionAd companionAd1 = new VastCompanionAd( + final VastCompanionAdConfig companionAd) { + final VastCompanionAdConfig companionAd1 = new VastCompanionAdConfig( companionAdXmlManager.getWidth(), companionAdXmlManager.getHeight(), VastResource.fromVastResourceXmlManager( @@ -1196,20 +1279,20 @@ private void assertCompanionAdsAreEqual( } private void assertCompanionAdsAreEqual( - final VastCompanionAd vastCompanionAd1, - final VastCompanionAd vastCompanionAd2) { - assertThat(vastCompanionAd1.getWidth()).isEqualTo(vastCompanionAd2.getWidth()); - assertThat(vastCompanionAd1.getHeight()).isEqualTo(vastCompanionAd2.getHeight()); - assertThat(vastCompanionAd1.getVastResource().getResource()) - .isEqualTo(vastCompanionAd2.getVastResource().getResource()); - assertThat(vastCompanionAd1.getVastResource().getType()) - .isEqualTo(vastCompanionAd2.getVastResource().getType()); - assertThat(vastCompanionAd1.getVastResource().getCreativeType()) - .isEqualTo(vastCompanionAd2.getVastResource().getCreativeType()); - assertThat(vastCompanionAd1.getClickThroughUrl()).isEqualTo(vastCompanionAd2.getClickThroughUrl()); - assertThat(vastCompanionAd1.getClickTrackers()).isEqualTo(vastCompanionAd2.getClickTrackers()); - assertThat(vastCompanionAd1.getCreativeViewTrackers()).isEqualTo( - vastCompanionAd2.getCreativeViewTrackers()); + final VastCompanionAdConfig vastCompanionAdConfig1, + final VastCompanionAdConfig vastCompanionAdConfig2) { + assertThat(vastCompanionAdConfig1.getWidth()).isEqualTo(vastCompanionAdConfig2.getWidth()); + assertThat(vastCompanionAdConfig1.getHeight()).isEqualTo(vastCompanionAdConfig2.getHeight()); + assertThat(vastCompanionAdConfig1.getVastResource().getResource()) + .isEqualTo(vastCompanionAdConfig2.getVastResource().getResource()); + assertThat(vastCompanionAdConfig1.getVastResource().getType()) + .isEqualTo(vastCompanionAdConfig2.getVastResource().getType()); + assertThat(vastCompanionAdConfig1.getVastResource().getCreativeType()) + .isEqualTo(vastCompanionAdConfig2.getVastResource().getCreativeType()); + assertThat(vastCompanionAdConfig1.getClickThroughUrl()).isEqualTo(vastCompanionAdConfig2.getClickThroughUrl()); + assertThat(vastCompanionAdConfig1.getClickTrackers()).isEqualTo(vastCompanionAdConfig2.getClickTrackers()); + assertThat(vastCompanionAdConfig1.getCreativeViewTrackers()).isEqualTo( + vastCompanionAdConfig2.getCreativeViewTrackers()); } private VastIconXmlManager initializeIconXmlManagerMock( diff --git a/mopub-sdk/src/test/java/com/mopub/mobileads/test/support/ShadowVastVideoView.java b/mopub-sdk/src/test/java/com/mopub/mobileads/test/support/ShadowVastVideoView.java new file mode 100644 index 000000000..b66c9708c --- /dev/null +++ b/mopub-sdk/src/test/java/com/mopub/mobileads/test/support/ShadowVastVideoView.java @@ -0,0 +1,10 @@ +package com.mopub.mobileads.test.support; + +import com.mopub.mobileads.VastVideoView; + +import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowVideoView; + +@Implements(VastVideoView.class) +public class ShadowVastVideoView extends ShadowVideoView { +} diff --git a/mopub-sdk/src/test/java/com/mopub/mraid/MraidControllerTest.java b/mopub-sdk/src/test/java/com/mopub/mraid/MraidControllerTest.java index bc6fce11e..be20f7065 100644 --- a/mopub-sdk/src/test/java/com/mopub/mraid/MraidControllerTest.java +++ b/mopub-sdk/src/test/java/com/mopub/mraid/MraidControllerTest.java @@ -516,10 +516,11 @@ public void handleOpen_withApplicationUrl_shouldStartNewIntent() { @Test public void handleOpen_withHttpApplicationUrl_shouldStartMoPubBrowser() { - String applicationUrl = "http://blah"; + String applicationUrl = "http://www.mopub.com/"; subject.handleOpen(applicationUrl); + Robolectric.runBackgroundTasks(); Intent startedIntent = Robolectric.getShadowApplication().getNextStartedActivity(); assertThat(startedIntent).isNotNull(); // Since we are not using an Activity context, we should have FLAG_ACTIVITY_NEW_TASK diff --git a/mopub-sdk/src/test/java/com/mopub/nativeads/ClickDestinationResolutionListenerTest.java b/mopub-sdk/src/test/java/com/mopub/nativeads/ClickDestinationResolutionListenerTest.java deleted file mode 100644 index 2cd79b4ce..000000000 --- a/mopub-sdk/src/test/java/com/mopub/nativeads/ClickDestinationResolutionListenerTest.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.mopub.nativeads; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.net.Uri; - -import com.mopub.common.MoPubBrowser; -import com.mopub.common.test.support.SdkTestRunner; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.Robolectric; - -import java.util.Iterator; - -import static org.fest.assertions.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(SdkTestRunner.class) -public class ClickDestinationResolutionListenerTest { - - private Activity context; - private Iterator mockIterator; - private SpinningProgressView mockSpinningProgressView; - private ClickDestinationResolutionListener subject; - - @Before - public void setUp() throws Exception { - context = spy(Robolectric.buildActivity(Activity.class).create().get()); - when(context.getApplicationContext()).thenReturn(context); - when(context.getPackageName()).thenReturn("testPackageName"); - mockIterator = mock(Iterator.class); - mockSpinningProgressView = mock(SpinningProgressView.class); - - subject = new ClickDestinationResolutionListener(context, mockIterator, - mockSpinningProgressView); - } - - @Test - public void onSuccess_withMoPubNativeBrowserUrl_shouldOpenExternalBrowserAndHideProgressView() { - subject.onSuccess("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); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withMalformedMoPubNativeBrowserUrl_shouldHideProgressViewButNotOpenExternalBrowser() { - // url2 is the wrong query parameter - subject.onSuccess("mopubnativebrowser://navigate?url2=https%3A%2F%2Fwww.example.com"); - - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withDeepLinkThatIsResolvable_shouldStartActionViewIntent_shouldRemoveSpinningProgressView() { - String deepLinkUrl = "appscheme://host"; - Robolectric.packageManager.addResolveInfoForIntent(new Intent(Intent.ACTION_VIEW, - Uri.parse(deepLinkUrl)), new ResolveInfo()); - - subject.onSuccess(deepLinkUrl); - - Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); - assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW); - assertThat(intent.getDataString()).isEqualTo("appscheme://host"); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withDeepLinkThatIsUnresolvable_shouldNotStartNewIntent_shouldRemoveSpinningProgressView() { - String deepLinkUrl = "appscheme://host"; - // don't add any relevant ResolveInfos to the Robolectric packageManager - - subject.onSuccess(deepLinkUrl); - - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withAppStoreUrl_shouldStartAppStoreIntent_shouldRemoveSpinningProgressView() { - final String appStoreUrl = "play.google.com/"; - Robolectric.packageManager.addResolveInfoForIntent(new Intent(Intent.ACTION_VIEW, - Uri.parse(appStoreUrl)), new ResolveInfo()); - - subject.onSuccess(appStoreUrl); - - Intent intent = Robolectric.getShadowApplication().getNextStartedActivity(); - assertThat(intent.getAction()).isEqualTo(Intent.ACTION_VIEW); - assertThat(intent.getDataString()).isEqualTo(appStoreUrl); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withHttpUrl_showOpenInMoPubBrowser_shouldRemoveSpinningProgressViewFromRoot() { - String httpUrl = "http://www.dotcom.com"; - - subject.onSuccess(httpUrl); - - ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(context).startActivity(intentCaptor.capture()); - - Intent intent = intentCaptor.getValue(); - - assertThat(intent.getComponent().getPackageName()).isEqualTo("testPackageName"); - assertThat(intent.getComponent().getClassName()).isEqualTo("com.mopub.common.MoPubBrowser"); - assertThat(intent.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)).isEqualTo(httpUrl); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withHttpsUrl_showOpenInMoPubBrowser_shouldRemoveSpinningProgressViewFromRoot() { - String httpsUrl = "https://www.comdot.com"; - - subject.onSuccess(httpsUrl); - - ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(context).startActivity(intentCaptor.capture()); - - Intent intent = intentCaptor.getValue(); - - assertThat(intent.getComponent().getPackageName()).isEqualTo("testPackageName"); - assertThat(intent.getComponent().getClassName()).isEqualTo("com.mopub.common.MoPubBrowser"); - assertThat(intent.getStringExtra(MoPubBrowser.DESTINATION_URL_KEY)).isEqualTo(httpsUrl); - verify(mockSpinningProgressView).removeFromRoot(); - } - - @Test - public void onSuccess_withAboutBlankUrl_shouldFailSilently_shouldRemoveSpinningProgressView() { - String url = "about:blank"; - - subject.onSuccess(url); - - assertThat(Robolectric.getShadowApplication().getNextStartedActivity()).isNull(); - verify(mockSpinningProgressView).removeFromRoot(); - } -} diff --git a/mopub-sdk/src/test/java/com/mopub/nativeads/NativeResponseTest.java b/mopub-sdk/src/test/java/com/mopub/nativeads/NativeResponseTest.java index 3ebefbe8c..0bbde8942 100644 --- a/mopub-sdk/src/test/java/com/mopub/nativeads/NativeResponseTest.java +++ b/mopub-sdk/src/test/java/com/mopub/nativeads/NativeResponseTest.java @@ -49,10 +49,15 @@ public class NativeResponseTest { private boolean baseNativeAdIsClicked; @Mock private MoPubRequestQueue mockRequestQueue; + private SpinningProgressView mockSpinningProgressView; @Before public void setUp() throws Exception { + setupWithClickUrl("clickDestinationUrl"); + } + + private void setupWithClickUrl(String clickUrl) { context = Robolectric.buildActivity(Activity.class).create().get(); mNativeAd = new BaseForwardingNativeAd() { @Override @@ -69,7 +74,7 @@ public void handleClick(@NonNull final View view) { mNativeAd.setText("text"); mNativeAd.setMainImageUrl("mainImageUrl"); mNativeAd.setIconImageUrl("iconImageUrl"); - mNativeAd.setClickDestinationUrl("clickDestinationUrl"); + mNativeAd.setClickDestinationUrl(clickUrl); mNativeAd.setCallToAction("callToAction"); mNativeAd.addExtra("extra", "extraValue"); mNativeAd.addExtra("extraImage", "extraImageUrl"); @@ -92,6 +97,8 @@ public void handleClick(@NonNull final View view) { "moPubImpressionTrackerUrl", "moPubClickTrackerUrl", "adunit_id", mMockNativeAd, moPubNativeListener); + + mockSpinningProgressView = mock(SpinningProgressView.class); } @Test @@ -279,6 +286,45 @@ public void handleClick_withBaseNativeAdClickDestinationUrl_shouldRecordClickAnd // Really difficult to test url resolution since it doesn't use the apache http client } + @Test + public void handleClick_shouldShowSpinner_shouldRemoveSpinner_WhenSucceeded() { + setupWithClickUrl("http://www.mopub.com"); + + Robolectric.getBackgroundScheduler().pause(); + + subject.handleClick(view, mockSpinningProgressView); + + verify(mockSpinningProgressView).addToRoot(view); + Robolectric.getBackgroundScheduler().unPause(); + verify(mockSpinningProgressView).removeFromRoot(); + } + + @Test + public void handleClick_shouldShowSpinner_shouldRemoveSpinner_WhenFailed() { + setupWithClickUrl(""); + + Robolectric.getBackgroundScheduler().pause(); + + subject.handleClick(view, mockSpinningProgressView); + + verify(mockSpinningProgressView).addToRoot(view); + Robolectric.getBackgroundScheduler().unPause(); + verify(mockSpinningProgressView).removeFromRoot(); + } + + @Test + public void handleClick_withNullView_shouldNotShowSpinner() { + setupWithClickUrl("http://www.mopub.com"); + + Robolectric.getBackgroundScheduler().pause(); + + subject.handleClick(null, mockSpinningProgressView); + + verify(mockSpinningProgressView, never()).addToRoot(view); + Robolectric.getBackgroundScheduler().unPause(); + verify(mockSpinningProgressView, never()).removeFromRoot(); + } + @Test public void handleClick_whenDestroyed_shouldReturnFast() { subject.destroy(); diff --git a/mopub-sdk/src/test/java/com/mopub/network/NetworkingTest.java b/mopub-sdk/src/test/java/com/mopub/network/NetworkingTest.java index 3153aa6f7..625c8a8cf 100644 --- a/mopub-sdk/src/test/java/com/mopub/network/NetworkingTest.java +++ b/mopub-sdk/src/test/java/com/mopub/network/NetworkingTest.java @@ -68,4 +68,11 @@ public void run() { semaphore.acquire(); assertThat(sUserAgent).isEqualTo("system level user agent"); } + + public void getCachedUserAgent_usesCachedUserAgent() { + Networking.setUserAgentForTesting("some cached user agent"); + String userAgent = Networking.getCachedUserAgent(); + + assertThat(userAgent).isEqualTo("some cached user agent"); + } } diff --git a/mopub-sdk/src/test/resources/org.robolectric.Config.properties b/mopub-sdk/src/test/resources/org.robolectric.Config.properties index ad8e27b61..973e581ed 100644 --- a/mopub-sdk/src/test/resources/org.robolectric.Config.properties +++ b/mopub-sdk/src/test/resources/org.robolectric.Config.properties @@ -1,2 +1,2 @@ emulateSdk=18 -shadows=com.mopub.nativeads.test.support.MoPubShadowDisplay,com.mopub.nativeads.test.support.MoPubShadowBitmap +shadows=com.mopub.nativeads.test.support.MoPubShadowDisplay,com.mopub.nativeads.test.support.MoPubShadowBitmap,com.mopub.mobileads.test.support.ShadowVastVideoView