diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 9c2988745..61ddced28 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,11 @@ +## 8.8 + +### New Features ++ MS-5349 Enabled lazy loading for banner native rendering + +### Improvement/Bug Fixes ++ MS-5371 Added additional information for INVALID_REQUEST code error messages + ## 8.7 ### New Features diff --git a/extras/AndroidAdvertisingID/project.properties b/extras/AndroidAdvertisingID/project.properties index 49f2a7c62..f26cf7065 100644 --- a/extras/AndroidAdvertisingID/project.properties +++ b/extras/AndroidAdvertisingID/project.properties @@ -7,7 +7,8 @@ # "ant.properties", and override values to adapt the script to your # project structure. # -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +# To enable ProGuard to shrink and obfuscate your +# code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt android.library=true diff --git a/instreamvideo/build.gradle b/instreamvideo/build.gradle index 722bdc137..4e0e0159b 100644 --- a/instreamvideo/build.gradle +++ b/instreamvideo/build.gradle @@ -1,5 +1,5 @@ // Project Properties -version = "1.46" // Instream SDK version +version = "1.47" // Instream SDK version apply plugin: 'com.android.library' @@ -10,7 +10,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 32 - versionCode 45 // An integer value that represents the version of the code, relative to other versions. Increase for each release. + versionCode 46 // An integer value that represents the version of the code, relative to other versions. Increase for each release. versionName version consumerProguardFiles 'proguard-project.txt' } diff --git a/sdk/build.gradle b/sdk/build.gradle index ffd176ff6..c156b84e0 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -1,5 +1,5 @@ // Project properties -version = "8.7" +version = "8.8" group='com.appnexus.opensdk' // Android build @@ -10,7 +10,7 @@ android { buildToolsVersion '32.0.0' defaultConfig { - versionCode 104 // An integer value that represents the version of the code, relative to other versions. Increase for each release. + versionCode 105 // An integer value that represents the version of the code, relative to other versions. Increase for each release. versionName version consumerProguardFiles 'proguard-project.txt' minSdkVersion 14 diff --git a/sdk/res/values/errors.xml b/sdk/res/values/errors.xml index 4519e595a..581fac299 100644 --- a/sdk/res/values/errors.xml +++ b/sdk/res/values/errors.xml @@ -161,7 +161,7 @@ loadLazyAd() failed, the Ad isn\'t lazy loaded yet. enableLazyLoad() failed, AdRequest is already in progress. enableLazyLoad() failed, Already enabled once. - loadLazyAd() failed, loadLazyAd can be applied only to the Banner Ad Type. + loadLazyAd() failed, loadLazyAd can be applied only to the Banner or Native Assembly Ad Type. Request Manager can\'t proceed as it has wo initialized owners Ad Request can\'t proceed without Activity Context diff --git a/sdk/src/com/appnexus/opensdk/AdFetcher.java b/sdk/src/com/appnexus/opensdk/AdFetcher.java index 07c5bc4cd..8326b660e 100644 --- a/sdk/src/com/appnexus/opensdk/AdFetcher.java +++ b/sdk/src/com/appnexus/opensdk/AdFetcher.java @@ -249,6 +249,12 @@ synchronized public void handleMessage(Message msg) { Clog.w(Clog.lazyLoadLogTag, "Not Fetching due to Lazy Load"); return; } + + // Condition to restrict the Auto Refresh if the AdType is not AdType.BANNER. + if (fetcher.owner != null && fetcher.owner instanceof AdView && ((AdView)fetcher.owner).getAdResponseInfo() != null && ((AdView)fetcher.owner).getAdResponseInfo().getAdType() != AdType.BANNER) { + Clog.w(Clog.baseLogTag, "Not Fetching due to AdType is not BANNER"); + return; + } } // Checks if the lazy load is enabled and de activates the Webview (activateWebview - boolean in the AdView), so that the AutoRefresh for Lazy Load can work. // Doing this will deActivate the Webview, which will be required to be activated by calling the loadLazyAd() later. @@ -280,7 +286,7 @@ synchronized public void handleMessage(Message msg) { fetcher.requestManager = new AdViewRequestManager(fetcher.owner); fetcher.requestManager.execute(); } else { - fetcher.owner.getAdDispatcher().onAdFailed(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST), null); + fetcher.owner.getAdDispatcher().onAdFailed(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Media type unknown"), null); } } } diff --git a/sdk/src/com/appnexus/opensdk/AdView.java b/sdk/src/com/appnexus/opensdk/AdView.java index df728c471..0e74e4524 100644 --- a/sdk/src/com/appnexus/opensdk/AdView.java +++ b/sdk/src/com/appnexus/opensdk/AdView.java @@ -112,6 +112,12 @@ public abstract class AdView extends FrameLayout implements Ad, MultiAd, Visibil */ protected boolean isAdResponseReceived = false; + /** + * This boolean keeps track, if the NativeAdResponse returned from impbus has a valid Native Renderer URL + * and is eligible to be displayed as a Banner Native Assembly Renderer Ad. + */ + protected boolean eligibleForNativeAssemblyRendering = false; + /** * Begin Construction */ @@ -1061,6 +1067,7 @@ public void run() { private void processAdLoaded(AdResponse ad) { isFetching = false; + eligibleForNativeAssemblyRendering = false; if (ad.getMediaType() == MediaType.BANNER || ad.getMediaType() == MediaType.INTERSTITIAL) { handleBannerOrInterstitialAd(ad); } else if (ad.getMediaType() == MediaType.NATIVE) { @@ -1092,6 +1099,7 @@ public void run() { private void processAdFailed(final ResultCode code, final ANAdResponseInfo adResponseInfo) { isFetching = false; + eligibleForNativeAssemblyRendering = false; handler.post(new Runnable() { @Override public void run() { @@ -1190,6 +1198,7 @@ public void run() { public void onAdResponseReceived() { Clog.d(Clog.baseLogTag, "onAdResponseReceived"); isAdResponseReceived = true; + eligibleForNativeAssemblyRendering = false; } private void handleNativeAd(AdResponse ad) { @@ -1596,8 +1605,8 @@ protected boolean loadLazyAd() { return false; } - // loadLazyAd() only if the AdType is AdType.BANNER - if (getAdResponseInfo().getAdType() != AdType.BANNER) { + // loadLazyAd() only if the AdType is AdType.BANNER or Native Assembly Ad Type + if (!isLastResponseSuccessful()) { Clog.w(Clog.lazyLoadLogTag, getContext().getString(R.string.apn_enable_lazy_webview_failure_non_banner)); return false; } @@ -1630,7 +1639,7 @@ protected void deactivateWebviewForNextCall() { * see {@link ANAdResponseInfo} */ protected boolean isLastResponseSuccessful() { - return getAdResponseInfo() != null && getAdResponseInfo().getAdType() == AdType.BANNER; + return getAdResponseInfo() != null && (getAdResponseInfo().getAdType() == AdType.BANNER || (getAdResponseInfo().getAdType() == AdType.NATIVE && isEligibleForNativeAssemblyRendering())); } @Override @@ -1650,4 +1659,12 @@ public Long getStartTime() { public Long getFinishTime() { return finishTime; } + + /** + * Retrieve the NativeAssemblyRenderer of the request + * + * @return true if it is NativeAssemblyRenderer, else false + * */ + public boolean isEligibleForNativeAssemblyRendering() { return eligibleForNativeAssemblyRendering; } + } diff --git a/sdk/src/com/appnexus/opensdk/AdViewRequestManager.java b/sdk/src/com/appnexus/opensdk/AdViewRequestManager.java index e767dac4d..eb1860353 100644 --- a/sdk/src/com/appnexus/opensdk/AdViewRequestManager.java +++ b/sdk/src/com/appnexus/opensdk/AdViewRequestManager.java @@ -266,8 +266,16 @@ private void handleNativeResponse(final Ad owner, final BaseAdResponse baseAdRes } if (owner instanceof BannerAdView && ((BannerAdView) owner).isNativeRenderingEnabled() && nativeAdResponse.getRendererUrl().length() > 0) { - initiateWebview(owner, baseAdResponse); + ((AdView)owner).eligibleForNativeAssemblyRendering = true; + if (((BannerAdView)owner).isLazyWebviewInactive()) { + ((AdDispatcher)owner.getAdDispatcher()).onLazyAdLoaded(currentAd.getAdResponseInfo()); + } else { + initiateWebview(owner, baseAdResponse); + } } else { + if (owner != null && owner instanceof BannerAdView) { + ((AdView)owner).eligibleForNativeAssemblyRendering = false; + } processNativeAd(nativeAdResponse, baseAdResponse); } } @@ -344,8 +352,8 @@ private void handleRTBResponse(Ad ownerAd, BaseAdResponse rtbAdResponse) { AdView owner = (AdView) ownerAd; fireImpressionTrackerIfBeginToRender(owner, rtbAdResponse); } else { - Clog.e(Clog.baseLogTag, "AdType can not be identified."); - continueWaterfall(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST)); + Clog.e(Clog.baseLogTag, "AdType cannot be identified."); + continueWaterfall(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "AdType cannot be identified.")); } } } else { @@ -408,7 +416,7 @@ private void handleCSMResponse(Ad ownerAd, final CSMSDKAdResponse csmSdkAdRespon owner.getAdDispatcher()); } else { Clog.e(Clog.baseLogTag, "MediaType type can not be identified."); - continueWaterfall(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST)); + continueWaterfall(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "MediaType type can not be identified")); } } } diff --git a/sdk/src/com/appnexus/opensdk/CSRNativeBannerController.java b/sdk/src/com/appnexus/opensdk/CSRNativeBannerController.java index 24569bc56..a5fb7f90f 100644 --- a/sdk/src/com/appnexus/opensdk/CSRNativeBannerController.java +++ b/sdk/src/com/appnexus/opensdk/CSRNativeBannerController.java @@ -71,7 +71,7 @@ public class CSRNativeBannerController implements CSRController { this, requester.getRequestParams().getTargetingParameters()); } else { - errorCode = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST); + errorCode = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Unable to get CSR mediated request params"); } } catch (ClassNotFoundException e) { // exception in Class.forName diff --git a/sdk/src/com/appnexus/opensdk/MediatedNativeAdController.java b/sdk/src/com/appnexus/opensdk/MediatedNativeAdController.java index 6c43b62ac..c9731b414 100644 --- a/sdk/src/com/appnexus/opensdk/MediatedNativeAdController.java +++ b/sdk/src/com/appnexus/opensdk/MediatedNativeAdController.java @@ -76,7 +76,7 @@ private MediatedNativeAdController(CSMSDKAdResponse currentAd, UTAdRequester req currentAd.getId(), this, requester.getRequestParams().getTargetingParameters()); } else { - errorCode = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST); + errorCode = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Mediated request params not found"); } } catch (ClassNotFoundException e) { // exception in Class.forName diff --git a/sdk/src/com/appnexus/opensdk/ut/UTAdRequest.java b/sdk/src/com/appnexus/opensdk/ut/UTAdRequest.java index abeb949ce..8914cee8e 100644 --- a/sdk/src/com/appnexus/opensdk/ut/UTAdRequest.java +++ b/sdk/src/com/appnexus/opensdk/ut/UTAdRequest.java @@ -280,7 +280,7 @@ void processResponse(HashMap adResponseMap) { if (adResponseMap == null) { Clog.e(Clog.httpRespLogTag, Clog.getString(R.string.no_response)); - fail(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST)); + fail(ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Server did not respond and failed to map response")); return; } @@ -306,7 +306,7 @@ void processResponse(HashMap adResponseMap) { } } else if (anMultiAdRequest != null) { if (adResponseMap == null) { - ResultCode code = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST); + ResultCode code = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Failed to map response"); Clog.e(Clog.SRMLogTag, "FAILED: " + code.getMessage()); anMultiAdRequest.onRequestFailed(code); } else { @@ -324,7 +324,7 @@ void processResponse(HashMap adResponseMap) { UTAdRequester requester = new AdViewRequestManager(ad); ad.getMultiAd().setRequestManager(requester); if (adResponseMap == null) { - ResultCode code = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST); + ResultCode code = ResultCode.getNewInstance(ResultCode.INVALID_REQUEST, "Ad response mapping is null"); Clog.e(Clog.SRMLogTag, "FAILED: " + code.getMessage()); requester.failed(code, null); continue; diff --git a/sdk/src/com/appnexus/opensdk/utils/Settings.java b/sdk/src/com/appnexus/opensdk/utils/Settings.java index 34de7087b..e35283094 100644 --- a/sdk/src/com/appnexus/opensdk/utils/Settings.java +++ b/sdk/src/com/appnexus/opensdk/utils/Settings.java @@ -68,7 +68,7 @@ public enum ImpressionType { public boolean debug_mode = false; // This should always be false here. public String ua = null; - public final String sdkVersion = "8.7"; + public final String sdkVersion = "8.8"; // BuildConfig.VERSION_NAME; diff --git a/sdk/test/com/appnexus/opensdk/AdListenerTest.java b/sdk/test/com/appnexus/opensdk/AdListenerTest.java index 967606b52..b6e044656 100644 --- a/sdk/test/com/appnexus/opensdk/AdListenerTest.java +++ b/sdk/test/com/appnexus/opensdk/AdListenerTest.java @@ -454,7 +454,109 @@ public void testloadLazyAdForDisabledLazyLoad() { assertFalse(adFailed); } + //Native Assembly Load Lazy Testing + @Test + public void testLazyNativeAssemblyAdLoaded() { + ShadowCustomWebView.simulateRendererScriptSuccess = true; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); + bannerAdView.setAllowNativeDemand(true); + bannerAdView.enableNativeRendering(true); + bannerAdView.enableLazyLoad(); + executeBannerRequest(); + + assertLazyLoadCallbackInProgress(); + bannerAdView.loadLazyAd(); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertLazyLoadCallbackSuccess(); + } + + // This proves that the second loadAd() behaves as a Lazy load even after the Lazy Ad has already been loaded once (after calling loadLazyAd()) + @Test + public void testLazyNativeAssemblyAdLoadedSuccessAndLoadAgain() { + ShadowCustomWebView.simulateRendererScriptSuccess = true; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); + bannerAdView.setAllowNativeDemand(true); + bannerAdView.enableNativeRendering(true); + bannerAdView.enableLazyLoad(); + executeBannerRequest(); + assertFalse(bannerAdView.getChildAt(0) instanceof WebView); + assertLazyLoadCallbackInProgress(); + bannerAdView.loadLazyAd(); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertLazyLoadCallbackSuccess(); + assertTrue(bannerAdView.getChildAt(0) instanceof WebView); + adLoaded = false; + adLazyLoaded = false; + adFailed = false; + restartServer(); + ShadowCustomWebView.simulateRendererScriptSuccess = true; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); + bannerAdView.setAllowNativeDemand(true); + bannerAdView.enableNativeRendering(true); + executeBannerRequest(); + assertLazyLoadCallbackInProgress(); + bannerAdView.loadLazyAd(); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertLazyLoadCallbackSuccess(); + assertTrue(bannerAdView.getChildAt(0) instanceof WebView); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + } + @Test + public void testloadLazyNativeAssemblyAdAfterAdLoad() { + ShadowCustomWebView.simulateRendererScriptSuccess = true; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); + bannerAdView.setAllowNativeDemand(true); + bannerAdView.enableNativeRendering(true); + assertTrue(bannerAdView.enableLazyLoad()); + executeBannerRequest(); + assertLazyLoadCallbackInProgress(); + assertTrue(bannerAdView.loadLazyAd()); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertLazyLoadCallbackSuccess(); + adLoaded = false; + adFailed = false; + assertFalse(bannerAdView.loadLazyAd()); + assertFalse(adLoaded); + assertFalse(adFailed); + } + + @Test + public void testLazyNativeAssemblyAdLoadWithloadLazyAdAlreadyCalled() { + ShadowCustomWebView.simulateRendererScriptSuccess = true; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); + bannerAdView.setAllowNativeDemand(true); + bannerAdView.enableNativeRendering(true); + bannerAdView.enableLazyLoad(); + assertFalse(bannerAdView.loadLazyAd()); + executeBannerRequest(); + assertLazyLoadCallbackInProgress(); + assertTrue(bannerAdView.loadLazyAd()); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertLazyLoadCallbackSuccess(); + } + + @Test + public void testLazyNativeAssemblyAdFailed() { + ShadowCustomWebView.simulateRendererScriptSuccess = false; + server.setDispatcher(getDispatcher(TestResponsesUT.anNativeRenderer())); // First queue a banner Native response + bannerAdView.setAllowNativeDemand(false); + bannerAdView.enableNativeRendering(false); + bannerAdView.enableLazyLoad(); + executeBannerRequest(); + bannerAdView.loadLazyAd(); + Robolectric.flushBackgroundThreadScheduler(); + Robolectric.flushForegroundThreadScheduler(); + assertFalse(bannerAdView.loadLazyAd()); + assertFalse(adFailed); + assertFalse(adLazyLoaded); + } @Test public void testBannerAdFailed() {