From 9030d0ca27ae926b24c433c4a660403668dcd327 Mon Sep 17 00:00:00 2001 From: runner Date: Thu, 28 Sep 2023 00:55:34 +0000 Subject: [PATCH] Release 4.9.0 --- app/build.gradle | 4 +- .../ads/example/ui/main/UnityAdsFragment.java | 13 +- fatAar.gradle | 2 - settings.gradle | 2 - unity-ads/build.gradle | 9 +- .../ads/gmascar/GMAScarAdapterBridgeTest.java | 20 +- .../adapters/ScarAdapterFactoryTest.java | 12 - .../bridges/MobileAdsBridgeLegacyTest.java | 21 -- .../gmascar/finder/ScarVersionFinderTest.java | 4 +- .../handlers/BiddingSignalsHandlerTest.java | 60 ++++- .../handlers/ScarBannerAdHandlerTest.java | 101 ++++++++ .../managers/BiddingBaseManagerTest.java | 80 ++---- .../managers/BiddingEagerManagerTest.java | 10 +- .../managers/BiddingLazyManagerTest.java | 46 ---- .../managers/BiddingOnDemandManagerTest.java | 45 ---- .../managers/ScarBiddingManagerEnumTest.java | 26 -- .../LoadModuleDecoratorTimeoutTests.java | 21 +- .../ShowModuleDecoratorTimeoutTests.java | 14 +- .../services/banners/BannerErrorInfoTest.java | 41 +++ .../banners/BannerViewCacheTests.java | 62 ++++- .../core/webview/WebViewUrlBuilderTest.java | 5 +- .../ads/test/integration/SDKMetricsTest.java | 41 --- .../unity3d/ads/test/legacy/DeviceTest.java | 5 + .../com/unity3d/services/SDKErrorHandler.kt | 9 +- .../services/ads/UnityAdsImplementation.java | 3 +- .../services/ads/adunit/AdUnitActivity.java | 5 +- .../ads/adunit/AdUnitRelativeLayout.java | 18 ++ .../com/unity3d/services/ads/api/GMAScar.java | 14 +- .../services/ads/api/Measurements.java | 47 ++++ .../com/unity3d/services/ads/api/Topics.java | 21 ++ .../configuration/AdsModuleConfiguration.java | 4 +- .../com/unity3d/services/ads/gmascar/GMA.java | 4 +- .../ads/gmascar/GMAScarAdapterBridge.java | 31 ++- .../gmascar/adapters/ScarAdapterFactory.java | 6 - .../mobileads/MobileAdsBridgeLegacy.java | 9 +- .../gmascar/finder/ScarAdapterVersion.java | 2 - .../handlers/BiddingSignalsHandler.java | 12 +- .../gmascar/handlers/ScarAdHandlerBase.java | 5 - .../gmascar/handlers/ScarBannerAdHandler.java | 48 ++++ .../handlers/ScarInterstitialAdHandler.java | 7 +- .../handlers/ScarRewardedAdHandler.java | 7 +- .../gmascar/managers/BiddingBaseManager.java | 62 ++--- .../managers/BiddingDisabledManager.java | 9 +- .../gmascar/managers/BiddingEagerManager.java | 12 +- .../gmascar/managers/BiddingLazyManager.java | 23 -- .../managers/BiddingManagerFactory.java | 36 +-- .../managers/BiddingOnDemandManager.java | 20 -- .../managers/SCARBiddingManagerType.java | 39 --- .../ads/gmascar/models/BiddingSignals.java | 31 ++- .../ads/gmascar/utils/ScarConstants.java | 2 + .../ads/measurements/MeasurementErrors.kt | 12 + .../ads/measurements/MeasurementEvents.kt | 10 + .../ads/measurements/MeasurementsReceiver.kt | 21 ++ .../ads/measurements/MeasurementsService.kt | 76 ++++++ .../MeasurementsStatusReceiver.kt | 17 ++ .../ads/operation/load/LoadBannerModule.java | 24 +- .../load/LoadBannerOperationState.java | 14 ++ .../ads/operation/load/LoadModule.java | 6 +- .../load/LoadModuleDecoratorTimeout.java | 11 +- .../ads/operation/show/ShowModule.java | 7 +- .../show/ShowModuleDecoratorTimeout.java | 11 +- .../services/ads/topics/TopicsErrors.kt | 5 + .../services/ads/topics/TopicsEvents.kt | 6 + .../services/ads/topics/TopicsReceiver.kt | 35 +++ .../services/ads/topics/TopicsService.kt | 64 +++++ .../services/ads/topics/TopicsStatus.kt | 9 + .../services/banners/BannerErrorInfo.java | 14 ++ .../unity3d/services/banners/BannerView.java | 19 ++ .../services/banners/BannerViewCache.java | 41 ++- .../unity3d/services/banners/api/Banner.java | 45 +++- .../services/banners/bridge/BannerBridge.java | 25 +- .../banners/view/ScarBannerContainer.java | 42 ++++ .../unity3d/services/core/api/DeviceInfo.java | 20 ++ .../core/configuration/Configuration.java | 7 + .../CoreModuleConfiguration.java | 16 ++ .../core/configuration/ExperimentObjects.java | 28 ++- .../core/configuration/Experiments.java | 27 +- .../core/configuration/ExperimentsBase.java | 7 +- .../core/configuration/IExperiments.java | 6 +- .../unity3d/services/core/device/Device.java | 14 ++ .../services/core/device/MimeTypes.java | 1 + .../core/device/reader/HdrInfoReader.java | 106 ++++++++ .../core/device/reader/IHdrInfoReader.java | 9 + .../services/core/di/ServiceProvider.kt | 8 +- .../services/core/domain/task/BaseTask.kt | 4 +- .../domain/task/ConfigFileFromLocalStorage.kt | 13 +- .../core/domain/task/InitializeSDK.kt | 131 +++++----- .../domain/task/InitializeStateComplete.kt | 9 +- .../core/domain/task/InitializeStateConfig.kt | 17 +- .../task/InitializeStateConfigWithLoader.kt | 181 +++++++------- .../core/domain/task/InitializeStateCreate.kt | 45 ++-- .../task/InitializeStateCreateWithRemote.kt | 43 ++-- .../core/domain/task/InitializeStateError.kt | 17 +- .../domain/task/InitializeStateLoadCache.kt | 27 +- .../domain/task/InitializeStateLoadWeb.kt | 83 ++++--- .../task/InitializeStateNetworkError.kt | 25 +- .../core/domain/task/InitializeStateReset.kt | 51 ++-- .../core/domain/task/InitializeStateRetry.kt | 19 -- .../services/core/domain/task/MetricTask.kt | 12 +- .../core/request/metrics/MetricSender.kt | 4 - .../request/metrics/MetricSenderWithBatch.kt | 4 - .../core/request/metrics/SDKMetrics.java | 9 +- .../core/request/metrics/SDKMetricsSender.kt | 1 - .../core/webview/WebViewEventCategory.java | 4 +- .../core/webview/WebViewUrlBuilder.java | 3 +- .../unity3d/services/SDKErrorHandlerTest.kt | 84 +++++++ .../managers/BiddingManagerFactoryTest.java | 121 --------- .../managers/BiddingManagerFactoryTest.kt | 77 ++++++ .../services/ads/topics/TopicsReceiverTest.kt | 88 +++++++ .../services/ads/topics/TopicsServiceTest.kt | 201 +++++++++++++++ .../configuration/ExperimentObjectsTest.java | 21 +- .../core/configuration/ExperimentsTest.java | 10 +- .../task/ConfigFileFromLocalStorageTest.kt | 9 +- .../core/domain/task/InitializeSDKTest.kt | 86 +++---- .../domain/task/InitializeStateConfigTest.kt | 2 +- .../InitializeStateConfigWithLoaderTest.kt | 24 +- .../domain/task/InitializeStateCreateTest.kt | 8 +- .../InitializeStateCreateWithRemoteTest.kt | 9 +- .../task/InitializeStateLoadCacheTest.kt | 12 +- .../domain/task/InitializeStateLoadWebTest.kt | 26 +- .../task/InitializeStateNetworkErrorTest.kt | 2 +- .../domain/task/InitializeStateResetTest.kt | 2 +- .../measurements/MeasurementsServiceTest.kt | 235 ++++++++++++++++++ unity-scaradapter-1920/.gitignore | 1 - unity-scaradapter-1920/build.gradle | 45 ---- unity-scaradapter-1920/consumer-rules.pro | 0 unity-scaradapter-1920/proguard-rules.pro | 21 -- .../src/androidTest/AndroidManifest.xml | 9 - .../ads/test/InstrumentationTestSuite.java | 13 - .../v1920/signals/SignalsCollectorTest.java | 49 ---- .../src/main/AndroidManifest.xml | 6 - .../scar/adapter/v1920/ScarAdapter.java | 61 ----- .../adapter/v1920/scarads/ScarAdBase.java | 40 --- .../v1920/scarads/ScarInterstitialAd.java | 42 ---- .../scarads/ScarInterstitialAdListener.java | 62 ----- .../adapter/v1920/scarads/ScarRewardedAd.java | 41 --- .../v1920/scarads/ScarRewardedAdListener.java | 69 ----- .../v1920/signals/QueryInfoCallback.java | 26 -- .../v1920/signals/SignalsCollector.java | 35 --- unity-scaradapter-1950/.gitignore | 1 - unity-scaradapter-1950/build.gradle | 45 ---- unity-scaradapter-1950/consumer-rules.pro | 0 unity-scaradapter-1950/proguard-rules.pro | 21 -- .../src/androidTest/AndroidManifest.xml | 8 - .../ads/test/InstrumentationTestSuite.java | 13 - .../v1950/signals/SignalsCollectorTest.java | 49 ---- .../src/main/AndroidManifest.xml | 6 - .../scar/adapter/v1950/ScarAdapter.java | 61 ----- .../adapter/v1950/scarads/ScarAdBase.java | 41 --- .../v1950/scarads/ScarInterstitialAd.java | 42 ---- .../scarads/ScarInterstitialAdListener.java | 63 ----- .../adapter/v1950/scarads/ScarRewardedAd.java | 41 --- .../v1950/scarads/ScarRewardedAdListener.java | 70 ------ .../v1950/signals/QueryInfoCallback.java | 26 -- .../v1950/signals/SignalsCollector.java | 35 --- .../v2000/signals/SignalsCollectorTest.java | 19 +- .../scar/adapter/v2000/ScarAdapter.java | 21 +- .../adapter/v2000/scarads/ScarAdBase.java | 4 +- .../adapter/v2000/scarads/ScarBannerAd.java | 46 ++++ .../v2000/scarads/ScarBannerAdListener.java | 61 +++++ .../v2000/scarads/ScarInterstitialAd.java | 3 +- .../adapter/v2000/scarads/ScarRewardedAd.java | 3 +- .../v2000/signals/SignalsCollector.java | 23 +- .../v2100/signals/SignalsCollectorTest.java | 19 +- .../src/main/AndroidManifest.xml | 1 + .../scar/adapter/v2100/ScarAdapter.java | 20 +- .../adapter/v2100/scarads/ScarAdBase.java | 4 +- .../adapter/v2100/scarads/ScarBannerAd.java | 46 ++++ .../v2100/scarads/ScarBannerAdListener.java | 61 +++++ .../v2100/scarads/ScarInterstitialAd.java | 3 +- .../adapter/v2100/scarads/ScarRewardedAd.java | 3 +- .../v2100/signals/SignalsCollector.java | 31 ++- .../common/IScarAdListenerWrapper.java | 5 - .../scar/adapter/common/IScarAdapter.java | 8 +- .../common/IScarBannerAdListenerWrapper.java | 9 + .../IScarInterstitialAdListenerWrapper.java | 5 + .../IScarRewardedAdListenerWrapper.java | 5 + .../scar/adapter/common/ScarAdapterBase.java | 17 +- .../scar/adapter/common/scarads/IScarAd.java | 1 - .../common/scarads/IScarFullScreenAd.java | 7 + .../adapter/common/scarads/UnityAdFormat.java | 7 + .../common/signals/ISignalsCollector.java | 13 +- .../common/signals/SignalsCollectorBase.java | 38 ++- 183 files changed, 2800 insertions(+), 2337 deletions(-) create mode 100644 unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/ScarBannerAdHandlerTest.java delete mode 100644 unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingLazyManagerTest.java delete mode 100644 unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingOnDemandManagerTest.java delete mode 100644 unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/ScarBiddingManagerEnumTest.java create mode 100644 unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerErrorInfoTest.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/api/Measurements.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/api/Topics.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarBannerAdHandler.java delete mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingLazyManager.java delete mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingOnDemandManager.java delete mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/SCARBiddingManagerType.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementErrors.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementEvents.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsReceiver.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsService.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsStatusReceiver.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsErrors.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsEvents.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsReceiver.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsService.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsStatus.kt create mode 100644 unity-ads/src/main/java/com/unity3d/services/banners/view/ScarBannerContainer.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/core/device/reader/HdrInfoReader.java create mode 100644 unity-ads/src/main/java/com/unity3d/services/core/device/reader/IHdrInfoReader.java delete mode 100644 unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateRetry.kt create mode 100644 unity-ads/src/test/java/com/unity3d/services/SDKErrorHandlerTest.kt delete mode 100644 unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.java create mode 100644 unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.kt create mode 100644 unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsReceiverTest.kt create mode 100644 unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsServiceTest.kt create mode 100644 unity-ads/src/test/java/com/unity3d/services/core/measurements/MeasurementsServiceTest.kt delete mode 100644 unity-scaradapter-1920/.gitignore delete mode 100644 unity-scaradapter-1920/build.gradle delete mode 100644 unity-scaradapter-1920/consumer-rules.pro delete mode 100644 unity-scaradapter-1920/proguard-rules.pro delete mode 100644 unity-scaradapter-1920/src/androidTest/AndroidManifest.xml delete mode 100644 unity-scaradapter-1920/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java delete mode 100644 unity-scaradapter-1920/src/androidTest/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollectorTest.java delete mode 100644 unity-scaradapter-1920/src/main/AndroidManifest.xml delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/ScarAdapter.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarAdBase.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAd.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAdListener.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAd.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAdListener.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/QueryInfoCallback.java delete mode 100644 unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollector.java delete mode 100644 unity-scaradapter-1950/.gitignore delete mode 100644 unity-scaradapter-1950/build.gradle delete mode 100644 unity-scaradapter-1950/consumer-rules.pro delete mode 100644 unity-scaradapter-1950/proguard-rules.pro delete mode 100644 unity-scaradapter-1950/src/androidTest/AndroidManifest.xml delete mode 100644 unity-scaradapter-1950/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java delete mode 100644 unity-scaradapter-1950/src/androidTest/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollectorTest.java delete mode 100644 unity-scaradapter-1950/src/main/AndroidManifest.xml delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/ScarAdapter.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarAdBase.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAd.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAdListener.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAd.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAdListener.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/QueryInfoCallback.java delete mode 100644 unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollector.java create mode 100644 unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAd.java create mode 100644 unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAdListener.java create mode 100644 unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAd.java create mode 100644 unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAdListener.java create mode 100644 unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarBannerAdListenerWrapper.java create mode 100644 unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarFullScreenAd.java create mode 100644 unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/UnityAdFormat.java diff --git a/app/build.gradle b/app/build.gradle index 1b8486c..0702517 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.unity3d.ads.example" minSdkVersion 19 targetSdkVersion 33 - versionCode = 4800 - versionName = "4.8.0" + versionCode = 4900 + versionName = "4.9.0" } buildTypes { diff --git a/app/src/main/java/com/unity3d/ads/example/ui/main/UnityAdsFragment.java b/app/src/main/java/com/unity3d/ads/example/ui/main/UnityAdsFragment.java index 53e9dea..87219ff 100644 --- a/app/src/main/java/com/unity3d/ads/example/ui/main/UnityAdsFragment.java +++ b/app/src/main/java/com/unity3d/ads/example/ui/main/UnityAdsFragment.java @@ -18,11 +18,7 @@ import android.widget.EditText; import android.widget.RelativeLayout; import android.widget.Toast; -import com.unity3d.ads.IUnityAdsInitializationListener; -import com.unity3d.ads.IUnityAdsLoadListener; -import com.unity3d.ads.IUnityAdsShowListener; -import com.unity3d.ads.UnityAds; -import com.unity3d.ads.UnityAdsShowOptions; +import com.unity3d.ads.*; import com.unity3d.ads.example.R; import com.unity3d.ads.metadata.MediationMetaData; import com.unity3d.ads.metadata.MetaData; @@ -68,6 +64,7 @@ public class UnityAdsFragment extends Fragment { @Override public void onBannerFailedToLoad(BannerView bannerAdView, BannerErrorInfo errorInfo) { Log.e(LOGTAG, "Unity Ads failed to load banner for " + bannerAdView.getPlacementId() + " with error: [" + errorInfo.errorCode + "] " + errorInfo.errorMessage); + enableButton(showBannerButton); } @Override @@ -203,6 +200,7 @@ public class UnityAdsFragment extends Fragment { this.showBannerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + disableButton(showBannerButton); bottomBanner = new BannerView((Activity)v.getContext(), "bannerads", new UnityBannerSize(320, 50)); bottomBanner.setListener(bannerListener); bottomBanner.load(); @@ -213,11 +211,12 @@ public class UnityAdsFragment extends Fragment { hideBannerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - bottomBanner.removeAllViews(); if (bottomBanner != null) { + bottomBanner.removeAllViews(); bottomBanner = null; } - showBannerButton.setEnabled(true); + enableButton(showBannerButton); + disableButton(hideBannerButton); } }); diff --git a/fatAar.gradle b/fatAar.gradle index a13c1df..57e9088 100644 --- a/fatAar.gradle +++ b/fatAar.gradle @@ -30,8 +30,6 @@ project.tasks.whenTaskAdded { Task theTask -> } if (tasksDependentOnScar("${buildType}").any { theTask.name == it }) { theTask.dependsOn(":unity-scaradapter-common:copyJars${buildType}") - theTask.dependsOn(":unity-scaradapter-1920:copyJars${buildType}") - theTask.dependsOn(":unity-scaradapter-1950:copyJars${buildType}") theTask.dependsOn(":unity-scaradapter-2000:copyJars${buildType}") theTask.dependsOn(":unity-scaradapter-2100:copyJars${buildType}") } diff --git a/settings.gradle b/settings.gradle index 41e4846..3b65f12 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,3 @@ -include ':unity-scaradapter-1920' -include ':unity-scaradapter-1950' include ':unity-scaradapter-2000' include ':unity-scaradapter-2100' include ':unity-scaradapter-common' diff --git a/unity-ads/build.gradle b/unity-ads/build.gradle index 017a78c..84ccf08 100644 --- a/unity-ads/build.gradle +++ b/unity-ads/build.gradle @@ -13,14 +13,15 @@ if (project.rootProject.file('local.properties').exists()) { ext { GROUP_ID = "com.unity3d.ads" ARTIFACT_ID = "unity-ads" - VERSION_ID = "4.8.0" - VERSION_CODE = 4800 + VERSION_ID = "4.9.0" + VERSION_CODE = 4900 SIGN_AAR = properties.getProperty("SIGN_AAR") ?: false } android { namespace = GROUP_ID compileSdk 33 + compileSdkExtension 5 DdmPreferences.setLogLevel("verbose") DdmPreferences.setTimeOut(10 * 60000) @@ -82,8 +83,6 @@ dependencies { implementation "com.google.android.gms:play-services-cronet:$play_services_cronet" androidTestCompileOnly project(':unity-scaradapter-2100') androidTestCompileOnly project(':unity-scaradapter-2000') - androidTestCompileOnly project(':unity-scaradapter-1950') - androidTestCompileOnly project(':unity-scaradapter-1920') androidTestCompileOnly project(':unity-scaradapter-common') androidTestImplementation 'junit:junit:4.13.2' androidTestImplementation 'org.mockito:mockito-core:2.28.2' @@ -98,8 +97,6 @@ dependencies { compileOnly 'com.google.ar:core:1.0.0' compileOnly project(':unity-scaradapter-2100') compileOnly project(':unity-scaradapter-2000') - compileOnly project(':unity-scaradapter-1950') - compileOnly project(':unity-scaradapter-1920') compileOnly project(':unity-scaradapter-common') testImplementation 'junit:junit:4.13.2' testImplementation "org.jetbrains.kotlin:kotlin-stdlib" diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/GMAScarAdapterBridgeTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/GMAScarAdapterBridgeTest.java index 216e34c..554e337 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/GMAScarAdapterBridgeTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/GMAScarAdapterBridgeTest.java @@ -10,10 +10,13 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; import android.app.Activity; import android.content.Context; +import android.widget.RelativeLayout; import com.unity3d.scar.adapter.common.IScarAdapter; +import com.unity3d.scar.adapter.common.IScarBannerAdListenerWrapper; import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; import com.unity3d.services.ads.gmascar.GMAScarAdapterBridge; import com.unity3d.services.ads.gmascar.adapters.ScarAdapterFactory; @@ -64,19 +67,19 @@ public class GMAScarAdapterBridgeTest { private static final ScarAdapterVersion VERSION = ScarAdapterVersion.V21; private GMAScarAdapterBridge gmaScarAdapterBridge; private IScarAdapter scarAdapter; + private boolean isBannerSignalEnabled = true; @Before public void setup() { scarAdapter = new IScarAdapter() { @Override - public void getSCARSignals(Context context, String[] strings, - String[] strings1, - ISignalCollectionListener iSignalCollectionListener) { + public void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, ISignalCollectionListener signalCompletionListener) { } @Override public void getSCARBiddingSignals(Context context, + boolean isBannerEnabled, ISignalCollectionListener iSignalCollectionListener) { iSignalCollectionListener.onSignalsCollected(SIGNAL); } @@ -95,6 +98,11 @@ public class GMAScarAdapterBridgeTest { } + @Override + public void loadBannerAd(Context context, RelativeLayout bannerView, ScarAdMetadata scarAdMetadata, int width, int height, IScarBannerAdListenerWrapper adListener) { + + } + @Override public void show(Activity activity, String s, String s1) { @@ -189,7 +197,7 @@ public class GMAScarAdapterBridgeTest { gmaEventSenderMock ); - gmaScarAdapterBridge.getSCARBiddingSignals(handler); + gmaScarAdapterBridge.getSCARBiddingSignals(isBannerSignalEnabled, handler); verify(handler, times(0)).onSignalsCollectionFailed(anyString()); verify(handler, times(1)).onSignalsCollected(SIGNAL); } @@ -208,7 +216,7 @@ public class GMAScarAdapterBridgeTest { gmaEventSenderMock ); - gmaScarAdapterBridge.getSCARBiddingSignals(handler); + gmaScarAdapterBridge.getSCARBiddingSignals(isBannerSignalEnabled, handler); verify(handler, times(0)).onSignalsCollected(anyString()); verify(handler, times(1)).onSignalsCollectionFailed("SCAR bidding unsupported."); } @@ -228,7 +236,7 @@ public class GMAScarAdapterBridgeTest { gmaEventSenderMock ); - gmaScarAdapterBridge.getSCARBiddingSignals(handler); + gmaScarAdapterBridge.getSCARBiddingSignals(isBannerSignalEnabled, handler); verify(handler, times(0)).onSignalsCollected(SIGNAL); verify(handler, times(1)).onSignalsCollectionFailed("Could not create SCAR adapter object."); } diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/adapters/ScarAdapterFactoryTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/adapters/ScarAdapterFactoryTest.java index 8f64b2d..c53502b 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/adapters/ScarAdapterFactoryTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/adapters/ScarAdapterFactoryTest.java @@ -19,18 +19,6 @@ public class ScarAdapterFactoryTest { private final ScarAdapterFactory _scarAdapterFactory = new ScarAdapterFactory(); - @Test - public void testScarAdapterFactory1920() { - IScarAdapter adapter = _scarAdapterFactory.createScarAdapter(ScarAdapterVersion.V192, adsErrorHandlerMock); - Assert.assertTrue(adapter instanceof com.unity3d.scar.adapter.v1920.ScarAdapter); - } - - @Test - public void testScarAdapterFactory1950() { - IScarAdapter adapter = _scarAdapterFactory.createScarAdapter(ScarAdapterVersion.V195, adsErrorHandlerMock); - Assert.assertTrue(adapter instanceof com.unity3d.scar.adapter.v1950.ScarAdapter); - } - @Test public void testScarAdapterFactory2000() { IScarAdapter adapter = _scarAdapterFactory.createScarAdapter(ScarAdapterVersion.V20, adsErrorHandlerMock); diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/bridges/MobileAdsBridgeLegacyTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/bridges/MobileAdsBridgeLegacyTest.java index c69c8ae..362571b 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/bridges/MobileAdsBridgeLegacyTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/bridges/MobileAdsBridgeLegacyTest.java @@ -34,27 +34,6 @@ public class MobileAdsBridgeLegacyTest { Assert.assertTrue(String.format("Minor version 223712000 is not found in %s", versionString), versionString.contains("223712000")); } - @Test - public void testGetAdapterVersionWhen192() { - MobileAdsBridgeLegacy mobileAdsBridge = new MobileAdsBridgeLegacy(); - ScarAdapterVersion adapterVersion = mobileAdsBridge.getAdapterVersion(MobileAdsBridgeLegacy.CODE_19_2); - Assert.assertEquals(ScarAdapterVersion.V192, adapterVersion); - } - - @Test - public void testGetAdapterVersionWhen195() { - MobileAdsBridgeLegacy mobileAdsBridge = new MobileAdsBridgeLegacy(); - ScarAdapterVersion adapterVersion = mobileAdsBridge.getAdapterVersion(MobileAdsBridgeLegacy.CODE_19_5); - Assert.assertEquals(ScarAdapterVersion.V195, adapterVersion); - } - - @Test - public void testGetAdapterVersionWhen198() { - MobileAdsBridgeLegacy mobileAdsBridge = new MobileAdsBridgeLegacy(); - ScarAdapterVersion adapterVersion = mobileAdsBridge.getAdapterVersion(MobileAdsBridgeLegacy.CODE_19_8); - Assert.assertEquals(ScarAdapterVersion.V195, adapterVersion); - } - @Test public void testGetAdapterVersionWhen20() { MobileAdsBridgeLegacy mobileAdsBridge = new MobileAdsBridgeLegacy(); diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/finder/ScarVersionFinderTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/finder/ScarVersionFinderTest.java index 4aa3c4b..7f7d52b 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/finder/ScarVersionFinderTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/finder/ScarVersionFinderTest.java @@ -38,10 +38,10 @@ public class ScarVersionFinderTest { public void testScarVersionFinderWithMobileAdsBridgeLegacy() { doCallRealMethod().when(mobileAdsBridgeMock).getVersionCodeIndex(); - Mockito.when(mobileAdsBridgeMock.getVersionString()).thenReturn("afma-sdk-a-v204890999.203404000.1"); + Mockito.when(mobileAdsBridgeMock.getVersionString()).thenReturn("afma-sdk-a-v204890999.210402000.1"); ScarVersionFinder scarVersionFinder = new ScarVersionFinder(mobileAdsBridgeMock, presenceDetector, gmaInitializer, new GMAEventSender()); long versionCode = scarVersionFinder.getVersionCode(); - Assert.assertEquals(MobileAdsBridgeLegacy.CODE_19_5, versionCode); + Assert.assertEquals(MobileAdsBridgeLegacy.CODE_20_0, versionCode); } @Test diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/BiddingSignalsHandlerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/BiddingSignalsHandlerTest.java index 8b0c7b1..08fa2a0 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/BiddingSignalsHandlerTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/BiddingSignalsHandlerTest.java @@ -22,12 +22,13 @@ public class BiddingSignalsHandlerTest { @Test public void testSignalsAreSetAfterOnSignalsCollectedWithValidMap() { - String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\",\"gmaScarBiddingInterstitialSignal\": \"inSig\"}"; + String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\",\"gmaScarBiddingInterstitialSignal\": \"inSig\", \"gmaScarBiddingBannerSignal\": \"bnSig\"}"; gmaScarBiddingSignalsListener = spy(new IBiddingSignalsListener() { @Override public void onSignalsReady(BiddingSignals signals) { assertEquals("rvSig", signals.getRvSignal()); assertEquals("inSig", signals.getInterstitialSignal()); + assertEquals("bnSig", signals.getBannerSignal()); } @Override @@ -35,7 +36,7 @@ public class BiddingSignalsHandlerTest { fail(); } }); - biddingSignalsHandler = new BiddingSignalsHandler(gmaScarBiddingSignalsListener); + biddingSignalsHandler = new BiddingSignalsHandler(true, gmaScarBiddingSignalsListener); biddingSignalsHandler.onSignalsCollected(map); verify(gmaScarBiddingSignalsListener, times(1)).onSignalsReady( @@ -44,13 +45,14 @@ public class BiddingSignalsHandlerTest { @Test public void testNoInterstitialSignalSetAfterOnSignalsCollectedWithMissingInterstitial() { - String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\",\"asdfasdfasf\": \"inSig\"}"; + String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\", \"gmaScarBiddingBannerSignal\": \"bnSig\"}"; gmaScarBiddingSignalsListener = spy(new IBiddingSignalsListener() { @Override public void onSignalsReady(BiddingSignals signals) { assertEquals("rvSig", signals.getRvSignal()); assertEquals("", signals.getInterstitialSignal()); + assertEquals("bnSig", signals.getBannerSignal()); } @Override @@ -58,7 +60,55 @@ public class BiddingSignalsHandlerTest { fail(); } }); - biddingSignalsHandler = new BiddingSignalsHandler(gmaScarBiddingSignalsListener); + biddingSignalsHandler = new BiddingSignalsHandler(true, gmaScarBiddingSignalsListener); + + biddingSignalsHandler.onSignalsCollected(map); + verify(gmaScarBiddingSignalsListener, times(1)).onSignalsReady( + isA(BiddingSignals.class)); + } + + @Test + public void testNoBannerSignalSetAfterOnSignalsCollectedWithBannerDisabled() { + String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\",\"gmaScarBiddingInterstitialSignal\": \"inSig\"}"; + + gmaScarBiddingSignalsListener = spy(new IBiddingSignalsListener() { + @Override + public void onSignalsReady(BiddingSignals signals) { + assertEquals("rvSig", signals.getRvSignal()); + assertEquals("inSig", signals.getInterstitialSignal()); + assertEquals("", signals.getBannerSignal()); + } + + @Override + public void onSignalsFailure(String msg) { + fail(); + } + }); + biddingSignalsHandler = new BiddingSignalsHandler(false, gmaScarBiddingSignalsListener); + + biddingSignalsHandler.onSignalsCollected(map); + verify(gmaScarBiddingSignalsListener, times(1)).onSignalsReady( + isA(BiddingSignals.class)); + } + + @Test + public void testNoBannerSignalSetAfterOnSignalsCollectedWithBannerPresent() { + String map = "{\"gmaScarBiddingRewardedSignal\": \"rvSig\",\"gmaScarBiddingInterstitialSignal\": \"inSig\", \"gmaScarBiddingBannerSignal\": \"bnSig\"}"; + + gmaScarBiddingSignalsListener = spy(new IBiddingSignalsListener() { + @Override + public void onSignalsReady(BiddingSignals signals) { + assertEquals("rvSig", signals.getRvSignal()); + assertEquals("inSig", signals.getInterstitialSignal()); + assertEquals("", signals.getBannerSignal()); + } + + @Override + public void onSignalsFailure(String msg) { + fail(); + } + }); + biddingSignalsHandler = new BiddingSignalsHandler(false, gmaScarBiddingSignalsListener); biddingSignalsHandler.onSignalsCollected(map); verify(gmaScarBiddingSignalsListener, times(1)).onSignalsReady( @@ -80,7 +130,7 @@ public class BiddingSignalsHandlerTest { fail(); } }); - biddingSignalsHandler = new BiddingSignalsHandler(gmaScarBiddingSignalsListener); + biddingSignalsHandler = new BiddingSignalsHandler(false, gmaScarBiddingSignalsListener); biddingSignalsHandler.onSignalsCollected(map); verify(gmaScarBiddingSignalsListener, times(1)).onSignalsReady( diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/ScarBannerAdHandlerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/ScarBannerAdHandlerTest.java new file mode 100644 index 0000000..088754f --- /dev/null +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/handlers/ScarBannerAdHandlerTest.java @@ -0,0 +1,101 @@ +package com.unity3d.ads.test.instrumentation.services.ads.gmascar.handlers; + +import com.unity3d.services.ads.gmascar.handlers.ScarBannerAdHandler; +import com.unity3d.services.banners.bridge.BannerBridge; +import com.unity3d.services.core.webview.WebViewApp; +import com.unity3d.services.core.webview.WebViewEventCategory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; + +@RunWith(MockitoJUnitRunner.class) +public class ScarBannerAdHandlerTest { + + @Mock + WebViewApp mockWebViewApp; + + private String testBannerId = "test-bannerId"; + + @Before + public void setup() { + WebViewApp.setCurrentApp(mockWebViewApp); + } + + @Test + public void testOnAdLoaded() { + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdLoaded(); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent(eq(WebViewEventCategory.BANNER), eq(BannerBridge.BannerEvent.SCAR_BANNER_LOADED), eq(testBannerId)); + } + + @Test + public void testOnAdFailedToLoad() { + int errorCode = 123; + String errorString = "Test Error Message"; + + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdFailedToLoad(errorCode, errorString); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent( + eq(WebViewEventCategory.BANNER), + eq(BannerBridge.BannerEvent.SCAR_BANNER_LOAD_FAILED), + eq(testBannerId) + ); + } + + @Test + public void testOnAdOpened() { + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdOpened(); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent( + eq(WebViewEventCategory.BANNER), + eq(BannerBridge.BannerEvent.SCAR_BANNER_OPENED), + eq(testBannerId) + ); + } + + @Test + public void testOnAdClicked() { + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdClicked(); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent( + eq(WebViewEventCategory.BANNER), + eq(BannerBridge.BannerEvent.SCAR_BANNER_CLICKED), + eq(testBannerId) + ); + } + + @Test + public void testOnAdClosed() { + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdClosed(); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent( + eq(WebViewEventCategory.BANNER), + eq(BannerBridge.BannerEvent.SCAR_BANNER_CLOSED), + eq(testBannerId) + ); + } + + @Test + public void testOnAdImpression() { + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(testBannerId); + adHandler.onAdImpression(); + + Mockito.verify(mockWebViewApp, times(1)).sendEvent( + eq(WebViewEventCategory.BANNER), + eq(BannerBridge.BannerEvent.SCAR_BANNER_IMPRESSION), + eq(testBannerId) + ); + } +} diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingBaseManagerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingBaseManagerTest.java index b180045..5779189 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingBaseManagerTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingBaseManagerTest.java @@ -38,7 +38,7 @@ public class BiddingBaseManagerTest { private BiddingBaseManager managerWithTokenListener; private BiddingBaseManager managerWithNullListener; - + private boolean isBannerEnabled = true; private String TEST_TOKEN = "token"; private boolean isAsyncTokenCall = true; private boolean isNotAsyncTokenCall = false; @@ -48,28 +48,18 @@ public class BiddingBaseManagerTest { public void setup() { ClientProperties.setApplication((Application) InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext()); ClientProperties.setApplicationContext(InstrumentationRegistry.getInstrumentation().getTargetContext()); - managerWithTokenListener = Mockito.spy(new BiddingBaseManager(publisherListener) { + managerWithTokenListener = Mockito.spy(new BiddingBaseManager(isBannerEnabled, publisherListener) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); - managerWithNullListener = Mockito.spy(new BiddingBaseManager(null) { + managerWithNullListener = Mockito.spy(new BiddingBaseManager(isBannerEnabled, null) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); Mockito.when(managerWithTokenListener.getMetricSender()).thenReturn(_metricSenderMock); @@ -115,16 +105,11 @@ public class BiddingBaseManagerTest { @Test public void testSendsAsyncMetricWhenUploadStartsAndSucceedsWithAsyncTokenCall() throws InterruptedException { - BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(publisherListener, _scarRequestHandlerMock) { + BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(isBannerEnabled, publisherListener, _scarRequestHandlerMock) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); Mockito.when(managerWithScarRequestSender.getMetricSender()).thenReturn(_metricSenderMock); @@ -133,7 +118,7 @@ public class BiddingBaseManagerTest { final Metric secondDesiredMetric = ScarMetric.hbSignalsUploadSuccess(isAsyncTokenCall); managerWithScarRequestSender.permitUpload(); - managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal")); + managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal", "testBannerSignal")); Thread.sleep(1000); @@ -170,21 +155,16 @@ public class BiddingBaseManagerTest { public void testSendsAsyncMetricWhenUploadRequestFailsWithMalformedUrlAndAsyncTokenCall() throws Exception { String errorMessage = "bad request"; Mockito.doThrow(new Exception(errorMessage)).when(_scarRequestHandlerMock).makeUploadRequest(Mockito.any(), Mockito.any(), any(String.class)); - BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(publisherListener, _scarRequestHandlerMock) { + BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(isBannerEnabled, publisherListener, _scarRequestHandlerMock) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); Mockito.when(managerWithScarRequestSender.getMetricSender()).thenReturn(_metricSenderMock); managerWithScarRequestSender.permitUpload(); - managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal")); + managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal", "testBannerSignal")); final ArgumentCaptor metricsCaptor = ArgumentCaptor.forClass(Metric.class); final Metric firstDesiredMetric = ScarMetric.hbSignalsUploadStart(isAsyncTokenCall); @@ -242,16 +222,11 @@ public class BiddingBaseManagerTest { @Test public void testSendsSyncMetricWhenUploadStartsAndSucceedsWithSyncTokenCall() throws InterruptedException { - BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(null, _scarRequestHandlerMock) { + BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(isBannerEnabled, null, _scarRequestHandlerMock) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); Mockito.when(managerWithScarRequestSender.getMetricSender()).thenReturn(_metricSenderMock); @@ -260,7 +235,7 @@ public class BiddingBaseManagerTest { final Metric secondDesiredMetric = ScarMetric.hbSignalsUploadSuccess(isNotAsyncTokenCall); managerWithScarRequestSender.permitUpload(); - managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal")); + managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal", "testBannerSignal")); Thread.sleep(1000); @@ -297,21 +272,16 @@ public class BiddingBaseManagerTest { public void testSendsSyncMetricWhenUploadRequestFailsWithMalformedUrlAndSyncTokenCall() throws Exception { String errorMessage = "bad request"; Mockito.doThrow(new Exception(errorMessage)).when(_scarRequestHandlerMock).makeUploadRequest(Mockito.any(), Mockito.any(), any(String.class)); - BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(null, _scarRequestHandlerMock) { + BiddingBaseManager managerWithScarRequestSender = Mockito.spy(new BiddingBaseManager(isBannerEnabled, null, _scarRequestHandlerMock) { @Override public void start() { } - - @Override - public void onUnityTokenSuccessfullyFetched() { - - } }); Mockito.when(managerWithScarRequestSender.getMetricSender()).thenReturn(_metricSenderMock); managerWithScarRequestSender.permitUpload(); - managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal")); + managerWithScarRequestSender.onSignalsReady(new BiddingSignals("testRewardedSignal", "testInterstitialSignal", "testBannerSignal")); final ArgumentCaptor metricsCaptor = ArgumentCaptor.forClass(Metric.class); final Metric firstDesiredMetric = ScarMetric.hbSignalsUploadStart(isNotAsyncTokenCall); @@ -336,29 +306,11 @@ public class BiddingBaseManagerTest { Mockito.verify(publisherListener, Mockito.times(1)).onUnityAdsTokenReady(TEST_TOKEN); } - @Test - public void testOnUnityTokenSuccessfullyFetchedAfterOnUnityAdsTokenReadyWithValidToken() { - managerWithTokenListener.onUnityAdsTokenReady(TEST_TOKEN); - Mockito.verify(managerWithTokenListener, Mockito.times(1)).onUnityTokenSuccessfullyFetched(); - } - - @Test - public void testOnUnityTokenSuccessfullyFetchedAfterOnUnityAdsTokenReadyWithNullToken() { - managerWithTokenListener.onUnityAdsTokenReady(null); - Mockito.verify(managerWithTokenListener, Mockito.times(0)).onUnityTokenSuccessfullyFetched(); - } - - @Test - public void testOnUnityTokenSuccessfullyFetchedAfterOnUnityAdsTokenReadyWithEmptyToken() { - managerWithTokenListener.onUnityAdsTokenReady(""); - Mockito.verify(managerWithTokenListener, Mockito.times(0)).onUnityTokenSuccessfullyFetched(); - } - @Test public void testUploadSignalsAfterPermittedAndSignalsReady() throws InterruptedException { managerWithTokenListener.permitSignalsUpload(); Thread.sleep(100); - managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test")); + managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test", "test")); Mockito.verify(managerWithTokenListener, Mockito.times(1)).uploadSignals(); } @@ -371,7 +323,7 @@ public class BiddingBaseManagerTest { @Test public void testUploadSignalsAfterSignalsReadyButNotPermitted() throws InterruptedException { - managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test")); + managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test", "test")); Thread.sleep(100); Mockito.verify(managerWithTokenListener, Mockito.times(0)).uploadSignals(); } @@ -381,9 +333,9 @@ public class BiddingBaseManagerTest { managerWithTokenListener.permitSignalsUpload(); Thread.sleep(100); Mockito.verify(managerWithTokenListener, Mockito.times(0)).uploadSignals(); - managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test")); - managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test")); - managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test")); + managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test", "test")); + managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test", "test")); + managerWithTokenListener.onSignalsReady(new BiddingSignals("test", "test", "test")); Mockito.verify(managerWithTokenListener, Mockito.times(1)).uploadSignals(); } } diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingEagerManagerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingEagerManagerTest.java index cd58e5c..908a98b 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingEagerManagerTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingEagerManagerTest.java @@ -17,10 +17,11 @@ public class BiddingEagerManagerTest { IUnityAdsTokenListener callerListener; private BiddingEagerManager manager; private String TEST_TOKEN = "token"; + private boolean isBannerEnabled = true; @Before public void setup() { - manager = Mockito.spy(new BiddingEagerManager(callerListener)); + manager = Mockito.spy(new BiddingEagerManager(isBannerEnabled, callerListener)); } @Test @@ -30,13 +31,6 @@ public class BiddingEagerManagerTest { Mockito.verify(manager, Mockito.times(1)).permitSignalsUpload(); } - @Test - public void testNoFetchAndUploadSignalsAfterOnUnityTokenSuccessfullyFetched() { - manager.onUnityTokenSuccessfullyFetched(); - Mockito.verify(manager, Mockito.times(0)).fetchSignals(); - Mockito.verify(manager, Mockito.times(0)).permitSignalsUpload(); - } - @Test public void testListenerIsInvokedOnUnityAdsTokenReady() { manager.onUnityAdsTokenReady(TEST_TOKEN); diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingLazyManagerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingLazyManagerTest.java deleted file mode 100644 index 12305dc..0000000 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingLazyManagerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.unity3d.ads.test.instrumentation.services.ads.gmascar.managers; - -import com.unity3d.ads.IUnityAdsTokenListener; -import com.unity3d.services.ads.gmascar.managers.BiddingLazyManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class BiddingLazyManagerTest { - - @Mock - IUnityAdsTokenListener callerListener; - private BiddingLazyManager manager; - private String TEST_TOKEN = "token"; - - @Before - public void setup() { - manager = Mockito.spy(new BiddingLazyManager(callerListener)); - } - - @Test - public void testNoActionAfterStartCalled() { - manager.start(); - Mockito.verify(manager, Mockito.times(0)).fetchSignals(); - Mockito.verify(manager, Mockito.times(0)).permitSignalsUpload(); - } - - @Test - public void testPermitAndFetchSignalsAfterStartCalled() { - manager.onUnityTokenSuccessfullyFetched(); - Mockito.verify(manager, Mockito.times(1)).fetchSignals(); - Mockito.verify(manager, Mockito.times(1)).permitSignalsUpload(); - } - - @Test - public void testListenerIsInvokedOnUnityAdsTokenReady() { - manager.onUnityAdsTokenReady(TEST_TOKEN); - Mockito.verify(callerListener, Mockito.times(1)).onUnityAdsTokenReady(TEST_TOKEN); - } - -} diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingOnDemandManagerTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingOnDemandManagerTest.java deleted file mode 100644 index 5c1a020..0000000 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/BiddingOnDemandManagerTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.unity3d.ads.test.instrumentation.services.ads.gmascar.managers; - -import com.unity3d.ads.IUnityAdsTokenListener; -import com.unity3d.services.ads.gmascar.managers.BiddingOnDemandManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -@RunWith(MockitoJUnitRunner.class) -public class BiddingOnDemandManagerTest { - - @Mock - IUnityAdsTokenListener callerListener; - private BiddingOnDemandManager manager; - private String TEST_TOKEN = "token"; - - @Before - public void setup() { - manager = Mockito.spy(new BiddingOnDemandManager(callerListener)); - } - - @Test - public void testOnlyFetchSignalsCalledAfterStartCalled() { - manager.start(); - Mockito.verify(manager, Mockito.times(1)).fetchSignals(); - Mockito.verify(manager, Mockito.times(0)).permitSignalsUpload(); - } - - @Test - public void testOnlyPermitSignalsCalledAfterOnUnityTokenSuccessfullyFetched() { - manager.onUnityTokenSuccessfullyFetched(); - Mockito.verify(manager, Mockito.times(0)).fetchSignals(); - Mockito.verify(manager, Mockito.times(1)).permitSignalsUpload(); - } - - @Test - public void testListenerIsInvokedOnUnityAdsTokenReady() { - manager.onUnityAdsTokenReady(TEST_TOKEN); - Mockito.verify(callerListener, Mockito.times(1)).onUnityAdsTokenReady(TEST_TOKEN); - } -} diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/ScarBiddingManagerEnumTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/ScarBiddingManagerEnumTest.java deleted file mode 100644 index 2e193d5..0000000 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/gmascar/managers/ScarBiddingManagerEnumTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.unity3d.ads.test.instrumentation.services.ads.gmascar.managers; - -import static org.junit.Assert.assertEquals; - -import com.unity3d.services.ads.gmascar.managers.SCARBiddingManagerType; - -import org.junit.Test; - -public class ScarBiddingManagerEnumTest { - - @Test - public void testEnumToNameMappings() { - assertEquals("dis", SCARBiddingManagerType.DISABLED.getName()); - assertEquals("hyb", SCARBiddingManagerType.HYBRID.getName()); - assertEquals("laz", SCARBiddingManagerType.LAZY.getName()); - assertEquals("eag", SCARBiddingManagerType.EAGER.getName()); - } - - @Test - public void testNameToEnumMappings() { - assertEquals(SCARBiddingManagerType.DISABLED, SCARBiddingManagerType.fromName("dis")); - assertEquals(SCARBiddingManagerType.HYBRID, SCARBiddingManagerType.fromName("hyb")); - assertEquals(SCARBiddingManagerType.LAZY, SCARBiddingManagerType.fromName("laz")); - assertEquals(SCARBiddingManagerType.EAGER, SCARBiddingManagerType.fromName("eag")); - } -} diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/LoadModuleDecoratorTimeoutTests.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/LoadModuleDecoratorTimeoutTests.java index 75c2aa5..648661e 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/LoadModuleDecoratorTimeoutTests.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/LoadModuleDecoratorTimeoutTests.java @@ -13,11 +13,12 @@ import com.unity3d.ads.test.TestUtilities; import com.unity3d.services.ads.operation.load.ILoadModule; import com.unity3d.services.ads.operation.load.LoadModuleDecoratorTimeout; import com.unity3d.services.ads.operation.load.LoadOperationState; -import com.unity3d.services.core.configuration.Configuration; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentObjects; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.request.metrics.SDKMetricsSender; import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker; +import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -35,23 +36,23 @@ public class LoadModuleDecoratorTimeoutTests { private IUnityAdsLoadListener loadListenerMock; private ILoadModule loadModuleMock; private SDKMetricsSender sdkMetricsMock; - private ConfigurationReader configurationReaderMock; + private ExperimentsReader experimentsReaderMock; @Before public void beforeEachTest() { loadListenerMock = mock(IUnityAdsLoadListener.class); loadModuleMock = mock(ILoadModule.class); sdkMetricsMock = mock(SDKMetricsSender.class); - configurationReaderMock = mock(ConfigurationReader.class); + experimentsReaderMock = mock(ExperimentsReader.class); - Mockito.when(configurationReaderMock.getCurrentConfiguration()).thenReturn(new Configuration()); + Mockito.when(experimentsReaderMock.getCurrentlyActiveExperiments()).thenReturn(new ExperimentObjects(new JSONObject())); } @Test public void onUnityAdsFailedToLoadIsCalledWhenTimeoutIsReached() { Mockito.when(loadModuleMock.getMetricSender()).thenReturn(sdkMetricsMock); LoadOperationState loadOperationState = new LoadOperationState(placementId, loadListenerMock, loadOptions, OperationTestUtilities.createConfigurationWithLoadTimeout(loadTimeout)); - LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, configurationReaderMock); + LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, experimentsReaderMock); timeoutDecorator.executeAdOperation(mock(IWebViewBridgeInvoker.class), loadOperationState); Mockito.verify(loadListenerMock, timeout(maxWaitTime).times(1)).onUnityAdsFailedToLoad(placementId, UnityAds.UnityAdsLoadError.TIMEOUT, "[UnityAds] Timeout while loading " + placementId); @@ -61,7 +62,7 @@ public class LoadModuleDecoratorTimeoutTests { public void onUnityAdsAdLoadedAndOnUnityAdsAdFailedToLoadIsNotCalledAgainWhenTimeoutHasBeenReached() { Mockito.when(loadModuleMock.getMetricSender()).thenReturn(sdkMetricsMock); LoadOperationState loadOperationState = new LoadOperationState(placementId, loadListenerMock, loadOptions, OperationTestUtilities.createConfigurationWithLoadTimeout(loadTimeout)); - LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, configurationReaderMock); + LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, experimentsReaderMock); timeoutDecorator.executeAdOperation(mock(IWebViewBridgeInvoker.class), loadOperationState); TestUtilities.SleepCurrentThread(loadTimeoutExpireMs); @@ -76,7 +77,7 @@ public class LoadModuleDecoratorTimeoutTests { public void onUnityAdsAdFailedToLoadIsNotCalledWhenOnUnityAdsAdLoadedIsCalledBeforeTimeout() { Mockito.when(loadModuleMock.getMetricSender()).thenReturn(sdkMetricsMock); LoadOperationState loadOperationState = new LoadOperationState(placementId, loadListenerMock, loadOptions, OperationTestUtilities.createConfigurationWithLoadTimeout(loadTimeout)); - LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, configurationReaderMock); + LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, experimentsReaderMock); timeoutDecorator.executeAdOperation(mock(IWebViewBridgeInvoker.class), loadOperationState); TestUtilities.SleepCurrentThread(25); @@ -88,14 +89,14 @@ public class LoadModuleDecoratorTimeoutTests { @Test public void noNPEIsThrownWhenOnUnityAdsAdLoadedIsCalledWithoutCallingExecuteAdOperation() { - LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, configurationReaderMock); + LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, experimentsReaderMock); timeoutDecorator.onUnityAdsAdLoaded(placementId); Mockito.verify(loadModuleMock, times(0)).onUnityAdsFailedToLoad(anyString(), any(UnityAds.UnityAdsLoadError.class), anyString()); } @Test public void noNPEIsThrownWhenOnUnityAdsAdFailedToLoadIsCalledWithoutCallingExecuteAdOperation() { - LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, configurationReaderMock); + LoadModuleDecoratorTimeout timeoutDecorator = new LoadModuleDecoratorTimeout(loadModuleMock, experimentsReaderMock); timeoutDecorator.onUnityAdsFailedToLoad(placementId, loadError, loadErrorMessage); Mockito.verify(loadModuleMock, times(0)).onUnityAdsAdLoaded(anyString()); } diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/ShowModuleDecoratorTimeoutTests.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/ShowModuleDecoratorTimeoutTests.java index 62823f8..e995f36 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/ShowModuleDecoratorTimeoutTests.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/ads/operation/ShowModuleDecoratorTimeoutTests.java @@ -17,8 +17,8 @@ import com.unity3d.services.ads.operation.show.IShowModule; import com.unity3d.services.ads.operation.show.ShowModule; import com.unity3d.services.ads.operation.show.ShowModuleDecoratorTimeout; import com.unity3d.services.ads.operation.show.ShowOperationState; -import com.unity3d.services.core.configuration.Configuration; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.Experiments; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.request.metrics.SDKMetricsSender; import com.unity3d.services.core.webview.bridge.CallbackStatus; import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker; @@ -41,7 +41,7 @@ public class ShowModuleDecoratorTimeoutTests { private IUnityAdsShowListener showListenerMock; private IShowModule showModule; private SDKMetricsSender sdkMetricsMock; - private ConfigurationReader configurationReaderMock; + private ExperimentsReader experimentsReaderMock; @Rule public final ActivityTestRule _activityRule = new ActivityTestRule<>(InstrumentationTestActivity.class); @@ -50,16 +50,16 @@ public class ShowModuleDecoratorTimeoutTests { public void beforeEachTest() { showListenerMock = mock(IUnityAdsShowListener.class); sdkMetricsMock = mock(SDKMetricsSender.class); - configurationReaderMock = mock(ConfigurationReader.class); + experimentsReaderMock = mock(ExperimentsReader.class); // We need a real instance since ShowModule will create the Operation object (which holds the State with Listener ID) showModule = new ShowModule(sdkMetricsMock); - Mockito.when(configurationReaderMock.getCurrentConfiguration()).thenReturn(new Configuration()); + Mockito.when(experimentsReaderMock.getCurrentlyActiveExperiments()).thenReturn(new Experiments()); } @Test public void testShowModuleDecoratorTimeout() { - ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule, configurationReaderMock); + ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule, experimentsReaderMock); ShowOperationState showOperationState = new ShowOperationState(placementId, showListenerMock, _activityRule.getActivity(), showOptions, OperationTestUtilities.createConfigurationWithShowTimeout(showTimeout)); showModuleDecoratorTimeout.executeAdOperation(mock(IWebViewBridgeInvoker.class), showOperationState); @@ -68,7 +68,7 @@ public class ShowModuleDecoratorTimeoutTests { @Test public void testShowModuleDecoratorShowConsentNoTimeout() { - ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule, configurationReaderMock); + ShowModuleDecoratorTimeout showModuleDecoratorTimeout = new ShowModuleDecoratorTimeout(showModule, experimentsReaderMock); ShowOperationState showOperationState = new ShowOperationState(placementId, showListenerMock, _activityRule.getActivity(), showOptions, OperationTestUtilities.createConfigurationWithShowTimeout(showTimeout)); IWebViewBridgeInvoker webViewBridgeInvoker = mock(IWebViewBridgeInvoker.class); when(webViewBridgeInvoker.invokeMethod(anyString(), anyString(), any(Method.class), any())).thenReturn(true); diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerErrorInfoTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerErrorInfoTest.java new file mode 100644 index 0000000..7f6f1a2 --- /dev/null +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerErrorInfoTest.java @@ -0,0 +1,41 @@ +package com.unity3d.ads.test.instrumentation.services.banners; + +import com.unity3d.ads.UnityAds; +import com.unity3d.services.banners.BannerErrorCode; +import com.unity3d.services.banners.BannerErrorInfo; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class BannerErrorInfoTest { + + private String errorMessage = "BANNER ERROR MSG"; + + @Test + public void testConvertNativeBannerErrorToLoadError() { + BannerErrorInfo nativeError = new BannerErrorInfo(errorMessage, BannerErrorCode.NATIVE_ERROR); + UnityAds.UnityAdsLoadError loadError = nativeError.toLoadError(); + assertEquals(UnityAds.UnityAdsLoadError.INVALID_ARGUMENT, loadError); + } + + @Test + public void testConvertNoFillBannerErrorToLoadError() { + BannerErrorInfo noFillError = new BannerErrorInfo(errorMessage, BannerErrorCode.NO_FILL); + UnityAds.UnityAdsLoadError loadError = noFillError.toLoadError(); + assertEquals(UnityAds.UnityAdsLoadError.NO_FILL, loadError); + } + + @Test + public void testConvertWebViewBannerErrorToLoadError() { + BannerErrorInfo webViewError = new BannerErrorInfo(errorMessage, BannerErrorCode.WEBVIEW_ERROR); + UnityAds.UnityAdsLoadError loadError = webViewError.toLoadError(); + assertEquals(UnityAds.UnityAdsLoadError.INTERNAL_ERROR, loadError); + } + + @Test + public void testConvertUnknownBannerErrorToLoadError() { + BannerErrorInfo unknownError = new BannerErrorInfo(errorMessage, BannerErrorCode.UNKNOWN); + UnityAds.UnityAdsLoadError loadError = unknownError.toLoadError(); + assertEquals(UnityAds.UnityAdsLoadError.INTERNAL_ERROR, loadError); + } +} diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerViewCacheTests.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerViewCacheTests.java index 8d24f21..655dff7 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerViewCacheTests.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/banners/BannerViewCacheTests.java @@ -68,18 +68,28 @@ public class BannerViewCacheTests { } @Test - public void testTriggerBannerLoadEvent() throws InterruptedException { + public void testTriggerBannerLoadEvent() throws InterruptedException, NoSuchFieldException, IllegalAccessException { BannerViewCache bannerViewCache = new BannerViewCache(); final BannerView bannerView = new BannerView(_activityRule.getActivity(), "test", new UnityBannerSize(320, 50)); String bannerAdId = bannerViewCache.addBannerView(bannerView); final Semaphore _loadedSemaphore = new Semaphore(0); + + ILoadModule loadBannerModule = new LoadBannerModule(Mockito.mock(SDKMetricsSender.class)); + ILoadModule spy = Mockito.spy(loadBannerModule); + + Field instance = LoadBannerModule.class.getDeclaredField("_instance"); + instance.setAccessible(true); + instance.set(LoadBannerModule.class, spy); + bannerView.setListener(new BannerView.Listener() { @Override public void onBannerLoaded(BannerView bannerAdView) { assertEquals(bannerView, bannerAdView); + Mockito.verify(spy).onUnityAdsAdLoaded(bannerAdId); _loadedSemaphore.release(); } }); + bannerViewCache.triggerBannerLoadEvent(bannerAdId); _loadedSemaphore.acquire(); } @@ -119,7 +129,7 @@ public class BannerViewCacheTests { } @Test - public void testTriggerBannerErrorEvent() throws InterruptedException, NoSuchFieldException, IllegalAccessException { + public void testTriggerBannerErrorEventWithNativeError() throws InterruptedException, NoSuchFieldException, IllegalAccessException { BannerViewCache bannerViewCache = new BannerViewCache(); final BannerView bannerView = new BannerView(_activityRule.getActivity(), "test", new UnityBannerSize(320, 50)); final BannerErrorInfo bannerErrorInfo = new BannerErrorInfo("test error", BannerErrorCode.NATIVE_ERROR); @@ -133,6 +143,52 @@ public class BannerViewCacheTests { ILoadOperation loadOperation = Mockito.mock(ILoadOperation.class); Mockito.when(loadOperation.getLoadOperationState()).thenReturn(loadOperationState); + ILoadModule loadBannerModule = new LoadBannerModule(Mockito.mock(SDKMetricsSender.class)); + ILoadModule spy = Mockito.spy(loadBannerModule); + Mockito.when(spy.get(Mockito.anyString())).thenReturn(loadOperation); + Mockito.doAnswer(invocation -> { + Mockito.doAnswer(invocation1 -> { + LoadOperationState state = invocation.getArgument(1); + state.onUnityAdsFailedToLoad(UnityAds.UnityAdsLoadError.INVALID_ARGUMENT, "test error"); + return null; + }).when(loadOperation).onUnityAdsFailedToLoad(Mockito.anyString(), Mockito.any(), Mockito.any()); + return null; + }).when(spy).executeAdOperation(Mockito.any(), Mockito.any()); + + Field instance = LoadBannerModule.class.getDeclaredField("_instance"); + instance.setAccessible(true); + instance.set(LoadBannerModule.class, spy); + + final Semaphore _errorSemaphore = new Semaphore(0); + bannerView.setListener(new BannerView.Listener() { + @Override + public void onBannerFailedToLoad(BannerView bannerAdView, BannerErrorInfo _bannerErrorInfo) { + assertEquals(bannerView, bannerAdView); + assertEquals(BannerErrorCode.NATIVE_ERROR, _bannerErrorInfo.errorCode); + Mockito.verify(spy).onUnityAdsFailedToLoad(bannerAdId, UnityAds.UnityAdsLoadError.INVALID_ARGUMENT, "test error"); + _errorSemaphore.release(); + } + }); + bannerView.load(); + bannerViewCache.triggerBannerErrorEvent(bannerAdId, bannerErrorInfo); + _errorSemaphore.acquire(); + } + + @Test + public void testTriggerBannerErrorEventWithWebViewError() throws InterruptedException, NoSuchFieldException, IllegalAccessException { + BannerViewCache bannerViewCache = new BannerViewCache(); + final BannerView bannerView = new BannerView(_activityRule.getActivity(), "test", new UnityBannerSize(320, 50)); + final BannerErrorInfo bannerErrorInfo = new BannerErrorInfo("test error", BannerErrorCode.WEBVIEW_ERROR); + String bannerAdId = bannerViewCache.addBannerView(bannerView); + + LoadOperationState loadOperationState = Mockito.mock(LoadOperationState.class); + Mockito.when(loadOperationState.isBanner()).thenReturn(true); + Mockito.when(loadOperationState.duration()).thenReturn(Long.MAX_VALUE); + loadOperationState.placementId = "test"; + + ILoadOperation loadOperation = Mockito.mock(ILoadOperation.class); + Mockito.when(loadOperation.getLoadOperationState()).thenReturn(loadOperationState); + ILoadModule loadBannerModule = new LoadBannerModule(Mockito.mock(SDKMetricsSender.class)); ILoadModule spy = Mockito.spy(loadBannerModule); Mockito.when(spy.get(Mockito.anyString())).thenReturn(loadOperation); @@ -154,6 +210,7 @@ public class BannerViewCacheTests { @Override public void onBannerFailedToLoad(BannerView bannerAdView, BannerErrorInfo _bannerErrorInfo) { assertEquals(bannerView, bannerAdView); + assertEquals(BannerErrorCode.WEBVIEW_ERROR, _bannerErrorInfo.errorCode); Mockito.verify(spy).onUnityAdsFailedToLoad(bannerAdId, UnityAds.UnityAdsLoadError.INTERNAL_ERROR, "test error"); _errorSemaphore.release(); } @@ -179,5 +236,4 @@ public class BannerViewCacheTests { bannerViewCache.triggerBannerLeftApplicationEvent(bannerAdId); _leftApplicationSemaphore.acquire(); } - } diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/core/webview/WebViewUrlBuilderTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/core/webview/WebViewUrlBuilderTest.java index 9a52ef7..805adde 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/core/webview/WebViewUrlBuilderTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/instrumentation/services/core/webview/WebViewUrlBuilderTest.java @@ -1,12 +1,9 @@ package com.unity3d.ads.test.instrumentation.services.core.webview; import com.unity3d.services.core.configuration.Configuration; -import com.unity3d.services.core.configuration.Experiments; import com.unity3d.services.core.request.metrics.SDKMetrics; import com.unity3d.services.core.webview.WebViewUrlBuilder; -import org.json.JSONException; -import org.json.JSONObject; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -57,7 +54,7 @@ public class WebViewUrlBuilderTest { @Test public void testWebViewUrlBuilderWithMetricsEnabled() { Mockito.when(_configMock.getExperiments()).thenReturn(null); - Mockito.when(_configMock.getMetricSampleRate()).thenReturn(100.0); + Mockito.when(_configMock.areMetricsEnabledForCurrentSession()).thenReturn(Boolean.TRUE); Mockito.when(_configMock.getMetricsUrl()).thenReturn(TEST_BASE_URL); SDKMetrics.setConfiguration(_configMock); WebViewUrlBuilder webViewUrlBuilder = new WebViewUrlBuilder(TEST_BASE_URL, _configMock); diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/integration/SDKMetricsTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/integration/SDKMetricsTest.java index 3e0d41d..1eb572e 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/integration/SDKMetricsTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/integration/SDKMetricsTest.java @@ -100,31 +100,6 @@ public class SDKMetricsTest { SDKMetrics.getInstance().sendEvent("test_event"); } - @Test - public void testSettingMsr100Then0() throws NoSuchFieldException, IllegalAccessException { - validateAndTestChangingSampleRate("testUrl", 100.0, 0.0, MetricSender.class); - Assert.assertTrue("Metrics expected to be enabled for session", SDKMetrics.getInstance().areMetricsEnabledForCurrentSession()); - } - - @Test - public void testSettingMsr0Then100() throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { - Class expectedClass = Class.forName("com.unity3d.services.core.request.metrics.SDKMetrics$NullInstance"); - validateAndTestChangingSampleRate("testUrl", 0.0, 100.0, expectedClass); - Assert.assertFalse("Metrics expected to be disabled for session", SDKMetrics.getInstance().areMetricsEnabledForCurrentSession()); - } - - @Test - public void testSettingMsrWithNullUrl() throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { - Class expectedClass = Class.forName("com.unity3d.services.core.request.metrics.SDKMetrics$NullInstance"); - validateAndTestChangingSampleRate(null, 100.0, 100.0, expectedClass); - } - - @Test - public void testSettingMsrWithEmptyUrl() throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { - Class expectedClass = Class.forName("com.unity3d.services.core.request.metrics.SDKMetrics$NullInstance"); - validateAndTestChangingSampleRate("", 100.0, 100.0, expectedClass); - } - @Test public void testMalformedUrlFromConfiguration() throws Exception { JSONObject json = new JSONObject(); @@ -159,20 +134,4 @@ public class SDKMetricsTest { Mockito.verify(_metricSenderMock).sendMetric(metricCapture.capture()); Assert.assertEquals(TEST_STATE_TAGS, metricCapture.getValue().getTags()); } - - private void validateAndTestChangingSampleRate(String metricsUrl, double oldMsr, double newMsr, Class expectedMetricsClass) throws NoSuchFieldException, IllegalAccessException { - Configuration mockConfiguration = Mockito.mock(Configuration.class); - Mockito.when(mockConfiguration.getMetricsUrl()).thenReturn(metricsUrl); - Mockito.when(mockConfiguration.getMetricSampleRate()).thenReturn(oldMsr); - SDKMetrics.setConfiguration(mockConfiguration); - SDKMetrics.getInstance(); - Field instanceField = SDKMetrics.class.getDeclaredField("_instance"); - instanceField.setAccessible(true); - Object instanceFieldObj = instanceField.get(SDKMetricsSender.class); - Assert.assertEquals(expectedMetricsClass, instanceFieldObj.getClass()); - Mockito.when(mockConfiguration.getMetricSampleRate()).thenReturn(newMsr); - SDKMetrics.setConfiguration(mockConfiguration); - instanceFieldObj = instanceField.get(SDKMetricsSender.class); - Assert.assertEquals(expectedMetricsClass, instanceFieldObj.getClass()); - } } diff --git a/unity-ads/src/androidTest/java/com/unity3d/ads/test/legacy/DeviceTest.java b/unity-ads/src/androidTest/java/com/unity3d/ads/test/legacy/DeviceTest.java index 2c0a31f..3962e54 100644 --- a/unity-ads/src/androidTest/java/com/unity3d/ads/test/legacy/DeviceTest.java +++ b/unity-ads/src/androidTest/java/com/unity3d/ads/test/legacy/DeviceTest.java @@ -40,6 +40,11 @@ public class DeviceTest { assertTrue("Expected SDK_INT should be > 9", Device.getApiLevel() >= 9); } + @Test + public void testExtensionVersion () { + assertTrue("Expected extension version should be > 4", Device.getExtensionVersion() >= -1); + } + @Test public void testScreenLayout () { assertTrue("Expected screenLayout property be something else than undefined (0)", Device.getScreenLayout() > 0); diff --git a/unity-ads/src/main/java/com/unity3d/services/SDKErrorHandler.kt b/unity-ads/src/main/java/com/unity3d/services/SDKErrorHandler.kt index d2aa726..04e3243 100644 --- a/unity-ads/src/main/java/com/unity3d/services/SDKErrorHandler.kt +++ b/unity-ads/src/main/java/com/unity3d/services/SDKErrorHandler.kt @@ -2,7 +2,6 @@ package com.unity3d.services import com.unity3d.services.core.domain.ISDKDispatchers import com.unity3d.services.core.request.metrics.Metric -import com.unity3d.services.core.request.metrics.SDKMetrics import com.unity3d.services.core.request.metrics.SDKMetricsSender import kotlinx.coroutines.CoroutineExceptionHandler import java.lang.IllegalStateException @@ -14,19 +13,19 @@ class SDKErrorHandler(private val dispatchers: ISDKDispatchers, private val sdkM override val key = CoroutineExceptionHandler.Key override fun handleException(context: CoroutineContext, exception: Throwable) { - val className: String = exception.stackTrace[0].fileName - val line: Int = exception.stackTrace[0].lineNumber + val className: String = exception.stackTrace[0]?.fileName ?: "unknown" + val line: Int = exception.stackTrace[0]?.lineNumber ?: 0 val name: String = when (exception) { is NullPointerException -> "native_exception_npe" is OutOfMemoryError -> "native_exception_oom" is IllegalStateException -> "native_exception_ise" - is RuntimeException -> "native_exception_re" is SecurityException -> "native_exception_se" + is RuntimeException -> "native_exception_re" else -> "native_exception" } - sendMetric(Metric(name, "{$className}_$line")) + sendMetric(Metric(name, "${className}_$line")) } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/UnityAdsImplementation.java b/unity-ads/src/main/java/com/unity3d/services/ads/UnityAdsImplementation.java index ffee052..f26768b 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/UnityAdsImplementation.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/UnityAdsImplementation.java @@ -27,7 +27,6 @@ import com.unity3d.services.core.log.DeviceLog; import com.unity3d.services.core.misc.Utilities; import com.unity3d.services.core.properties.ClientProperties; import com.unity3d.services.core.request.metrics.AdOperationMetric; -import com.unity3d.services.core.request.metrics.SDKMetrics; import com.unity3d.services.core.request.metrics.SDKMetricsSender; import com.unity3d.services.core.webview.WebViewApp; import com.unity3d.services.core.webview.bridge.WebViewBridgeInvoker; @@ -203,7 +202,7 @@ public final class UnityAdsImplementation implements IUnityAds { } Configuration config = configuration == null ? new ConfigurationReader().getCurrentConfiguration() : configuration; - BiddingBaseManager manager = BiddingManagerFactory.getInstance().createManager(listener, config.getExperiments()); + BiddingBaseManager manager = BiddingManagerFactory.getInstance().createManager(null, config.getExperiments()); manager.start(); asyncTokenStorage.getToken(manager); diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitActivity.java b/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitActivity.java index 617aba2..bafe8a4 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitActivity.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitActivity.java @@ -75,9 +75,10 @@ public class AdUnitActivity extends Activity implements IAdUnitActivity { @Override protected void onDestroy() { + if (_controller != null) { + _controller.onDestroy(); + } super.onDestroy(); - - _controller.onDestroy(); } @Override diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitRelativeLayout.java b/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitRelativeLayout.java index 2bcb2b8..7fe9a90 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitRelativeLayout.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/adunit/AdUnitRelativeLayout.java @@ -1,9 +1,15 @@ package com.unity3d.services.ads.adunit; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_POINTER_DOWN; +import static android.view.MotionEvent.ACTION_POINTER_UP; +import static android.view.MotionEvent.ACTION_UP; + import android.annotation.TargetApi; import android.content.Context; import android.util.SparseArray; import android.util.SparseIntArray; +import android.view.InputEvent; import android.view.MotionEvent; import android.widget.RelativeLayout; @@ -13,6 +19,7 @@ public class AdUnitRelativeLayout extends RelativeLayout { private final ArrayList _motionEvents = new ArrayList<>(); private int _maxEvents = 10000; private boolean _shouldCapture = false; + private InputEvent _lastInputEvent; public AdUnitRelativeLayout(Context context) { super(context); @@ -22,6 +29,13 @@ public class AdUnitRelativeLayout extends RelativeLayout { public boolean onInterceptTouchEvent(MotionEvent e) { super.onInterceptTouchEvent(e); + if (e.getActionMasked() == ACTION_UP || + e.getActionMasked() == ACTION_DOWN || + e.getActionMasked() == ACTION_POINTER_UP || + e.getActionMasked() == ACTION_POINTER_DOWN) { + _lastInputEvent = e; + } + if (_shouldCapture) { if (_motionEvents.size() < _maxEvents) { boolean isObscured = (e.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0; @@ -102,4 +116,8 @@ public class AdUnitRelativeLayout extends RelativeLayout { return returnArray; } + + public InputEvent getLastInputEvent() { + return _lastInputEvent; + } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/api/GMAScar.java b/unity-ads/src/main/java/com/unity3d/services/ads/api/GMAScar.java index 36dd6b0..079c911 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/api/GMAScar.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/api/GMAScar.java @@ -1,5 +1,6 @@ package com.unity3d.services.ads.api; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.services.ads.gmascar.GMAScarAdapterBridge; import com.unity3d.services.ads.gmascar.GMA; import com.unity3d.services.core.webview.bridge.WebViewCallback; @@ -30,8 +31,8 @@ public class GMAScar { } @WebViewExposed - public static void getSCARSignals(final JSONArray interstitialList, final JSONArray rewardedList, final WebViewCallback callback) throws JSONException { - gmaScarAdapterBridge.getSCARSignals(getPlacementList(interstitialList), getPlacementList(rewardedList)); + public static void getSCARSignal(final String placementId, final String adFormatStr, final WebViewCallback callback) { + gmaScarAdapterBridge.getSCARSignal(placementId, UnityAdFormat.valueOf(adFormatStr.toUpperCase())); callback.invoke(); } @@ -46,13 +47,4 @@ public class GMAScar { gmaScarAdapterBridge.show(placementId, queryId, canSkip); callback.invoke(); } - - private static String[] getPlacementList(JSONArray placements) throws JSONException { - String[] placementIdList = new String[placements.length()]; - for (int placementIndex = 0; placementIndex < placements.length(); placementIndex++) { - placementIdList[placementIndex] = placements.getString(placementIndex); - } - return placementIdList; - } - } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/api/Measurements.java b/unity-ads/src/main/java/com/unity3d/services/ads/api/Measurements.java new file mode 100644 index 0000000..f11fba4 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/api/Measurements.java @@ -0,0 +1,47 @@ +package com.unity3d.services.ads.api; + +import android.view.InputEvent; + +import com.unity3d.services.ads.measurements.MeasurementsErrors; +import com.unity3d.services.ads.measurements.MeasurementsService; +import com.unity3d.services.core.misc.Utilities; +import com.unity3d.services.core.webview.bridge.WebViewCallback; +import com.unity3d.services.core.webview.bridge.WebViewExposed; + +public class Measurements { + private static final MeasurementsService measurementsService = Utilities.getService(MeasurementsService.class); + + @WebViewExposed + public static void checkAvailability(WebViewCallback callback) { + measurementsService.checkAvailability(); + callback.invoke(); + } + + @WebViewExposed + public static void registerView(final String url, WebViewCallback callback) { + measurementsService.registerView(url); + callback.invoke(); + } + + @WebViewExposed + public static void registerClick(final String url, WebViewCallback callback) { + if (AdUnit.getAdUnitActivity() == null) { + callback.error(MeasurementsErrors.ERROR_AD_UNIT_NULL); + return; + } + + if (AdUnit.getAdUnitActivity().getLayout() == null) { + callback.error(MeasurementsErrors.ERROR_LAYOUT_NULL); + return; + } + + InputEvent lastInputEvent = AdUnit.getAdUnitActivity().getLayout().getLastInputEvent(); + if (lastInputEvent == null) { + callback.error(MeasurementsErrors.ERROR_LAST_INPUT_EVENT_NULL); + return; + } + + measurementsService.registerClick(url, lastInputEvent); + callback.invoke(); + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/api/Topics.java b/unity-ads/src/main/java/com/unity3d/services/ads/api/Topics.java new file mode 100644 index 0000000..1a38043 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/api/Topics.java @@ -0,0 +1,21 @@ +package com.unity3d.services.ads.api; + +import com.unity3d.services.ads.topics.TopicsService; +import com.unity3d.services.core.misc.Utilities; +import com.unity3d.services.core.webview.bridge.WebViewCallback; +import com.unity3d.services.core.webview.bridge.WebViewExposed; + +public class Topics { + private static final TopicsService topicsService = Utilities.getService(TopicsService.class); + + @WebViewExposed + public static void checkAvailability(WebViewCallback callback) { + callback.invoke(topicsService.checkAvailability()); + } + + @WebViewExposed + public static void getTopics(String adsSdkName, Boolean shouldRecordObservation, WebViewCallback callback) { + topicsService.getTopics(adsSdkName, shouldRecordObservation); + callback.invoke(); + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/configuration/AdsModuleConfiguration.java b/unity-ads/src/main/java/com/unity3d/services/ads/configuration/AdsModuleConfiguration.java index 49096e9..deef0a0 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/configuration/AdsModuleConfiguration.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/configuration/AdsModuleConfiguration.java @@ -30,7 +30,9 @@ public class AdsModuleConfiguration implements IAdsModuleConfiguration { com.unity3d.services.ads.api.Load.class, com.unity3d.services.ads.api.Show.class, com.unity3d.services.ads.api.Token.class, - com.unity3d.services.ads.api.GMAScar.class + com.unity3d.services.ads.api.GMAScar.class, + com.unity3d.services.ads.api.Measurements.class, + com.unity3d.services.ads.api.Topics.class, }; return list; diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMA.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMA.java index b38e533..00e1c93 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMA.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMA.java @@ -52,7 +52,7 @@ public class GMA { * @param listener {@link IBiddingSignalsListener} implementation, to be notified when * signals are ready. */ - public void getSCARBiddingSignals(IBiddingSignalsListener listener) { - _gmaScarAdapterBridge.getSCARBiddingSignals(new BiddingSignalsHandler(listener)); + public void getSCARBiddingSignals(boolean isBannerEnabled, IBiddingSignalsListener listener) { + _gmaScarAdapterBridge.getSCARBiddingSignals(isBannerEnabled, new BiddingSignalsHandler(isBannerEnabled, listener)); } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMAScarAdapterBridge.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMAScarAdapterBridge.java index 5fedbc5..a4dfff0 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMAScarAdapterBridge.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/GMAScarAdapterBridge.java @@ -1,9 +1,11 @@ package com.unity3d.services.ads.gmascar; +import android.content.Context; import com.unity3d.scar.adapter.common.GMAAdsError; import com.unity3d.scar.adapter.common.GMAEvent; import com.unity3d.scar.adapter.common.IScarAdapter; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.services.ads.gmascar.adapters.ScarAdapterFactory; import com.unity3d.services.ads.gmascar.bridges.AdapterStatusBridge; import com.unity3d.services.ads.gmascar.bridges.InitializationStatusBridge; @@ -13,16 +15,17 @@ import com.unity3d.services.ads.gmascar.finder.GMAInitializer; import com.unity3d.services.ads.gmascar.finder.PresenceDetector; import com.unity3d.services.ads.gmascar.finder.ScarAdapterVersion; import com.unity3d.services.ads.gmascar.finder.ScarVersionFinder; -import com.unity3d.services.ads.gmascar.handlers.BiddingSignalsHandler; -import com.unity3d.services.ads.gmascar.handlers.ScarInterstitialAdHandler; -import com.unity3d.services.ads.gmascar.handlers.ScarRewardedAdHandler; -import com.unity3d.services.ads.gmascar.handlers.SignalsHandler; -import com.unity3d.services.ads.gmascar.handlers.WebViewErrorHandler; +import com.unity3d.services.ads.gmascar.handlers.*; import com.unity3d.services.ads.gmascar.utils.GMAEventSender; +import com.unity3d.services.banners.BannerView; +import com.unity3d.services.banners.UnityBannerSize; +import com.unity3d.services.banners.bridge.BannerBridge; import com.unity3d.services.core.misc.EventSubject; import com.unity3d.services.core.properties.ClientProperties; import com.unity3d.services.core.timer.DefaultIntervalTimerFactory; +import com.unity3d.services.core.webview.WebViewApp; +import com.unity3d.services.core.webview.WebViewEventCategory; import org.jetbrains.annotations.Nullable; import java.util.ArrayDeque; @@ -81,12 +84,12 @@ public class GMAScarAdapterBridge { _scarVersionFinder.getVersion(); } - public void getSCARSignals(String[] interstitialList, String[] rewardedList) { + public void getSCARSignal(String placementId, UnityAdFormat adFormat) { _scarAdapter = getScarAdapterObject(); SignalsHandler signalListener = new SignalsHandler(_gmaEventSender); if (_scarAdapter != null) { - _scarAdapter.getSCARSignals(ClientProperties.getApplicationContext(), interstitialList, rewardedList, signalListener); + _scarAdapter.getSCARSignal(ClientProperties.getApplicationContext(), placementId, adFormat, signalListener); } else { _webViewErrorHandler.handleError(GMAAdsError.InternalSignalsError("Could not create SCAR adapter object")); } @@ -111,11 +114,11 @@ public class GMAScarAdapterBridge { * * @param handler {@link BiddingSignalsHandler} to be notified when signals are ready. */ - public void getSCARBiddingSignals(BiddingSignalsHandler handler) { + public void getSCARBiddingSignals(boolean isBannerEnabled, BiddingSignalsHandler handler) { if (_mobileAdsBridge != null && _mobileAdsBridge.hasSCARBiddingSupport()) { _scarAdapter = getScarAdapterObject(); if (_scarAdapter != null) { - _scarAdapter.getSCARBiddingSignals(ClientProperties.getApplicationContext(), handler); + _scarAdapter.getSCARBiddingSignals(ClientProperties.getApplicationContext(), isBannerEnabled, handler); } else { handler.onSignalsCollectionFailed("Could not create SCAR adapter object."); } @@ -148,6 +151,16 @@ public class GMAScarAdapterBridge { _scarAdapter.loadRewardedAd(ClientProperties.getApplicationContext(), scarAdMetadata, adListener); } + public void loadBanner(final Context context, final BannerView bannerView, final String operationId, final ScarAdMetadata scarAdMetadata, final UnityBannerSize bannerSize) { + _scarAdapter = getScarAdapterObject(); + ScarBannerAdHandler adHandler = new ScarBannerAdHandler(operationId); + if (_scarAdapter != null) { + _scarAdapter.loadBannerAd(context, bannerView, scarAdMetadata, bannerSize.getWidth(), bannerSize.getHeight(), adHandler); + } else { + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_LOAD_FAILED, operationId); + } + } + public void show(final String placementId, final String queryId, final boolean canSkip) { ScarAdMetadata scarAdMetadata = new ScarAdMetadata(placementId, queryId); _scarAdapter = getScarAdapterObject(); diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/adapters/ScarAdapterFactory.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/adapters/ScarAdapterFactory.java index 1bc423e..c08e39a 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/adapters/ScarAdapterFactory.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/adapters/ScarAdapterFactory.java @@ -14,12 +14,6 @@ public class ScarAdapterFactory { IScarAdapter scarAdapter = null; switch (adapterVersion) { - case V192: - scarAdapter = new com.unity3d.scar.adapter.v1920.ScarAdapter(adsErrorHandler); - break; - case V195: - scarAdapter = new com.unity3d.scar.adapter.v1950.ScarAdapter(adsErrorHandler); - break; case V20: scarAdapter = new com.unity3d.scar.adapter.v2000.ScarAdapter(adsErrorHandler); break; diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/bridges/mobileads/MobileAdsBridgeLegacy.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/bridges/mobileads/MobileAdsBridgeLegacy.java index 858a4dd..b219c7d 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/bridges/mobileads/MobileAdsBridgeLegacy.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/bridges/mobileads/MobileAdsBridgeLegacy.java @@ -12,9 +12,6 @@ public class MobileAdsBridgeLegacy extends MobileAdsBridgeBase { // Codes returned by getVersionString in V20 and below public static final int CODE_21_0 = 221310000; public static final int CODE_20_0 = 210402000; - public static final int CODE_19_8 = 204890000; - public static final int CODE_19_5 = 203404000; - public static final int CODE_19_2 = 201604000; // Deprecated in V21 - requires initialization and returns internal version (e.g., "afma-sdk-a-v..X") public static final String versionStringMethodName = "getVersionString"; @@ -44,11 +41,7 @@ public class MobileAdsBridgeLegacy extends MobileAdsBridgeBase { @Override public ScarAdapterVersion getAdapterVersion(int versionCode) { // Version codes in V20 and below are returned as internal nine digit numbers (e.g., "afma-sdk-a-vX.210402000.X) - if (versionCode >= CODE_19_2 && versionCode < CODE_19_5) { - return ScarAdapterVersion.V192; - } else if (versionCode >= CODE_19_5 && versionCode <= CODE_19_8) { - return ScarAdapterVersion.V195; - } else if (versionCode >= CODE_20_0 && versionCode < CODE_21_0) { + if (versionCode >= CODE_20_0 && versionCode < CODE_21_0) { return ScarAdapterVersion.V20; } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/finder/ScarAdapterVersion.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/finder/ScarAdapterVersion.java index ffd61f5..d50c285 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/finder/ScarAdapterVersion.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/finder/ScarAdapterVersion.java @@ -1,8 +1,6 @@ package com.unity3d.services.ads.gmascar.finder; public enum ScarAdapterVersion { - V192, - V195, V20, V21, NA diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/BiddingSignalsHandler.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/BiddingSignalsHandler.java index cfa1b65..7101f22 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/BiddingSignalsHandler.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/BiddingSignalsHandler.java @@ -15,14 +15,16 @@ import org.json.JSONObject; public class BiddingSignalsHandler implements ISignalCollectionListener { private final IBiddingSignalsListener listener; + private final boolean isBannerEnabled; /** * Constructor that initializes the handler with the passed listener. * * @param listener {@link IBiddingSignalsListener} implementation to notify sender. */ - public BiddingSignalsHandler(IBiddingSignalsListener listener) { + public BiddingSignalsHandler(boolean isBannerEnabled, IBiddingSignalsListener listener) { this.listener = listener; + this.isBannerEnabled = isBannerEnabled; } @Override @@ -39,6 +41,14 @@ public class BiddingSignalsHandler implements ISignalCollectionListener { private BiddingSignals getSignals(String signalsMap) { try { JSONObject signalsJson = new JSONObject(signalsMap); + + if (isBannerEnabled) { + return new BiddingSignals( + getSignalFromJson(signalsJson, SignalsCollectorBase.SCAR_RV_SIGNAL), + getSignalFromJson(signalsJson, SignalsCollectorBase.SCAR_INT_SIGNAL), + getSignalFromJson(signalsJson, SignalsCollectorBase.SCAR_BAN_SIGNAL) + ); + } return new BiddingSignals( getSignalFromJson(signalsJson, SignalsCollectorBase.SCAR_RV_SIGNAL), getSignalFromJson(signalsJson, SignalsCollectorBase.SCAR_INT_SIGNAL) diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarAdHandlerBase.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarAdHandlerBase.java index 08c7e02..8738d40 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarAdHandlerBase.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarAdHandlerBase.java @@ -46,11 +46,6 @@ public abstract class ScarAdHandlerBase implements IScarAdListenerWrapper { _gmaEventSender.send(GMAEvent.AD_CLICKED); } - @Override - public void onAdSkipped() { - _gmaEventSender.send(GMAEvent.AD_SKIPPED); - } - @Override public void onAdClosed() { _gmaEventSender.send(GMAEvent.AD_CLOSED); diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarBannerAdHandler.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarBannerAdHandler.java new file mode 100644 index 0000000..a409528 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarBannerAdHandler.java @@ -0,0 +1,48 @@ +package com.unity3d.services.ads.gmascar.handlers; + +import com.unity3d.scar.adapter.common.IScarBannerAdListenerWrapper; +import com.unity3d.services.banners.BannerViewCache; +import com.unity3d.services.banners.bridge.BannerBridge; +import com.unity3d.services.core.webview.WebViewApp; +import com.unity3d.services.core.webview.WebViewEventCategory; + +public class ScarBannerAdHandler implements IScarBannerAdListenerWrapper { + + private String _operationId; + + public ScarBannerAdHandler(String operationId) { + _operationId = operationId; + } + + @Override + public void onAdLoaded() { + BannerViewCache.getInstance().addScarContainer(_operationId); + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_LOADED, _operationId); + } + + @Override + public void onAdFailedToLoad(int errorCode, String errorString) { + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_LOAD_FAILED, _operationId, errorCode, errorString); + } + + @Override + public void onAdOpened() { + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_OPENED, _operationId); + } + + @Override + public void onAdClicked() { + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_CLICKED, _operationId); + } + + @Override + public void onAdClosed() { + // Code to be executed when the user is about to return to the app after tapping on an ad. + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_CLOSED, _operationId); + } + + @Override + public void onAdImpression() { + WebViewApp.getCurrentApp().sendEvent(WebViewEventCategory.BANNER, BannerBridge.BannerEvent.SCAR_BANNER_IMPRESSION, _operationId); + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarInterstitialAdHandler.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarInterstitialAdHandler.java index ca58c89..e7c04fa 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarInterstitialAdHandler.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarInterstitialAdHandler.java @@ -17,10 +17,15 @@ public class ScarInterstitialAdHandler extends ScarAdHandlerBase implements ISca _gmaEventSender.send(GMAEvent.INTERSTITIAL_SHOW_ERROR, _scarAdMetadata.getPlacementId(), _scarAdMetadata.getQueryId(), errorString, errorCode); } + @Override + public void onAdSkipped() { + _gmaEventSender.send(GMAEvent.AD_SKIPPED); + } + @Override public void onAdClosed() { if (!_eventSubject.eventQueueIsEmpty()) { - super.onAdSkipped(); + onAdSkipped(); } super.onAdClosed(); } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarRewardedAdHandler.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarRewardedAdHandler.java index d99dccb..b363b24 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarRewardedAdHandler.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/handlers/ScarRewardedAdHandler.java @@ -25,10 +25,15 @@ public class ScarRewardedAdHandler extends ScarAdHandlerBase implements IScarRew _gmaEventSender.send(GMAEvent.AD_EARNED_REWARD); } + @Override + public void onAdSkipped() { + _gmaEventSender.send(GMAEvent.AD_SKIPPED); + } + @Override public void onAdClosed() { if (!_hasEarnedReward) { - super.onAdSkipped(); + onAdSkipped(); } super.onAdClosed(); } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingBaseManager.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingBaseManager.java index 5fea1d1..e769d6e 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingBaseManager.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingBaseManager.java @@ -11,7 +11,6 @@ import com.unity3d.services.ads.gmascar.utils.ScarRequestHandler; import com.unity3d.services.core.configuration.ConfigurationReader; import com.unity3d.services.core.misc.Utilities; import com.unity3d.services.core.request.metrics.SDKMetricsSender; -import com.unity3d.services.core.request.metrics.SDKMetrics; import com.unity3d.services.core.request.metrics.ScarMetric; import java.util.UUID; @@ -25,16 +24,17 @@ public abstract class BiddingBaseManager implements IBiddingManager { private final IUnityAdsTokenListener unityAdsTokenListener; private final ScarRequestHandler _scarRequestHandler; private final boolean _isAsyncTokenCall; - + private final boolean _isBannerEnabled; private final AtomicReference signals = new AtomicReference<>(); - public BiddingBaseManager(IUnityAdsTokenListener unityAdsTokenListener) { - this(unityAdsTokenListener, new ScarRequestHandler()); + public BiddingBaseManager(boolean isBannerEnabled, IUnityAdsTokenListener unityAdsTokenListener) { + this(isBannerEnabled, unityAdsTokenListener, new ScarRequestHandler()); } - public BiddingBaseManager(IUnityAdsTokenListener unityAdsTokenListener, ScarRequestHandler requestSender) { + public BiddingBaseManager(boolean isBannerEnabled, IUnityAdsTokenListener unityAdsTokenListener, ScarRequestHandler requestSender) { this.tokenIdentifier = UUID.randomUUID().toString(); + this._isBannerEnabled = isBannerEnabled; this.unityAdsTokenListener = unityAdsTokenListener; this._isAsyncTokenCall = unityAdsTokenListener != null; this._scarRequestHandler = requestSender; @@ -42,8 +42,6 @@ public abstract class BiddingBaseManager implements IBiddingManager { public abstract void start(); - public abstract void onUnityTokenSuccessfullyFetched(); - @Override public String getTokenIdentifier() { return tokenIdentifier; @@ -53,7 +51,7 @@ public abstract class BiddingBaseManager implements IBiddingManager { public String getFormattedToken(String unityToken) { if (unityToken == null || unityToken.isEmpty()) return null; String tokenIdentifier = getTokenIdentifier(); - if (tokenIdentifier == null || (tokenIdentifier != null && tokenIdentifier.isEmpty())) return unityToken; + if (tokenIdentifier == null || tokenIdentifier.isEmpty()) return unityToken; else return String.format(TOKEN_WITH_SCAR_FORMAT, tokenIdentifier, unityToken); } @@ -62,10 +60,6 @@ public abstract class BiddingBaseManager implements IBiddingManager { if (unityAdsTokenListener != null) { wrapCustomerListener(() -> unityAdsTokenListener.onUnityAdsTokenReady(token)); } - - if (token != null && !token.isEmpty()) { - onUnityTokenSuccessfullyFetched(); - } } public void permitUpload() { @@ -80,23 +74,18 @@ public abstract class BiddingBaseManager implements IBiddingManager { public void fetchSignals() { getMetricSender().sendMetric(ScarMetric.hbSignalsFetchStart(_isAsyncTokenCall)); - new Thread(new Runnable() { + new Thread(() -> GMA.getInstance().getSCARBiddingSignals(this._isBannerEnabled, new IBiddingSignalsListener() { @Override - public void run() { - GMA.getInstance().getSCARBiddingSignals(new IBiddingSignalsListener() { - @Override - public void onSignalsReady(BiddingSignals signals) { - BiddingBaseManager.this.onSignalsReady(signals); - sendFetchResult(""); - } - - @Override - public void onSignalsFailure(String msg) { - sendFetchResult(msg); - } - }); + public void onSignalsReady(BiddingSignals signals) { + BiddingBaseManager.this.onSignalsReady(signals); + sendFetchResult(""); } - }).start(); + + @Override + public void onSignalsFailure(String msg) { + sendFetchResult(msg); + } + })).start(); } public void sendFetchResult(String errorMsg) { @@ -129,17 +118,14 @@ public abstract class BiddingBaseManager implements IBiddingManager { return; } - new Thread(new Runnable() { - @Override - public void run() { - try { - // Since there are potential side effects of file read in the - // getCurrentConfiguration call, we don't want this to be called in the constructor. - _scarRequestHandler.makeUploadRequest(tokenIdentifier, signals, new ConfigurationReader().getCurrentConfiguration().getScarBiddingUrl()); - getMetricSender().sendMetric(ScarMetric.hbSignalsUploadSuccess(_isAsyncTokenCall)); - } catch (Exception e) { - getMetricSender().sendMetric(ScarMetric.hbSignalsUploadFailure(_isAsyncTokenCall, e.getLocalizedMessage())); - } + new Thread(() -> { + try { + // Since there are potential side effects of file read in the + // getCurrentConfiguration call, we don't want this to be called in the constructor. + _scarRequestHandler.makeUploadRequest(tokenIdentifier, signals, new ConfigurationReader().getCurrentConfiguration().getScarBiddingUrl()); + getMetricSender().sendMetric(ScarMetric.hbSignalsUploadSuccess(_isAsyncTokenCall)); + } catch (Exception e) { + getMetricSender().sendMetric(ScarMetric.hbSignalsUploadFailure(_isAsyncTokenCall, e.getLocalizedMessage())); } }).start(); } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingDisabledManager.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingDisabledManager.java index 4b9236b..66f4afe 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingDisabledManager.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingDisabledManager.java @@ -5,7 +5,7 @@ import com.unity3d.ads.IUnityAdsTokenListener; public class BiddingDisabledManager extends BiddingBaseManager { public BiddingDisabledManager(IUnityAdsTokenListener unityAdsTokenListener) { - super(unityAdsTokenListener); + super(false, unityAdsTokenListener); } @Override @@ -18,9 +18,4 @@ public class BiddingDisabledManager extends BiddingBaseManager { public void start() { // SCAR bidding signals collection should be blocked. } - - @Override - public void onUnityTokenSuccessfullyFetched() { - // SCAR bidding signals collection should be blocked. - } -} +} \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingEagerManager.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingEagerManager.java index 5d08247..90662bf 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingEagerManager.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingEagerManager.java @@ -4,8 +4,8 @@ import com.unity3d.ads.IUnityAdsTokenListener; public class BiddingEagerManager extends BiddingBaseManager { - public BiddingEagerManager(IUnityAdsTokenListener unityAdsTokenListener) { - super(unityAdsTokenListener); + public BiddingEagerManager(boolean isBannerEnabled, IUnityAdsTokenListener unityAdsTokenListener) { + super(isBannerEnabled, unityAdsTokenListener); } @Override @@ -13,12 +13,4 @@ public class BiddingEagerManager extends BiddingBaseManager { permitSignalsUpload(); fetchSignals(); } - - @Override - public void onUnityTokenSuccessfullyFetched() { - // Not relevant. - // - // Signals upload will be start once scar signals are ready regardless of unityToken - // validity. - } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingLazyManager.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingLazyManager.java deleted file mode 100644 index efe485d..0000000 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingLazyManager.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.unity3d.services.ads.gmascar.managers; - -import com.unity3d.ads.IUnityAdsTokenListener; - -public class BiddingLazyManager extends BiddingBaseManager { - - public BiddingLazyManager(IUnityAdsTokenListener unityAdsTokenListener) { - super(unityAdsTokenListener); - } - - @Override - public void start() { - // Not relevant. - // - // Signals fetch will be start once valid unity token is fetched. - } - - @Override - public void onUnityTokenSuccessfullyFetched() { - permitSignalsUpload(); - fetchSignals(); - } -} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactory.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactory.java index 72066d4..3840822 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactory.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactory.java @@ -21,40 +21,10 @@ public class BiddingManagerFactory { public BiddingBaseManager createManager(IUnityAdsTokenListener unityAdsTokenListener, IExperiments experiments) { if (GMA.getInstance().hasSCARBiddingSupport()) { - return getExperiment(unityAdsTokenListener, experiments); + boolean isBannerEnabled = experiments != null && experiments.isScarBannerHbEnabled(); + return new BiddingEagerManager(isBannerEnabled, unityAdsTokenListener); } return new BiddingDisabledManager(unityAdsTokenListener); } - - private BiddingBaseManager getExperiment(IUnityAdsTokenListener unityAdsTokenListener, - IExperiments experiments) { - if (experiments == null || experiments.getScarBiddingManager() == null) { - return new BiddingDisabledManager(unityAdsTokenListener); - } - - String biddingManager = experiments.getScarBiddingManager(); - SCARBiddingManagerType biddingManagerType = SCARBiddingManagerType.fromName(biddingManager); - - /* - If unityAdsTokenListener is null it is a synchronous getToken call and we should use - the EAGER bidding manager if part of any of the enabled experiment types since we do not - have to listen for a token fetch result - */ - if (unityAdsTokenListener == null && biddingManagerType != SCARBiddingManagerType.DISABLED) { - return new BiddingEagerManager(null); - } - - switch (biddingManagerType) { - case EAGER: - return new BiddingEagerManager(unityAdsTokenListener); - case LAZY: - return new BiddingLazyManager(unityAdsTokenListener); - case HYBRID: - return new BiddingOnDemandManager(unityAdsTokenListener); - case DISABLED: - default: - return new BiddingDisabledManager(unityAdsTokenListener); - } - } -} +} \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingOnDemandManager.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingOnDemandManager.java deleted file mode 100644 index a207742..0000000 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/BiddingOnDemandManager.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.unity3d.services.ads.gmascar.managers; - -import com.unity3d.ads.IUnityAdsTokenListener; - -public class BiddingOnDemandManager extends BiddingBaseManager { - - public BiddingOnDemandManager(IUnityAdsTokenListener unityAdsTokenListener) { - super(unityAdsTokenListener); - } - - @Override - public void start() { - fetchSignals(); - } - - @Override - public void onUnityTokenSuccessfullyFetched() { - permitSignalsUpload(); - } -} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/SCARBiddingManagerType.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/SCARBiddingManagerType.java deleted file mode 100644 index 6649112..0000000 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/managers/SCARBiddingManagerType.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.unity3d.services.ads.gmascar.managers; - -public enum SCARBiddingManagerType { - DISABLED(Constants.DIS), - EAGER(Constants.EAG), - LAZY(Constants.LAZ), - HYBRID(Constants.HYB); - - private final String name; - - SCARBiddingManagerType(final String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - public static SCARBiddingManagerType fromName(final String name) { - switch(name) { - case Constants.EAG: - return EAGER; - case Constants.LAZ: - return LAZY; - case Constants.HYB: - return HYBRID; - case Constants.DIS: - default: - return DISABLED; - } - } - - private static class Constants { - private static final String LAZ = "laz"; - private static final String EAG = "eag"; - private static final String HYB = "hyb"; - private static final String DIS = "dis"; - } -} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/models/BiddingSignals.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/models/BiddingSignals.java index 3151783..133824f 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/models/BiddingSignals.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/models/BiddingSignals.java @@ -7,8 +7,7 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; -import static com.unity3d.services.ads.gmascar.utils.ScarConstants.IN_SIGNAL_KEY; -import static com.unity3d.services.ads.gmascar.utils.ScarConstants.RV_SIGNAL_KEY; +import static com.unity3d.services.ads.gmascar.utils.ScarConstants.*; /** * Data structure for GMA bidding signals. @@ -17,6 +16,7 @@ public class BiddingSignals { private final String rvSignal; private final String interstitialSignal; + private final String bannerSignal; /** * Constructor that initialized the object with passed GMA bidding signals. @@ -24,9 +24,16 @@ public class BiddingSignals { * @param rvSignal rewarded video GMA Scar bidding signal. * @param interstitialSignal interstitial GMA Scar bidding signal. */ + public BiddingSignals(String rvSignal, String interstitialSignal, String bannerSignal) { + this.rvSignal = rvSignal; + this.interstitialSignal = interstitialSignal; + this.bannerSignal = bannerSignal; + } + public BiddingSignals(String rvSignal, String interstitialSignal) { this.rvSignal = rvSignal; this.interstitialSignal = interstitialSignal; + this.bannerSignal = ""; } /** @@ -50,12 +57,22 @@ public class BiddingSignals { } /** - * Checks if both bidding signals are empty in which case they should not be uploaded + * Getter for banner GMA SCAR signal. * - * @return true if both signals are empty, false otherwise + * @return banner bidding signal + */ + @Nullable + public String getBannerSignal() { + return bannerSignal; + } + + /** + * Checks if all bidding signals are empty in which case they should not be uploaded + * + * @return true if all signals are empty, false otherwise */ public boolean isEmpty () { - return TextUtils.isEmpty(getRvSignal()) && TextUtils.isEmpty(getInterstitialSignal()); + return TextUtils.isEmpty(getRvSignal()) && TextUtils.isEmpty(getInterstitialSignal()) && TextUtils.isEmpty(getBannerSignal()); } /** @@ -74,6 +91,10 @@ public class BiddingSignals { signalsMap.put(IN_SIGNAL_KEY, getInterstitialSignal()); } + if (!TextUtils.isEmpty(getBannerSignal())) { + signalsMap.put(BN_SIGNAL_KEY, getBannerSignal()); + } + return signalsMap; } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/utils/ScarConstants.java b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/utils/ScarConstants.java index cb542db..0c13aad 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/utils/ScarConstants.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/gmascar/utils/ScarConstants.java @@ -6,6 +6,8 @@ public class ScarConstants { public static final String TOKEN_ID_KEY = "tid"; public static final String RV_SIGNAL_KEY = "rv"; public static final String IN_SIGNAL_KEY = "in"; + public static final String BN_SIGNAL_KEY = "bn"; + public static final String SCAR_TOKEN_IDENTIFIER_KEY = "scarId"; public static final String TOKEN_WITH_SCAR_FORMAT = "%s:%s"; } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementErrors.kt b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementErrors.kt new file mode 100644 index 0000000..27f5a90 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementErrors.kt @@ -0,0 +1,12 @@ +package com.unity3d.services.ads.measurements + +enum class MeasurementsErrors { + ERROR_AD_SERVICES_DISABLED, + ERROR_EXTENSION_BELOW_4, + ERROR_API_BELOW_33, + ERROR_MANAGER_NULL, + ERROR_EXCEPTION, + ERROR_AD_UNIT_NULL, + ERROR_LAYOUT_NULL, + ERROR_LAST_INPUT_EVENT_NULL, +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementEvents.kt b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementEvents.kt new file mode 100644 index 0000000..0f11e74 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementEvents.kt @@ -0,0 +1,10 @@ +package com.unity3d.services.ads.measurements + +enum class MeasurementsEvents { + NOT_AVAILABLE, + AVAILABLE, + VIEW_SUCCESSFUL, + VIEW_ERROR, + CLICK_SUCCESSFUL, + CLICK_ERROR, +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsReceiver.kt b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsReceiver.kt new file mode 100644 index 0000000..12854b8 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsReceiver.kt @@ -0,0 +1,21 @@ +package com.unity3d.services.ads.measurements + +import android.annotation.SuppressLint +import android.os.OutcomeReceiver +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender + +@SuppressLint("NewApi", "MissingPermission") +class MeasurementsReceiver( + private val eventSender: IEventSender, + private val successEvent: MeasurementsEvents, + private val errorEvent: MeasurementsEvents, +): OutcomeReceiver { + override fun onResult(p0: Any) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, successEvent) + } + + override fun onError(error: Exception) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, errorEvent, error.toString()) + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsService.kt b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsService.kt new file mode 100644 index 0000000..9f7771c --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsService.kt @@ -0,0 +1,76 @@ +package com.unity3d.services.ads.measurements + +import android.adservices.AdServicesState +import android.adservices.measurement.MeasurementManager +import android.annotation.SuppressLint +import android.content.Context +import android.net.Uri +import android.os.OutcomeReceiver +import android.os.ext.SdkExtensions +import android.view.InputEvent +import com.unity3d.services.core.device.Device +import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import kotlinx.coroutines.asExecutor + +@SuppressLint("NewApi", "MissingPermission") +class MeasurementsService(context: Context, private val dispatchers: ISDKDispatchers, private val eventSender: IEventSender) { + private val measurementManager: MeasurementManager? = getMeasurementManager(context) + + fun checkAvailability() { + if (Device.getApiLevel() < 33) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_API_BELOW_33) + return + } + + if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_EXTENSION_BELOW_4) + return + } + + if (measurementManager == null) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_MANAGER_NULL) + return + } + + if (!AdServicesState.isAdServicesStateEnabled()) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_AD_SERVICES_DISABLED) + return + } + + measurementManager.getMeasurementApiStatus(dispatchers.default.asExecutor(), MeasurementsStatusReceiver(eventSender)) + } + + fun registerView(url: String) { + measurementManager?.registerSource( + Uri.parse(url), + null, + dispatchers.default.asExecutor(), + MeasurementsReceiver(eventSender, MeasurementsEvents.VIEW_SUCCESSFUL, MeasurementsEvents.VIEW_ERROR) + ) + } + + fun registerClick(url: String, inputEvent: InputEvent) { + measurementManager?.registerSource( + Uri.parse(url), + inputEvent, + dispatchers.default.asExecutor(), + MeasurementsReceiver(eventSender, MeasurementsEvents.CLICK_SUCCESSFUL, MeasurementsEvents.CLICK_ERROR) + ) + } + + private fun getMeasurementManager(context: Context): MeasurementManager? { + // accessing MeasurementManager without API level and extension version checks can crash old Android devices + // also accessing SdkExtensions below API level 30 causes exception so check API level first + if (Device.getApiLevel() < 33) { + return null + } + + if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) { + return null + } + + return context.getSystemService(MeasurementManager::class.java) + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsStatusReceiver.kt b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsStatusReceiver.kt new file mode 100644 index 0000000..56dc984 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/measurements/MeasurementsStatusReceiver.kt @@ -0,0 +1,17 @@ +package com.unity3d.services.ads.measurements + +import android.annotation.SuppressLint +import android.os.OutcomeReceiver +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender + +@SuppressLint("NewApi", "MissingPermission") +class MeasurementsStatusReceiver(private val eventSender: IEventSender) : OutcomeReceiver { + override fun onResult(status: Int) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.AVAILABLE, status) + } + + override fun onError(error: Exception) { + eventSender.sendEvent(WebViewEventCategory.MEASUREMENTS, MeasurementsEvents.NOT_AVAILABLE, MeasurementsErrors.ERROR_EXCEPTION, error.toString()) + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerModule.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerModule.java index feb5791..cc6de22 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerModule.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerModule.java @@ -1,13 +1,9 @@ package com.unity3d.services.ads.operation.load; -import com.unity3d.services.banners.BannerViewCache; -import com.unity3d.services.banners.UnityBannerSize; -import com.unity3d.services.banners.bridge.BannerBridge; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.configuration.InitializationNotificationCenter; import com.unity3d.services.core.misc.Utilities; import com.unity3d.services.core.request.metrics.SDKMetricsSender; -import com.unity3d.services.core.request.metrics.SDKMetrics; import org.json.JSONException; import org.json.JSONObject; @@ -20,7 +16,7 @@ public class LoadBannerModule extends BaseLoadModule { if (_instance == null) { LoadBannerModule loadModule = new LoadBannerModule(Utilities.getService(SDKMetricsSender.class)); LoadModuleDecoratorInitializationBuffer bufferedLoadModule = new LoadModuleDecoratorInitializationBuffer(loadModule, InitializationNotificationCenter.getInstance()); - LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ConfigurationReader()); + LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ExperimentsReader()); _instance = timedLoadModule; } return _instance; @@ -37,20 +33,4 @@ public class LoadBannerModule extends BaseLoadModule { parameters.put("height", ((LoadBannerOperationState) state).getSize().getHeight()); } } - - @Override - public void onUnityAdsAdLoaded(String operationId) { - final ILoadOperation loadOperation = get(operationId); - if (loadOperation == null || loadOperation.getLoadOperationState() == null) return; - final LoadOperationState state = loadOperation.getLoadOperationState(); - if (state instanceof LoadBannerOperationState) { - String bannerAdId = state.getId(); - UnityBannerSize size = ((LoadBannerOperationState) state).getSize(); - boolean successfullyLoaded = BannerViewCache.getInstance().loadWebPlayer(bannerAdId, size); - if (successfullyLoaded) { - BannerBridge.didLoad(operationId); - } - super.onUnityAdsAdLoaded(operationId); - } - } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerOperationState.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerOperationState.java index ef51b9b..fd449c4 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerOperationState.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadBannerOperationState.java @@ -2,11 +2,13 @@ package com.unity3d.services.ads.operation.load; import com.unity3d.ads.IUnityAdsLoadListener; import com.unity3d.ads.UnityAdsLoadOptions; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.services.banners.UnityBannerSize; import com.unity3d.services.core.configuration.Configuration; public class LoadBannerOperationState extends LoadOperationState { private UnityBannerSize _size; + private ScarAdMetadata _scarAdMetadata; public LoadBannerOperationState(String placementId, String bannerAdId, UnityBannerSize size, IUnityAdsLoadListener listener, UnityAdsLoadOptions loadOptions, Configuration configuration) { super(placementId, listener, loadOptions, configuration); @@ -21,4 +23,16 @@ public class LoadBannerOperationState extends LoadOperationState { public void setSize(UnityBannerSize size) { _size = size; } + + public void setScarAdMetadata(ScarAdMetadata scarAdMetadata) { + _scarAdMetadata = scarAdMetadata; + } + + public ScarAdMetadata getScarAdMetadata() { + return _scarAdMetadata; + } + + public boolean isScarAd() { + return _scarAdMetadata != null; + } } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModule.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModule.java index cb01bbe..3832d67 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModule.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModule.java @@ -1,13 +1,11 @@ package com.unity3d.services.ads.operation.load; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.configuration.InitializationNotificationCenter; import com.unity3d.services.core.misc.Utilities; import com.unity3d.services.core.request.metrics.SDKMetricsSender; -import com.unity3d.services.core.request.metrics.SDKMetrics; -import org.json.JSONException; import org.json.JSONObject; public class LoadModule extends BaseLoadModule { @@ -18,7 +16,7 @@ public class LoadModule extends BaseLoadModule { if (_instance == null) { LoadModule loadModule = new LoadModule(Utilities.getService(SDKMetricsSender.class)); LoadModuleDecoratorInitializationBuffer bufferedLoadModule = new LoadModuleDecoratorInitializationBuffer(loadModule, InitializationNotificationCenter.getInstance()); - LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ConfigurationReader()); + LoadModuleDecoratorTimeout timedLoadModule = new LoadModuleDecoratorTimeout(bufferedLoadModule, new ExperimentsReader()); _instance = timedLoadModule; } return _instance; diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModuleDecoratorTimeout.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModuleDecoratorTimeout.java index b9c53bc..7045333 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModuleDecoratorTimeout.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/load/LoadModuleDecoratorTimeout.java @@ -1,7 +1,7 @@ package com.unity3d.services.ads.operation.load; import com.unity3d.ads.UnityAds; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.request.metrics.AdOperationError; import com.unity3d.services.core.request.metrics.AdOperationMetric; import com.unity3d.services.core.timer.BaseTimer; @@ -13,15 +13,20 @@ import java.util.concurrent.Executors; public class LoadModuleDecoratorTimeout extends LoadModuleDecorator { private static final String errorMsgTimeoutLoading = "[UnityAds] Timeout while loading "; - public LoadModuleDecoratorTimeout(ILoadModule loadModule, ConfigurationReader configurationReader) { + private final ExperimentsReader _experimentsReader; + + public LoadModuleDecoratorTimeout(ILoadModule loadModule, ExperimentsReader experimentsReader) { super(loadModule); + this._experimentsReader = experimentsReader; } @Override public void executeAdOperation(IWebViewBridgeInvoker webViewBridgeInvoker, LoadOperationState state) { getMetricSender().sendMetricWithInitState(AdOperationMetric.newAdLoadStart()); state.start(); - startLoadTimeout(state); + if (!_experimentsReader.getCurrentlyActiveExperiments().isNativeLoadTimeoutDisabled()) { + startLoadTimeout(state); + } super.executeAdOperation(webViewBridgeInvoker, state); } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModule.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModule.java index 86ad1d2..3187f2c 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModule.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModule.java @@ -10,14 +10,14 @@ import android.view.WindowManager; import com.unity3d.ads.UnityAds; import com.unity3d.services.ads.operation.AdModule; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.device.Device; +import com.unity3d.services.core.device.reader.HdrInfoReader; import com.unity3d.services.core.misc.Utilities; import com.unity3d.services.core.properties.ClientProperties; import com.unity3d.services.core.request.metrics.AdOperationError; import com.unity3d.services.core.request.metrics.AdOperationMetric; import com.unity3d.services.core.request.metrics.SDKMetricsSender; -import com.unity3d.services.core.request.metrics.SDKMetrics; import com.unity3d.services.core.webview.bridge.CallbackStatus; import com.unity3d.services.core.webview.bridge.IWebViewBridgeInvoker; import com.unity3d.services.core.webview.bridge.invocation.IWebViewBridgeInvocationCallback; @@ -34,7 +34,7 @@ public class ShowModule extends AdModule imp public static IShowModule getInstance() { if (instance == null) { - instance = new ShowModuleDecoratorTimeout(new ShowModule(Utilities.getService(SDKMetricsSender.class)), new ConfigurationReader()); + instance = new ShowModuleDecoratorTimeout(new ShowModule(Utilities.getService(SDKMetricsSender.class)), new ExperimentsReader()); } return instance; } @@ -106,6 +106,7 @@ public class ShowModule extends AdModule imp set(showOperation); showOperation.invoke(state.configuration.getWebViewBridgeTimeout(), parameters); + HdrInfoReader.getInstance().captureHDRCapabilityMetrics(activity, new ExperimentsReader()); } public void onUnityAdsShowFailure(String id, UnityAds.UnityAdsShowError error, String message) { diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModuleDecoratorTimeout.java b/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModuleDecoratorTimeout.java index 521cf11..f3203af 100644 --- a/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModuleDecoratorTimeout.java +++ b/unity-ads/src/main/java/com/unity3d/services/ads/operation/show/ShowModuleDecoratorTimeout.java @@ -1,7 +1,7 @@ package com.unity3d.services.ads.operation.show; import com.unity3d.ads.UnityAds; -import com.unity3d.services.core.configuration.ConfigurationReader; +import com.unity3d.services.core.configuration.ExperimentsReader; import com.unity3d.services.core.request.metrics.AdOperationError; import com.unity3d.services.core.request.metrics.AdOperationMetric; import com.unity3d.services.core.timer.BaseTimer; @@ -13,15 +13,20 @@ import java.util.concurrent.Executors; public class ShowModuleDecoratorTimeout extends ShowModuleDecorator { private static final String errorMsgTimeout = "[UnityAds] Timeout while trying to show "; - public ShowModuleDecoratorTimeout(IShowModule showModule, ConfigurationReader configurationReader) { + private final ExperimentsReader _experimentsReader; + + public ShowModuleDecoratorTimeout(IShowModule showModule, ExperimentsReader experimentsReader) { super(showModule); + this._experimentsReader = experimentsReader; } @Override public void executeAdOperation(IWebViewBridgeInvoker webViewBridgeInvoker, ShowOperationState state) { getMetricSender().sendMetricWithInitState(AdOperationMetric.newAdShowStart()); state.start(); - startShowTimeout(state); + if (!_experimentsReader.getCurrentlyActiveExperiments().isNativeShowTimeoutDisabled()) { + startShowTimeout(state); + } super.executeAdOperation(webViewBridgeInvoker, state); } diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsErrors.kt b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsErrors.kt new file mode 100644 index 0000000..c3c893b --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsErrors.kt @@ -0,0 +1,5 @@ +package com.unity3d.services.ads.topics + +enum class TopicsErrors { + ERROR_EXCEPTION, +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsEvents.kt b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsEvents.kt new file mode 100644 index 0000000..594f475 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsEvents.kt @@ -0,0 +1,6 @@ +package com.unity3d.services.ads.topics + +enum class TopicsEvents { + NOT_AVAILABLE, + TOPICS_AVAILABLE, +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsReceiver.kt b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsReceiver.kt new file mode 100644 index 0000000..6f93285 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsReceiver.kt @@ -0,0 +1,35 @@ +package com.unity3d.services.ads.topics + +import android.adservices.topics.GetTopicsResponse +import android.adservices.topics.Topic +import android.annotation.SuppressLint +import android.os.OutcomeReceiver +import com.unity3d.services.core.log.DeviceLog +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import org.json.JSONArray +import org.json.JSONObject + +@SuppressLint("NewApi", "MissingPermission") +class TopicsReceiver(private val eventSender: IEventSender) : OutcomeReceiver { + override fun onResult(result: GetTopicsResponse) { + val resultArray = JSONArray() + result.topics.forEach { + resultArray.put(formatTopic(it)) + } + eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.TOPICS_AVAILABLE, resultArray.toString()) + } + + override fun onError(error: Exception) { + DeviceLog.debug("GetTopics exception: $error") + eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, error.toString()) + } + + fun formatTopic(topic: Topic): JSONObject { + val resultObject = JSONObject() + resultObject.put("taxonomyVersion", topic.taxonomyVersion) + resultObject.put("modelVersion", topic.modelVersion) + resultObject.put("topicId", topic.topicId) + return resultObject + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsService.kt b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsService.kt new file mode 100644 index 0000000..955441d --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsService.kt @@ -0,0 +1,64 @@ +package com.unity3d.services.ads.topics + +import android.adservices.AdServicesState +import android.adservices.topics.GetTopicsRequest +import android.adservices.topics.TopicsManager +import android.annotation.SuppressLint +import android.content.Context +import android.os.ext.SdkExtensions +import com.unity3d.services.core.device.Device +import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.log.DeviceLog +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import kotlinx.coroutines.asExecutor + +@SuppressLint("NewApi", "MissingPermission") +class TopicsService(context: Context, private val dispatchers: ISDKDispatchers, private val eventSender: IEventSender) { + private val topicsManager: TopicsManager? = getTopicsManager(context) + + fun checkAvailability(): TopicsStatus { + if (Device.getApiLevel() < 33) { + return TopicsStatus.ERROR_API_BELOW_33 + } + + if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) { + return TopicsStatus.ERROR_EXTENSION_BELOW_4 + } + + if (topicsManager == null) { + return TopicsStatus.ERROR_TOPICSMANAGER_NULL + } + + if (!AdServicesState.isAdServicesStateEnabled()) { + return TopicsStatus.ERROR_AD_SERVICES_DISABLED + } + + return TopicsStatus.TOPICS_AVAILABLE + } + + fun getTopics(adsSdkName: String, shouldRecordObservation: Boolean) { + val callback = TopicsReceiver(eventSender) + val topicsRequest = GetTopicsRequest.Builder().setAdsSdkName(adsSdkName).setShouldRecordObservation(shouldRecordObservation).build() + try { + topicsManager?.getTopics(topicsRequest, dispatchers.default.asExecutor(), callback) + } catch (error: Exception) { + eventSender.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, error.toString()) + DeviceLog.debug("Failed to get topics with error: $error") + } + } + + private fun getTopicsManager(context: Context): TopicsManager? { + // accessing TopicsManager without API level and extension version checks can crash old Android devices + // also accessing SdkExtensions below API level 30 causes exception so check API level first + if (Device.getApiLevel() < 33) { + return null + } + + if (SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) < 4) { + return null + } + + return context.getSystemService(TopicsManager::class.java) + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsStatus.kt b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsStatus.kt new file mode 100644 index 0000000..c85d01b --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/ads/topics/TopicsStatus.kt @@ -0,0 +1,9 @@ +package com.unity3d.services.ads.topics + +enum class TopicsStatus { + TOPICS_AVAILABLE, + ERROR_TOPICSMANAGER_NULL, + ERROR_API_BELOW_33, + ERROR_EXTENSION_BELOW_4, + ERROR_AD_SERVICES_DISABLED, +} diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/BannerErrorInfo.java b/unity-ads/src/main/java/com/unity3d/services/banners/BannerErrorInfo.java index 05c9d14..9221a68 100644 --- a/unity-ads/src/main/java/com/unity3d/services/banners/BannerErrorInfo.java +++ b/unity-ads/src/main/java/com/unity3d/services/banners/BannerErrorInfo.java @@ -11,6 +11,18 @@ public class BannerErrorInfo { this.errorMessage = errorMessage; } + public UnityAds.UnityAdsLoadError toLoadError() { + switch (errorCode) { + case NATIVE_ERROR: + return UnityAds.UnityAdsLoadError.INVALID_ARGUMENT; + case NO_FILL: + return UnityAds.UnityAdsLoadError.NO_FILL; + case WEBVIEW_ERROR: + return UnityAds.UnityAdsLoadError.INTERNAL_ERROR; + } + return UnityAds.UnityAdsLoadError.INTERNAL_ERROR; + } + public static BannerErrorInfo fromLoadError(UnityAds.UnityAdsLoadError error, String message) { switch (error) { case INITIALIZE_FAILED: @@ -19,6 +31,8 @@ public class BannerErrorInfo { return new BannerErrorInfo(message, BannerErrorCode.NATIVE_ERROR); case INTERNAL_ERROR: return new BannerErrorInfo(message, BannerErrorCode.WEBVIEW_ERROR); + case NO_FILL: + return new BannerErrorInfo(message, BannerErrorCode.NO_FILL); default: return new BannerErrorInfo(message, BannerErrorCode.UNKNOWN); } diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/BannerView.java b/unity-ads/src/main/java/com/unity3d/services/banners/BannerView.java index 3c958e9..0cdb405 100644 --- a/unity-ads/src/main/java/com/unity3d/services/banners/BannerView.java +++ b/unity-ads/src/main/java/com/unity3d/services/banners/BannerView.java @@ -7,9 +7,13 @@ import android.view.ViewParent; import android.widget.RelativeLayout; import com.unity3d.ads.UnityAdsLoadOptions; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.services.ads.gmascar.GMA; +import com.unity3d.services.ads.gmascar.GMAScarAdapterBridge; import com.unity3d.services.ads.webplayer.WebPlayerSettingsCache; import com.unity3d.services.banners.bridge.BannerBridge; import com.unity3d.services.banners.view.BannerWebPlayerContainer; +import com.unity3d.services.banners.view.ScarBannerContainer; import com.unity3d.services.core.configuration.ErrorState; import com.unity3d.services.core.configuration.IInitializationListener; import com.unity3d.services.core.configuration.InitializationNotificationCenter; @@ -29,7 +33,9 @@ public class BannerView extends RelativeLayout { private UnityBannerSize size; private IListener listener; private BannerWebPlayerContainer bannerWebPlayerContainer; + private ScarBannerContainer scarBannerContainer; private IInitializationListener initializationListener; + private final GMAScarAdapterBridge gmaScarAdapterBridge = GMA.getInstance().getBridge(); // Public @@ -95,6 +101,10 @@ public class BannerView extends RelativeLayout { bannerWebPlayerContainer.destroy(); } + if (scarBannerContainer != null) { + scarBannerContainer.destroy(); + } + // Log the banner was destroyed DeviceLog.info("Banner [" + this.placementId + "] was destroyed"); @@ -139,6 +149,15 @@ public class BannerView extends RelativeLayout { // Module Private + void loadScarPlayer(String operationId, ScarAdMetadata scarAdMetadata, UnityBannerSize size) { + gmaScarAdapterBridge.loadBanner(getContext(), this, operationId, scarAdMetadata, size); + } + + public void addScarContainer() { + scarBannerContainer = new ScarBannerContainer(getContext(), viewId); + Utilities.runOnUiThread(() -> addView(scarBannerContainer)); + } + void loadWebPlayer(final UnityBannerSize unityBannerSize) { final BannerView self = this; Utilities.runOnUiThread(new Runnable() { diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/BannerViewCache.java b/unity-ads/src/main/java/com/unity3d/services/banners/BannerViewCache.java index 75a2f21..a64dad3 100644 --- a/unity-ads/src/main/java/com/unity3d/services/banners/BannerViewCache.java +++ b/unity-ads/src/main/java/com/unity3d/services/banners/BannerViewCache.java @@ -1,8 +1,9 @@ package com.unity3d.services.banners; import com.unity3d.ads.UnityAds; -import com.unity3d.services.ads.operation.load.ILoadModule; -import com.unity3d.services.ads.operation.load.LoadBannerModule; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.services.ads.operation.load.*; +import com.unity3d.services.banners.bridge.BannerBridge; import com.unity3d.services.core.misc.Utilities; import java.lang.ref.WeakReference; @@ -44,6 +45,37 @@ public class BannerViewCache { _bannerViews.remove(bannerAdId); } + public synchronized void loadBanner(LoadBannerOperationState state) { + String bannerAdId = state.getId(); + UnityBannerSize size = state.getSize(); + + if (state.isScarAd()) { + ScarAdMetadata scarAdMetadata = state.getScarAdMetadata(); + loadScarPlayer(bannerAdId, scarAdMetadata, size); + } else { + boolean successfullyLoaded = loadWebPlayer(bannerAdId, size); + if (successfullyLoaded) { + BannerBridge.didLoad(bannerAdId); + } + } + } + + public synchronized void loadScarPlayer(String bannerAdId, ScarAdMetadata scarAdMetadata, UnityBannerSize size) { + BannerView bannerView = this.getBannerView(bannerAdId); + + if (bannerView != null) { + bannerView.loadScarPlayer(bannerAdId, scarAdMetadata, size); + } + } + + public synchronized void addScarContainer(String bannerAdId) { + BannerView bannerView = this.getBannerView(bannerAdId); + + if (bannerView != null) { + bannerView.addScarContainer(); + } + } + public synchronized boolean loadWebPlayer(String bannerAdId, UnityBannerSize size) { BannerView bannerView = this.getBannerView(bannerAdId); if (bannerView != null) { @@ -57,6 +89,8 @@ public class BannerViewCache { public synchronized void triggerBannerLoadEvent(String bannerAdId) { final BannerView bannerView = this.getBannerView(bannerAdId); if (bannerView != null && bannerView.getListener() != null) { + LoadBannerModule.getInstance().onUnityAdsAdLoaded(bannerAdId); + final BannerView.IListener listener = bannerView.getListener(); Utilities.runOnUiThread(new Runnable() { @Override @@ -100,7 +134,8 @@ public class BannerViewCache { } public synchronized void triggerBannerErrorEvent(String bannerAdId, final BannerErrorInfo bannerErrorInfo) { - LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, UnityAds.UnityAdsLoadError.INTERNAL_ERROR, bannerErrorInfo.errorMessage); + final UnityAds.UnityAdsLoadError unityAdsLoadError = bannerErrorInfo.toLoadError(); + LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, unityAdsLoadError, bannerErrorInfo.errorMessage); } public synchronized void triggerBannerLeftApplicationEvent(String bannerAdId) { diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/api/Banner.java b/unity-ads/src/main/java/com/unity3d/services/banners/api/Banner.java index aefa928..bff1c11 100644 --- a/unity-ads/src/main/java/com/unity3d/services/banners/api/Banner.java +++ b/unity-ads/src/main/java/com/unity3d/services/banners/api/Banner.java @@ -2,6 +2,7 @@ package com.unity3d.services.banners.api; import static com.unity3d.ads.UnityAds.UnityAdsLoadError.INTERNAL_ERROR; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.services.ads.operation.load.ILoadOperation; import com.unity3d.services.ads.operation.load.LoadBannerModule; import com.unity3d.services.ads.operation.load.LoadBannerOperationState; @@ -33,11 +34,13 @@ public class Banner { final BannerViewType bannerViewType = BannerViewType.fromString(bannerViewTypeString); switch (bannerViewType) { case WEB_PLAYER: - ILoadOperation operationState = LoadBannerModule.getInstance().get(bannerAdId); - if (operationState instanceof LoadBannerOperationState) { - ((LoadBannerOperationState) operationState).setSize(new UnityBannerSize(width, height)); + final LoadBannerOperationState state = getBannerOperationState(bannerAdId); + if (state == null) { + break; } - LoadBannerModule.getInstance().onUnityAdsAdLoaded(bannerAdId); + + state.setSize(new UnityBannerSize(width, height)); + BannerViewCache.getInstance().loadBanner(state); break; case UNKNOWN: LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, INTERNAL_ERROR, "Unknown banner type"); @@ -47,6 +50,24 @@ public class Banner { callback.invoke(); } + @WebViewExposed + public static void loadScar(final String bannerAdId, final String placementId, final String queryId, final String adUnitId, final String adString, final Integer width, final Integer height, final WebViewCallback callback) { + final LoadBannerOperationState state = getBannerOperationState(bannerAdId); + if (state == null) { + callback.invoke(); + return; + } + + state.setSize(new UnityBannerSize(width, height)); + + ScarAdMetadata scarAdMetadata = new ScarAdMetadata(placementId, queryId, adUnitId, adString, 0); + state.setScarAdMetadata(scarAdMetadata); + + BannerViewCache.getInstance().loadBanner(state); + + callback.invoke(); + } + @WebViewExposed public static void setRefreshRate(final String placementId, final Integer refreshRate, WebViewCallback callback) { if (placementId != null && refreshRate != null) { @@ -55,4 +76,20 @@ public class Banner { callback.invoke(); } + private static LoadBannerOperationState getBannerOperationState(String bannerAdId) { + ILoadOperation operationState = LoadBannerModule.getInstance().get(bannerAdId); + if (operationState == null || operationState.getLoadOperationState() == null) { + LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, INTERNAL_ERROR, "No operation found for requested banner"); + return null; + } + + LoadOperationState state = operationState.getLoadOperationState(); + if (state instanceof LoadBannerOperationState) { + return (LoadBannerOperationState) state; + } + + LoadBannerModule.getInstance().onUnityAdsFailedToLoad(bannerAdId, INTERNAL_ERROR, "Operation state found is not for banner ad"); + return null; + } + } diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/bridge/BannerBridge.java b/unity-ads/src/main/java/com/unity3d/services/banners/bridge/BannerBridge.java index 0d0e0b6..8084ad7 100644 --- a/unity-ads/src/main/java/com/unity3d/services/banners/bridge/BannerBridge.java +++ b/unity-ads/src/main/java/com/unity3d/services/banners/bridge/BannerBridge.java @@ -104,6 +104,20 @@ public class BannerBridge { } } + public static void didAttachScarBanner(String bannerAdId) { + WebViewApp webViewApp = WebViewApp.getCurrentApp(); + if (webViewApp != null) { + webViewApp.sendEvent(WebViewEventCategory.BANNER, BannerEvent.SCAR_BANNER_ATTACHED, bannerAdId); + } + } + + public static void didDetachScarBanner(String bannerAdId) { + WebViewApp webViewApp = WebViewApp.getCurrentApp(); + if (webViewApp != null) { + webViewApp.sendEvent(WebViewEventCategory.BANNER, BannerEvent.SCAR_BANNER_DETACHED, bannerAdId); + } + } + public enum BannerEvent { BANNER_VISIBILITY_CHANGED, BANNER_RESIZED, @@ -112,6 +126,15 @@ public class BannerBridge { BANNER_ATTACHED, BANNER_DETACHED, BANNER_LOAD_PLACEMENT, - BANNER_DESTROY_BANNER + BANNER_DESTROY_BANNER, + // Used for SCAR banners only + SCAR_BANNER_LOADED, + SCAR_BANNER_LOAD_FAILED, + SCAR_BANNER_ATTACHED, + SCAR_BANNER_DETACHED, + SCAR_BANNER_OPENED, + SCAR_BANNER_CLOSED, + SCAR_BANNER_IMPRESSION, + SCAR_BANNER_CLICKED } } diff --git a/unity-ads/src/main/java/com/unity3d/services/banners/view/ScarBannerContainer.java b/unity-ads/src/main/java/com/unity3d/services/banners/view/ScarBannerContainer.java new file mode 100644 index 0000000..56e45ae --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/banners/view/ScarBannerContainer.java @@ -0,0 +1,42 @@ +package com.unity3d.services.banners.view; + +import android.content.Context; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.RelativeLayout; + +import com.unity3d.services.banners.bridge.BannerBridge; +import com.unity3d.services.core.misc.Utilities; + +public class ScarBannerContainer extends RelativeLayout { + + private String _bannerAdId; + + public ScarBannerContainer(Context context, String bannerAdId) { + super(context); + _bannerAdId = bannerAdId; + } + + public void destroy() { + final ScarBannerContainer self = this; + Utilities.runOnUiThread(() -> { + self.removeAllViews(); + ViewParent parent = self.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(self); + } + }); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + BannerBridge.didAttachScarBanner(_bannerAdId); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + BannerBridge.didDetachScarBanner(_bannerAdId); + } +} diff --git a/unity-ads/src/main/java/com/unity3d/services/core/api/DeviceInfo.java b/unity-ads/src/main/java/com/unity3d/services/core/api/DeviceInfo.java index 1cca572..644b137 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/api/DeviceInfo.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/api/DeviceInfo.java @@ -53,6 +53,11 @@ public class DeviceInfo { callback.invoke(Device.getApiLevel()); } + @WebViewExposed + public static void getExtensionVersion (WebViewCallback callback) { + callback.invoke(Device.getExtensionVersion()); + } + @WebViewExposed public static void getOsVersion (WebViewCallback callback) { callback.invoke(Device.getOsVersion()); @@ -521,5 +526,20 @@ public class DeviceInfo { public static void getBuildVersionIncremental(WebViewCallback callback) { callback.invoke(Device.getBuildVersionIncremental()); } + + @WebViewExposed + public static void hasX264HWDecoder(WebViewCallback callback) { + callback.invoke(Device.hasX264Decoder()); + } + + @WebViewExposed + public static void hasX265HWDecoder(WebViewCallback callback) { + callback.invoke(Device.hasX265Decoder()); + } + + @WebViewExposed + public static void hasAV1HWDecoder(WebViewCallback callback) { + callback.invoke(Device.hasAV1Decoder()); + } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/Configuration.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/Configuration.java index 014498c..b749d9c 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/Configuration.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/Configuration.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Random; public class Configuration { private String _webViewUrl; @@ -49,6 +50,7 @@ public class Configuration { private double _metricSampleRate; private long _webViewAppCreateTimeout; private String _scarBiddingUrl; + private Boolean _metricsEnabled; private String _filteredJsonString; private JSONObject _rawJsonData; @@ -276,6 +278,7 @@ public class Configuration { _privacyRequestWaitTimeout = configData.optInt("prwto", 3000); _src = configData.optString("src", null); _scarBiddingUrl = configData.optString("scurl", SCAR_PRD_BIDDING_ENDPOINT); + _metricsEnabled = _metricSampleRate >= new Random().nextInt(99) + 1; IExperiments experiments; if (configData.has("expo")) { @@ -322,4 +325,8 @@ public class Configuration { return filteredConfig; } + public Boolean areMetricsEnabledForCurrentSession() { + return _metricsEnabled; + } + } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/CoreModuleConfiguration.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/CoreModuleConfiguration.java index 7358a1a..230417d 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/CoreModuleConfiguration.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/CoreModuleConfiguration.java @@ -1,5 +1,8 @@ package com.unity3d.services.core.configuration; +import android.content.Context; +import android.content.pm.PackageManager; + import androidx.startup.AppInitializer; import com.unity3d.ads.UnityAds; @@ -106,11 +109,14 @@ public class CoreModuleConfiguration implements IModuleConfiguration { List metrics = new ArrayList<>(); int hasX264 = Device.hasX264Decoder() ? 1 : 0; int hasX265 = Device.hasX265Decoder() ? 1 : 0; + int hasAV1 = Device.hasAV1Decoder() ? 1 : 0; metrics.add(new Metric("native_device_decoder_x264", hasX264)); metrics.add(new Metric("native_device_decoder_x265", hasX265)); + metrics.add(new Metric("native_device_decoder_av1", hasAV1)); SDKMetricsSender sdkMetricsSender = Utilities.getService(SDKMetricsSender.class); sdkMetricsSender.sendMetrics(metrics); checkForCronet(configuration); + checkForPC(configuration, sdkMetricsSender); } private void checkForCronet(Configuration configuration) { @@ -119,4 +125,14 @@ public class CoreModuleConfiguration implements IModuleConfiguration { .initializeComponent(CronetInitializer.class); } } + + private void checkForPC(Configuration configuration, SDKMetricsSender sdkMetricsSender) { + if (configuration.getExperiments().isPCCheckEnabled()) { + Context context = ClientProperties.getApplicationContext(); + if (context == null) return; + PackageManager pm = context.getPackageManager(); + boolean isPC = pm.hasSystemFeature("com.google.android.play.feature.HPE_EXPERIENCE"); + sdkMetricsSender.sendMetric(new Metric("native_device_is_pc", isPC ? 1 : 0)); + } + } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentObjects.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentObjects.java index 286cae8..18f0e97 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentObjects.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentObjects.java @@ -1,7 +1,5 @@ package com.unity3d.services.core.configuration; -import com.unity3d.services.ads.gmascar.managers.SCARBiddingManagerType; - import org.json.JSONObject; import java.util.HashMap; @@ -53,11 +51,6 @@ public class ExperimentObjects extends ExperimentsBase { return getExperimentValueOrDefault(EXP_TAG_SCAR_INIT); } - @Override - public String getScarBiddingManager() { - return getExperimentValue(EXP_TAG_SCAR_BIDDING_MANAGER, SCARBiddingManagerType.DISABLED.getName()); - } - @Override public boolean isJetpackLifecycle() { return getExperimentValueOrDefault(EXP_TAG_JETPACK_LIFECYCLE); @@ -83,6 +76,27 @@ public class ExperimentObjects extends ExperimentsBase { return getExperimentValueOrDefault(EXP_TAG_CRONET_CHECK); } + @Override + public boolean isNativeShowTimeoutDisabled() { + return getExperimentValueOrDefault(EXP_TAG_SHOW_TIMEOUT_DISABLED); + } + + @Override + public boolean isNativeLoadTimeoutDisabled() { + return getExperimentValueOrDefault(EXP_TAG_LOAD_TIMEOUT_DISABLED); + } + + @Override + public boolean isCaptureHDRCapabilitiesEnabled() { + return getExperimentValueOrDefault(EXP_TAG_HDR_CAPABILITIES); + } + + @Override + public boolean isScarBannerHbEnabled() { return getExperimentValueOrDefault(EXP_TAG_SCAR_HB_BN); } + + @Override + public boolean isPCCheckEnabled() { return getExperimentValueOrDefault(EXP_TAG_IS_PC_CHECK_ENABLED); } + private String getExperimentValue(String experimentName, String defaultValue) { ExperimentObject expo = getExperimentObject(experimentName); return (expo != null) ? expo.getStringValue() : defaultValue; diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/Experiments.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/Experiments.java index c50f076..20757a9 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/Experiments.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/Experiments.java @@ -1,10 +1,7 @@ package com.unity3d.services.core.configuration; -import com.unity3d.services.ads.gmascar.managers.SCARBiddingManagerType; - import org.json.JSONObject; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -56,8 +53,8 @@ public class Experiments extends ExperimentsBase { } @Override - public String getScarBiddingManager() { - return _experimentData.optString(EXP_TAG_SCAR_BIDDING_MANAGER, SCARBiddingManagerType.DISABLED.getName()); + public boolean isScarBannerHbEnabled() { + return _experimentData.optBoolean(EXP_TAG_SCAR_HB_BN, false); } @Override @@ -85,6 +82,26 @@ public class Experiments extends ExperimentsBase { return _experimentData.optBoolean(EXP_TAG_CRONET_CHECK, false); } + @Override + public boolean isNativeShowTimeoutDisabled() { + return _experimentData.optBoolean(EXP_TAG_SHOW_TIMEOUT_DISABLED, false); + } + + @Override + public boolean isNativeLoadTimeoutDisabled() { + return _experimentData.optBoolean(EXP_TAG_LOAD_TIMEOUT_DISABLED, false); + } + + @Override + public boolean isCaptureHDRCapabilitiesEnabled() { + return _experimentData.optBoolean(EXP_TAG_HDR_CAPABILITIES, false); + } + + @Override + public boolean isPCCheckEnabled() { + return _experimentData.optBoolean(EXP_TAG_IS_PC_CHECK_ENABLED, false); + } + public JSONObject getExperimentsAsJson() { return _experimentData; } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentsBase.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentsBase.java index b8c7812..fd74d07 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentsBase.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/ExperimentsBase.java @@ -6,12 +6,15 @@ public abstract class ExperimentsBase implements IExperiments { static final String EXP_TAG_WEB_AD_ASSET_CACHING = "wac"; static final String EXP_TAG_WEB_GESTURE_NOT_REQUIRED = "wgr"; static final String EXP_TAG_SCAR_INIT = "scar_init"; - static final String EXP_TAG_SCAR_BIDDING_MANAGER = "scar_bm"; static final String EXP_TAG_JETPACK_LIFECYCLE = "gjl"; static final String EXP_TAG_OK_HTTP = "okhttp"; static final String EXP_TAG_WEB_MESSAGE = "jwm"; static final String EXP_TAG_WEBVIEW_ASYNC_DOWNLOAD = "wad"; static final String EXP_TAG_CRONET_CHECK = "cce"; - + static final String EXP_TAG_SHOW_TIMEOUT_DISABLED = "nstd"; + static final String EXP_TAG_LOAD_TIMEOUT_DISABLED = "nltd"; + static final String EXP_TAG_HDR_CAPABILITIES = "hdrc"; + static final String EXP_TAG_SCAR_HB_BN = "scar_bn"; + static final String EXP_TAG_IS_PC_CHECK_ENABLED = "pc_check"; static final boolean EXP_DEFAULT_VALUE = false; } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/configuration/IExperiments.java b/unity-ads/src/main/java/com/unity3d/services/core/configuration/IExperiments.java index cfe14d2..66d29fb 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/configuration/IExperiments.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/configuration/IExperiments.java @@ -10,12 +10,16 @@ public interface IExperiments { boolean isWebAssetAdCaching(); boolean isWebGestureNotRequired(); boolean isScarInitEnabled(); - String getScarBiddingManager(); boolean isJetpackLifecycle(); boolean isOkHttpEnabled(); boolean isWebMessageEnabled(); boolean isWebViewAsyncDownloadEnabled(); boolean isCronetCheckEnabled(); + boolean isNativeShowTimeoutDisabled(); + boolean isNativeLoadTimeoutDisabled(); + boolean isCaptureHDRCapabilitiesEnabled(); + boolean isScarBannerHbEnabled(); + boolean isPCCheckEnabled(); JSONObject getCurrentSessionExperiments(); JSONObject getNextSessionExperiments(); diff --git a/unity-ads/src/main/java/com/unity3d/services/core/device/Device.java b/unity-ads/src/main/java/com/unity3d/services/core/device/Device.java index be821e5..810be76 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/device/Device.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/device/Device.java @@ -1,5 +1,6 @@ package com.unity3d.services.core.device; + import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Context; @@ -19,6 +20,7 @@ import android.net.NetworkInfo; import android.os.BatteryManager; import android.os.Build; import android.os.SystemClock; +import android.os.ext.SdkExtensions; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -61,6 +63,14 @@ public class Device { return Build.VERSION.SDK_INT; } + public static int getExtensionVersion() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R); + } else { + return -1; + } + } + public static String getOsVersion() { return Build.VERSION.RELEASE; } @@ -699,6 +709,10 @@ public class Device { return Device.selectAllDecodeCodecs(MimeTypes.VIDEO_H265).size() > 0; } + public static boolean hasAV1Decoder() { + return Device.selectAllDecodeCodecs(MimeTypes.VIDEO_AV1).size() > 0; + } + public static List selectAllDecodeCodecs(String mimeType) { List result = new ArrayList<>(); int numCodecs = MediaCodecList.getCodecCount(); diff --git a/unity-ads/src/main/java/com/unity3d/services/core/device/MimeTypes.java b/unity-ads/src/main/java/com/unity3d/services/core/device/MimeTypes.java index 1f2226b..e27bdb0 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/device/MimeTypes.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/device/MimeTypes.java @@ -7,4 +7,5 @@ public class MimeTypes { public static final String VIDEO_WEBM = BASE_TYPE_VIDEO + "/webm"; public static final String VIDEO_H264 = BASE_TYPE_VIDEO + "/avc"; public static final String VIDEO_H265 = BASE_TYPE_VIDEO + "/hevc"; + public static final String VIDEO_AV1 = BASE_TYPE_VIDEO + "/av01"; } \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/core/device/reader/HdrInfoReader.java b/unity-ads/src/main/java/com/unity3d/services/core/device/reader/HdrInfoReader.java new file mode 100644 index 0000000..65e084a --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/core/device/reader/HdrInfoReader.java @@ -0,0 +1,106 @@ +package com.unity3d.services.core.device.reader; + +import static android.view.Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION; +import static android.view.Display.HdrCapabilities.HDR_TYPE_HDR10; +import static android.view.Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS; +import static android.view.Display.HdrCapabilities.HDR_TYPE_HLG; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.view.Display; +import android.view.WindowManager; + +import com.unity3d.services.core.configuration.ExperimentsReader; +import com.unity3d.services.core.misc.Utilities; +import com.unity3d.services.core.request.metrics.Metric; +import com.unity3d.services.core.request.metrics.SDKMetricsSender; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class HdrInfoReader implements IHdrInfoReader { + + private final SDKMetricsSender _sdkMetricsSender = Utilities.getService(SDKMetricsSender.class); + private static final AtomicBoolean _hdrMetricsCaptured = new AtomicBoolean(false); + + private static volatile HdrInfoReader _instance; + + private HdrInfoReader() {} + + public static HdrInfoReader getInstance() { + if (_instance == null) { + synchronized (HdrInfoReader.class) { + if (_instance == null) { + _instance = new HdrInfoReader(); + } + } + } + + return _instance; + } + + @Override + public void captureHDRCapabilityMetrics(Activity activity, ExperimentsReader experimentsReader) { + if (activity == null) return; + + if (!experimentsReader.getCurrentlyActiveExperiments().isCaptureHDRCapabilitiesEnabled()) return; + + if (_hdrMetricsCaptured.compareAndSet(false, true)) { + + List hdrMetrics = new ArrayList<>(5); + + int hasDolbyVision = 0; + int hasHDR10 = 0; + int hasHDR10Plus = 0; + int hasHLG = 0; + int isScreenHDR = 0; + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Display display = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + Display.HdrCapabilities hdrCapabilities = display.getHdrCapabilities(); + + int[] types = hdrCapabilities.getSupportedHdrTypes(); + for (int type : types) { + switch (type) { + case HDR_TYPE_DOLBY_VISION: + hasDolbyVision = 1; + break; + case HDR_TYPE_HDR10: + hasHDR10 = 1; + break; + case HDR_TYPE_HLG: + hasHLG = 1; + break; + case HDR_TYPE_HDR10_PLUS: + hasHDR10Plus = 1; + break; + } + } + + long maxAverage = Math.round(hdrCapabilities.getDesiredMaxAverageLuminance()); + long maxLum = Math.round(hdrCapabilities.getDesiredMaxLuminance()); + long minLum = Math.round(hdrCapabilities.getDesiredMinLuminance()); + + hdrMetrics.add(new Metric("native_device_hdr_lum_max_average", maxAverage)); + hdrMetrics.add(new Metric("native_device_hdr_lum_max", maxLum)); + hdrMetrics.add(new Metric("native_device_hdr_lum_min", minLum)); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + Configuration configuration = activity.getResources().getConfiguration(); + isScreenHDR = configuration.isScreenHdr() ? 1 : 0; + } + } + + hdrMetrics.add(new Metric("native_device_hdr_dolby_vision", hasDolbyVision)); + hdrMetrics.add(new Metric("native_device_hdr_hdr10", hasHDR10)); + hdrMetrics.add(new Metric("native_device_hdr_hdr10_plus", hasHDR10Plus)); + hdrMetrics.add(new Metric("native_device_hdr_hlg", hasHLG)); + hdrMetrics.add(new Metric("native_device_hdr_screen_hdr", isScreenHDR)); + + _sdkMetricsSender.sendMetrics(hdrMetrics); + } + } + +} \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/core/device/reader/IHdrInfoReader.java b/unity-ads/src/main/java/com/unity3d/services/core/device/reader/IHdrInfoReader.java new file mode 100644 index 0000000..d5ce399 --- /dev/null +++ b/unity-ads/src/main/java/com/unity3d/services/core/device/reader/IHdrInfoReader.java @@ -0,0 +1,9 @@ +package com.unity3d.services.core.device.reader; + +import android.app.Activity; + +import com.unity3d.services.core.configuration.ExperimentsReader; + +public interface IHdrInfoReader { + void captureHDRCapabilityMetrics(Activity activity, ExperimentsReader experimentsReader); +} \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/core/di/ServiceProvider.kt b/unity-ads/src/main/java/com/unity3d/services/core/di/ServiceProvider.kt index 77200d8..83fbe75 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/di/ServiceProvider.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/di/ServiceProvider.kt @@ -3,10 +3,12 @@ package com.unity3d.services.core.di import android.os.Handler import android.os.Looper import com.unity3d.services.SDKErrorHandler +import com.unity3d.services.ads.measurements.MeasurementsService import com.unity3d.services.ads.token.AsyncTokenStorage import com.unity3d.services.ads.token.InMemoryAsyncTokenStorage import com.unity3d.services.ads.token.InMemoryTokenStorage import com.unity3d.services.ads.token.TokenStorage +import com.unity3d.services.ads.topics.TopicsService import com.unity3d.services.core.device.VolumeChange import com.unity3d.services.core.device.VolumeChangeContentObserver import com.unity3d.services.core.device.VolumeChangeMonitor @@ -15,6 +17,7 @@ import com.unity3d.services.core.domain.SDKDispatchers import com.unity3d.services.core.domain.task.* import com.unity3d.services.core.network.core.LegacyHttpClient import com.unity3d.services.core.network.core.HttpClient +import com.unity3d.services.core.properties.ClientProperties import com.unity3d.services.core.network.core.OkHttp3Client import com.unity3d.services.core.request.metrics.SDKMetrics import com.unity3d.services.core.request.metrics.SDKMetricsSender @@ -84,6 +87,9 @@ object ServiceProvider : IServiceProvider { single { VolumeChangeContentObserver() } single { VolumeChangeMonitor(SharedInstances.webViewEventSender, get()) } + // android privacy sandbox + single { MeasurementsService(ClientProperties.getApplicationContext(), get(), SharedInstances.webViewEventSender) } + single { TopicsService(ClientProperties.getApplicationContext(), get(), SharedInstances.webViewEventSender) } } /** @@ -125,7 +131,7 @@ object ServiceProvider : IServiceProvider { */ private fun provideHttpClient(dispatchers: ISDKDispatchers, configFileFromLocalStorage: ConfigFileFromLocalStorage): HttpClient { val config = runBlocking { - runCatching { configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) }.getOrNull() + configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()).getOrNull() } if (config?.experiments?.isOkHttpEnabled == true) { diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/BaseTask.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/BaseTask.kt index 6e97092..90ca390 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/BaseTask.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/BaseTask.kt @@ -8,8 +8,8 @@ import com.unity3d.services.core.di.IServiceComponent */ interface BaseTask: IServiceComponent { - suspend operator fun invoke(params: P): R = doWork(params) + suspend operator fun invoke(params: P): Result = doWork(params) - suspend fun doWork(params: P): R + suspend fun doWork(params: P): Result } \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorage.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorage.kt index 23eb69f..fb9c397 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorage.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorage.kt @@ -2,6 +2,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.properties.SdkProperties import kotlinx.coroutines.withContext import org.json.JSONObject @@ -20,12 +21,14 @@ class ConfigFileFromLocalStorage( return getMetricNameForInitializeTask("read_local_config") } - override suspend fun doWork(params: Params): Configuration = + override suspend fun doWork(params: Params): Result = withContext(dispatchers.io) { - val configFile = File(SdkProperties.getLocalConfigurationFilepath()) - val fileContent = configFile.readText() - val loadedJson = JSONObject(fileContent) - Configuration(loadedJson) + runReturnSuspendCatching { + val configFile = File(SdkProperties.getLocalConfigurationFilepath()) + val fileContent = configFile.readText() + val loadedJson = JSONObject(fileContent) + Configuration(loadedJson) + } } /** diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeSDK.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeSDK.kt index d8fa82e..872741d 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeSDK.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeSDK.kt @@ -5,6 +5,7 @@ import com.unity3d.services.core.configuration.ErrorState import com.unity3d.services.core.configuration.InitializeEventsMetricSender import com.unity3d.services.core.domain.ISDKDispatchers import com.unity3d.services.core.domain.getInitializationExceptionOrThrow +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.lifecycle.CachedLifecycle import com.unity3d.services.core.log.DeviceLog import kotlinx.coroutines.CoroutineName @@ -31,80 +32,82 @@ class InitializeSDK( return getMetricNameForInitializeTask("initialize") } - override suspend fun doWork(params: EmptyParams) = + override suspend fun doWork(params: EmptyParams) : Result = withContext(dispatchers.default) { - InitializeEventsMetricSender.getInstance().didInitStart() - CachedLifecycle.register() + runReturnSuspendCatching { + InitializeEventsMetricSender.getInstance().didInitStart() + CachedLifecycle.register() - // check if we have a configuration cached - DeviceLog.debug("Unity Ads Init: Loading Config File From Local Storage") - val configuration = runCatching { configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) } - .onFailure { DeviceLog.debug("Unity Ads Init: Could not load config file from local storage: ${it.message}") } - .getOrDefault(Configuration()) + // check if we have a configuration cached + DeviceLog.debug("Unity Ads Init: Loading Config File From Local Storage") + val configuration = configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) + .onFailure { DeviceLog.debug("Unity Ads Init: Could not load config file from local storage: ${it.message}") } + .getOrDefault(Configuration()) - // reset modules - val resetResult = runCatching { initializeStateReset(InitializeStateReset.Params(configuration)) } - if (resetResult.isFailure) { - executeErrorState(ErrorState.ResetWebApp, resetResult.exceptionOrNull(), configuration) - throw resetResult.exceptionOrNull() ?: Exception(ErrorState.ResetWebApp.toString()) - } + // reset modules + val resetResult = initializeStateReset(InitializeStateReset.Params(configuration)) + if (resetResult.isFailure) { + executeErrorState(ErrorState.ResetWebApp, resetResult.exceptionOrNull(), configuration) + throw resetResult.exceptionOrNull() ?: Exception(ErrorState.ResetWebApp.toString()) + } - // get native config - val configResult = runCatching { initializeStateConfig(InitializeStateConfig.Params(configuration)) } - if (configResult.isFailure) { - handleInitializationException(configResult.getInitializationExceptionOrThrow()) - } + // get native config + val configResult = initializeStateConfig(InitializeStateConfig.Params(configuration)) + if (configResult.isFailure) { + handleInitializationException(configResult.getInitializationExceptionOrThrow()) + } - if (configuration.experiments.isNativeWebViewCacheEnabled) { - // load webview from remote url - val createWithRemoteResult = runCatching { - initializeStateCreateWithRemote( - InitializeStateCreateWithRemote.Params(configResult.getOrThrow()) + if (configuration.experiments.isNativeWebViewCacheEnabled) { + // load webview from remote url + val createWithRemoteResult = initializeStateCreateWithRemote( + InitializeStateCreateWithRemote.Params(configResult.getOrThrow()) ) - } - if (createWithRemoteResult.isSuccess) { - initializeStateComplete(InitializeStateComplete.Params(configResult.getOrThrow())) - return@withContext - } else { - handleInitializationException(createWithRemoteResult.getInitializationExceptionOrThrow()) - } - } - - // load WebView from cache if available and correct, if not fetch and load - val loadCacheResult = - runCatching { initializeStateLoadCache(InitializeStateLoadCache.Params(configResult.getOrThrow())) } - if (loadCacheResult.isFailure) { - executeErrorState(ErrorState.LoadCache, loadCacheResult.exceptionOrNull(), configuration) - throw loadCacheResult.exceptionOrNull() ?: Exception(ErrorState.LoadCache.toString()) - } - - val loadCacheResultData = loadCacheResult.getOrThrow() - val webViewData: String = if (loadCacheResultData.hasHashMismatch) { - // cached data has mismatch on checksum - if (configuration.experiments.isWebViewAsyncDownloadEnabled && loadCacheResultData.webViewData != null) { - // Fire and forget webView download, will be used in next session. - launch(CoroutineName("LaunchLoadWeb")) { runCatching { initializeStateLoadWeb(InitializeStateLoadWeb.Params(configResult.getOrThrow())) }} - loadCacheResultData.webViewData - } else { - // We don't have any cached WebView, we must wait for download to complete to continue init - val loadWebResult = runCatching { initializeStateLoadWeb(InitializeStateLoadWeb.Params(configResult.getOrThrow())) } - if (loadWebResult.isFailure) { - handleInitializationException(loadWebResult.getInitializationExceptionOrThrow()) + if (createWithRemoteResult.isSuccess) { + initializeStateComplete(InitializeStateComplete.Params(configResult.getOrThrow())).getOrThrow() + return@runReturnSuspendCatching + } else { + handleInitializationException(createWithRemoteResult.getInitializationExceptionOrThrow()) } - loadWebResult.getOrThrow().webViewDataString } - } else { - checkNotNull(loadCacheResultData.webViewData) { "WebView is missing." } - } - val createResult = - runCatching { initializeStateCreate(InitializeStateCreate.Params(configResult.getOrThrow(), webViewData)) } - if (createResult.isFailure) { - handleInitializationException(createResult.getInitializationExceptionOrThrow()) - } + // load WebView from cache if available and correct, if not fetch and load + val loadCacheResult = initializeStateLoadCache(InitializeStateLoadCache.Params(configResult.getOrThrow())) - initializeStateComplete(InitializeStateComplete.Params(configResult.getOrThrow())) - return@withContext + if (loadCacheResult.isFailure) { + executeErrorState(ErrorState.LoadCache, loadCacheResult.exceptionOrNull(), configuration) + throw loadCacheResult.exceptionOrNull() ?: Exception(ErrorState.LoadCache.toString()) + } + + val loadCacheResultData = loadCacheResult.getOrThrow() + val webViewData: String = if (loadCacheResultData.hasHashMismatch) { + // cached data has mismatch on checksum + if (configuration.experiments.isWebViewAsyncDownloadEnabled && loadCacheResultData.webViewData != null) { + // Fire and forget webView download, will be used in next session. + launch(CoroutineName("LaunchLoadWeb")) { + initializeStateLoadWeb(InitializeStateLoadWeb.Params(configResult.getOrThrow())) + } + loadCacheResultData.webViewData + } else { + // We don't have any cached WebView, we must wait for download to complete to continue init + val loadWebResult = initializeStateLoadWeb(InitializeStateLoadWeb.Params(configResult.getOrThrow())) + + if (loadWebResult.isFailure) { + handleInitializationException(loadWebResult.getInitializationExceptionOrThrow()) + } + loadWebResult.getOrThrow().webViewDataString + } + } else { + checkNotNull(loadCacheResultData.webViewData) { "WebView is missing." } + } + + val createResult = initializeStateCreate(InitializeStateCreate.Params(configResult.getOrThrow(), webViewData)) + + if (createResult.isFailure) { + handleInitializationException(createResult.getInitializationExceptionOrThrow()) + } + + initializeStateComplete(InitializeStateComplete.Params(configResult.getOrThrow())).getOrThrow() + } } private suspend fun handleInitializationException(exception: InitializationException) { diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateComplete.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateComplete.kt index 1a918d7..19fef2c 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateComplete.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateComplete.kt @@ -2,6 +2,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import kotlinx.coroutines.withContext class InitializeStateComplete( @@ -12,9 +13,11 @@ class InitializeStateComplete( return getMetricNameForInitializeTask("completion") } - override suspend fun doWork(params: Params): Unit = withContext(dispatchers.default) { - for (moduleName in params.config.moduleConfigurationList) { - params.config.getModuleConfiguration(moduleName)?.initCompleteState(params.config) + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { + runReturnSuspendCatching { + for (moduleName in params.config.moduleConfigurationList) { + params.config.getModuleConfiguration(moduleName)?.initCompleteState(params.config) + } } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfig.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfig.kt index 2b93eab..147703d 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfig.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfig.kt @@ -2,6 +2,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.properties.SdkProperties import kotlinx.coroutines.withContext @@ -15,15 +16,17 @@ class InitializeStateConfig( return getMetricNameForInitializeTask("config_fetch") } - override suspend fun doWork(params: Params): Configuration = + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { - DeviceLog.info("Unity Ads init: load configuration from " + SdkProperties.getConfigUrl()) - val configuration = Configuration( - SdkProperties.getConfigUrl(), - params.config.experimentsReader - ) + runReturnSuspendCatching { + DeviceLog.info("Unity Ads init: load configuration from " + SdkProperties.getConfigUrl()) + val configuration = Configuration( + SdkProperties.getConfigUrl(), + params.config.experimentsReader + ) - initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configuration)) + initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configuration)).getOrThrow() + } } data class Params(val config: Configuration) : BaseParams diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoader.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoader.kt index 4483e39..250375a 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoader.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoader.kt @@ -6,8 +6,8 @@ import com.unity3d.services.core.device.reader.DeviceInfoDataFactory import com.unity3d.services.core.di.get import com.unity3d.services.core.domain.ISDKDispatchers import com.unity3d.services.core.extensions.AbortRetryException +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.extensions.withRetry -import com.unity3d.services.core.request.metrics.SDKMetrics import com.unity3d.services.core.request.metrics.SDKMetricsSender import com.unity3d.services.core.request.metrics.TSIMetric import kotlinx.coroutines.withContext @@ -27,105 +27,114 @@ class InitializeStateConfigWithLoader( private val sdkMetricsSender: SDKMetricsSender ) : BaseTask { - override suspend fun doWork(params: Params) = + override suspend fun doWork(params: Params) : Result = withContext(dispatchers.default) { - val privacyConfigStorage = PrivacyConfigStorage.getInstance() - val deviceInfoDataFactory = DeviceInfoDataFactory() + runReturnSuspendCatching { + val privacyConfigStorage = PrivacyConfigStorage.getInstance() + val deviceInfoDataFactory = DeviceInfoDataFactory() - var configurationLoader: IConfigurationLoader = ConfigurationLoader( - ConfigurationRequestFactory( - params.config, - deviceInfoDataFactory.getDeviceInfoData(InitRequestType.TOKEN) - ), get() - ) - configurationLoader = PrivacyConfigurationLoader( - configurationLoader, - ConfigurationRequestFactory( - params.config, - deviceInfoDataFactory.getDeviceInfoData(InitRequestType.PRIVACY) - ), - privacyConfigStorage - ) - var config = Configuration() - - val configResult = runCatching { - withRetry( - retries = params.config.maxRetries, - scalingFactor = params.config.retryScalingFactor, - retryDelay = params.config.retryDelay, - fallbackException = InitializationException( - ErrorState.NetworkConfigRequest, - Exception(), - params.config + var configurationLoader: IConfigurationLoader = ConfigurationLoader( + ConfigurationRequestFactory( + params.config, + deviceInfoDataFactory.getDeviceInfoData(InitRequestType.TOKEN) + ), get() + ) + configurationLoader = PrivacyConfigurationLoader( + configurationLoader, + ConfigurationRequestFactory( + params.config, + deviceInfoDataFactory.getDeviceInfoData(InitRequestType.PRIVACY) ), - ) { - if (it > 0) InitializeEventsMetricSender.getInstance().onRetryConfig() - withContext(dispatchers.io) { - configurationLoader.loadConfiguration(object : - IConfigurationLoaderListener { - override fun onSuccess(configuration: Configuration) { - config = configuration - config.saveToDisk() - tokenStorage.setInitToken(config.unifiedAuctionToken) - } + privacyConfigStorage + ) + var config = Configuration() - override fun onError(errorMsg: String) { - sdkMetricsSender.sendMetric(TSIMetric.newEmergencySwitchOff()) - // Shall return with error and stop retries - throw AbortRetryException(errorMsg) - } - }) + val configResult = runCatching { + withRetry( + retries = params.config.maxRetries, + scalingFactor = params.config.retryScalingFactor, + retryDelay = params.config.retryDelay, + fallbackException = InitializationException( + ErrorState.NetworkConfigRequest, + Exception(), + params.config + ), + ) { + if (it > 0) InitializeEventsMetricSender.getInstance().onRetryConfig() + withContext(dispatchers.io) { + configurationLoader.loadConfiguration(object : + IConfigurationLoaderListener { + override fun onSuccess(configuration: Configuration) { + config = configuration + config.saveToDisk() + tokenStorage.setInitToken(config.unifiedAuctionToken) + } + + override fun onError(errorMsg: String) { + sdkMetricsSender.sendMetric(TSIMetric.newEmergencySwitchOff()) + // Shall return with error and stop retries + throw AbortRetryException(errorMsg) + } + }) + } } } - } - config = if (configResult.isFailure) { - // Check if it as an aborted exception - val configResultException = configResult.exceptionOrNull() - if (configResultException is AbortRetryException) { - // Abort init! - throw InitializationException( - ErrorState.NetworkConfigRequest, - configResultException, - params.config - ) - } - val haveNetwork = - runCatching { initializeStateNetworkError(InitializeStateNetworkError.Params(params.config)) } - if (haveNetwork.isSuccess) { - InitializeEventsMetricSender.getInstance().onRetryConfig() - withContext(dispatchers.io) { - configurationLoader.loadConfiguration(object : IConfigurationLoaderListener { - override fun onSuccess(configuration: Configuration) { - config = configuration - config.saveToDisk() - tokenStorage.setInitToken(config.unifiedAuctionToken) - } - - override fun onError(errorMsg: String) { - sdkMetricsSender.sendMetric(TSIMetric.newEmergencySwitchOff()) - // Shall return with an error - throw InitializationException( - ErrorState.NetworkConfigRequest, - Exception(errorMsg), + config = if (configResult.isFailure) { + // Check if it as an aborted exception + val configResultException = configResult.exceptionOrNull() + if (configResultException is AbortRetryException) { + // Abort init! + throw InitializationException( + ErrorState.NetworkConfigRequest, + configResultException, + params.config + ) + } + val haveNetwork = + runCatching { + initializeStateNetworkError( + InitializeStateNetworkError.Params( params.config ) - } - }) + ) + } + if (haveNetwork.isSuccess) { + InitializeEventsMetricSender.getInstance().onRetryConfig() + withContext(dispatchers.io) { + configurationLoader.loadConfiguration(object : + IConfigurationLoaderListener { + override fun onSuccess(configuration: Configuration) { + config = configuration + config.saveToDisk() + tokenStorage.setInitToken(config.unifiedAuctionToken) + } + + override fun onError(errorMsg: String) { + sdkMetricsSender.sendMetric(TSIMetric.newEmergencySwitchOff()) + // Shall return with an error + throw InitializationException( + ErrorState.NetworkConfigRequest, + Exception(errorMsg), + params.config + ) + } + }) + } + config + } else { + throw InitializationException( + ErrorState.NetworkConfigRequest, + Exception("No connected events within the timeout!"), + params.config + ) } - config } else { - throw InitializationException( - ErrorState.NetworkConfigRequest, - Exception("No connected events within the timeout!"), - params.config - ) + config } - } else { + config } - - config } /** diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreate.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreate.kt index 782920e..bcd40a7 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreate.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreate.kt @@ -3,6 +3,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.configuration.ErrorState import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.webview.WebViewApp import kotlinx.coroutines.withContext @@ -22,28 +23,34 @@ class InitializeStateCreate( return getMetricNameForInitializeTask("create_web_view") } - override suspend fun doWork(params: Params): Configuration = withContext(dispatchers.default) { - DeviceLog.debug("Unity Ads init: creating webapp") + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { + runReturnSuspendCatching { + DeviceLog.debug("Unity Ads init: creating webapp") - val configuration: Configuration = params.config - configuration.webViewData = params.webViewData + val configuration: Configuration = params.config + configuration.webViewData = params.webViewData - val createErrorState: ErrorState? = try { - WebViewApp.create(configuration, false) - } catch (e: IllegalThreadStateException) { - DeviceLog.exception("Illegal Thread", e) - throw InitializationException(ErrorState.CreateWebApp, e, configuration) - } - - if (createErrorState == null) { - configuration - } else { - var errorMessage: String? = "Unity Ads WebApp creation failed" - if (WebViewApp.getCurrentApp().webAppFailureMessage != null) { - errorMessage = WebViewApp.getCurrentApp().webAppFailureMessage + val createErrorState: ErrorState? = try { + WebViewApp.create(configuration, false) + } catch (e: IllegalThreadStateException) { + DeviceLog.exception("Illegal Thread", e) + throw InitializationException(ErrorState.CreateWebApp, e, configuration) + } + + if (createErrorState == null) { + configuration + } else { + var errorMessage: String? = "Unity Ads WebApp creation failed" + if (WebViewApp.getCurrentApp().webAppFailureMessage != null) { + errorMessage = WebViewApp.getCurrentApp().webAppFailureMessage + } + DeviceLog.error(errorMessage) + throw InitializationException( + createErrorState, + Exception(errorMessage), + configuration + ) } - DeviceLog.error(errorMessage) - throw InitializationException(createErrorState, Exception(errorMessage), configuration) } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemote.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemote.kt index b40516a..66fe02d 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemote.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemote.kt @@ -3,6 +3,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.configuration.ErrorState import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.webview.WebViewApp import kotlinx.coroutines.withContext @@ -22,28 +23,34 @@ class InitializeStateCreateWithRemote( return getMetricNameForInitializeTask("create_web_view") } - override suspend fun doWork(params: Params): Configuration = + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { - DeviceLog.debug("Unity Ads init: creating webapp") + runReturnSuspendCatching { + DeviceLog.debug("Unity Ads init: creating webapp") - val configuration: Configuration = params.config + val configuration: Configuration = params.config - val createErrorState: ErrorState? = try { - WebViewApp.create(configuration, true) - } catch (e: IllegalThreadStateException) { - DeviceLog.exception("Illegal Thread", e) - throw InitializationException(ErrorState.CreateWebApp, e, configuration) - } - - if (createErrorState == null) { - configuration - } else { - var errorMessage: String? = "Unity Ads WebApp creation failed" - if (WebViewApp.getCurrentApp().webAppFailureMessage != null) { - errorMessage = WebViewApp.getCurrentApp().webAppFailureMessage + val createErrorState: ErrorState? = try { + WebViewApp.create(configuration, true) + } catch (e: IllegalThreadStateException) { + DeviceLog.exception("Illegal Thread", e) + throw InitializationException(ErrorState.CreateWebApp, e, configuration) + } + + if (createErrorState == null) { + configuration + } else { + var errorMessage: String? = "Unity Ads WebApp creation failed" + if (WebViewApp.getCurrentApp().webAppFailureMessage != null) { + errorMessage = WebViewApp.getCurrentApp().webAppFailureMessage + } + DeviceLog.error(errorMessage) + throw InitializationException( + createErrorState, + Exception(errorMessage), + configuration + ) } - DeviceLog.error(errorMessage) - throw InitializationException(createErrorState, Exception(errorMessage), configuration) } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateError.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateError.kt index 0fd58b7..749b4a7 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateError.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateError.kt @@ -3,6 +3,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.configuration.ErrorState import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import kotlinx.coroutines.withContext @@ -22,14 +23,16 @@ class InitializeStateError( override suspend fun doWork(params: Params) = withContext(dispatchers.default) { - DeviceLog.error("Unity Ads init: halting init in " + params.errorState.metricName + ": " + params.exception.message) + runReturnSuspendCatching { + DeviceLog.error("Unity Ads init: halting init in " + params.errorState.metricName + ": " + params.exception.message) - for (moduleName in params.config.moduleConfigurationList ?: emptyArray()) { - params.config.getModuleConfiguration(moduleName)?.initErrorState( - params.config, - params.errorState, - params.exception.message - ) + for (moduleName in params.config.moduleConfigurationList ?: emptyArray()) { + params.config.getModuleConfiguration(moduleName)?.initErrorState( + params.config, + params.errorState, + params.exception.message + ) + } } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadCache.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadCache.kt index af1563e..3951893 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadCache.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadCache.kt @@ -2,6 +2,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.misc.Utilities import com.unity3d.services.core.properties.SdkProperties @@ -25,23 +26,27 @@ class InitializeStateLoadCache( return getMetricNameForInitializeTask("read_local_webview") } - override suspend fun doWork(params: Params): LoadCacheResult = + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { - DeviceLog.debug("Unity Ads init: check if webapp can be loaded from local cache") + runReturnSuspendCatching { + DeviceLog.debug("Unity Ads init: check if webapp can be loaded from local cache") - val localWebViewData: ByteArray = getWebViewData() ?: return@withContext LoadCacheResult(hasHashMismatch = true) - val localWebViewHash: String? = Utilities.Sha256(localWebViewData) + val localWebViewData: ByteArray = + getWebViewData() ?: return@runReturnSuspendCatching LoadCacheResult(hasHashMismatch = true) + val localWebViewHash: String? = Utilities.Sha256(localWebViewData) - // If charset isn't supported on device, might throw an exception (result.isFailure) - val webViewDataString = String(localWebViewData, Charset.forName("UTF-8")) + // If charset isn't supported on device, might throw an exception (result.isFailure) + val webViewDataString = String(localWebViewData, Charset.forName("UTF-8")) - val hashMismatch = localWebViewHash == null || localWebViewHash != params.config.webViewHash + val hashMismatch = + localWebViewHash == null || localWebViewHash != params.config.webViewHash - if (!hashMismatch) { - DeviceLog.info("Unity Ads init: webapp loaded from local cache") + if (!hashMismatch) { + DeviceLog.info("Unity Ads init: webapp loaded from local cache") + } + + LoadCacheResult(hashMismatch, webViewDataString) } - - LoadCacheResult(hashMismatch, webViewDataString) } /** diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadWeb.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadWeb.kt index 8882ac2..c1fe83a 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadWeb.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateLoadWeb.kt @@ -5,6 +5,7 @@ import com.unity3d.services.core.configuration.ErrorState import com.unity3d.services.core.configuration.InitializeEventsMetricSender import com.unity3d.services.core.domain.ISDKDispatchers import com.unity3d.services.core.domain.task.InitializeStateLoadWeb.LoadWebResult +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.extensions.withRetry import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.misc.Utilities @@ -33,53 +34,65 @@ class InitializeStateLoadWeb( return getMetricNameForInitializeTask("download_web_view") } - override suspend fun doWork(params: Params): LoadWebResult = withContext(dispatchers.default) { - DeviceLog.info("Unity Ads init: loading webapp from " + params.config.webViewUrl) + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { + runReturnSuspendCatching { + DeviceLog.info("Unity Ads init: loading webapp from " + params.config.webViewUrl) - val request = HttpRequest(baseURL = params.config.webViewUrl, method = RequestType.GET) + val request = HttpRequest(baseURL = params.config.webViewUrl, method = RequestType.GET) - val webViewDataResult = runCatching { - withRetry( - retries = params.config.maxRetries, - scalingFactor = params.config.retryScalingFactor, - retryDelay = params.config.retryDelay, - fallbackException = InitializationException( - ErrorState.NetworkWebviewRequest, - Exception(), - params.config - ), - ) { - if (it > 0) InitializeEventsMetricSender.getInstance().onRetryWebview() - withContext(dispatchers.io) { httpClient.execute(request) } + val webViewDataResult = runCatching { + withRetry( + retries = params.config.maxRetries, + scalingFactor = params.config.retryScalingFactor, + retryDelay = params.config.retryDelay, + fallbackException = InitializationException( + ErrorState.NetworkWebviewRequest, + Exception(), + params.config + ), + ) { + if (it > 0) InitializeEventsMetricSender.getInstance().onRetryWebview() + withContext(dispatchers.io) { httpClient.execute(request) } + } } - } - val webViewData: String = if (webViewDataResult.isFailure) { - val haveNetwork = - runCatching { initializeStateNetworkError(InitializeStateNetworkError.Params(params.config)) } - if (haveNetwork.isSuccess) { - withContext(dispatchers.io) { httpClient.execute(request).body.toString() } + val webViewData: String = if (webViewDataResult.isFailure) { + val haveNetwork = + runCatching { + initializeStateNetworkError( + InitializeStateNetworkError.Params( + params.config + ) + ) + } + if (haveNetwork.isSuccess) { + withContext(dispatchers.io) { httpClient.execute(request).body.toString() } + } else { + throw InitializationException( + ErrorState.NetworkWebviewRequest, + Exception("No connected events within the timeout!"), + params.config + ) + } } else { + webViewDataResult.getOrThrow().body.toString() + } + + val webViewHash: String? = params.config.webViewHash + if (webViewHash != null && Utilities.Sha256(webViewData) != webViewHash) { throw InitializationException( - ErrorState.NetworkWebviewRequest, - Exception("No connected events within the timeout!"), + ErrorState.InvalidHash, + Exception("Invalid webViewHash"), params.config ) } - } else { - webViewDataResult.getOrThrow().body.toString() - } - val webViewHash: String? = params.config.webViewHash - if (webViewHash != null && Utilities.Sha256(webViewData) != webViewHash) { - throw InitializationException(ErrorState.InvalidHash, Exception("Invalid webViewHash"), params.config) - } + if (webViewHash != null) { + Utilities.writeFile(File(SdkProperties.getLocalWebViewFile()), webViewData) + } - if (webViewHash != null) { - Utilities.writeFile(File(SdkProperties.getLocalWebViewFile()), webViewData) + LoadWebResult(params.config, webViewData) } - - LoadWebResult(params.config, webViewData) } data class Params(val config: Configuration) : BaseParams diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateNetworkError.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateNetworkError.kt index 56b22b5..5a856f3 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateNetworkError.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateNetworkError.kt @@ -4,6 +4,7 @@ import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.connectivity.ConnectivityMonitor import com.unity3d.services.core.connectivity.IConnectivityListener import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext @@ -30,20 +31,22 @@ class InitializeStateNetworkError( } override suspend fun doWork(params: Params) = withContext(dispatchers.default) { - DeviceLog.error("Unity Ads init: network error, waiting for connection events") - maximumConnectedEvents = params.config.maximumConnectedEvents - connectedEventThreshold = params.config.connectedEventThreshold + runReturnSuspendCatching { + DeviceLog.error("Unity Ads init: network error, waiting for connection events") + maximumConnectedEvents = params.config.maximumConnectedEvents + connectedEventThreshold = params.config.connectedEventThreshold - val success = withTimeoutOrNull(params.config.networkErrorTimeout) { - suspendCancellableCoroutine { cont -> - startListening(cont) + val success = withTimeoutOrNull(params.config.networkErrorTimeout) { + suspendCancellableCoroutine { cont -> + startListening(cont) + } } - } - // We timed out - if (success == null) { - ConnectivityMonitor.removeListener(this@InitializeStateNetworkError) - throw Exception("No connected events within the timeout!") + // We timed out + if (success == null) { + ConnectivityMonitor.removeListener(this@InitializeStateNetworkError) + throw Exception("No connected events within the timeout!") + } } } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateReset.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateReset.kt index 46f35e0..5af355e 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateReset.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateReset.kt @@ -3,6 +3,7 @@ package com.unity3d.services.core.domain.task import com.unity3d.services.core.api.Lifecycle import com.unity3d.services.core.configuration.Configuration import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.extensions.runReturnSuspendCatching import com.unity3d.services.core.log.DeviceLog import com.unity3d.services.core.properties.ClientProperties import com.unity3d.services.core.properties.SdkProperties @@ -26,37 +27,39 @@ open class InitializeStateReset( return getMetricNameForInitializeTask("reset") } - override suspend fun doWork(params: Params): Configuration = + override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { - DeviceLog.debug("Unity Ads init: starting init") + runReturnSuspendCatching { + DeviceLog.debug("Unity Ads init: starting init") - val currentApp: WebViewApp? = WebViewApp.getCurrentApp() + val currentApp: WebViewApp? = WebViewApp.getCurrentApp() - currentApp?.resetWebViewAppInitialization() - if (currentApp?.webView != null) { - val success = withTimeoutOrNull(params.config.webViewAppCreateTimeout) { - withContext(dispatchers.main) { - currentApp.webView?.destroy() - currentApp.webView = null + currentApp?.resetWebViewAppInitialization() + if (currentApp?.webView != null) { + val success = withTimeoutOrNull(params.config.webViewAppCreateTimeout) { + withContext(dispatchers.main) { + currentApp.webView?.destroy() + currentApp.webView = null + } } - } - if (success == null) { - throw Exception("Reset failed on opening ConditionVariable") + if (success == null) { + throw Exception("Reset failed on opening ConditionVariable") + } + } + unregisterLifecycleCallbacks() + + SdkProperties.setCacheDirectory(null) + SdkProperties.getCacheDirectory() ?: throw Exception("Cache directory is NULL") + + SdkProperties.setInitialized(false) + + for (moduleName in params.config.moduleConfigurationList ?: emptyArray()) { + params.config.getModuleConfiguration(moduleName)?.resetState(params.config) + } + params.config } - - unregisterLifecycleCallbacks() - - SdkProperties.setCacheDirectory(null) - SdkProperties.getCacheDirectory() ?: throw Exception("Cache directory is NULL") - - SdkProperties.setInitialized(false) - - for (moduleName in params.config.moduleConfigurationList ?: emptyArray()) { - params.config.getModuleConfiguration(moduleName)?.resetState(params.config) - } - params.config } private fun unregisterLifecycleCallbacks() { diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateRetry.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateRetry.kt deleted file mode 100644 index 5e890d9..0000000 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/InitializeStateRetry.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.unity3d.services.core.domain.task - -import com.unity3d.services.core.configuration.Configuration -import com.unity3d.services.core.domain.ISDKDispatchers -import com.unity3d.services.core.extensions.runReturnSuspendCatching -import kotlinx.coroutines.withContext - -class InitializeStateRetry( - private val dispatchers: ISDKDispatchers, -) : BaseTask> { - - override suspend fun doWork(params: Params): Result = withContext(dispatchers.default) { - runReturnSuspendCatching { - // interactor logic - } - } - - data class Params(val config: Configuration) : BaseParams -} \ No newline at end of file diff --git a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/MetricTask.kt b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/MetricTask.kt index 505e81b..de2ad38 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/domain/task/MetricTask.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/domain/task/MetricTask.kt @@ -17,8 +17,8 @@ abstract class MetricTask : BaseTask { var duration: Long = 0L var taskStatus: String = "unknown" - override suspend fun invoke(params: P): R { - var result: R + override suspend fun invoke(params: P): Result { + var result: Result duration = TimeUnit.NANOSECONDS.toMillis( measureNanoTime { result = super.invoke(params) @@ -27,12 +27,8 @@ abstract class MetricTask : BaseTask { return result } - private fun captureMetric(result: R) { - taskStatus = if (result is Result<*>) { - if (result.isSuccess) "success" else "failure" - } else { - "success" - } + private fun captureMetric(result: Result) { + taskStatus = if (result.isSuccess) "success" else "failure" sendMetric() } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSender.kt b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSender.kt index 4658935..293063c 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSender.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSender.kt @@ -28,10 +28,6 @@ open class MetricSender( override val metricEndPoint: String? = configuration.metricsUrl - override fun areMetricsEnabledForCurrentSession(): Boolean { - return true - } - override fun sendEvent(event: String, value: String?, tags: Map) { if (event.isEmpty()) { DeviceLog.debug("Metric event not sent due to being null or empty: $event") diff --git a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSenderWithBatch.kt b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSenderWithBatch.kt index 9fd9d17..d4b4e95 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSenderWithBatch.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/MetricSenderWithBatch.kt @@ -16,10 +16,6 @@ class MetricSenderWithBatch( _original = metrics } - override fun areMetricsEnabledForCurrentSession(): Boolean { - return _original.areMetricsEnabledForCurrentSession() - } - override fun sendEvent(event: String, value: String?, tags: Map) { if (event.isEmpty()) { DeviceLog.debug("Metric event not sent due to being empty: $event") diff --git a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetrics.java b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetrics.java index 9ed917c..03300c7 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetrics.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetrics.java @@ -4,7 +4,6 @@ package com.unity3d.services.core.request.metrics; import android.text.TextUtils; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.unity3d.services.core.configuration.Configuration; import com.unity3d.services.core.log.DeviceLog; @@ -12,7 +11,6 @@ import com.unity3d.services.core.properties.InitializationStatusReader; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; public final class SDKMetrics { @@ -37,7 +35,7 @@ public final class SDKMetrics { ((MetricSender) _instance).shutdown(); } - if (configuration.getMetricSampleRate() >= new Random().nextInt(99) + 1) { + if (configuration.areMetricsEnabledForCurrentSession()) { _instance = new MetricSender(configuration, new InitializationStatusReader()); } else { DeviceLog.debug("Metrics will not be sent from the device for this session"); @@ -79,11 +77,6 @@ public final class SDKMetrics { _metricEndpoint = url; } - @Override - public boolean areMetricsEnabledForCurrentSession() { - return false; - } - public void sendEvent(@NonNull final String event) { DeviceLog.debug("Metric " + event + " was skipped from being sent"); } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetricsSender.kt b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetricsSender.kt index cf4b39c..60c4316 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetricsSender.kt +++ b/unity-ads/src/main/java/com/unity3d/services/core/request/metrics/SDKMetricsSender.kt @@ -1,7 +1,6 @@ package com.unity3d.services.core.request.metrics interface SDKMetricsSender { - fun areMetricsEnabledForCurrentSession(): Boolean fun sendEvent(event: String) = sendEvent(event, null) fun sendEvent(event: String, value: String? = null, tags: Map = emptyMap()) fun sendMetric(metric: Metric) diff --git a/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewEventCategory.java b/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewEventCategory.java index 845ab1e..e372894 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewEventCategory.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewEventCategory.java @@ -20,5 +20,7 @@ public enum WebViewEventCategory { LOAD_API, TOKEN, INIT_GMA, - GMA + GMA, + MEASUREMENTS, + TOPICS } diff --git a/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewUrlBuilder.java b/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewUrlBuilder.java index cac7efd..10534d1 100644 --- a/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewUrlBuilder.java +++ b/unity-ads/src/main/java/com/unity3d/services/core/webview/WebViewUrlBuilder.java @@ -18,8 +18,7 @@ public class WebViewUrlBuilder { queryString += buildQueryParam("origin", configuration.getWebViewUrl()); queryString += buildQueryParam("version", configuration.getWebViewVersion()); - queryString += buildQueryParam("isNativeCollectingMetrics", String.valueOf(_sdkMetricsSender.areMetricsEnabledForCurrentSession())); - + queryString += buildQueryParam("isNativeCollectingMetrics", String.valueOf(configuration.areMetricsEnabledForCurrentSession())); _urlWithQueryString = baseUrl + queryString; } diff --git a/unity-ads/src/test/java/com/unity3d/services/SDKErrorHandlerTest.kt b/unity-ads/src/test/java/com/unity3d/services/SDKErrorHandlerTest.kt new file mode 100644 index 0000000..097c7e8 --- /dev/null +++ b/unity-ads/src/test/java/com/unity3d/services/SDKErrorHandlerTest.kt @@ -0,0 +1,84 @@ +package com.unity3d.services + +import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.request.metrics.Metric +import com.unity3d.services.core.request.metrics.SDKMetricsSender +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.junit.Before +import org.junit.Test +import kotlin.coroutines.CoroutineContext +import kotlin.test.assertEquals + +class SDKErrorHandlerTest { + @MockK + private lateinit var dispatchers: ISDKDispatchers + + @MockK + private lateinit var sdkMetricsSender: SDKMetricsSender + + @MockK + private lateinit var coroutineContext: CoroutineContext + + @MockK + private lateinit var exceptionMock: Exception + + @InjectMockKs + private lateinit var sdkErrorHandler: SDKErrorHandler + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxed = true) + } + + @Test + fun handleException_exceptionProvided_metricSent() { + // given + val exception = RuntimeException() + + // when + sdkErrorHandler.handleException(coroutineContext, exception) + + // then + verify { sdkMetricsSender.sendMetric(any()) } + } + + @Test + fun handleException_exceptionProvidedWithStackTraceNullElement_metricSent() { + // given + val capturedMetric = slot() + every { exceptionMock.stackTrace } returns arrayOf(null) + every { sdkMetricsSender.sendMetric(capture(capturedMetric)) } returns Unit + + // when + sdkErrorHandler.handleException(coroutineContext, exceptionMock) + + // then + verify { sdkMetricsSender.sendMetric(any()) } + assertEquals("native_exception", capturedMetric.captured.name) + assertEquals("unknown_0", capturedMetric.captured.value) + } + + @Test + fun handleException_exceptionProvidedWithStackTraceButNullFileName_metricSent() { + // given + val capturedMetric = slot() + val mockedStackTraceElement: StackTraceElement = mockk(relaxed = true) + every { mockedStackTraceElement.fileName } returns null + every { exceptionMock.stackTrace } returns arrayOf(mockedStackTraceElement) + every { sdkMetricsSender.sendMetric(capture(capturedMetric)) } returns Unit + + // when + sdkErrorHandler.handleException(coroutineContext, exceptionMock) + + // then + verify { sdkMetricsSender.sendMetric(any()) } + assertEquals("native_exception", capturedMetric.captured.name) + assertEquals("unknown_0", capturedMetric.captured.value) + } +} \ No newline at end of file diff --git a/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.java b/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.java deleted file mode 100644 index 5779e36..0000000 --- a/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.unity3d.services.ads.gmascar.managers; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.unity3d.ads.IUnityAdsTokenListener; -import com.unity3d.services.ads.gmascar.GMA; -import com.unity3d.services.core.configuration.IExperiments; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - - -@RunWith(PowerMockRunner.class) -@PrepareForTest({GMA.class}) -public class BiddingManagerFactoryTest { - - BiddingManagerFactory biddingManagerFactory = BiddingManagerFactory.getInstance(); - IExperiments experiments = mock(IExperiments.class); - GMA gma = mock(GMA.class); - - @Before - public void setup() throws Exception { - PowerMockito.whenNew(GMA.class).withAnyArguments().thenReturn(gma); - when(gma.hasSCARBiddingSupport()).thenReturn(true); - } - - @Test - public void createManagerNoExperiment() { - BiddingBaseManager manager = biddingManagerFactory.createManager(new IUnityAdsTokenListener() { - @Override - public void onUnityAdsTokenReady(String token) { - - } - }, null); - assertThat(manager, instanceOf(BiddingDisabledManager.class)); - } - - @Test - public void createManagerNoListenerNullExperiments() { - BiddingBaseManager manager = biddingManagerFactory - .createManager(null, null); - assertThat(manager, instanceOf(BiddingDisabledManager.class)); - } - - @Test - public void createManagerNoListenerNullGetScarBmExperiment() { - BiddingBaseManager manager = biddingManagerFactory - .createManager(null, experiments); - assertThat(manager, instanceOf(BiddingDisabledManager.class)); - } - - @Test - public void createManagerNoListenerDisabledExperiment() { - when(experiments.getScarBiddingManager()).thenReturn("dis"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(null, experiments); - assertThat(manager, instanceOf(BiddingDisabledManager.class)); - } - - @Test - public void createManagerNoListenerExperimentEager() { - when(experiments.getScarBiddingManager()).thenReturn("eag"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(null, experiments); - assertThat(manager, instanceOf(BiddingEagerManager.class)); - } - - @Test - public void createManagerNoListenerAnyExperiment() { - when(experiments.getScarBiddingManager()).thenReturn("laz"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(null, experiments); - assertThat(manager, instanceOf(BiddingEagerManager.class)); - } - - @Test - public void createManagerExperimentEager() { - when(experiments.getScarBiddingManager()).thenReturn("eag"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(mock(IUnityAdsTokenListener.class), experiments); - assertThat(manager, instanceOf(BiddingEagerManager.class)); - } - - @Test - public void createManagerExperimentLazy() { - when(experiments.getScarBiddingManager()).thenReturn("laz"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(mock(IUnityAdsTokenListener.class), experiments); - assertThat(manager, instanceOf(BiddingLazyManager.class)); - } - - @Test - public void createManagerExperimentHybrid() { - when(experiments.getScarBiddingManager()).thenReturn("hyb"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(mock(IUnityAdsTokenListener.class), experiments); - assertThat(manager, instanceOf(BiddingOnDemandManager.class)); - } - - @Test - public void createManagerExperimentDisabled() { - when(experiments.getScarBiddingManager()).thenReturn("dis"); - - BiddingBaseManager manager = biddingManagerFactory - .createManager(mock(IUnityAdsTokenListener.class), experiments); - assertThat(manager, instanceOf(BiddingDisabledManager.class)); - } -} diff --git a/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.kt b/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.kt new file mode 100644 index 0000000..68406eb --- /dev/null +++ b/unity-ads/src/test/java/com/unity3d/services/ads/gmascar/managers/BiddingManagerFactoryTest.kt @@ -0,0 +1,77 @@ +package com.unity3d.services.ads.gmascar.managers + +import com.unity3d.ads.IUnityAdsTokenListener +import com.unity3d.services.ads.gmascar.GMA +import com.unity3d.services.core.configuration.IExperiments +import io.mockk.* +import io.mockk.impl.annotations.MockK +import org.hamcrest.CoreMatchers.instanceOf +import org.hamcrest.MatcherAssert.assertThat +import kotlin.test.AfterTest +import kotlin.test.BeforeTest +import kotlin.test.Test + +class BiddingManagerFactoryTest { + + private lateinit var biddingManagerFactory: BiddingManagerFactory + + @MockK + private lateinit var experiments: IExperiments + + @MockK + private lateinit var gma: GMA + + @BeforeTest + fun setup() { + biddingManagerFactory = BiddingManagerFactory.getInstance() + + MockKAnnotations.init(this, relaxed = true) + + mockkStatic(GMA::class) + every { GMA.getInstance() } returns gma + } + + @AfterTest + fun tearDown() { + unmockkStatic(GMA::class) + } + + @Test + fun createManagerScarSupportedNullExperiments() { + every { gma.hasSCARBiddingSupport() } returns true + val manager = biddingManagerFactory.createManager(IUnityAdsTokenListener { }, null) + assertThat(manager, instanceOf(BiddingEagerManager::class.java)) + } + + @Test + fun createManagerScarUnsupportedNullExperiments() { + every { gma.hasSCARBiddingSupport() } returns false + val manager = biddingManagerFactory.createManager(IUnityAdsTokenListener { }, null) + assertThat(manager, instanceOf(BiddingDisabledManager::class.java)) + } + + @Test + fun createManagerScarUnsupportedValidExperiments() { + every { gma.hasSCARBiddingSupport() } returns false + val manager = biddingManagerFactory.createManager(IUnityAdsTokenListener { }, experiments) + assertThat(manager, instanceOf(BiddingDisabledManager::class.java)) + } + + @Test + fun createManagerScarSupportedExperimentTrue() { + every { gma.hasSCARBiddingSupport() } returns true + every { experiments.isScarBannerHbEnabled } returns true + + val manager = biddingManagerFactory.createManager(IUnityAdsTokenListener { }, experiments) + assertThat(manager, instanceOf(BiddingEagerManager::class.java)) + } + + @Test + fun createManagerScarSupportedExperimentFalse() { + every { gma.hasSCARBiddingSupport() } returns true + every { experiments.isScarBannerHbEnabled } returns false + + val manager = biddingManagerFactory.createManager(IUnityAdsTokenListener { }, experiments) + assertThat(manager, instanceOf(BiddingEagerManager::class.java)) + } +} \ No newline at end of file diff --git a/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsReceiverTest.kt b/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsReceiverTest.kt new file mode 100644 index 0000000..5b5f1fd --- /dev/null +++ b/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsReceiverTest.kt @@ -0,0 +1,88 @@ +package com.unity3d.services.ads.topics + +import android.adservices.topics.GetTopicsResponse +import android.adservices.topics.Topic +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.json.JSONArray +import org.junit.Test +import kotlin.test.assertEquals + +class TopicsReceiverTest { + @Test + fun onResult_success_sendEvent() { + // given + val eventSenderMock: IEventSender = mockk() + every { eventSenderMock.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.TOPICS_AVAILABLE, allAny()) } returns true + + val receiver = TopicsReceiver(eventSenderMock) + val topicsresponse: GetTopicsResponse = mockk() + + val topic1: Topic = mockk() + every { topic1.taxonomyVersion } returns 1 + every { topic1.modelVersion } returns 11 + every { topic1.topicId } returns 111 + + val topic2: Topic = mockk() + every { topic2.taxonomyVersion } returns 2 + every { topic2.modelVersion } returns 22 + every { topic2.topicId } returns 222 + + val topic3: Topic = mockk() + every { topic3.taxonomyVersion } returns 3 + every { topic3.modelVersion } returns 33 + every { topic3.topicId } returns 333 + + every { topicsresponse.topics } returns listOf(topic1, topic2, topic3) + + // when + receiver.onResult(topicsresponse) + + // then + val resultArray = JSONArray() + resultArray.put(receiver.formatTopic(topic1)) + resultArray.put(receiver.formatTopic(topic2)) + resultArray.put(receiver.formatTopic(topic3)) + val expectedResult = resultArray.toString() + + verify { eventSenderMock.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.TOPICS_AVAILABLE, expectedResult) } + } + + @Test + fun onError_failure_sendEvent() { + // given + val exception: Exception = mockk() + val exceptionDescription = "test exception description" + every { exception.toString() } returns exceptionDescription + val eventSenderMock: IEventSender = mockk() + every { eventSenderMock.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, allAny()) } returns true + val receiver = TopicsReceiver(eventSenderMock) + + // when + receiver.onError(exception) + + // then + verify { eventSenderMock.sendEvent(WebViewEventCategory.TOPICS, TopicsEvents.NOT_AVAILABLE, TopicsErrors.ERROR_EXCEPTION, exceptionDescription)} + } + + @Test + fun formatTopic_topicProvided_properJsonResult() { + // given + val receiver = TopicsReceiver(mockk()) + val topic: Topic = mockk() + every { topic.taxonomyVersion } returns 1 + every { topic.modelVersion } returns 2 + every { topic.topicId } returns 3 + + // when + val result = receiver.formatTopic(topic) + + // then + assertEquals(result.getLong("taxonomyVersion"), 1) + assertEquals(result.getLong("modelVersion"), 2) + assertEquals(result.getInt("topicId"), 3) + } +} diff --git a/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsServiceTest.kt b/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsServiceTest.kt new file mode 100644 index 0000000..963b20f --- /dev/null +++ b/unity-ads/src/test/java/com/unity3d/services/ads/topics/TopicsServiceTest.kt @@ -0,0 +1,201 @@ +package com.unity3d.services.ads.topics + +import android.adservices.AdServicesState +import android.adservices.topics.GetTopicsRequest +import android.adservices.topics.TopicsManager +import android.content.Context +import android.os.ext.SdkExtensions +import com.unity3d.services.core.device.Device +import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.domain.task.TestSDKDispatchers +import com.unity3d.services.core.properties.ClientProperties +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import io.mockk.* +import io.mockk.impl.annotations.MockK +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals + +class TopicsServiceTest { + @MockK + private lateinit var context: Context + + @MockK + private lateinit var eventSender: IEventSender + + private val dispatchers: ISDKDispatchers = TestSDKDispatchers() + + @Before + fun setup() { + MockKAnnotations.init(this, relaxed = true) + + mockkStatic(ClientProperties::class) + every { ClientProperties.getApplicationContext() } returns context + } + + @Test + fun checkAvailability_error_topicsManagerNull() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + every { context.getSystemService(TopicsManager::class.java) } returns null + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + val service = TopicsService(context, dispatchers, eventSender) + + // when + val result = service.checkAvailability() + + // then + assertEquals(TopicsStatus.ERROR_TOPICSMANAGER_NULL, result) + } + } + + @Test + fun checkAvailability_error_apiBelow33() { + mockkStatic(Device::class) { + // given + val topicsManager: TopicsManager = mockk() + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 32 + val service = TopicsService(context, dispatchers, eventSender) + + // when + val result = service.checkAvailability() + + // then + assertEquals(TopicsStatus.ERROR_API_BELOW_33, result) + } + } + + @Test + fun checkAvailability_error_extensionBelow4() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + val topicsManager: TopicsManager = mockk() + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 3 + val service = TopicsService(context, dispatchers, eventSender) + + // when + val result = service.checkAvailability() + + // then + assertEquals(TopicsStatus.ERROR_EXTENSION_BELOW_4, result) + } + } + + @Test + fun checkAvailability_error_adServicesDisabled() { + mockkStatic(Device::class, SdkExtensions::class, AdServicesState::class) { + // given + val topicsManager: TopicsManager = mockk() + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 34 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { AdServicesState.isAdServicesStateEnabled() } returns false + val service = TopicsService(context, dispatchers, eventSender) + + // when + val result = service.checkAvailability() + + // then + assertEquals(TopicsStatus.ERROR_AD_SERVICES_DISABLED, result) + } + } + + @Test + fun checkAvailability_success_topicsAvailable() { + mockkStatic(Device::class, SdkExtensions::class, AdServicesState::class) { + // given + val topicsManager: TopicsManager = mockk() + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 34 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { AdServicesState.isAdServicesStateEnabled() } returns true + val service = TopicsService(context, dispatchers, eventSender) + + // when + val result = service.checkAvailability() + + // then + assertEquals(TopicsStatus.TOPICS_AVAILABLE, result) + } + } + + @Test + fun getTopics_success_getTopics() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + val topicsManager: TopicsManager = mockk() + every { topicsManager.getTopics(any(), any(), any()) } returns Unit + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + val service = TopicsService(context, dispatchers, eventSender) + val topicsRequest: GetTopicsRequest = mockk() + val builder: GetTopicsRequest.Builder = mockk() + every { builder.setAdsSdkName(any()) } returns builder + every { builder.setShouldRecordObservation(any()) } returns builder + every { builder.build() } returns topicsRequest + mockkConstructor(GetTopicsRequest.Builder::class) + every { anyConstructed().setAdsSdkName("UnityAds") } returns mockk { + every { setShouldRecordObservation(false) } returns mockk { + every { build() } returns topicsRequest + } + } + + // when + service.getTopics("UnityAds", false) + + // then + verify { topicsManager.getTopics(topicsRequest, any(), any()) } + } + } + + @Test + fun getTopics_failure_sendEvent() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + val topicsManager: TopicsManager = mockk() + every { topicsManager.getTopics(any(), any(), any()) } throws Exception("test error") + every { context.getSystemService(TopicsManager::class.java) } returns topicsManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { + eventSender.sendEvent( + WebViewEventCategory.TOPICS, + TopicsEvents.NOT_AVAILABLE, + TopicsErrors.ERROR_EXCEPTION, + any() + ) + } returns true + val service = TopicsService(context, dispatchers, eventSender) + val topicsRequest: GetTopicsRequest = mockk() + val builder: GetTopicsRequest.Builder = mockk() + every { builder.setAdsSdkName(any()) } returns builder + every { builder.setShouldRecordObservation(any()) } returns builder + every { builder.build() } returns topicsRequest + mockkConstructor(GetTopicsRequest.Builder::class) + every { anyConstructed().setAdsSdkName("UnityAds") } returns mockk { + every { setShouldRecordObservation(false) } returns mockk { + every { build() } returns topicsRequest + } + } + + // when + service.getTopics("UnityAds", false) + + // then + verify { + eventSender.sendEvent( + WebViewEventCategory.TOPICS, + TopicsEvents.NOT_AVAILABLE, + TopicsErrors.ERROR_EXCEPTION, + any() + ) + } + } + } +} diff --git a/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentObjectsTest.java b/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentObjectsTest.java index 81a0e9d..b22a37b 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentObjectsTest.java +++ b/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentObjectsTest.java @@ -32,21 +32,12 @@ public class ExperimentObjectsTest { Assert.assertFalse(expo.isNativeWebViewCacheEnabled()); } - @Test - public void testExperimentObjectsWithString() throws JSONException { - IExperiments expo = new ExperimentObjects(new JSONObject("{\"tsi_prw\": {\"value\": \"true\"}," - + "\"scar_bm\": {\"value\": \"eag\"}}")); - Assert.assertEquals("eag", expo.getScarBiddingManager()); - Assert.assertTrue(expo.shouldNativeTokenAwaitPrivacy()); - Assert.assertFalse(expo.isNativeWebViewCacheEnabled()); - } - @Test public void testExperimentObjectsCurrentSession() throws JSONException { IExperiments expo = new ExperimentObjects(new JSONObject("{\"tsi_prw\": {\"value\": \"true\", \"applied\": \"next\"}," + "\"scar_init\": {\"value\": true, \"applied\": \"next\"}," + "\"nilt\": {\"value\": false, \"applied\": \"next\"}," - + "\"scar_bm\": {\"value\": \"eag\", \"applied\": \"next\"}," + + "\"scar_bn\": {\"value\": true, \"applied\": \"next\"}," + "\"wac\": {\"value\": \"true\", \"applied\": \"immediate\"}}")); Assert.assertFalse(expo.getCurrentSessionExperiments().has("tsi_prw")); Assert.assertTrue(expo.getCurrentSessionExperiments().has("wac")); @@ -60,15 +51,15 @@ public class ExperimentObjectsTest { IExperiments expo = new ExperimentObjects(new JSONObject("{\"tsi_prw\": {\"value\": \"true\", \"applied\": \"next\"}," + "\"scar_init\": {\"value\": true, \"applied\": \"next\"}," + "\"nilt\": {\"value\": false, \"applied\": \"next\"}," - + "\"scar_bm\": {\"value\": \"eag\", \"applied\": \"next\"}," + + "\"scar_bn\": {\"value\": true, \"applied\": \"next\"}," + "\"wac\": {\"value\": \"true\", \"applied\": \"immediate\"}}")); Assert.assertTrue(expo.getNextSessionExperiments().has("tsi_prw")); Assert.assertFalse(expo.getNextSessionExperiments().has("wac")); - JSONObject expectedOut = new JSONObject("{\"nilt\":\"false\",\"scar_bm\":\"eag\",\"tsi_prw\":\"true\",\"scar_init\":\"true\"}"); + JSONObject expectedOut = new JSONObject("{\"nilt\":\"false\",\"scar_bn\":\"true\",\"tsi_prw\":\"true\",\"scar_init\":\"true\"}"); Assert.assertEquals(expectedOut.length(), expo.getNextSessionExperiments().length()); Assert.assertEquals(expectedOut.get("nilt"), expo.getNextSessionExperiments().get("nilt")); - Assert.assertEquals(expectedOut.get("scar_bm"), expo.getNextSessionExperiments().get("scar_bm")); + Assert.assertEquals(expectedOut.get("scar_bn"), expo.getNextSessionExperiments().get("scar_bn")); Assert.assertEquals(expectedOut.get("tsi_prw"), expo.getNextSessionExperiments().get("tsi_prw")); Assert.assertEquals(expectedOut.get("scar_init"), expo.getNextSessionExperiments().get("scar_init")); } @@ -79,13 +70,13 @@ public class ExperimentObjectsTest { IExperiments expo = new ExperimentObjects(new JSONObject("{\"tsi_prw\": {\"value\": \"true\", \"applied\": \"next\"}," + "\"scar_init\": {\"value\": true, \"applied\": \"next\"}," + "\"nilt\": {\"value\": false, \"applied\": \"next\"}," - + "\"scar_bm\": {\"value\": \"eag\", \"applied\": \"next\"}," + + "\"scar_bn\": {\"value\": true, \"applied\": \"next\"}," + "\"wac\": {\"value\": \"true\", \"applied\": \"immediate\"}}")); Map expectedOut = new HashMap<>(); expectedOut.put("tsi_prw", "true"); expectedOut.put("wac", "true"); expectedOut.put("scar_init", "true"); - expectedOut.put("scar_bm", "eag"); + expectedOut.put("scar_bn", "true"); expectedOut.put("nilt", "false"); Assert.assertEquals(expectedOut.entrySet(), expo.getExperimentTags().entrySet()); } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentsTest.java b/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentsTest.java index d3d3d8e..edc06c9 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentsTest.java +++ b/unity-ads/src/test/java/com/unity3d/services/core/configuration/ExperimentsTest.java @@ -12,11 +12,9 @@ public class ExperimentsTest { private static final String TSI_TAG_NATIVE_WEBVIEW_CACHE = "nwc"; private static final String TSI_TAG_WEB_AD_ASSET_CACHING = "wac"; private static final String EXP_TAG_SCAR_INIT = "scar_init"; - - private static final String EXP_TAG_SCAR_BIDDING_MANAGER = "scar_bm"; - private static final String EXP_TAG_JETPACK_LIFECYCLE = "gjl"; private static final String EXP_TAG_WEBVIEW_ASYNC_DOWNLOAD = "wad"; + private static final String EXP_TAG_SCAR_HB_BN = "scar_bn"; @Test public void testExperimentsWithData() throws JSONException { @@ -25,16 +23,16 @@ public class ExperimentsTest { jsonObject.put(TSI_TAG_NATIVE_WEBVIEW_CACHE, true); jsonObject.put(TSI_TAG_WEB_AD_ASSET_CACHING, true); jsonObject.put(EXP_TAG_SCAR_INIT, true); - jsonObject.put(EXP_TAG_SCAR_BIDDING_MANAGER, "laz"); jsonObject.put(EXP_TAG_JETPACK_LIFECYCLE, true); jsonObject.put(EXP_TAG_WEBVIEW_ASYNC_DOWNLOAD, true); + jsonObject.put(EXP_TAG_SCAR_HB_BN, true); Experiments experiments = new Experiments(jsonObject); Assert.assertTrue(experiments.shouldNativeTokenAwaitPrivacy()); Assert.assertTrue(experiments.isNativeWebViewCacheEnabled()); Assert.assertTrue(experiments.isWebAssetAdCaching()); Assert.assertTrue(experiments.isScarInitEnabled()); - Assert.assertEquals("laz", experiments.getScarBiddingManager()); Assert.assertTrue(experiments.isWebViewAsyncDownloadEnabled()); + Assert.assertTrue(experiments.isScarBannerHbEnabled()); } @Test @@ -100,9 +98,9 @@ public class ExperimentsTest { Assert.assertFalse(experiments.isNativeWebViewCacheEnabled()); Assert.assertFalse(experiments.isWebAssetAdCaching()); Assert.assertFalse(experiments.isScarInitEnabled()); - Assert.assertEquals("dis", experiments.getScarBiddingManager()); Assert.assertFalse(experiments.isJetpackLifecycle()); Assert.assertFalse(experiments.isWebViewAsyncDownloadEnabled()); + Assert.assertFalse(experiments.isScarBannerHbEnabled()); } } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorageTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorageTest.kt index 0fdde8d..9d77d17 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorageTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/ConfigFileFromLocalStorageTest.kt @@ -42,8 +42,7 @@ class ConfigFileFromLocalStorageTest { every { SdkProperties.getLocalConfigurationFilepath() } returns null // when - val stateLoadConfigFileResult = - runCatching { configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) } + val stateLoadConfigFileResult = configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) // then assertTrue(stateLoadConfigFileResult.isFailure) @@ -57,8 +56,7 @@ class ConfigFileFromLocalStorageTest { every { SdkProperties.getLocalConfigurationFilepath() } returns "" // when - val stateLoadConfigFileResult = - runCatching { configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) } + val stateLoadConfigFileResult = configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) // then assertTrue(stateLoadConfigFileResult.isFailure) @@ -75,8 +73,7 @@ class ConfigFileFromLocalStorageTest { every { SdkProperties.getLocalConfigurationFilepath() } returns temporaryFile.absolutePath // when - val stateLoadConfigFileResult = - runCatching { configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) } + val stateLoadConfigFileResult = configFileFromLocalStorage(ConfigFileFromLocalStorage.Params()) // then assertTrue(stateLoadConfigFileResult.isSuccess) diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeSDKTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeSDKTest.kt index a557c8d..cf294c1 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeSDKTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeSDKTest.kt @@ -8,7 +8,6 @@ import com.unity3d.utils.corountine.coroutineNameIsUsed import io.mockk.* import io.mockk.impl.annotations.InjectMockKs import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.resetMain @@ -17,10 +16,8 @@ import kotlinx.coroutines.test.setMain import kotlinx.coroutines.withContext import org.junit.After import org.junit.Before +import org.junit.Ignore import org.junit.Test -import kotlin.coroutines.Continuation -import kotlin.coroutines.ContinuationInterceptor -import kotlin.coroutines.CoroutineContext import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -64,7 +61,7 @@ class InitializeSDKTest { @Before fun setUp() { - MockKAnnotations.init(this) + MockKAnnotations.init(this, relaxed = true) every { configMock.experiments.isNativeWebViewCacheEnabled } returns false every { configMock.experiments.isWebViewAsyncDownloadEnabled } returns false Dispatchers.setMain(dispatchers.main) @@ -79,7 +76,7 @@ class InitializeSDKTest { @Test fun doWork_everyStateSuccess_initCompleteCalledReturnSuccess() = runTest { // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isSuccess) @@ -91,10 +88,10 @@ class InitializeSDKTest { @Test fun doWork_failOnlyOnLoadConfigFile_returnSuccess() = runTest { // given - coEvery { configFileFromLocalStorage(any()) } throws Exception() + coEvery { configFileFromLocalStorage.doWork(any()) } returns Result.failure(Exception()) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isSuccess) @@ -107,14 +104,14 @@ class InitializeSDKTest { fun doWork_failOnlyStateReset_returnFailure() = runTest { //given val exception = Exception("Reset failed on opening ConditionVariable") - coEvery { initializeStateReset(any()) } throws exception + coEvery { initializeStateReset.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) - assertEquals(exception, result.exceptionOrNull()?.cause) + assertEquals(exception, result.exceptionOrNull()) coVerify(exactly = 1) { initializeStateReset.doWork(any()) } coVerify(exactly = 1) { initializeStateError.doWork(any()) } coVerify(exactly = 0) { initializeStateComplete.doWork(any()) } @@ -128,10 +125,10 @@ class InitializeSDKTest { Exception("No connected events within the timeout!"), configMock ) - coEvery { initializeStateConfig(any()) } throws exception + coEvery { initializeStateConfig.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) @@ -146,10 +143,10 @@ class InitializeSDKTest { //given every { configMock.experiments.isNativeWebViewCacheEnabled } returns true val exception = InitializationException(ErrorState.CreateWebApp, Exception(), configMock) - coEvery { initializeStateCreateWithRemote(any()) } throws exception + coEvery { initializeStateCreateWithRemote.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) @@ -163,14 +160,14 @@ class InitializeSDKTest { fun doWork_failOnlyLoadCacheWithNativeWebViewCacheFalse_returnFailure() = runTest { //given val exception = Exception(ErrorState.LoadCache.toString()) - coEvery { initializeStateLoadCache(any()) } throws exception + coEvery { initializeStateLoadCache.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) - assertEquals(exception, result.exceptionOrNull()?.cause) + assertEquals(exception, result.exceptionOrNull()) coVerify(exactly = 1) { initializeStateLoadCache.doWork(any()) } coVerify(exactly = 1) { initializeStateError.doWork(any()) } coVerify(exactly = 0) { initializeStateComplete.doWork(any()) } @@ -183,13 +180,13 @@ class InitializeSDKTest { mockkConstructor(Configuration::class) every { configMock.experiments.isWebViewAsyncDownloadEnabled } returns true every { anyConstructed().experiments.isNativeWebViewCacheEnabled } returns false - coEvery { initializeStateLoadCache.doWork(any()) } returns InitializeStateLoadCache.LoadCacheResult( + coEvery { initializeStateLoadCache.doWork(any()) } returns Result.success(InitializeStateLoadCache.LoadCacheResult( true, null - ) + )) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isSuccess) @@ -205,11 +202,11 @@ class InitializeSDKTest { fun doWork_loadCacheReturnNullAndLoadWebFailsWithNativeWebViewCacheFalse_returnFailure() = runTest { //given val webException = InitializationException(ErrorState.InvalidHash, Exception("Invalid webViewHash"), configMock) - coEvery { initializeStateLoadCache.doWork(any()) } returns InitializeStateLoadCache.LoadCacheResult(true, null) - coEvery { initializeStateLoadWeb.doWork(any()) } throws webException + coEvery { initializeStateLoadCache.doWork(any()) } returns Result.success(InitializeStateLoadCache.LoadCacheResult(true, null)) + coEvery { initializeStateLoadWeb.doWork(any()) } returns Result.failure(webException) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) @@ -228,13 +225,13 @@ class InitializeSDKTest { mockkConstructor(Configuration::class) every { anyConstructed().experiments.isNativeWebViewCacheEnabled } returns false every { configMock.experiments.isWebViewAsyncDownloadEnabled } returns true - coEvery { initializeStateLoadCache.doWork(any()) } returns InitializeStateLoadCache.LoadCacheResult( + coEvery { initializeStateLoadCache.doWork(any()) } returns Result.success(InitializeStateLoadCache.LoadCacheResult( true, "WebView HTML Data" - ) + )) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isSuccess) @@ -251,14 +248,13 @@ class InitializeSDKTest { fun doWork_initializeStateCreateFailsAndLoadWebWithNativeWebViewCacheFalse_returnFailure() = runTest { //given val exception = InitializationException(ErrorState.CreateWebApp, Exception(), configMock) - coEvery { initializeStateCreate(any()) } throws exception + coEvery { initializeStateCreate.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) - assertEquals(exception, result.exceptionOrNull()) coVerify(exactly = 1) { initializeStateError.doWork(any()) } coVerify(exactly = 0) { initializeStateComplete.doWork(any()) } } @@ -267,14 +263,14 @@ class InitializeSDKTest { fun doWork_initializeStateCompleteFailsAndLoadWebWithNativeWebViewCacheFalse_returnFailure() = runTest { //given val exception = Exception() - coEvery { initializeStateComplete(any()) } throws exception + coEvery { initializeStateComplete.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) - assertEquals(exception, result.exceptionOrNull()?.cause) + assertEquals(exception, result.exceptionOrNull()) coVerify(exactly = 0) { initializeStateError.doWork(any()) } coVerify(exactly = 1) { initializeStateComplete.doWork(any()) } } @@ -283,36 +279,36 @@ class InitializeSDKTest { fun doWork_initializeStateCompleteFailsAndLoadWebWithNativeWebViewCacheTrue_returnFailure() = runTest { //given val exception = Exception() - coEvery { initializeStateComplete(any()) } throws exception + coEvery { initializeStateComplete.doWork(any()) } returns Result.failure(exception) // when - val result = runCatching { initializeSDK(EmptyParams) } + val result = initializeSDK(EmptyParams) // then assertTrue(result.isFailure) - assertEquals(exception, result.exceptionOrNull()?.cause) + assertEquals(exception, result.exceptionOrNull()) coVerify(exactly = 0) { initializeStateError.doWork(any()) } coVerify(exactly = 1) { initializeStateComplete.doWork(any()) } } private fun defaultSuccessMocks() { - coEvery { configFileFromLocalStorage.doWork(any()) } returns configMock + coEvery { configFileFromLocalStorage.doWork(any()) } returns Result.success(configMock) coEvery { configFileFromLocalStorage.getMetricName() } returns "loadConfigFile" - coEvery { initializeStateReset.doWork(any()) } returns configMock + coEvery { initializeStateReset.doWork(any()) } returns Result.success(configMock) coEvery { initializeStateReset.getMetricName() } returns "reset" - coEvery { initializeStateError.doWork(any()) } returns Unit + coEvery { initializeStateError.doWork(any()) } returns Result.success(Unit) coEvery { initializeStateError.getMetricName() } returns "error" - coEvery { initializeStateConfig.doWork(any()) } returns configMock + coEvery { initializeStateConfig.doWork(any()) } returns Result.success(configMock) coEvery { initializeStateConfig.getMetricName() } returns "config" - coEvery { initializeStateCreate.doWork(any()) } returns configMock + coEvery { initializeStateCreate.doWork(any()) } returns Result.success(configMock) coEvery { initializeStateCreate.getMetricName() } returns "create" - coEvery { initializeStateLoadCache.doWork(any()) } returns InitializeStateLoadCache.LoadCacheResult(false, "") + coEvery { initializeStateLoadCache.doWork(any()) } returns Result.success(InitializeStateLoadCache.LoadCacheResult(false, "")) coEvery { initializeStateLoadCache.getMetricName() } returns "loadCache" - coEvery { initializeStateCreateWithRemote.doWork(any()) } returns configMock + coEvery { initializeStateCreateWithRemote.doWork(any()) } returns Result.success(configMock) coEvery { initializeStateCreateWithRemote.getMetricName() } returns "createWithRemote" - coEvery { initializeStateLoadWeb.doWork(any()) } returns InitializeStateLoadWeb.LoadWebResult(configMock, "") + coEvery { initializeStateLoadWeb.doWork(any()) } returns Result.success(InitializeStateLoadWeb.LoadWebResult(configMock, "")) coEvery { initializeStateLoadWeb.getMetricName() } returns "loadWeb" - coEvery { initializeStateComplete.doWork(any()) } returns Unit + coEvery { initializeStateComplete.doWork(any()) } returns Result.success(Unit) coEvery { initializeStateComplete.getMetricName() } returns "complete" } } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigTest.kt index d80b9e7..328422f 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigTest.kt @@ -42,7 +42,7 @@ class InitializeStateConfigTest { every { configMock.experiments } returns experimentsMock every { configMock.experimentsReader } returns experimentsReaderMock every { experimentsReaderMock.currentlyActiveExperiments } returns experimentsMock - coEvery { initializeStateConfigWithLoaderMock(any()) } returns configMock + coEvery { initializeStateConfigWithLoaderMock(any()) } returns Result.success(configMock) Dispatchers.setMain(dispatchers.main) } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoaderTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoaderTest.kt index 0cf74a3..1cdba67 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoaderTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateConfigWithLoaderTest.kt @@ -63,11 +63,7 @@ class InitializeStateConfigWithLoaderTest { every { tokenStorage.setInitToken(any()) } returns Unit // when - val configWithLoaderResult = runCatching { - initializeStateConfigWithLoader( - InitializeStateConfigWithLoader.Params(configMock) - ) - } + val configWithLoaderResult = initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configMock)) // then Assert.assertTrue(configWithLoaderResult.isSuccess) @@ -87,11 +83,7 @@ class InitializeStateConfigWithLoaderTest { every { configMock.maxRetries } returns 5 // when - val configWithLoaderResult = runCatching { - initializeStateConfigWithLoader( - InitializeStateConfigWithLoader.Params(configMock) - ) - } + val configWithLoaderResult = initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configMock)) // then Assert.assertTrue(configWithLoaderResult.isFailure) @@ -112,11 +104,7 @@ class InitializeStateConfigWithLoaderTest { every { configMock.maxRetries } returns 5 // when - val configWithLoaderResult = runCatching { - initializeStateConfigWithLoader( - InitializeStateConfigWithLoader.Params(configMock) - ) - } + val configWithLoaderResult = initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configMock)) // then Assert.assertTrue(configWithLoaderResult.isFailure) @@ -136,11 +124,7 @@ class InitializeStateConfigWithLoaderTest { every { configMock.maxRetries } returns 5 // when - val configWithLoaderResult = runCatching { - initializeStateConfigWithLoader( - InitializeStateConfigWithLoader.Params(configMock) - ) - } + val configWithLoaderResult = initializeStateConfigWithLoader(InitializeStateConfigWithLoader.Params(configMock)) // then Assert.assertTrue(configWithLoaderResult.isFailure) diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateTest.kt index cb2321a..2659bf0 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateTest.kt @@ -61,7 +61,7 @@ class InitializeStateCreateTest { every { WebViewApp.create(config, false) } returns null // when - val result = runCatching { initializeSateCreate(InitializeStateCreate.Params(config, webViewData)) } + val result = initializeSateCreate(InitializeStateCreate.Params(config, webViewData)) // then assertTrue(result.isSuccess) @@ -78,7 +78,7 @@ class InitializeStateCreateTest { every { WebViewApp.create(configMock, false) } returns null // when - val result = runCatching { initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) } + val result = initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) // then assertTrue(result.isSuccess) @@ -98,7 +98,7 @@ class InitializeStateCreateTest { every { WebViewApp.create(any(), false) } returns ErrorState.CreateWebview // when - val result = runCatching { initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) } + val result = initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) // then assertTrue(result.isFailure) @@ -124,7 +124,7 @@ class InitializeStateCreateTest { every { WebViewApp.create(any(), false) } returns ErrorState.CreateWebview // when - val result = runCatching { initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) } + val result = initializeSateCreate(InitializeStateCreate.Params(configMock, webViewData)) // then assertTrue(result.isFailure) diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemoteTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemoteTest.kt index 74115b2..60455c5 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemoteTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateCreateWithRemoteTest.kt @@ -51,8 +51,7 @@ class InitializeStateCreateWithRemoteTest { every { WebViewApp.create(any(), true) } returns null // when - val result = - runCatching { initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) } + val result = initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) // then assertTrue(result.isSuccess) @@ -72,8 +71,7 @@ class InitializeStateCreateWithRemoteTest { every { WebViewApp.create(any(), true) } returns ErrorState.CreateWebview // when - val result = - runCatching { initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) } + val result = initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) // then assertTrue(result.isFailure) @@ -99,8 +97,7 @@ class InitializeStateCreateWithRemoteTest { every { WebViewApp.create(any(), true) } returns ErrorState.CreateWebview // when - val result = - runCatching { initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) } + val result = initializeSateCreateWithRemote(InitializeStateCreateWithRemote.Params(configMock)) // then assertTrue(result.isFailure) diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadCacheTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadCacheTest.kt index 0a90eef..87f848c 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadCacheTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadCacheTest.kt @@ -49,8 +49,7 @@ class InitializeStateLoadCacheTest { every { SdkProperties.getLocalWebViewFile() } returns null // when - val stateLoadConfigFileResult = - runCatching { initializeStateLoadCache(InitializeStateLoadCache.Params(Configuration())) } + val stateLoadConfigFileResult = initializeStateLoadCache(InitializeStateLoadCache.Params(Configuration())) // then assertTrue(stateLoadConfigFileResult.isSuccess) @@ -68,8 +67,7 @@ class InitializeStateLoadCacheTest { every { configMock.webViewHash } returns "testHash" // when - val stateLoadConfigFileResult = - runCatching { initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) } + val stateLoadConfigFileResult = initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) // then assertTrue(stateLoadConfigFileResult.isSuccess) @@ -89,8 +87,7 @@ class InitializeStateLoadCacheTest { every { configMock.webViewHash } returns "testHash" // when - val stateLoadConfigFileResult = - runCatching { initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) } + val stateLoadConfigFileResult = initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) // then assertTrue(stateLoadConfigFileResult.isSuccess) @@ -109,8 +106,7 @@ class InitializeStateLoadCacheTest { every { configMock.webViewHash } returns "ba477a0ac57e10dd90bb5bf0289c5990fe839c619b26fde7c2aac62f526d4113" // when - val stateLoadConfigFileResult = - runCatching { initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) } + val stateLoadConfigFileResult = initializeStateLoadCache(InitializeStateLoadCache.Params(configMock)) // then assertTrue(stateLoadConfigFileResult.isSuccess) diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadWebTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadWebTest.kt index 301f94b..8add608 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadWebTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateLoadWebTest.kt @@ -62,11 +62,7 @@ class InitializeStateLoadWebTest { coEvery { httpClient.execute(any()) } returns HttpResponse(body = TESTDATA) // when - val loadWebResult = runCatching { - initializeStateLoadWeb( - InitializeStateLoadWeb.Params(configMock) - ) - } + val loadWebResult = initializeStateLoadWeb(InitializeStateLoadWeb.Params(configMock)) // then Assert.assertTrue(loadWebResult.isSuccess) @@ -84,11 +80,7 @@ class InitializeStateLoadWebTest { coEvery { httpClient.execute(any()) } returns HttpResponse(body = TESTDATA) // when - val loadWebResult = runCatching { - initializeStateLoadWeb( - InitializeStateLoadWeb.Params(configMock) - ) - } + val loadWebResult = initializeStateLoadWeb(InitializeStateLoadWeb.Params(configMock)) // then Assert.assertTrue(loadWebResult.isFailure) @@ -110,11 +102,7 @@ class InitializeStateLoadWebTest { coEvery { initializeStateNetworkError.doWork(any()) } throws Exception("Network Error") // when - val loadWebResult = runCatching { - initializeStateLoadWeb( - InitializeStateLoadWeb.Params(configMock) - ) - } + val loadWebResult = initializeStateLoadWeb(InitializeStateLoadWeb.Params(configMock)) // then Assert.assertTrue(loadWebResult.isFailure) @@ -135,14 +123,10 @@ class InitializeStateLoadWebTest { every { SdkProperties.getLocalWebViewFile() } returns "" coEvery { httpClient.execute(any()) } throws Exception() every { configMock.webViewHash } returns TESTHASH - coEvery { initializeStateNetworkError.doWork(any()) } returns Unit + coEvery { initializeStateNetworkError.doWork(any()) } returns Result.success(Unit) // when - val loadWebResult = runCatching { - initializeStateLoadWeb( - InitializeStateLoadWeb.Params(configMock) - ) - } + val loadWebResult = initializeStateLoadWeb(InitializeStateLoadWeb.Params(configMock)) // then Assert.assertTrue(loadWebResult.isFailure) // Failure still cause can't mock second request being success. diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateNetworkErrorTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateNetworkErrorTest.kt index 5ffe310..765cd75 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateNetworkErrorTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateNetworkErrorTest.kt @@ -76,7 +76,7 @@ class InitializeStateNetworkErrorTest { advanceTimeBy(300) } // when - val result = runCatching { initializeStateNetworkError(InitializeStateNetworkError.Params(configMock)) } + val result = initializeStateNetworkError(InitializeStateNetworkError.Params(configMock)) // then verify(exactly = 1) { ConnectivityMonitor.removeListener(any()) } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateResetTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateResetTest.kt index 16f2659..c140542 100644 --- a/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateResetTest.kt +++ b/unity-ads/src/test/java/com/unity3d/services/core/domain/task/InitializeStateResetTest.kt @@ -88,7 +88,7 @@ class InitializeStateResetTest { advanceTimeBy(300) } // when - val result = runCatching { initializeStateReset(InitializeStateReset.Params(configMock)) } + val result = initializeStateReset(InitializeStateReset.Params(configMock)) // then verify(exactly = 1) { webViewAppMock.resetWebViewAppInitialization() } diff --git a/unity-ads/src/test/java/com/unity3d/services/core/measurements/MeasurementsServiceTest.kt b/unity-ads/src/test/java/com/unity3d/services/core/measurements/MeasurementsServiceTest.kt new file mode 100644 index 0000000..aa947fb --- /dev/null +++ b/unity-ads/src/test/java/com/unity3d/services/core/measurements/MeasurementsServiceTest.kt @@ -0,0 +1,235 @@ +package com.unity3d.services.core.measurements + +import android.adservices.AdServicesState +import android.adservices.measurement.MeasurementManager +import android.content.Context +import android.net.Uri +import android.os.OutcomeReceiver +import android.os.ext.SdkExtensions +import android.view.InputEvent +import com.unity3d.services.ads.measurements.MeasurementsErrors +import com.unity3d.services.ads.measurements.MeasurementsEvents +import com.unity3d.services.ads.measurements.MeasurementsService +import com.unity3d.services.core.device.Device +import com.unity3d.services.core.domain.ISDKDispatchers +import com.unity3d.services.core.domain.task.TestSDKDispatchers +import com.unity3d.services.core.properties.ClientProperties +import com.unity3d.services.core.webview.WebViewEventCategory +import com.unity3d.services.core.webview.bridge.IEventSender +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.verify +import org.junit.Before +import org.junit.Test + +class MeasurementsServiceTest { + @MockK + private lateinit var mockContext: Context + @MockK + private lateinit var mockEventSender: IEventSender + @MockK + private lateinit var mockMeasurementManager: MeasurementManager + @MockK + private lateinit var mockInputEvent: InputEvent + + private val dispatchers: ISDKDispatchers = TestSDKDispatchers() + + private lateinit var measurementsService: MeasurementsService + + @Before + fun setUp() { + MockKAnnotations.init(this, relaxed = true) + mockkStatic(ClientProperties::class) + every { ClientProperties.getApplicationContext() } returns mockContext + + mockkStatic(Uri::class) + every { Uri.parse(any()) } returns mockk() + } + + @Test + fun checkAvailability_measurementsManager_isNull() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { mockContext.getSystemService(MeasurementManager::class.java) } returns null + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + // when + measurementsService.checkAvailability() + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.NOT_AVAILABLE, + MeasurementsErrors.ERROR_MANAGER_NULL + ) + } + } + } + + @Test + fun checkAvailability_api_below33() { + mockkStatic(Device::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 32 + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + // when + measurementsService.checkAvailability() + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.NOT_AVAILABLE, + MeasurementsErrors.ERROR_API_BELOW_33 + ) + } + } + } + + @Test + fun checkAvailability_sdkExtension_below4() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 3 + + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + // when + measurementsService.checkAvailability() + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.NOT_AVAILABLE, + MeasurementsErrors.ERROR_EXTENSION_BELOW_4 + ) + } + } + } + + @Test + fun checkAvailability_adServices_disabled() { + mockkStatic(Device::class, SdkExtensions::class, AdServicesState::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { AdServicesState.isAdServicesStateEnabled() } returns false + + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + // when + measurementsService.checkAvailability() + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.NOT_AVAILABLE, + MeasurementsErrors.ERROR_AD_SERVICES_DISABLED + ) + } + } + } + + @Test + fun checkAvailability_success() { + mockkStatic(Device::class, SdkExtensions::class, AdServicesState::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + every { AdServicesState.isAdServicesStateEnabled() } returns true + + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + every { mockMeasurementManager.getMeasurementApiStatus(any(), any()) } answers { + val callback = secondArg>() + callback.onResult(200) + } + + // when + measurementsService.checkAvailability() + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.AVAILABLE, + 200 + ) + } + } + } + + @Test + fun registerView_callsInvokeCallback() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + every { mockMeasurementManager.registerSource(any(), any(), any(), any()) } answers { + val callback = lastArg>() + callback.onResult(200) + } + + every { Uri.parse(any()) } returns mockk() + + // when + measurementsService.registerView("https://example.com") + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.VIEW_SUCCESSFUL + ) + } + } + } + + @Test + fun registerClick_callsInvokeCallback() { + mockkStatic(Device::class, SdkExtensions::class) { + // given + every { mockContext.getSystemService(MeasurementManager::class.java) } returns mockMeasurementManager + every { Device.getApiLevel() } returns 33 + every { SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) } returns 4 + + measurementsService = MeasurementsService(mockContext, dispatchers, mockEventSender) + + every { mockMeasurementManager.registerSource(any(), any(), any(), any()) } answers { + val callback = lastArg>() + callback.onResult(200) + } + + every { Uri.parse(any()) } returns mockk() + + // when + measurementsService.registerClick("https://example.com", mockInputEvent) + + // then + verify { + mockEventSender.sendEvent( + WebViewEventCategory.MEASUREMENTS, + MeasurementsEvents.CLICK_SUCCESSFUL + ) + } + } + } +} \ No newline at end of file diff --git a/unity-scaradapter-1920/.gitignore b/unity-scaradapter-1920/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/unity-scaradapter-1920/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/unity-scaradapter-1920/build.gradle b/unity-scaradapter-1920/build.gradle deleted file mode 100644 index 27d1b6b..0000000 --- a/unity-scaradapter-1920/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -plugins { - id 'com.android.library' -} - -android { - compileSdkVersion 30 - - defaultConfig { - minSdkVersion 16 - targetSdkVersion 30 - multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles "consumer-rules.pro" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - minifyEnabled false - testCoverageEnabled true - } - } -} - -dependencies { - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation "org.mockito:mockito-android:2.25.0" - androidTestImplementation 'com.google.android.gms:play-services-ads:19.2.0' - testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:2.28.2' - testImplementation 'com.google.android.gms:play-services-ads:19.2.0' - api project(':unity-scaradapter-common') - compileOnly 'com.google.android.gms:play-services-ads:19.2.0' -} - -apply from: '../fatAar.gradle' diff --git a/unity-scaradapter-1920/consumer-rules.pro b/unity-scaradapter-1920/consumer-rules.pro deleted file mode 100644 index e69de29..0000000 diff --git a/unity-scaradapter-1920/proguard-rules.pro b/unity-scaradapter-1920/proguard-rules.pro deleted file mode 100644 index 481bb43..0000000 --- a/unity-scaradapter-1920/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/unity-scaradapter-1920/src/androidTest/AndroidManifest.xml b/unity-scaradapter-1920/src/androidTest/AndroidManifest.xml deleted file mode 100644 index af6b39b..0000000 --- a/unity-scaradapter-1920/src/androidTest/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ -> - - - - \ No newline at end of file diff --git a/unity-scaradapter-1920/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java b/unity-scaradapter-1920/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java deleted file mode 100644 index 8fb363a..0000000 --- a/unity-scaradapter-1920/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.unity3d.ads.test; - -import com.unity3d.scar.adapter.v1920.signals.SignalsCollectorTest; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ - SignalsCollectorTest.class -}) -public class InstrumentationTestSuite { -} diff --git a/unity-scaradapter-1920/src/androidTest/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollectorTest.java b/unity-scaradapter-1920/src/androidTest/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollectorTest.java deleted file mode 100644 index 8f5d9a8..0000000 --- a/unity-scaradapter-1920/src/androidTest/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollectorTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.unity3d.scar.adapter.v1920.signals; - -import android.content.Context; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.mockito.Matchers.any; - -@RunWith(MockitoJUnitRunner.class) -public class SignalsCollectorTest { - private Context context = InstrumentationRegistry.getInstrumentation().getContext(); - private ISignalCollectionListener _signalCollectionListener; - - @Before - public void before() { - _signalCollectionListener = Mockito.mock(ISignalCollectionListener.class); - } - - @Test - public void testGetScarSignals() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - - @Test - public void testGetScarSignalsNoRewarded() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - - @Test - public void testGetScarSignalsNoInterstitial() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - -} diff --git a/unity-scaradapter-1920/src/main/AndroidManifest.xml b/unity-scaradapter-1920/src/main/AndroidManifest.xml deleted file mode 100644 index 25f7030..0000000 --- a/unity-scaradapter-1920/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/ScarAdapter.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/ScarAdapter.java deleted file mode 100644 index f60bcf6..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/ScarAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.unity3d.scar.adapter.v1920; - -import android.content.Context; - -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarAdapter; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.ScarAdapterBase; -import com.unity3d.scar.adapter.common.WebViewAdsError; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; -import com.unity3d.scar.adapter.v1920.scarads.ScarInterstitialAd; -import com.unity3d.scar.adapter.v1920.scarads.ScarRewardedAd; -import com.unity3d.scar.adapter.v1920.signals.SignalsCollector; - -import static com.unity3d.scar.adapter.common.Utils.runOnUiThread; - -public class ScarAdapter extends ScarAdapterBase implements IScarAdapter { - - private SignalsStorage _signalsStorage; - - public ScarAdapter(IAdsErrorHandler adsErrorHandler) { - super(adsErrorHandler); - _signalsStorage = new SignalsStorage<>(); - _signalCollector = new SignalsCollector(_signalsStorage); - } - - public void loadInterstitialAd(Context context, final ScarAdMetadata scarAd, final IScarInterstitialAdListenerWrapper adListenerWrapper) { - final ScarInterstitialAd interstitialAd = new ScarInterstitialAd(context, _signalsStorage.getQueryInfo(scarAd.getPlacementId()), scarAd, _adsErrorHandler, adListenerWrapper); - runOnUiThread(new Runnable() { - @Override - public void run() { - interstitialAd.loadAd(new IScarLoadListener() { - @Override - public void onAdLoaded() { - _loadedAds.put(scarAd.getPlacementId(), interstitialAd); - } - }); - } - }); - } - - public void loadRewardedAd(Context context, final ScarAdMetadata scarAd, final IScarRewardedAdListenerWrapper adListenerWrapper) { - final ScarRewardedAd rewardedAd = new ScarRewardedAd(context, _signalsStorage.getQueryInfo(scarAd.getPlacementId()), scarAd, _adsErrorHandler, adListenerWrapper); - runOnUiThread(new Runnable() { - @Override - public void run() { - rewardedAd.loadAd(new IScarLoadListener() { - @Override - public void onAdLoaded() { - _loadedAds.put(scarAd.getPlacementId(), rewardedAd); - } - }); - } - }); - } - -} diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarAdBase.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarAdBase.java deleted file mode 100644 index 1f54527..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarAdBase.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.unity3d.scar.adapter.v1920.scarads; - -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.AdInfo; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.scarads.IScarAd; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public abstract class ScarAdBase implements IScarAd { - - protected Context _context; - protected ScarAdMetadata _scarAdMetadata; - protected QueryInfo _queryInfo; - protected IAdsErrorHandler _adsErrorHandler; - - public ScarAdBase(Context context, ScarAdMetadata scarAdMetadata, QueryInfo queryInfo, IAdsErrorHandler adsErrorHandler) { - _context = context; - _scarAdMetadata = scarAdMetadata; - _queryInfo = queryInfo; - _adsErrorHandler = adsErrorHandler; - } - - @Override - public void loadAd(IScarLoadListener loadListener) { - if (_queryInfo != null) { - AdInfo adInfo = new AdInfo(_queryInfo, _scarAdMetadata.getAdString()); - AdRequest adRequest = new AdRequest.Builder().setAdInfo(adInfo).build(); - loadAdInternal(loadListener, adRequest); - } else { - _adsErrorHandler.handleError(GMAAdsError.QueryNotFoundError(_scarAdMetadata)); - } - } - - protected abstract void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest); -} diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAd.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAd.java deleted file mode 100644 index f671efe..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAd.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.unity3d.scar.adapter.v1920.scarads; - -import android.app.Activity; -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.InterstitialAd; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public class ScarInterstitialAd extends ScarAdBase { - - private InterstitialAd _interstitialAd; - private ScarInterstitialAdListener _interstitialAdDelegate; - - public ScarInterstitialAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarInterstitialAdListenerWrapper adListener) { - super(context, scarAdMetadata, queryInfo, adsErrorHandler); - _interstitialAd = new InterstitialAd(_context); - _interstitialAd.setAdUnitId(_scarAdMetadata.getAdUnitId()); - _interstitialAdDelegate = new ScarInterstitialAdListener(_interstitialAd, adListener); - } - - @Override - public void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest) { - _interstitialAd.setAdListener(_interstitialAdDelegate.getAdListener()); - _interstitialAdDelegate.setLoadListener(loadListener); - _interstitialAd.loadAd(adRequest); - } - - @Override - public void show(Activity activity) { - if (_interstitialAd.isLoaded()) { - _interstitialAd.show(); - } else { - _adsErrorHandler.handleError(GMAAdsError.AdNotLoadedError(_scarAdMetadata)); - } - } -} diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAdListener.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAdListener.java deleted file mode 100644 index 568f4b3..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarInterstitialAdListener.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.unity3d.scar.adapter.v1920.scarads; - -import com.google.android.gms.ads.AdListener; -import com.google.android.gms.ads.InterstitialAd; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; - -public class ScarInterstitialAdListener { - - private InterstitialAd _interstitialAd; - private IScarInterstitialAdListenerWrapper _adListenerWrapper; - private IScarLoadListener _loadListener; - - public ScarInterstitialAdListener(InterstitialAd interstitialAd, IScarInterstitialAdListenerWrapper adListenerWrapper) { - _interstitialAd = interstitialAd; - _adListenerWrapper = adListenerWrapper; - } - - private AdListener _adListener = new AdListener() { - @Override - public void onAdLoaded() { - _adListenerWrapper.onAdLoaded(); - if (_loadListener != null) { - _loadListener.onAdLoaded(); - } - } - - @Override - public void onAdFailedToLoad(int adErrorCode) { - _adListenerWrapper.onAdFailedToLoad(adErrorCode, "SCAR ad failed to load"); - } - - @Override - public void onAdOpened() { - _adListenerWrapper.onAdOpened(); - } - - @Override - public void onAdClicked() { - _adListenerWrapper.onAdClicked(); - } - - @Override - public void onAdLeftApplication() { - _adListenerWrapper.onAdLeftApplication(); - } - - @Override - public void onAdClosed() { - _adListenerWrapper.onAdClosed(); - } - }; - - public AdListener getAdListener() { - return _adListener; - } - - public void setLoadListener(IScarLoadListener loadListener) { - _loadListener = loadListener; - } - -} diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAd.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAd.java deleted file mode 100644 index a61c6d2..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAd.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.unity3d.scar.adapter.v1920.scarads; - -import android.app.Activity; -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.QueryInfo; -import com.google.android.gms.ads.rewarded.RewardedAd; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public class ScarRewardedAd extends ScarAdBase { - - private RewardedAd _rewardedAd; - private ScarRewardedAdListener _rewardedAdDelegate; - - public ScarRewardedAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarRewardedAdListenerWrapper adListener) { - super(context, scarAdMetadata, queryInfo, adsErrorHandler); - _rewardedAd = new RewardedAd(_context, _scarAdMetadata.getAdUnitId()); - _rewardedAdDelegate = new ScarRewardedAdListener(_rewardedAd, adListener); - } - - @Override - public void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest) { - _rewardedAdDelegate.setLoadListener(loadListener); - _rewardedAd.loadAd(adRequest, _rewardedAdDelegate.getRewardedAdLoadCallback()); - } - - @Override - public void show(Activity activity) { - if (_rewardedAd.isLoaded()) { - _rewardedAd.show(activity, _rewardedAdDelegate.getRewardedAdCallback()); - } else { - _adsErrorHandler.handleError(GMAAdsError.AdNotLoadedError(_scarAdMetadata)); - } - } - -} \ No newline at end of file diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAdListener.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAdListener.java deleted file mode 100644 index ae013fc..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/scarads/ScarRewardedAdListener.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.unity3d.scar.adapter.v1920.scarads; - -import com.google.android.gms.ads.rewarded.RewardedAd; - -import com.google.android.gms.ads.rewarded.RewardItem; -import com.google.android.gms.ads.rewarded.RewardedAdCallback; -import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; -import com.unity3d.scar.adapter.common.GMAEvent; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; - -public class ScarRewardedAdListener { - - private RewardedAd _rewardedAd; - private IScarRewardedAdListenerWrapper _adListenerWrapper; - private IScarLoadListener _loadListener; - - public ScarRewardedAdListener(RewardedAd rewardedAd, IScarRewardedAdListenerWrapper adListenerWrapper) { - _rewardedAd = rewardedAd; - _adListenerWrapper = adListenerWrapper; - } - - private RewardedAdLoadCallback _rewardedAdLoadCallback = new RewardedAdLoadCallback() { - @Override - public void onRewardedAdLoaded() { - _adListenerWrapper.onAdLoaded(); - if (_loadListener != null) { - _loadListener.onAdLoaded(); - } - } - - @Override - public void onRewardedAdFailedToLoad(int adErrorCode) { - _adListenerWrapper.onAdFailedToLoad(adErrorCode, "SCAR ad failed to show"); - } - }; - - private RewardedAdCallback rewardedAdCallback = new RewardedAdCallback () { - @Override - public void onRewardedAdOpened() { - _adListenerWrapper.onAdOpened(); - } - - @Override - public void onRewardedAdFailedToShow(int adErrorCode) { - _adListenerWrapper.onAdFailedToShow(adErrorCode, "SCAR ad failed to show"); - } - - @Override - public void onUserEarnedReward(RewardItem rewardItem) { - _adListenerWrapper.onUserEarnedReward(); - } - - @Override - public void onRewardedAdClosed() { - _adListenerWrapper.onAdClosed(); - } - }; - - public RewardedAdCallback getRewardedAdCallback() { - return rewardedAdCallback; - } - - public RewardedAdLoadCallback getRewardedAdLoadCallback() { return _rewardedAdLoadCallback; } - - public void setLoadListener(IScarLoadListener loadListener) { - _loadListener = loadListener; - } -} diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/QueryInfoCallback.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/QueryInfoCallback.java deleted file mode 100644 index 037c53b..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/QueryInfoCallback.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.unity3d.scar.adapter.v1920.signals; - -import com.google.android.gms.ads.query.QueryInfo; -import com.google.android.gms.ads.query.QueryInfoGenerationCallback; -import com.unity3d.scar.adapter.common.signals.ISignalCallbackListener; - -public class QueryInfoCallback extends QueryInfoGenerationCallback { - - private String _placementId; - private ISignalCallbackListener _signalCallbackListener; - - public QueryInfoCallback(final String placementId, final ISignalCallbackListener signalCallbackListener) { - _placementId = placementId; - _signalCallbackListener = signalCallbackListener; - } - - @Override - public void onSuccess(final QueryInfo queryInfo) { - _signalCallbackListener.onSuccess(_placementId, queryInfo.getQuery(), queryInfo); - } - - @Override - public void onFailure(String errorMessage) { - _signalCallbackListener.onFailure(errorMessage); - } -} \ No newline at end of file diff --git a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollector.java b/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollector.java deleted file mode 100644 index 7e76427..0000000 --- a/unity-scaradapter-1920/src/main/java/com/unity3d/scar/adapter/v1920/signals/SignalsCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.unity3d.scar.adapter.v1920.signals; - -import android.content.Context; - -import com.google.android.gms.ads.AdFormat; -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.DispatchGroup; -import com.unity3d.scar.adapter.common.signals.ISignalsCollector; -import com.unity3d.scar.adapter.common.signals.SignalCallbackListener; -import com.unity3d.scar.adapter.common.signals.SignalsCollectorBase; -import com.unity3d.scar.adapter.common.signals.SignalsResult; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; - -public class SignalsCollector extends SignalsCollectorBase implements ISignalsCollector { - private SignalsStorage _signalsStorage; - - public SignalsCollector(SignalsStorage signalsStorage) { - _signalsStorage = signalsStorage; - } - - @Override - public void getSCARSignal(final Context context, final String placementId, final boolean isInterstitial, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { - AdRequest request = new AdRequest.Builder().build(); - AdFormat adFormat = isInterstitial ? AdFormat.INTERSTITIAL : AdFormat.REWARDED; - QueryInfoCallback queryInfoCallback = new QueryInfoCallback(placementId, new SignalCallbackListener(dispatchGroup, _signalsStorage, signalsResult)); - QueryInfo.generate(context, adFormat, request, queryInfoCallback); - } - - @Override - public void getSCARSignal(Context context, boolean isInterstitial, DispatchGroup dispatchGroup, SignalsResult signalsResult) { - onOperationNotSupported("GMA v1920 - SCAR signal retrieval required a placementId", - dispatchGroup, signalsResult); - } -} diff --git a/unity-scaradapter-1950/.gitignore b/unity-scaradapter-1950/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/unity-scaradapter-1950/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/unity-scaradapter-1950/build.gradle b/unity-scaradapter-1950/build.gradle deleted file mode 100644 index f71aa92..0000000 --- a/unity-scaradapter-1950/build.gradle +++ /dev/null @@ -1,45 +0,0 @@ -plugins { - id 'com.android.library' -} - -android { - compileSdkVersion 30 - - defaultConfig { - minSdkVersion 16 - targetSdkVersion 30 - multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles "consumer-rules.pro" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - debug { - minifyEnabled false - testCoverageEnabled true - } - } -} - -dependencies { - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation "org.mockito:mockito-android:2.25.0" - androidTestImplementation 'com.google.android.gms:play-services-ads:19.5.0' - testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:2.28.2' - testImplementation 'com.google.android.gms:play-services-ads:19.2.0' - api project(':unity-scaradapter-common') - compileOnly 'com.google.android.gms:play-services-ads:19.5.0' -} - -apply from: '../fatAar.gradle' \ No newline at end of file diff --git a/unity-scaradapter-1950/consumer-rules.pro b/unity-scaradapter-1950/consumer-rules.pro deleted file mode 100644 index e69de29..0000000 diff --git a/unity-scaradapter-1950/proguard-rules.pro b/unity-scaradapter-1950/proguard-rules.pro deleted file mode 100644 index 481bb43..0000000 --- a/unity-scaradapter-1950/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/unity-scaradapter-1950/src/androidTest/AndroidManifest.xml b/unity-scaradapter-1950/src/androidTest/AndroidManifest.xml deleted file mode 100644 index 4d4bd46..0000000 --- a/unity-scaradapter-1950/src/androidTest/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ -> - - - - \ No newline at end of file diff --git a/unity-scaradapter-1950/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java b/unity-scaradapter-1950/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java deleted file mode 100644 index 99f15d7..0000000 --- a/unity-scaradapter-1950/src/androidTest/java/com/unity3d/ads/test/InstrumentationTestSuite.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.unity3d.ads.test; - -import com.unity3d.scar.adapter.v1950.signals.SignalsCollectorTest; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ - SignalsCollectorTest.class -}) -public class InstrumentationTestSuite { -} diff --git a/unity-scaradapter-1950/src/androidTest/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollectorTest.java b/unity-scaradapter-1950/src/androidTest/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollectorTest.java deleted file mode 100644 index f8bbb0f..0000000 --- a/unity-scaradapter-1950/src/androidTest/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollectorTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.unity3d.scar.adapter.v1950.signals; - -import android.content.Context; - -import androidx.test.platform.app.InstrumentationRegistry; - -import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.mockito.Matchers.any; - -@RunWith(MockitoJUnitRunner.class) -public class SignalsCollectorTest { - private Context context = InstrumentationRegistry.getInstrumentation().getContext(); - private ISignalCollectionListener _signalCollectionListener; - - @Before - public void before() { - _signalCollectionListener = Mockito.mock(ISignalCollectionListener.class); - } - - @Test - public void testGetScarSignals() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - - @Test - public void testGetScarSignalsNoRewarded() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - - @Test - public void testGetScarSignalsNoInterstitial() { - SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); - } - -} diff --git a/unity-scaradapter-1950/src/main/AndroidManifest.xml b/unity-scaradapter-1950/src/main/AndroidManifest.xml deleted file mode 100644 index 726faf5..0000000 --- a/unity-scaradapter-1950/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/ScarAdapter.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/ScarAdapter.java deleted file mode 100644 index cd7ca4a..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/ScarAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.unity3d.scar.adapter.v1950; - -import android.content.Context; - -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarAdapter; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.ScarAdapterBase; -import com.unity3d.scar.adapter.common.WebViewAdsError; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; -import com.unity3d.scar.adapter.v1950.scarads.ScarInterstitialAd; -import com.unity3d.scar.adapter.v1950.scarads.ScarRewardedAd; -import com.unity3d.scar.adapter.v1950.signals.SignalsCollector; - -import static com.unity3d.scar.adapter.common.Utils.runOnUiThread; - -public class ScarAdapter extends ScarAdapterBase implements IScarAdapter { - - private SignalsStorage _signalsStorage; - - public ScarAdapter(IAdsErrorHandler adsErrorHandler) { - super(adsErrorHandler); - _signalsStorage = new SignalsStorage<>(); - _signalCollector = new SignalsCollector(_signalsStorage); - } - - public void loadInterstitialAd(Context context, final ScarAdMetadata scarAd, final IScarInterstitialAdListenerWrapper adListenerWrapper) { - final ScarInterstitialAd interstitialAd = new ScarInterstitialAd(context, _signalsStorage.getQueryInfo(scarAd.getPlacementId()), scarAd, _adsErrorHandler, adListenerWrapper); - runOnUiThread(new Runnable() { - @Override - public void run() { - interstitialAd.loadAd(new IScarLoadListener() { - @Override - public void onAdLoaded() { - _loadedAds.put(scarAd.getPlacementId(), interstitialAd); - } - }); - } - }); - } - - public void loadRewardedAd(Context context, final ScarAdMetadata scarAd, final IScarRewardedAdListenerWrapper adListenerWrapper) { - final ScarRewardedAd rewardedAd = new ScarRewardedAd(context, _signalsStorage.getQueryInfo(scarAd.getPlacementId()), scarAd, _adsErrorHandler, adListenerWrapper); - runOnUiThread(new Runnable() { - @Override - public void run() { - rewardedAd.loadAd(new IScarLoadListener() { - @Override - public void onAdLoaded() { - _loadedAds.put(scarAd.getPlacementId(), rewardedAd); - } - }); - } - }); - } - -} diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarAdBase.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarAdBase.java deleted file mode 100644 index 431130e..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarAdBase.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.unity3d.scar.adapter.v1950.scarads; - -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.AdInfo; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.scarads.IScarAd; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public abstract class ScarAdBase implements IScarAd { - - protected Context _context; - protected ScarAdMetadata _scarAdMetadata; - protected QueryInfo _queryInfo; - protected IAdsErrorHandler _adsErrorHandler; - - public ScarAdBase(Context context, ScarAdMetadata scarAdMetadata, QueryInfo queryInfo, IAdsErrorHandler adsErrorHandler) { - _context = context; - _scarAdMetadata = scarAdMetadata; - _queryInfo = queryInfo; - _adsErrorHandler = adsErrorHandler; - } - - @Override - public void loadAd(IScarLoadListener loadListener) { - if (_queryInfo != null) { - AdInfo adInfo = new AdInfo(_queryInfo, _scarAdMetadata.getAdString()); - AdRequest adRequest = new AdRequest.Builder().setAdInfo(adInfo).build(); - loadAdInternal(loadListener, adRequest); - } else { - _adsErrorHandler.handleError(GMAAdsError.QueryNotFoundError(_scarAdMetadata)); - } - } - - protected abstract void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest); - -} diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAd.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAd.java deleted file mode 100644 index 4e70984..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAd.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.unity3d.scar.adapter.v1950.scarads; - -import android.app.Activity; -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.InterstitialAd; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public class ScarInterstitialAd extends ScarAdBase { - - private InterstitialAd _interstitialAd; - private ScarInterstitialAdListener _interstitialAdDelegate; - - public ScarInterstitialAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarInterstitialAdListenerWrapper adListener) { - super(context, scarAdMetadata, queryInfo, adsErrorHandler); - _interstitialAd = new InterstitialAd(_context); - _interstitialAd.setAdUnitId(_scarAdMetadata.getAdUnitId()); - _interstitialAdDelegate = new ScarInterstitialAdListener(_interstitialAd, adListener); - } - - @Override - public void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest) { - _interstitialAd.setAdListener(_interstitialAdDelegate.getAdListener()); - _interstitialAdDelegate.setLoadListener(loadListener); - _interstitialAd.loadAd(adRequest); - } - - @Override - public void show(Activity activity) { - if (_interstitialAd.isLoaded()) { - _interstitialAd.show(); - } else { - _adsErrorHandler.handleError(GMAAdsError.AdNotLoadedError(_scarAdMetadata)); - } - } -} diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAdListener.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAdListener.java deleted file mode 100644 index 12c47e1..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarInterstitialAdListener.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.unity3d.scar.adapter.v1950.scarads; - -import com.google.android.gms.ads.AdListener; -import com.google.android.gms.ads.InterstitialAd; -import com.google.android.gms.ads.LoadAdError; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; - -public class ScarInterstitialAdListener { - - private InterstitialAd _interstitialAd; - private IScarInterstitialAdListenerWrapper _adListenerWrapper; - private IScarLoadListener _loadListener; - - public ScarInterstitialAdListener(InterstitialAd interstitialAd, IScarInterstitialAdListenerWrapper adListenerWrapper) { - _interstitialAd = interstitialAd; - _adListenerWrapper = adListenerWrapper; - } - - private AdListener _adListener = new AdListener() { - @Override - public void onAdLoaded() { - _adListenerWrapper.onAdLoaded(); - if (_loadListener != null) { - _loadListener.onAdLoaded(); - } - } - - @Override - public void onAdFailedToLoad(LoadAdError adErrorCode) { - _adListenerWrapper.onAdFailedToLoad(adErrorCode.getCode(), adErrorCode.toString()); - } - - @Override - public void onAdOpened() { - _adListenerWrapper.onAdOpened(); - } - - @Override - public void onAdClicked() { - _adListenerWrapper.onAdClicked(); - } - - @Override - public void onAdLeftApplication() { - _adListenerWrapper.onAdLeftApplication(); - } - - @Override - public void onAdClosed() { - _adListenerWrapper.onAdClosed(); - } - }; - - public AdListener getAdListener() { - return _adListener; - } - - public void setLoadListener(IScarLoadListener loadListener) { - _loadListener = loadListener; - } - -} diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAd.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAd.java deleted file mode 100644 index de0a4cb..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAd.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.unity3d.scar.adapter.v1950.scarads; - -import android.app.Activity; -import android.content.Context; - -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.QueryInfo; -import com.google.android.gms.ads.rewarded.RewardedAd; -import com.unity3d.scar.adapter.common.GMAAdsError; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; -import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; - -public class ScarRewardedAd extends ScarAdBase { - - private RewardedAd _rewardedAd; - private ScarRewardedAdListener _rewardedAdDelegate; - - public ScarRewardedAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarRewardedAdListenerWrapper adListener) { - super(context, scarAdMetadata, queryInfo, adsErrorHandler); - _rewardedAd = new RewardedAd(_context, _scarAdMetadata.getAdUnitId()); - _rewardedAdDelegate = new ScarRewardedAdListener(_rewardedAd, adListener); - } - - @Override - public void loadAdInternal(IScarLoadListener loadListener, AdRequest adRequest) { - _rewardedAdDelegate.setLoadListener(loadListener); - _rewardedAd.loadAd(adRequest, _rewardedAdDelegate.getRewardedAdLoadCallback()); - } - - @Override - public void show(Activity activity) { - if (_rewardedAd.isLoaded()) { - _rewardedAd.show(activity, _rewardedAdDelegate.getRewardedAdCallback()); - } else { - _adsErrorHandler.handleError(GMAAdsError.AdNotLoadedError(_scarAdMetadata)); - } - } - -} \ No newline at end of file diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAdListener.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAdListener.java deleted file mode 100644 index 5d9e52f..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/scarads/ScarRewardedAdListener.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.unity3d.scar.adapter.v1950.scarads; - -import com.google.android.gms.ads.AdError; -import com.google.android.gms.ads.LoadAdError; -import com.google.android.gms.ads.rewarded.RewardItem; -import com.google.android.gms.ads.rewarded.RewardedAd; -import com.google.android.gms.ads.rewarded.RewardedAdCallback; -import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; -import com.unity3d.scar.adapter.common.GMAEvent; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; - -public class ScarRewardedAdListener { - - private RewardedAd _rewardedAd; - private IScarRewardedAdListenerWrapper _adListenerWrapper; - private IScarLoadListener _loadListener; - - public ScarRewardedAdListener(RewardedAd rewardedAd, IScarRewardedAdListenerWrapper adListenerWrapper) { - _rewardedAd = rewardedAd; - _adListenerWrapper = adListenerWrapper; - } - - private RewardedAdLoadCallback _rewardedAdLoadCallback = new RewardedAdLoadCallback() { - @Override - public void onRewardedAdLoaded() { - _adListenerWrapper.onAdLoaded(); - if (_loadListener != null) { - _loadListener.onAdLoaded(); - } - } - - @Override - public void onRewardedAdFailedToLoad(LoadAdError adError) { - _adListenerWrapper.onAdFailedToLoad(adError.getCode(), adError.toString()); - } - }; - - private RewardedAdCallback rewardedAdCallback = new RewardedAdCallback () { - @Override - public void onRewardedAdOpened() { - _adListenerWrapper.onAdOpened(); - } - - @Override - public void onRewardedAdFailedToShow(AdError adError) { - _adListenerWrapper.onAdFailedToShow(adError.getCode(), adError.toString()); - } - - @Override - public void onUserEarnedReward(RewardItem rewardItem) { - _adListenerWrapper.onUserEarnedReward(); - } - - @Override - public void onRewardedAdClosed() { - _adListenerWrapper.onAdClosed(); - } - }; - - public RewardedAdCallback getRewardedAdCallback() { - return rewardedAdCallback; - } - - public RewardedAdLoadCallback getRewardedAdLoadCallback() { return _rewardedAdLoadCallback; } - - public void setLoadListener(IScarLoadListener loadListener) { - _loadListener = loadListener; - } -} \ No newline at end of file diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/QueryInfoCallback.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/QueryInfoCallback.java deleted file mode 100644 index 43f20b4..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/QueryInfoCallback.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.unity3d.scar.adapter.v1950.signals; - -import com.google.android.gms.ads.query.QueryInfo; -import com.google.android.gms.ads.query.QueryInfoGenerationCallback; -import com.unity3d.scar.adapter.common.signals.ISignalCallbackListener; - -public class QueryInfoCallback extends QueryInfoGenerationCallback { - - private String _placementId; - private ISignalCallbackListener _signalCallbackListener; - - public QueryInfoCallback(final String placementId, final ISignalCallbackListener signalCallbackListener) { - _placementId = placementId; - _signalCallbackListener = signalCallbackListener; - } - - @Override - public void onSuccess(final QueryInfo queryInfo) { - _signalCallbackListener.onSuccess(_placementId, queryInfo.getQuery(), queryInfo); - } - - @Override - public void onFailure(String errorMessage) { - _signalCallbackListener.onFailure(errorMessage); - } -} diff --git a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollector.java b/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollector.java deleted file mode 100644 index 63cc95e..0000000 --- a/unity-scaradapter-1950/src/main/java/com/unity3d/scar/adapter/v1950/signals/SignalsCollector.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.unity3d.scar.adapter.v1950.signals; - -import android.content.Context; - -import com.google.android.gms.ads.AdFormat; -import com.google.android.gms.ads.AdRequest; -import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.DispatchGroup; -import com.unity3d.scar.adapter.common.signals.ISignalsCollector; -import com.unity3d.scar.adapter.common.signals.SignalCallbackListener; -import com.unity3d.scar.adapter.common.signals.SignalsCollectorBase; -import com.unity3d.scar.adapter.common.signals.SignalsResult; -import com.unity3d.scar.adapter.common.signals.SignalsStorage; - -public class SignalsCollector extends SignalsCollectorBase implements ISignalsCollector { - private SignalsStorage _signalsStorage; - - public SignalsCollector(SignalsStorage signalsStorage) { - _signalsStorage = signalsStorage; - } - - @Override - public void getSCARSignal(final Context context, final String placementId, final boolean isInterstitial, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { - AdRequest request = new AdRequest.Builder().build(); - AdFormat adFormat = isInterstitial ? AdFormat.INTERSTITIAL : AdFormat.REWARDED; - QueryInfoCallback queryInfoCallback = new QueryInfoCallback(placementId, new SignalCallbackListener(dispatchGroup, _signalsStorage, signalsResult)); - QueryInfo.generate(context, adFormat, request, queryInfoCallback); - } - - @Override - public void getSCARSignal(Context context, boolean isInterstitial, DispatchGroup dispatchGroup, SignalsResult signalsResult) { - onOperationNotSupported("GMA v1950 - SCAR signal retrieval required a placementId", - dispatchGroup, signalsResult); - } -} diff --git a/unity-scaradapter-2000/src/androidTest/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollectorTest.java b/unity-scaradapter-2000/src/androidTest/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollectorTest.java index 77967ec..03a0bee 100644 --- a/unity-scaradapter-2000/src/androidTest/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollectorTest.java +++ b/unity-scaradapter-2000/src/androidTest/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollectorTest.java @@ -5,6 +5,7 @@ import android.content.Context; import androidx.test.platform.app.InstrumentationRegistry; import com.google.android.gms.ads.query.QueryInfo; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; import com.unity3d.scar.adapter.common.signals.SignalsStorage; @@ -28,23 +29,23 @@ public class SignalsCollectorTest { } @Test - public void testGetScarSignals() { + public void testGetScarSignalInterstitial() { SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "video", UnityAdFormat.INTERSTITIAL, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"video\":")); } @Test - public void testGetScarSignalsNoRewarded() { + public void testGetScarSignalRewarded() { SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "rewarded", UnityAdFormat.REWARDED, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"rewarded\":")); } @Test - public void testGetScarSignalsNoInterstitial() { + public void testGetScarSignalBanner() { SignalsCollector signalsCollector = new SignalsCollector(new SignalsStorage()); - signalsCollector.getSCARSignals(context, new String[]{}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "banner", UnityAdFormat.BANNER, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"banner\":")); } } diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/ScarAdapter.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/ScarAdapter.java index b4564a1..44060a6 100644 --- a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/ScarAdapter.java +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/ScarAdapter.java @@ -2,16 +2,13 @@ package com.unity3d.scar.adapter.v2000; import android.content.Context; +import android.widget.RelativeLayout; import com.google.android.gms.ads.query.QueryInfo; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarAdapter; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.ScarAdapterBase; -import com.unity3d.scar.adapter.common.WebViewAdsError; +import com.unity3d.scar.adapter.common.*; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.scar.adapter.common.signals.SignalsStorage; +import com.unity3d.scar.adapter.v2000.scarads.ScarBannerAd; import com.unity3d.scar.adapter.v2000.scarads.ScarInterstitialAd; import com.unity3d.scar.adapter.v2000.scarads.ScarRewardedAd; import com.unity3d.scar.adapter.v2000.signals.SignalsCollector; @@ -58,4 +55,16 @@ public class ScarAdapter extends ScarAdapterBase implements IScarAdapter { }); } + @Override + public void loadBannerAd(Context context, RelativeLayout bannerView, ScarAdMetadata scarAd, int width, int height, IScarBannerAdListenerWrapper adListener) { + final ScarBannerAd bannerAd = new ScarBannerAd(context, _signalsStorage.getQueryInfo(scarAd.getPlacementId()), bannerView, scarAd, width, height, _adsErrorHandler, adListener); + runOnUiThread(new Runnable() { + @Override + public void run() { + // We do not need to store the banner ad since there is no show + bannerAd.loadAd(null); + } + }); + } + } diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarAdBase.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarAdBase.java index c884f1f..45cf757 100644 --- a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarAdBase.java +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarAdBase.java @@ -39,7 +39,9 @@ public abstract class ScarAdBase implements IScarAd { if (_queryInfo != null) { AdInfo adInfo = new AdInfo(_queryInfo, _scarAdMetadata.getAdString()); AdRequest adRequest = new AdRequest.Builder().setAdInfo(adInfo).build(); - _scarAdListener.setLoadListener(loadListener); + if (loadListener != null) { + _scarAdListener.setLoadListener(loadListener); + } loadAdInternal(adRequest, loadListener); } else { _adsErrorHandler.handleError(GMAAdsError.QueryNotFoundError(_scarAdMetadata)); diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAd.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAd.java new file mode 100644 index 0000000..0de44f3 --- /dev/null +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAd.java @@ -0,0 +1,46 @@ +package com.unity3d.scar.adapter.v2000.scarads; + +import android.content.Context; +import android.widget.RelativeLayout; +import com.google.android.gms.ads.*; +import com.google.android.gms.ads.query.QueryInfo; +import com.unity3d.scar.adapter.common.*; +import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; + +public class ScarBannerAd extends ScarAdBase{ + + private RelativeLayout _bannerView; + private int _width; + private int _height; + private AdView _adView; + + public ScarBannerAd(Context context, QueryInfo queryInfo, RelativeLayout bannerView, ScarAdMetadata scarAdMetadata, int width, int height, IAdsErrorHandler adsErrorHandler, IScarBannerAdListenerWrapper adListener) { + super(context, scarAdMetadata, queryInfo, adsErrorHandler); + _bannerView = bannerView; + _width = width; + _height = height; + _adView = new AdView(_context); + _scarAdListener = new ScarBannerAdListener(adListener, this); + } + + public void removeAdView() { + if (_bannerView != null && _adView != null) { + _bannerView.removeView(_adView); + } + } + + @Override + protected void loadAdInternal(AdRequest adRequest, IScarLoadListener loadListener) { + if (_bannerView != null && _adView != null) { + _bannerView.addView(_adView); + + _adView.setAdSize(new AdSize(_width, _height)); + _adView.setAdUnitId(_scarAdMetadata.getAdUnitId()); + + _adView.setAdListener(((ScarBannerAdListener) _scarAdListener).getAdListener()); + + _adView.loadAd(adRequest); + } + } +} diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAdListener.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAdListener.java new file mode 100644 index 0000000..43a197e --- /dev/null +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarBannerAdListener.java @@ -0,0 +1,61 @@ +package com.unity3d.scar.adapter.v2000.scarads; + +import androidx.annotation.NonNull; +import com.google.android.gms.ads.AdListener; +import com.google.android.gms.ads.LoadAdError; +import com.unity3d.scar.adapter.common.IScarBannerAdListenerWrapper; + +public class ScarBannerAdListener extends ScarAdListener { + + private final IScarBannerAdListenerWrapper _adListenerWrapper; + private final ScarBannerAd _scarBannerAd; + + public ScarBannerAdListener(IScarBannerAdListenerWrapper adListenerWrapper, ScarBannerAd scarBannerAd) { + _adListenerWrapper = adListenerWrapper; + _scarBannerAd = scarBannerAd; + } + + private final AdListener _adListener = new AdListener() { + @Override + public void onAdClicked() { + super.onAdClicked(); + _adListenerWrapper.onAdClicked(); + } + + @Override + public void onAdClosed() { + super.onAdClosed(); + _adListenerWrapper.onAdClosed(); + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + super.onAdFailedToLoad(loadAdError); + _scarBannerAd.removeAdView(); + _adListenerWrapper.onAdFailedToLoad(loadAdError.getCode(), loadAdError.getMessage()); + } + + @Override + public void onAdImpression() { + super.onAdImpression(); + _adListenerWrapper.onAdImpression(); + } + + @Override + public void onAdLoaded() { + super.onAdLoaded(); + _adListenerWrapper.onAdLoaded(); + } + + @Override + public void onAdOpened() { + super.onAdOpened(); + _adListenerWrapper.onAdOpened(); + } + }; + + public AdListener getAdListener() { + return _adListener; + } +} + diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarInterstitialAd.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarInterstitialAd.java index 82dc9c9..c979c56 100644 --- a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarInterstitialAd.java +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarInterstitialAd.java @@ -9,10 +9,11 @@ import com.google.android.gms.ads.query.QueryInfo; import com.unity3d.scar.adapter.common.GMAAdsError; import com.unity3d.scar.adapter.common.IAdsErrorHandler; import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; +import com.unity3d.scar.adapter.common.scarads.IScarFullScreenAd; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; -public class ScarInterstitialAd extends ScarAdBase { +public class ScarInterstitialAd extends ScarAdBase implements IScarFullScreenAd { public ScarInterstitialAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarInterstitialAdListenerWrapper adListener) { super(context, scarAdMetadata, queryInfo, adsErrorHandler); diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarRewardedAd.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarRewardedAd.java index 7a39de8..22c2c50 100644 --- a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarRewardedAd.java +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/scarads/ScarRewardedAd.java @@ -9,10 +9,11 @@ import com.google.android.gms.ads.rewarded.RewardedAd; import com.unity3d.scar.adapter.common.GMAAdsError; import com.unity3d.scar.adapter.common.IAdsErrorHandler; import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; +import com.unity3d.scar.adapter.common.scarads.IScarFullScreenAd; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; -public class ScarRewardedAd extends ScarAdBase { +public class ScarRewardedAd extends ScarAdBase implements IScarFullScreenAd { public ScarRewardedAd(Context context, QueryInfo queryInfo, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarRewardedAdListenerWrapper adListener) { super(context, scarAdMetadata, queryInfo, adsErrorHandler); diff --git a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollector.java b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollector.java index 6ca5ecd..cebd075 100644 --- a/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollector.java +++ b/unity-scaradapter-2000/src/main/java/com/unity3d/scar/adapter/v2000/signals/SignalsCollector.java @@ -6,6 +6,7 @@ import com.google.android.gms.ads.AdFormat; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.query.QueryInfo; import com.unity3d.scar.adapter.common.DispatchGroup; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalsCollector; import com.unity3d.scar.adapter.common.signals.SignalCallbackListener; import com.unity3d.scar.adapter.common.signals.SignalsCollectorBase; @@ -20,19 +21,27 @@ public class SignalsCollector extends SignalsCollectorBase implements ISignalsCo } @Override - public void getSCARSignal(final Context context, final String placementId, final boolean isInterstitial, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { + public void getSCARSignal(final Context context, final String placementId, final UnityAdFormat adFormat, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { AdRequest request = new AdRequest.Builder().build(); - AdFormat adFormat = isInterstitial ? AdFormat.INTERSTITIAL : AdFormat.REWARDED; QueryInfoCallback queryInfoCallback = new QueryInfoCallback(placementId, new SignalCallbackListener(dispatchGroup, _signalsStorage, signalsResult)); - QueryInfo.generate(context, adFormat, request, queryInfoCallback); + QueryInfo.generate(context, getAdFormat(adFormat), request, queryInfoCallback); } @Override - public void getSCARSignal(Context context, - boolean isInterstitial, - DispatchGroup dispatchGroup, - SignalsResult signalsResult) { + public void getSCARSignalForHB(final Context context, final UnityAdFormat adFormat, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { onOperationNotSupported("GMA v2000 - SCAR signal retrieval without a placementId not relevant", dispatchGroup, signalsResult); } + + public AdFormat getAdFormat(UnityAdFormat adFormat) { + switch (adFormat) { + case BANNER: + return AdFormat.BANNER; + case INTERSTITIAL: + return AdFormat.INTERSTITIAL; + case REWARDED: + return AdFormat.REWARDED; + } + return AdFormat.BANNER; + } } diff --git a/unity-scaradapter-2100/src/androidTest/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollectorTest.java b/unity-scaradapter-2100/src/androidTest/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollectorTest.java index af63ca0..87f69c0 100644 --- a/unity-scaradapter-2100/src/androidTest/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollectorTest.java +++ b/unity-scaradapter-2100/src/androidTest/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollectorTest.java @@ -5,6 +5,7 @@ import android.content.Context; import androidx.test.platform.app.InstrumentationRegistry; import com.unity3d.scar.adapter.common.requests.RequestExtras; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; @@ -29,24 +30,24 @@ public class SignalsCollectorTest { } @Test - public void testGetScarSignals() { + public void testGetScarSignalInterstitial() { SignalsCollector signalsCollector = new SignalsCollector(adRequestFactory); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "video", UnityAdFormat.INTERSTITIAL, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"video\":")); } @Test - public void testGetScarSignalsNoRewarded() { + public void testGetScarSignalRewarded() { SignalsCollector signalsCollector = new SignalsCollector(adRequestFactory); - signalsCollector.getSCARSignals(context, new String[]{"video"}, new String[]{}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "rewarded", UnityAdFormat.REWARDED, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"rewarded\":")); } @Test - public void testGetScarSignalsNoInterstitial() { + public void testGetScarSignalBanner() { SignalsCollector signalsCollector = new SignalsCollector(adRequestFactory); - signalsCollector.getSCARSignals(context, new String[]{}, new String[]{"rewarded"}, _signalCollectionListener); - Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(any(String.class)); + signalsCollector.getSCARSignal(context, "banner", UnityAdFormat.BANNER, _signalCollectionListener); + Mockito.verify(_signalCollectionListener, Mockito.timeout(10000).times(1)).onSignalsCollected(Mockito.contains("{\"banner\":")); } } diff --git a/unity-scaradapter-2100/src/main/AndroidManifest.xml b/unity-scaradapter-2100/src/main/AndroidManifest.xml index 114c52c..91fd45e 100644 --- a/unity-scaradapter-2100/src/main/AndroidManifest.xml +++ b/unity-scaradapter-2100/src/main/AndroidManifest.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/ScarAdapter.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/ScarAdapter.java index be1f96d..9a589a9 100644 --- a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/ScarAdapter.java +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/ScarAdapter.java @@ -2,16 +2,13 @@ package com.unity3d.scar.adapter.v2100; import android.content.Context; -import com.unity3d.scar.adapter.common.IAdsErrorHandler; -import com.unity3d.scar.adapter.common.IScarAdapter; -import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; -import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; -import com.unity3d.scar.adapter.common.ScarAdapterBase; -import com.unity3d.scar.adapter.common.WebViewAdsError; +import android.widget.RelativeLayout; +import com.unity3d.scar.adapter.common.*; import com.unity3d.scar.adapter.common.requests.RequestExtras; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; +import com.unity3d.scar.adapter.v2100.scarads.ScarBannerAd; import com.unity3d.scar.adapter.v2100.scarads.ScarInterstitialAd; import com.unity3d.scar.adapter.v2100.scarads.ScarRewardedAd; import com.unity3d.scar.adapter.v2100.signals.SignalsCollector; @@ -57,4 +54,15 @@ public class ScarAdapter extends ScarAdapterBase implements IScarAdapter { }); } + @Override + public void loadBannerAd(Context context, final RelativeLayout bannerView, final ScarAdMetadata scarAdMetadata, final int width, final int height, final IScarBannerAdListenerWrapper adListener) { + final ScarBannerAd bannerAd = new ScarBannerAd(context, bannerView, _adRequestFactory, scarAdMetadata, width, height, _adsErrorHandler, adListener); + runOnUiThread(new Runnable() { + @Override + public void run() { + // We do not need to store the banner ad since there is no show call for banners + bannerAd.loadAd(null); + } + }); + } } diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarAdBase.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarAdBase.java index fa71f49..1432200 100644 --- a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarAdBase.java +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarAdBase.java @@ -32,7 +32,9 @@ public abstract class ScarAdBase implements IScarAd { @Override public void loadAd(IScarLoadListener loadListener) { AdRequest adRequest = _adRequestFactory.buildAdRequestWithAdString(_scarAdMetadata.getAdString()); - _scarAdListener.setLoadListener(loadListener); + if (loadListener != null) { + _scarAdListener.setLoadListener(loadListener); + } loadAdInternal(adRequest, loadListener); } diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAd.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAd.java new file mode 100644 index 0000000..e2c3320 --- /dev/null +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAd.java @@ -0,0 +1,46 @@ +package com.unity3d.scar.adapter.v2100.scarads; + +import android.content.Context; +import android.widget.RelativeLayout; +import com.google.android.gms.ads.*; +import com.unity3d.scar.adapter.common.*; +import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; +import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; + +public class ScarBannerAd extends ScarAdBase{ + + private RelativeLayout _bannerView; + private int _width; + private int _height; + private AdView _adView; + + public ScarBannerAd(Context context, RelativeLayout bannerView, AdRequestFactory adRequestFactory, ScarAdMetadata scarAdMetadata, int width, int height, IAdsErrorHandler adsErrorHandler, IScarBannerAdListenerWrapper adListener) { + super(context, scarAdMetadata, adRequestFactory, adsErrorHandler); + _bannerView = bannerView; + _width = width; + _height = height; + _adView = new AdView(_context); + _scarAdListener = new ScarBannerAdListener(adListener, this); + } + + public void removeAdView() { + if (_bannerView != null && _adView != null) { + _bannerView.removeView(_adView); + } + } + + @Override + protected void loadAdInternal(AdRequest adRequest, IScarLoadListener loadListener) { + if (_bannerView != null && _adView != null) { + _bannerView.addView(_adView); + + _adView.setAdSize(new AdSize(_width, _height)); + _adView.setAdUnitId(_scarAdMetadata.getAdUnitId()); + + _adView.setAdListener(((ScarBannerAdListener)_scarAdListener).getAdListener()); + + _adView.loadAd(adRequest); + } + } +} diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAdListener.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAdListener.java new file mode 100644 index 0000000..56ec982 --- /dev/null +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarBannerAdListener.java @@ -0,0 +1,61 @@ +package com.unity3d.scar.adapter.v2100.scarads; + +import androidx.annotation.NonNull; +import com.google.android.gms.ads.AdListener; +import com.google.android.gms.ads.LoadAdError; +import com.unity3d.scar.adapter.common.IScarBannerAdListenerWrapper; + +public class ScarBannerAdListener extends ScarAdListener { + + private final IScarBannerAdListenerWrapper _adListenerWrapper; + private final ScarBannerAd _scarBannerAd; + + public ScarBannerAdListener(IScarBannerAdListenerWrapper adListenerWrapper, ScarBannerAd scarBannerAd) { + _adListenerWrapper = adListenerWrapper; + _scarBannerAd = scarBannerAd; + } + + private final AdListener _adListener = new AdListener() { + @Override + public void onAdClicked() { + super.onAdClicked(); + _adListenerWrapper.onAdClicked(); + } + + @Override + public void onAdClosed() { + super.onAdClosed(); + _adListenerWrapper.onAdClosed(); + } + + @Override + public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { + super.onAdFailedToLoad(loadAdError); + _scarBannerAd.removeAdView(); + _adListenerWrapper.onAdFailedToLoad(loadAdError.getCode(), loadAdError.getMessage()); + } + + @Override + public void onAdImpression() { + super.onAdImpression(); + _adListenerWrapper.onAdImpression(); + } + + @Override + public void onAdLoaded() { + super.onAdLoaded(); + _adListenerWrapper.onAdLoaded(); + } + + @Override + public void onAdOpened() { + super.onAdOpened(); + _adListenerWrapper.onAdOpened(); + } + }; + + public AdListener getAdListener() { + return _adListener; + } +} + diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarInterstitialAd.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarInterstitialAd.java index 1907281..c3c121e 100644 --- a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarInterstitialAd.java +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarInterstitialAd.java @@ -8,11 +8,12 @@ import com.google.android.gms.ads.interstitial.InterstitialAd; import com.unity3d.scar.adapter.common.GMAAdsError; import com.unity3d.scar.adapter.common.IAdsErrorHandler; import com.unity3d.scar.adapter.common.IScarInterstitialAdListenerWrapper; +import com.unity3d.scar.adapter.common.scarads.IScarFullScreenAd; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; -public class ScarInterstitialAd extends ScarAdBase { +public class ScarInterstitialAd extends ScarAdBase implements IScarFullScreenAd { public ScarInterstitialAd(Context context, AdRequestFactory adRequestFactory, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarInterstitialAdListenerWrapper adListener) { super(context, scarAdMetadata, adRequestFactory, adsErrorHandler); diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarRewardedAd.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarRewardedAd.java index 497a3ce..bb10744 100644 --- a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarRewardedAd.java +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/scarads/ScarRewardedAd.java @@ -8,11 +8,12 @@ import com.google.android.gms.ads.rewarded.RewardedAd; import com.unity3d.scar.adapter.common.GMAAdsError; import com.unity3d.scar.adapter.common.IAdsErrorHandler; import com.unity3d.scar.adapter.common.IScarRewardedAdListenerWrapper; +import com.unity3d.scar.adapter.common.scarads.IScarFullScreenAd; import com.unity3d.scar.adapter.common.scarads.IScarLoadListener; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; -public class ScarRewardedAd extends ScarAdBase { +public class ScarRewardedAd extends ScarAdBase implements IScarFullScreenAd { public ScarRewardedAd(Context context, AdRequestFactory adRequestFactory, ScarAdMetadata scarAdMetadata, IAdsErrorHandler adsErrorHandler, IScarRewardedAdListenerWrapper adListener) { super(context, scarAdMetadata, adRequestFactory, adsErrorHandler); diff --git a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollector.java b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollector.java index 432261e..12bcaf9 100644 --- a/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollector.java +++ b/unity-scaradapter-2100/src/main/java/com/unity3d/scar/adapter/v2100/signals/SignalsCollector.java @@ -6,10 +6,8 @@ import com.google.android.gms.ads.AdFormat; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.query.QueryInfo; import com.unity3d.scar.adapter.common.DispatchGroup; -import com.unity3d.scar.adapter.common.signals.ISignalsCollector; -import com.unity3d.scar.adapter.common.signals.SignalCallbackListener; -import com.unity3d.scar.adapter.common.signals.SignalsCollectorBase; -import com.unity3d.scar.adapter.common.signals.SignalsResult; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; +import com.unity3d.scar.adapter.common.signals.*; import com.unity3d.scar.adapter.v2100.requests.AdRequestFactory; public class SignalsCollector extends SignalsCollectorBase implements ISignalsCollector { @@ -20,19 +18,26 @@ public class SignalsCollector extends SignalsCollectorBase implements ISignalsCo } @Override - public void getSCARSignal(final Context context, final String placementId, final boolean isInterstitial, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { + public void getSCARSignal(final Context context, final String placementId, final UnityAdFormat adFormat, final DispatchGroup dispatchGroup, final SignalsResult signalsResult) { AdRequest request = _adRequestFactory.buildAdRequest(); - AdFormat adFormat = isInterstitial ? AdFormat.INTERSTITIAL : AdFormat.REWARDED; QueryInfoCallback queryInfoCallback = new QueryInfoCallback(placementId, new SignalCallbackListener(dispatchGroup, signalsResult)); - QueryInfo.generate(context, adFormat, request, queryInfoCallback); + QueryInfo.generate(context, getAdFormat(adFormat), request, queryInfoCallback); } @Override - public void getSCARSignal(Context context, boolean isInterstitial, DispatchGroup dispatchGroup, SignalsResult signalsResult) { - getSCARSignal(context, - // this will act as the tag - isInterstitial ? SignalsCollectorBase.SCAR_INT_SIGNAL : SignalsCollectorBase.SCAR_RV_SIGNAL, - isInterstitial, dispatchGroup, signalsResult - ); + public void getSCARSignalForHB(Context context, UnityAdFormat adFormat, DispatchGroup dispatchGroup, SignalsResult signalsResult) { + getSCARSignal(context, getAdKey(adFormat), adFormat, dispatchGroup, signalsResult); + } + + public AdFormat getAdFormat(UnityAdFormat adFormat) { + switch (adFormat) { + case BANNER: + return AdFormat.BANNER; + case INTERSTITIAL: + return AdFormat.INTERSTITIAL; + case REWARDED: + return AdFormat.REWARDED; + } + return AdFormat.UNKNOWN; } } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdListenerWrapper.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdListenerWrapper.java index e4aca0d..58cdd34 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdListenerWrapper.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdListenerWrapper.java @@ -22,11 +22,6 @@ public interface IScarAdListenerWrapper { */ void onAdClicked(); - /** - * Called when the user does not watch the ad to completion. - */ - void onAdSkipped(); - /** * Called when an ad is closed. */ diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdapter.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdapter.java index a1b1a29..f38c86f 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdapter.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarAdapter.java @@ -3,14 +3,16 @@ package com.unity3d.scar.adapter.common; import android.app.Activity; import android.content.Context; +import android.widget.RelativeLayout; import com.unity3d.scar.adapter.common.scarads.ScarAdMetadata; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; public interface IScarAdapter { - - void getSCARSignals(Context context, String[] interstitialList, String[] rewardedList, ISignalCollectionListener signalCompletionListener); - void getSCARBiddingSignals(Context context, ISignalCollectionListener signalCompletionListener); + void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, ISignalCollectionListener signalCompletionListener); + void getSCARBiddingSignals(Context context, boolean isBannerEnabled, ISignalCollectionListener signalCompletionListener); void loadInterstitialAd(Context context, ScarAdMetadata scarAdMetadata, IScarInterstitialAdListenerWrapper adListener); void loadRewardedAd(Context context, ScarAdMetadata scarAdMetadata, IScarRewardedAdListenerWrapper adListener); + void loadBannerAd(Context context, RelativeLayout bannerView, ScarAdMetadata scarAdMetadata, int width, int height, IScarBannerAdListenerWrapper adListener); void show(Activity activity, String queryId, String placementId); } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarBannerAdListenerWrapper.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarBannerAdListenerWrapper.java new file mode 100644 index 0000000..e2af1c0 --- /dev/null +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarBannerAdListenerWrapper.java @@ -0,0 +1,9 @@ +package com.unity3d.scar.adapter.common; + +public interface IScarBannerAdListenerWrapper extends IScarAdListenerWrapper { + + /** + * Called when an impression is recorded for an ad. + */ + void onAdImpression(); +} diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarInterstitialAdListenerWrapper.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarInterstitialAdListenerWrapper.java index 21aef5d..6171b9a 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarInterstitialAdListenerWrapper.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarInterstitialAdListenerWrapper.java @@ -19,4 +19,9 @@ public interface IScarInterstitialAdListenerWrapper extends IScarAdListenerWrapp * Called when an impression is recorded for an ad. */ void onAdImpression(); + + /** + * Called when the user does not watch the ad to completion. + */ + void onAdSkipped(); } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarRewardedAdListenerWrapper.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarRewardedAdListenerWrapper.java index f22c11b..cbfc30c 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarRewardedAdListenerWrapper.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/IScarRewardedAdListenerWrapper.java @@ -19,4 +19,9 @@ public interface IScarRewardedAdListenerWrapper extends IScarAdListenerWrapper { * Called when an impression is recorded for an ad. */ void onAdImpression(); + + /** + * Called when the user does not watch the ad to completion. + */ + void onAdSkipped(); } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/ScarAdapterBase.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/ScarAdapterBase.java index 2315c2c..14e6eb7 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/ScarAdapterBase.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/ScarAdapterBase.java @@ -3,7 +3,8 @@ package com.unity3d.scar.adapter.common; import android.app.Activity; import android.content.Context; -import com.unity3d.scar.adapter.common.scarads.IScarAd; +import com.unity3d.scar.adapter.common.scarads.IScarFullScreenAd; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import com.unity3d.scar.adapter.common.signals.ISignalCollectionListener; import com.unity3d.scar.adapter.common.signals.ISignalsCollector; @@ -14,8 +15,8 @@ import static com.unity3d.scar.adapter.common.Utils.runOnUiThread; public abstract class ScarAdapterBase implements IScarAdapter { protected ISignalsCollector _signalCollector; - protected Map _loadedAds = new ConcurrentHashMap<>(); - protected IScarAd _currentAdReference; + protected Map _loadedAds = new ConcurrentHashMap<>(); + protected IScarFullScreenAd _currentAdReference; protected IAdsErrorHandler _adsErrorHandler; public ScarAdapterBase(IAdsErrorHandler adsErrorHandler) { @@ -23,18 +24,18 @@ public abstract class ScarAdapterBase implements IScarAdapter { } @Override - public void getSCARBiddingSignals(Context context, ISignalCollectionListener signalCompletionListener) { - _signalCollector.getSCARBiddingSignals(context, signalCompletionListener); + public void getSCARBiddingSignals(Context context, boolean isBannerEnabled, ISignalCollectionListener signalCompletionListener) { + _signalCollector.getSCARBiddingSignals(context, isBannerEnabled, signalCompletionListener); } @Override - public void getSCARSignals(Context context, String[] interstitialList, String[] rewardedList, ISignalCollectionListener signalCompletionListener) { - _signalCollector.getSCARSignals(context, interstitialList, rewardedList, signalCompletionListener); + public void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, ISignalCollectionListener signalCompletionListener) { + _signalCollector.getSCARSignal(context, placementId, adFormat, signalCompletionListener); } @Override public void show(final Activity activity, String queryId, String placementId) { - IScarAd scarAd = _loadedAds.get(placementId); + IScarFullScreenAd scarAd = _loadedAds.get(placementId); if (scarAd == null) { _adsErrorHandler.handleError(GMAAdsError.NoAdsError(placementId, queryId, "Could not find ad for placement '" + placementId + "'.")); diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarAd.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarAd.java index 3647ff1..af9b796 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarAd.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarAd.java @@ -4,5 +4,4 @@ import android.app.Activity; public interface IScarAd { void loadAd(IScarLoadListener loadListener); - void show(Activity activity); } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarFullScreenAd.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarFullScreenAd.java new file mode 100644 index 0000000..f4e9187 --- /dev/null +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/IScarFullScreenAd.java @@ -0,0 +1,7 @@ +package com.unity3d.scar.adapter.common.scarads; + +import android.app.Activity; + +public interface IScarFullScreenAd extends IScarAd { + void show(Activity activity); +} diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/UnityAdFormat.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/UnityAdFormat.java new file mode 100644 index 0000000..93e1115 --- /dev/null +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/scarads/UnityAdFormat.java @@ -0,0 +1,7 @@ +package com.unity3d.scar.adapter.common.scarads; + +public enum UnityAdFormat { + INTERSTITIAL, + REWARDED, + BANNER +} diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/ISignalsCollector.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/ISignalsCollector.java index 8572e33..c5a602c 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/ISignalsCollector.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/ISignalsCollector.java @@ -3,13 +3,14 @@ package com.unity3d.scar.adapter.common.signals; import android.content.Context; import com.unity3d.scar.adapter.common.DispatchGroup; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; public interface ISignalsCollector { - void getSCARSignals(Context context, String[] interstitialList, String[] rewardedList, + void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, ISignalCollectionListener signalCompletionListener); - void getSCARSignal(Context context, String placementId, boolean isInterstitial, - DispatchGroup dispatchGroup, SignalsResult signalsResult); - void getSCARSignal(Context context, boolean isInterstitial, final DispatchGroup dispatchGroup, - final SignalsResult signalsResult) ; - void getSCARBiddingSignals(Context context, ISignalCollectionListener signalCompletionListener); + void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, final DispatchGroup dispatchGroup, + final SignalsResult signalsResult); + void getSCARSignalForHB(Context context, UnityAdFormat adFormat, final DispatchGroup dispatchGroup, + final SignalsResult signalsResult); + void getSCARBiddingSignals(Context context, boolean isBannerEnabled, ISignalCollectionListener signalCompletionListener); } diff --git a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/SignalsCollectorBase.java b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/SignalsCollectorBase.java index ac85eb4..985c4d0 100644 --- a/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/SignalsCollectorBase.java +++ b/unity-scaradapter-common/src/main/java/com/unity3d/scar/adapter/common/signals/SignalsCollectorBase.java @@ -4,6 +4,7 @@ import android.content.Context; import com.unity3d.scar.adapter.common.DispatchGroup; +import com.unity3d.scar.adapter.common.scarads.UnityAdFormat; import org.json.JSONObject; import java.util.Map; @@ -12,38 +13,37 @@ public abstract class SignalsCollectorBase implements ISignalsCollector { public static final String SCAR_RV_SIGNAL = "gmaScarBiddingRewardedSignal"; public static final String SCAR_INT_SIGNAL = "gmaScarBiddingInterstitialSignal"; + public static final String SCAR_BAN_SIGNAL = "gmaScarBiddingBannerSignal"; public SignalsCollectorBase() {} @Override - public void getSCARSignals(Context context, String[] interstitialList, String[] rewardedList, + public void getSCARSignal(Context context, String placementId, UnityAdFormat adFormat, ISignalCollectionListener signalCompletionListener) { DispatchGroup dispatchGroup = new DispatchGroup(); SignalsResult signalsResult = new SignalsResult(); - for (String interstitialId : interstitialList) { - dispatchGroup.enter(); - getSCARSignal(context, interstitialId, true, dispatchGroup, signalsResult); - } - - for (String rewardedId : rewardedList) { - dispatchGroup.enter(); - getSCARSignal(context, rewardedId, false, dispatchGroup, signalsResult); - } + dispatchGroup.enter(); + getSCARSignal(context, placementId, adFormat, dispatchGroup, signalsResult); dispatchGroup.notify(new GMAScarDispatchCompleted(signalCompletionListener, signalsResult)); } @Override - public void getSCARBiddingSignals(Context context, ISignalCollectionListener signalCompletionListener) { + public void getSCARBiddingSignals(Context context, boolean isBannerEnabled, ISignalCollectionListener signalCompletionListener) { DispatchGroup dispatchGroup = new DispatchGroup(); SignalsResult signalsResult = new SignalsResult(); dispatchGroup.enter(); - getSCARSignal(context, true, dispatchGroup, signalsResult); + getSCARSignalForHB(context, UnityAdFormat.INTERSTITIAL, dispatchGroup, signalsResult); dispatchGroup.enter(); - getSCARSignal(context, false, dispatchGroup, signalsResult); + getSCARSignalForHB(context, UnityAdFormat.REWARDED, dispatchGroup, signalsResult); + + if (isBannerEnabled) { + dispatchGroup.enter(); + getSCARSignalForHB(context, UnityAdFormat.BANNER, dispatchGroup, signalsResult); + } dispatchGroup.notify(new GMAScarDispatchCompleted(signalCompletionListener, signalsResult)); } @@ -79,4 +79,16 @@ public abstract class SignalsCollectorBase implements ISignalsCollector { } } } + + public String getAdKey(UnityAdFormat adFormat) { + switch (adFormat) { + case BANNER: + return SCAR_BAN_SIGNAL; + case INTERSTITIAL: + return SCAR_INT_SIGNAL; + case REWARDED: + return SCAR_RV_SIGNAL; + } + return ""; + } }