diff --git a/ThirdPartyAdapters/yandex/.gitignore b/ThirdPartyAdapters/yandex/.gitignore new file mode 100644 index 000000000..916b2457a --- /dev/null +++ b/ThirdPartyAdapters/yandex/.gitignore @@ -0,0 +1,7 @@ +*.iml +.gradle +/local.properties +/.idea +.DS_Store +/build +/captures \ No newline at end of file diff --git a/ThirdPartyAdapters/yandex/CHANGELOG.md b/ThirdPartyAdapters/yandex/CHANGELOG.md new file mode 100644 index 000000000..1c1c57a84 --- /dev/null +++ b/ThirdPartyAdapters/yandex/CHANGELOG.md @@ -0,0 +1,8 @@ +# Change Log +All notable changes to Yandex Adapter for AdMob Mediation will be documented in this file. + +## Version 6.0.1.0 + +#### Updated +* Added support for Google Mobile Ads SDK 22.2.0 +* Added support for Yandex Mobile Ads SDK version to 6.0.1 \ No newline at end of file diff --git a/ThirdPartyAdapters/yandex/build.gradle b/ThirdPartyAdapters/yandex/build.gradle new file mode 100644 index 000000000..042d2fe9c --- /dev/null +++ b/ThirdPartyAdapters/yandex/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + kotlinVersion = '1.8.0' + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/ThirdPartyAdapters/yandex/gradle.properties b/ThirdPartyAdapters/yandex/gradle.properties new file mode 100644 index 000000000..d015431a8 --- /dev/null +++ b/ThirdPartyAdapters/yandex/gradle.properties @@ -0,0 +1,2 @@ +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.jar b/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..13372aef5 Binary files /dev/null and b/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.jar differ diff --git a/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.properties b/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..235737bec --- /dev/null +++ b/ThirdPartyAdapters/yandex/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Sep 25 16:33:41 PDT 2023 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/ThirdPartyAdapters/yandex/gradlew b/ThirdPartyAdapters/yandex/gradlew new file mode 100755 index 000000000..9d82f7891 --- /dev/null +++ b/ThirdPartyAdapters/yandex/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/ThirdPartyAdapters/yandex/gradlew.bat b/ThirdPartyAdapters/yandex/gradlew.bat new file mode 100644 index 000000000..8a0b282aa --- /dev/null +++ b/ThirdPartyAdapters/yandex/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ThirdPartyAdapters/yandex/settings.gradle b/ThirdPartyAdapters/yandex/settings.gradle new file mode 100644 index 000000000..b6b44dc7b --- /dev/null +++ b/ThirdPartyAdapters/yandex/settings.gradle @@ -0,0 +1 @@ +include ':yandex' \ No newline at end of file diff --git a/ThirdPartyAdapters/yandex/yandex/build.gradle b/ThirdPartyAdapters/yandex/yandex/build.gradle new file mode 100644 index 000000000..344a9818c --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/build.gradle @@ -0,0 +1,145 @@ +plugins { + id 'com.android.library' + id 'maven-publish' + id 'org.jetbrains.kotlin.android' +} + +/** + * Extra properties used by the project. + */ +ext { + // String property to store the proper name of the mediation network adapter. + adapterName = "Yandex" + // String property to store version name. + stringVersion = "6.0.1.0" + // String property to store group id. + stringGroupId = "com.google.ads.mediation" +} + +kotlin { + jvmToolchain(11) +} + +android { + compileSdkVersion 31 + defaultConfig { + minSdkVersion 16 + targetSdkVersion 31 + versionCode 6000100 + versionName stringVersion + buildConfigField('String', 'ADAPTER_VERSION', "\"${stringVersion}\"") + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation 'com.yandex.android:mobileads:6.0.1' + implementation 'com.yandex.android:mobmetricalib:5.0.0' + implementation 'androidx.annotation:annotation:1.1.0' + implementation 'com.google.android.gms:play-services-ads:22.2.0' +} + +/** + * Jar task to make a sources jar. + */ +task sourcesJar(type: Jar) { + archiveClassifier = 'sources' + from android.sourceSets.main.java.srcDirs +} + +/** + * Publish closure consisting of maven publications. + */ +publishing { + publications { + adapterPublications(MavenPublication) { + groupId = stringGroupId + artifactId = project.name + version = stringVersion + + // Add the aar artifact to publication. + artifact("$buildDir/outputs/aar/${project.name}-release.aar") { + builtBy build + } + + // Add the sources jar artifact to the publication. + artifact(sourcesJar) + + // Generate the pom file. + pom { + name = "${adapterName} mediation adapter for the Google Mobile Ads SDK" + description = "The ${adapterName} mediation adapter is a library that handles " + + "communication between the Google Mobile Ads SDK and the ${adapterName} " + + "SDK. It enables you to load ads from ${adapterName} using the mediation " + + "feature in the Google Mobile Ads SDK." + url = "https://developers.google.com/admob/android/mediation/${project.name}" + licenses { + license { + name = 'Apache-2.0' + url = 'https://github.com/googleads/googleads-mobile-android-mediation/blob/master/LICENSE' + distribution = 'repo' + } + } + } + + // Add the required dependencies to the generated `pom.xml` file. + pom.withXml { + final dependenciesNode = asNode().appendNode('dependencies') + configurations.implementation.allDependencies.each { + // Exclude filetree dependencies. + if (it.name != 'unspecified') { + println("Adding dependency: " + it.group + ":" + it.name + ":" + it.version) + + final dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + if (it.artifacts.size() > 0) { + dependencyNode.appendNode('type', it.artifacts[0].type) + } + } + } + } + } + } +} + +/** + * Copy artifacts into a single directory for redistribution. + */ +task copyArtifactsForDistribution(type: Copy) { + from "$buildDir/outputs/aar/${project.name}-release.aar", + "$buildDir/libs/${project.name}-sources.jar", + "$buildDir/publications/adapterPublications/pom-default.xml" + into "$buildDir/distribution" +} + +/** + * Create `zip` file for redistribution under `build/distribution` directory. + */ +task packageDistribution(type: Zip) { + from("$buildDir/distribution") { + rename("${project.name}-release.aar", "${project.name}-${stringVersion}.aar") + rename("${project.name}-sources.jar", "${project.name}-${stringVersion}-sources.jar") + rename("pom-default.xml", "${project.name}-${stringVersion}.pom") + } + + archiveFileName = "${adapterName}AndroidAdapter-${stringVersion}.zip" + destinationDirectory = file("${rootProject.projectDir}/build/distribution") +} + +build.dependsOn clean +build.mustRunAfter clean +copyArtifactsForDistribution.dependsOn(build, sourcesJar, generatePomFileForAdapterPublicationsPublication) +packageDistribution.dependsOn copyArtifactsForDistribution \ No newline at end of file diff --git a/ThirdPartyAdapters/yandex/yandex/proguard-rules.pro b/ThirdPartyAdapters/yandex/yandex/proguard-rules.pro new file mode 100644 index 000000000..d6d833d0c --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/sbagadi/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# 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/ThirdPartyAdapters/yandex/yandex/src/main/AndroidManifest.xml b/ThirdPartyAdapters/yandex/yandex/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8dc133555 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/YandexAdapter.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/YandexAdapter.kt new file mode 100644 index 000000000..49aef0e93 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/YandexAdapter.kt @@ -0,0 +1,211 @@ +package com.google.ads.mediation.yandex + +import android.content.Context +import com.google.ads.mediation.yandex.banner.BannerAdViewWrapper +import com.google.ads.mediation.yandex.banner.MediationAdEventListener +import com.google.ads.mediation.yandex.banner.YandexAdSizeProvider +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.ads.mediation.yandex.base.AdMobServerExtrasParserProvider +import com.google.ads.mediation.yandex.base.AdRequestMapper +import com.google.ads.mediation.yandex.base.MediationAdRequestWrapper +import com.google.ads.mediation.yandex.base.YandexAdRequestCreator +import com.google.ads.mediation.yandex.base.YandexErrorConverter +import com.google.ads.mediation.yandex.base.YandexVersionInfoProvider +import com.google.ads.mediation.yandex.interstitial.InterstitialAdLoadListenerFactory +import com.google.ads.mediation.yandex.interstitial.InterstitialLoaderFactory +import com.google.ads.mediation.yandex.nativeads.YandexNativeAdLoadListener +import com.google.ads.mediation.yandex.rewarded.RewardedAdLoadListenerFactory +import com.google.ads.mediation.yandex.rewarded.RewardedLoaderFactory +import com.google.android.gms.ads.mediation.Adapter +import com.google.android.gms.ads.mediation.InitializationCompleteCallback +import com.google.android.gms.ads.mediation.MediationAdLoadCallback +import com.google.android.gms.ads.mediation.MediationBannerAd +import com.google.android.gms.ads.mediation.MediationBannerAdCallback +import com.google.android.gms.ads.mediation.MediationBannerAdConfiguration +import com.google.android.gms.ads.mediation.MediationConfiguration +import com.google.android.gms.ads.mediation.MediationInterstitialAd +import com.google.android.gms.ads.mediation.MediationInterstitialAdCallback +import com.google.android.gms.ads.mediation.MediationInterstitialAdConfiguration +import com.google.android.gms.ads.mediation.MediationNativeAdCallback +import com.google.android.gms.ads.mediation.MediationNativeAdConfiguration +import com.google.android.gms.ads.mediation.MediationRewardedAd +import com.google.android.gms.ads.mediation.MediationRewardedAdCallback +import com.google.android.gms.ads.mediation.MediationRewardedAdConfiguration +import com.google.android.gms.ads.mediation.UnifiedNativeAdMapper +import com.yandex.mobile.ads.banner.BannerAdView +import com.yandex.mobile.ads.common.MobileAds +import com.yandex.mobile.ads.nativeads.NativeAdLoader + +internal class YandexAdapter @JvmOverloads constructor( + private val yandexAdRequestCreator: YandexAdRequestCreator = YandexAdRequestCreator(), + private val adRequestMapper: AdRequestMapper = AdRequestMapper(), + private val interstitialLoaderFactory: InterstitialLoaderFactory = InterstitialLoaderFactory(), + private val rewardedLoaderFactory: RewardedLoaderFactory = RewardedLoaderFactory(), + private val interstitialAdLoadListenerFactory: InterstitialAdLoadListenerFactory = + InterstitialAdLoadListenerFactory(), + private val rewardedAdLoadListenerFactory: RewardedAdLoadListenerFactory = RewardedAdLoadListenerFactory(), + private val adMobAdErrorCreator: AdMobAdErrorCreator = AdMobAdErrorCreator(), + private val yandexErrorConverter: YandexErrorConverter = YandexErrorConverter(), + private val adMobServerExtrasParserProvider: AdMobServerExtrasParserProvider = AdMobServerExtrasParserProvider(), + private val yandexVersionInfoProvider: YandexVersionInfoProvider = YandexVersionInfoProvider(), + private val yandexAdSizeProvider: YandexAdSizeProvider = YandexAdSizeProvider() +) : Adapter() { + + override fun getSDKVersionInfo() = yandexVersionInfoProvider.getSdkVersionInfo() + + override fun getVersionInfo() = yandexVersionInfoProvider.adapterVersionInfo + + override fun initialize( + context: Context, + initializationCompleteCallback: InitializationCompleteCallback, + list: MutableList + ) { + MobileAds.initialize(context) { + initializationCompleteCallback.onInitializationSucceeded() + } + } + + override fun loadBannerAd( + mediationBannerAdConfiguration: MediationBannerAdConfiguration, + callback: MediationAdLoadCallback + ) { + try { + val serverExtrasParser = adMobServerExtrasParserProvider.getServerExtrasParser( + mediationBannerAdConfiguration.serverParameters, + CUSTOM_EVENT_SERVER_PARAMETER_FIELD + ) + val adRequestWrapper = MediationAdRequestWrapper(mediationBannerAdConfiguration) + val adRequest = yandexAdRequestCreator.createAdRequest(adRequestWrapper) + val context = mediationBannerAdConfiguration.context + + val adUnitId = serverExtrasParser.parseAdUnitId() + if (adUnitId.isNullOrEmpty() == false) { + val bannerAdView = BannerAdView(context) + val adViewWrapper = BannerAdViewWrapper(bannerAdView) + + val adSize = yandexAdSizeProvider.getAdSize( + context, serverExtrasParser, mediationBannerAdConfiguration.adSize + ) + val bannerAdEventListener = MediationAdEventListener(adViewWrapper, callback, adMobAdErrorCreator) + bannerAdView.apply { + adSize?.let { setAdSize(it) } + setAdUnitId(adUnitId) + setBannerAdEventListener(bannerAdEventListener) + + loadAd(adRequest) + } + } else { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(ERROR_MESSAGE_INVALID_REQUEST) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } catch (t: Throwable) { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(t.message) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } + + override fun loadNativeAd( + mediationNativeAdConfiguration: MediationNativeAdConfiguration, + callback: MediationAdLoadCallback + ) { + try { + val serverExtrasParser = adMobServerExtrasParserProvider.getServerExtrasParser( + mediationNativeAdConfiguration.serverParameters, + CUSTOM_EVENT_SERVER_PARAMETER_FIELD + ) + val adRequestWrapper = MediationAdRequestWrapper(mediationNativeAdConfiguration) + val context = mediationNativeAdConfiguration.context + + val adUnitId = serverExtrasParser.parseAdUnitId() + if (adUnitId.isNullOrEmpty() == false) { + val nativeAdLoader = NativeAdLoader(context) + val nativeAdLoadListener = YandexNativeAdLoadListener( + context, + callback, + mediationNativeAdConfiguration.mediationExtras + ) + + val configuration = + yandexAdRequestCreator.createNativeAdRequestConfiguration(adRequestWrapper, adUnitId) + + nativeAdLoader.apply { + setNativeAdLoadListener(nativeAdLoadListener) + loadAd(configuration) + } + } else { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(ERROR_MESSAGE_INVALID_REQUEST) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } catch (t: Throwable) { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(t.message) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } + + override fun loadInterstitialAd( + mediationInterstitialAdConfiguration: MediationInterstitialAdConfiguration, + callback: MediationAdLoadCallback + ) { + try { + val serverExtrasParser = adMobServerExtrasParserProvider.getServerExtrasParser( + mediationInterstitialAdConfiguration.serverParameters, + CUSTOM_EVENT_SERVER_PARAMETER_FIELD + ) + val configuration = adRequestMapper.toAdRequestConfiguration(serverExtrasParser) + + if (configuration != null) { + val context = mediationInterstitialAdConfiguration.context + val interstitialAdLoadListener = interstitialAdLoadListenerFactory.create( + callback, adMobAdErrorCreator + ) + + with(interstitialLoaderFactory.create(context)) { + setAdLoadListener(interstitialAdLoadListener) + loadAd(configuration) + } + } else { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(ERROR_MESSAGE_INVALID_REQUEST) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } catch (t: Throwable) { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(t.message) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } + + override fun loadRewardedAd( + mediationRewardedAdConfiguration: MediationRewardedAdConfiguration, + callback: MediationAdLoadCallback + ) { + try { + val serverExtrasParser = adMobServerExtrasParserProvider.getServerExtrasParser( + mediationRewardedAdConfiguration.serverParameters, + CUSTOM_EVENT_SERVER_PARAMETER_FIELD + ) + val configuration = adRequestMapper.toAdRequestConfiguration(serverExtrasParser) + if (configuration != null) { + val context = mediationRewardedAdConfiguration.context + val rewardedAdLoadListener = rewardedAdLoadListenerFactory.create( + callback, adMobAdErrorCreator + ) + + with(rewardedLoaderFactory.create(context)) { + setAdLoadListener(rewardedAdLoadListener) + loadAd(configuration) + } + } else { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(ERROR_MESSAGE_INVALID_REQUEST) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } catch (t: Throwable) { + val adRequestError = yandexErrorConverter.convertToInvalidRequestError(t.message) + callback.onFailure(adMobAdErrorCreator.createLoadAdError(adRequestError)) + } + } + + companion object { + + private const val CUSTOM_EVENT_SERVER_PARAMETER_FIELD = "parameter" + private const val ERROR_MESSAGE_INVALID_REQUEST = "Invalid request" + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/BannerAdViewWrapper.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/BannerAdViewWrapper.kt new file mode 100644 index 000000000..fa74d2bb8 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/BannerAdViewWrapper.kt @@ -0,0 +1,11 @@ +package com.google.ads.mediation.yandex.banner + +import android.view.View +import com.google.android.gms.ads.mediation.MediationBannerAd +import com.yandex.mobile.ads.banner.BannerAdView + +class BannerAdViewWrapper(private val bannerAdView: BannerAdView) : MediationBannerAd { + override fun getView(): View { + return bannerAdView.rootView + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/MediationAdEventListener.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/MediationAdEventListener.kt new file mode 100644 index 000000000..62af76d5c --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/MediationAdEventListener.kt @@ -0,0 +1,41 @@ +package com.google.ads.mediation.yandex.banner + +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.mediation.MediationAdLoadCallback +import com.google.android.gms.ads.mediation.MediationBannerAd +import com.google.android.gms.ads.mediation.MediationBannerAdCallback +import com.yandex.mobile.ads.banner.BannerAdEventListener +import com.yandex.mobile.ads.common.AdRequestError +import com.yandex.mobile.ads.common.ImpressionData + +internal class MediationAdEventListener( + private val mediationBannerAd: MediationBannerAd, + private val mediationAdLoadCallback: MediationAdLoadCallback, + private val adMobAdErrorCreator: AdMobAdErrorCreator +) : BannerAdEventListener { + + private var bannerAdCallback: MediationBannerAdCallback? = null + + override fun onImpression(impressionData: ImpressionData?) = Unit + + override fun onAdLoaded() { + bannerAdCallback = mediationAdLoadCallback.onSuccess(mediationBannerAd) + } + + override fun onAdFailedToLoad(adRequestError: AdRequestError) { + val adError = adMobAdErrorCreator.createLoadAdError(adRequestError) + mediationAdLoadCallback.onFailure(adError) + } + + override fun onAdClicked() { + bannerAdCallback?.reportAdClicked() + } + + override fun onLeftApplication() { + bannerAdCallback?.onAdLeftApplication() + } + + override fun onReturnedToApplication() { + bannerAdCallback?.onAdClosed() + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/YandexAdSizeProvider.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/YandexAdSizeProvider.kt new file mode 100644 index 000000000..e386d9bd0 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/banner/YandexAdSizeProvider.kt @@ -0,0 +1,29 @@ +package com.google.ads.mediation.yandex.banner + +import android.content.Context +import com.google.ads.mediation.yandex.base.AdMobServerExtrasParser +import com.yandex.mobile.ads.banner.BannerAdSize +import com.google.android.gms.ads.AdSize as GoogleAdSize + +internal class YandexAdSizeProvider { + + fun getAdSize( + context: Context, + serverExtrasParser: AdMobServerExtrasParser, + adMobAdSize: GoogleAdSize? + ): BannerAdSize? { + var adSize = serverExtrasParser.parseAdSize(context) + + if (adSize == null) { + adSize = getAdSizeFromAdMobAdSize(context, adMobAdSize) + } + + return adSize + } + + private fun getAdSizeFromAdMobAdSize(context: Context, adMobAdSize: GoogleAdSize?): BannerAdSize? { + return adMobAdSize?.let { + BannerAdSize.fixedSize(context, adMobAdSize.width, adMobAdSize.height) + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdErrorCreator.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdErrorCreator.kt new file mode 100644 index 000000000..e353c3da9 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdErrorCreator.kt @@ -0,0 +1,51 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.AdRequest +import com.yandex.mobile.ads.common.AdError +import com.yandex.mobile.ads.common.AdRequestError +import com.google.android.gms.ads.AdError as AdMobError + +class AdMobAdErrorCreator { + + private val yandexErrorConverter: YandexErrorConverter = YandexErrorConverter() + + fun createLoadAdError(code: Int): AdMobError { + return AdMobError(code, FAILED_TO_LOAD_AD_MESSAGE, YANDEX_MOBILE_ADS_DOMAIN) + } + + fun createLoadAdError(adRequestError: AdRequestError?): AdMobError { + return if (adRequestError != null) { + val code = yandexErrorConverter.convertToAdMobErrorCode(adRequestError) + AdMobError(code, adRequestError.description, YANDEX_MOBILE_ADS_DOMAIN) + } else { + AdMobError( + AdRequest.ERROR_CODE_INVALID_REQUEST, + FAILED_TO_LOAD_AD_MESSAGE, + YANDEX_MOBILE_ADS_DOMAIN, + null + ) + } + } + + fun createRequiresActivityError() = AdMobError( + yandexErrorConverter.convertToAdMobErrorCode(null), + REQUIRES_ACTIVITY_MESSAGE, + YANDEX_MOBILE_ADS_DOMAIN + ) + + fun convertToAdMobError(adError: AdError): AdMobError { + return AdMobError( + yandexErrorConverter.convertToAdMobErrorCode(null), + adError.description, + YANDEX_MOBILE_ADS_DOMAIN + ) + } + + companion object { + + private const val REQUIRES_ACTIVITY_MESSAGE = + "Yandex Mobile Ads SDK requires an Activity context to show an ad." + private const val FAILED_TO_LOAD_AD_MESSAGE = "Failed to load ad" + private const val YANDEX_MOBILE_ADS_DOMAIN = "com.yandex.mobile.ads" + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdRequestParametersProvider.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdRequestParametersProvider.kt new file mode 100644 index 000000000..865d108fb --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobAdRequestParametersProvider.kt @@ -0,0 +1,41 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.MobileAds +import com.google.ads.mediation.yandex.BuildConfig + +internal class AdMobAdRequestParametersProvider { + + private val adapterVersion: String + get() = BuildConfig.ADAPTER_VERSION + + fun getAdRequestParameters(): Map { + val adRequestParameters: MutableMap = HashMap() + adRequestParameters[ADAPTER_NETWORK_NAME_KEY] = ADAPTER_NETWORK_NAME + appendVersionParameters(adRequestParameters) + + return adRequestParameters + } + + private fun getAdMobSdkVersion(): String? { + return try { + MobileAds.getVersion().toString() + } catch (ignored: Throwable) { + null + } + } + + private fun appendVersionParameters(adRequestParameters: MutableMap) { + val adMobSdkVersion = getAdMobSdkVersion() + if (adMobSdkVersion != null) { + adRequestParameters[ADAPTER_NETWORK_SDK_VERSION_KEY] = adMobSdkVersion + } + adRequestParameters[ADAPTER_VERSION_KEY] = adapterVersion + } + + companion object { + private const val ADAPTER_VERSION_KEY = "adapter_version" + private const val ADAPTER_NETWORK_NAME_KEY = "adapter_network_name" + private const val ADAPTER_NETWORK_SDK_VERSION_KEY = "adapter_network_sdk_version" + private const val ADAPTER_NETWORK_NAME = "admob" + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParser.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParser.kt new file mode 100644 index 000000000..f5c025bdc --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParser.kt @@ -0,0 +1,53 @@ +package com.google.ads.mediation.yandex.base + +import android.content.Context +import com.yandex.mobile.ads.banner.BannerAdSize +import org.json.JSONObject + +class AdMobServerExtrasParser(private val serverExtras: JSONObject) { + + fun parseAdUnitId(): String? { + var adUnitId = serverExtras.optString(AD_UNIT_ID) + if (adUnitId.isNullOrEmpty()) { + adUnitId = serverExtras.optString(BLOCK_ID) + } + + return adUnitId + } + + fun parseShouldOpenLinksInApp(): Boolean { + return serverExtras.optBoolean(OPEN_LINKS_IN_APP) + } + + fun parseAdSize(context: Context): BannerAdSize? { + val serverAdWidth = parseInteger(AD_WIDTH_KEY) + val serverAdHeight = parseInteger(AD_HEIGHT_KEY) + return if (serverAdWidth != null && serverAdHeight != null) { + BannerAdSize.fixedSize(context, serverAdWidth, serverAdHeight) + } else { + null + } + } + + private fun parseInteger(key: String): Int? { + val numberExtra = serverExtras.optString(key) + var number: Int? = null + + try { + if (numberExtra != null) { + number = numberExtra.toInt() + } + } catch (ignored: NumberFormatException) { + } + + return number + } + + companion object { + private const val BLOCK_ID = "blockID" + private const val AD_UNIT_ID = "adUnitId" + private const val AD_WIDTH_KEY = "adWidth" + private const val AD_HEIGHT_KEY = "adHeight" + private const val OPEN_LINKS_IN_APP = "openLinksInApp" + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParserProvider.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParserProvider.kt new file mode 100644 index 000000000..ad881b704 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdMobServerExtrasParserProvider.kt @@ -0,0 +1,26 @@ +package com.google.ads.mediation.yandex.base + +import android.os.Bundle +import org.json.JSONException +import org.json.JSONObject + +class AdMobServerExtrasParserProvider { + + @Throws(JSONException::class) + fun getServerExtrasParser(serverParameter: String?): AdMobServerExtrasParser { + if (serverParameter == null) { + throw JSONException("Server parameter must be not null") + } + val serverExtras = JSONObject(serverParameter) + return AdMobServerExtrasParser(serverExtras) + } + + @Throws(JSONException::class) + fun getServerExtrasParser( + serverParameters: Bundle, + parametersKey: String? + ): AdMobServerExtrasParser { + val serverParameter = serverParameters.getString(parametersKey) + return getServerExtrasParser(serverParameter) + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdRequestMapper.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdRequestMapper.kt new file mode 100644 index 000000000..1323c0351 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/AdRequestMapper.kt @@ -0,0 +1,19 @@ +package com.google.ads.mediation.yandex.base + +import com.yandex.mobile.ads.common.AdRequestConfiguration + +internal class AdRequestMapper( + private val adRequestParametersProvider: AdMobAdRequestParametersProvider = AdMobAdRequestParametersProvider() +) { + + fun toAdRequestConfiguration(parser: AdMobServerExtrasParser): AdRequestConfiguration? { + val adUnitId = parser.parseAdUnitId() + ?.takeIf { it.isNotBlank() } + ?: return null + + val params = adRequestParametersProvider.getAdRequestParameters() + return AdRequestConfiguration.Builder(adUnitId) + .setParameters(params) + .build() + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/MediationAdRequestWrapper.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/MediationAdRequestWrapper.kt new file mode 100644 index 000000000..ff014cf17 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/MediationAdRequestWrapper.kt @@ -0,0 +1,13 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.mediation.MediationAdConfiguration + +class MediationAdRequestWrapper( + private val mediationBannerAdConfiguration: MediationAdConfiguration +) { + val keywords: Set? + get() = mediationBannerAdConfiguration.mediationExtras.keySet() + + val taggedForChildDirectedTreatment: Int + get() = mediationBannerAdConfiguration.taggedForChildDirectedTreatment() +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexAdRequestCreator.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexAdRequestCreator.kt new file mode 100644 index 000000000..361d3f1f0 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexAdRequestCreator.kt @@ -0,0 +1,62 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.RequestConfiguration +import com.yandex.mobile.ads.common.AdRequest +import com.yandex.mobile.ads.common.MobileAds +import com.yandex.mobile.ads.nativeads.NativeAdRequestConfiguration + +class YandexAdRequestCreator { + + private val adRequestParametersProvider: AdMobAdRequestParametersProvider = AdMobAdRequestParametersProvider() + + fun createAdRequest(mediationAdRequest: MediationAdRequestWrapper): AdRequest { + val adRequestParameters = adRequestParametersProvider.getAdRequestParameters() + val adRequestBuilder = AdRequest.Builder() + adRequestBuilder.setParameters(adRequestParameters) + + setAgeRestrictedUser(mediationAdRequest) + + val mediationKeywords = mediationAdRequest.keywords + if (mediationKeywords != null) { + val keywords = ArrayList(mediationKeywords) + adRequestBuilder.setContextTags(keywords) + } + + return adRequestBuilder.build() + } + + fun createAdRequest(): AdRequest { + val adRequestParameters = adRequestParametersProvider.getAdRequestParameters() + val adRequestBuilder = AdRequest.Builder() + adRequestBuilder.setParameters(adRequestParameters) + + return adRequestBuilder.build() + } + + fun createNativeAdRequestConfiguration( + adRequestWrapper: MediationAdRequestWrapper, + adUnitId: String + ): NativeAdRequestConfiguration { + val adRequestParameters = adRequestParametersProvider.getAdRequestParameters() + val adRequestConfigurationBuilder = NativeAdRequestConfiguration.Builder(adUnitId) + adRequestConfigurationBuilder.setParameters(adRequestParameters) + + val mediationKeywords = adRequestWrapper.keywords + if (mediationKeywords != null) { + val keywords = ArrayList(mediationKeywords) + adRequestConfigurationBuilder.setContextTags(keywords) + } + + return adRequestConfigurationBuilder.build() + } + + private fun setAgeRestrictedUser(adRequestWrapper: MediationAdRequestWrapper) { + val tagForChildDirectedTreatment = adRequestWrapper.taggedForChildDirectedTreatment + + if (tagForChildDirectedTreatment == RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE) { + MobileAds.setAgeRestrictedUser(true) + } else if (tagForChildDirectedTreatment == RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_FALSE) { + MobileAds.setAgeRestrictedUser(false) + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexErrorConverter.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexErrorConverter.kt new file mode 100644 index 000000000..db6d9ab1c --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexErrorConverter.kt @@ -0,0 +1,28 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.AdRequest +import com.yandex.mobile.ads.common.AdRequestError + +class YandexErrorConverter { + + fun convertToAdMobErrorCode(adRequestError: AdRequestError?): Int { + + return when (adRequestError?.code) { + + AdRequestError.Code.INTERNAL_ERROR, + AdRequestError.Code.SYSTEM_ERROR -> AdRequest.ERROR_CODE_INTERNAL_ERROR + + AdRequestError.Code.INVALID_REQUEST -> AdRequest.ERROR_CODE_INVALID_REQUEST + + AdRequestError.Code.NETWORK_ERROR -> AdRequest.ERROR_CODE_NETWORK_ERROR + + AdRequestError.Code.NO_FILL -> AdRequest.ERROR_CODE_NO_FILL + + else -> AdRequest.ERROR_CODE_INTERNAL_ERROR + } + } + + fun convertToInvalidRequestError(message: String?): AdRequestError { + return AdRequestError(AdRequestError.Code.INVALID_REQUEST, message) + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexVersionInfoProvider.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexVersionInfoProvider.kt new file mode 100644 index 000000000..338f24a37 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/base/YandexVersionInfoProvider.kt @@ -0,0 +1,48 @@ +package com.google.ads.mediation.yandex.base + +import com.google.android.gms.ads.VersionInfo +import com.google.ads.mediation.yandex.BuildConfig; +import com.yandex.mobile.ads.common.MobileAds + +class YandexVersionInfoProvider { + + val adapterVersion: String + get() = BuildConfig.ADAPTER_VERSION + + val adapterVersionInfo: VersionInfo + get() = createVersionInfo(adapterVersion) + + fun getSdkVersionInfo(): VersionInfo { + val sdkVersionString = MobileAds.getLibraryVersion() + val normalizedSdkVersionString = sdkVersionString ?: "" + return createVersionInfo(normalizedSdkVersionString) + } + + private fun createVersionInfo(version: String): VersionInfo { + val splitVersion = version.split(VERSION_SPLIT_REGEX).toTypedArray() + + val numbers = splitVersion.map { parseInt(it) } + + val versionInfo: VersionInfo = if (numbers.size >= SEMANTIC_VERSION_LENGTH) { + VersionInfo(numbers[0], numbers[1], numbers[2]) + } else { + VersionInfo(0, 0, 0) + } + + return versionInfo + } + + private fun parseInt(value: String): Int { + return try { + value.toInt() + } catch (e: NumberFormatException) { + DEFAULT_PARSE_VALUE + } + } + + companion object { + private const val SEMANTIC_VERSION_LENGTH = 3 + private const val DEFAULT_PARSE_VALUE = 0 + private const val VERSION_SPLIT_REGEX = "." + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialAdLoadListenerFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialAdLoadListenerFactory.kt new file mode 100644 index 000000000..0192688af --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialAdLoadListenerFactory.kt @@ -0,0 +1,44 @@ +package com.google.ads.mediation.yandex.interstitial + +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.mediation.MediationAdLoadCallback +import com.google.android.gms.ads.mediation.MediationInterstitialAd +import com.google.android.gms.ads.mediation.MediationInterstitialAdCallback +import com.yandex.mobile.ads.common.AdRequestError +import com.yandex.mobile.ads.interstitial.InterstitialAd +import com.yandex.mobile.ads.interstitial.InterstitialAdLoadListener + +internal class InterstitialAdLoadListenerFactory { + + fun create( + callback: MediationAdLoadCallback, + adMobAdErrorCreator: AdMobAdErrorCreator, + mediationInterstitialAdFactory: MediationInterstitialAdFactory = MediationInterstitialAdFactory() + ) = object : InterstitialAdLoadListener { + + var interstitialAdCallback: MediationInterstitialAdCallback? = null + + override fun onAdLoaded(loadedAd: InterstitialAd) { + val mediationInterstitialAd = mediationInterstitialAdFactory.create( + loadedAd, ::onContextIsNotActivityError + ) + interstitialAdCallback = callback.onSuccess(mediationInterstitialAd).also { interstitialAdCallback -> + val mediationInterstitialAdEventListener = MediationInterstitialAdEventListener( + interstitialAdCallback, + adMobAdErrorCreator + ) + loadedAd.setAdEventListener(mediationInterstitialAdEventListener) + } + } + + override fun onAdFailedToLoad(error: AdRequestError) { + val adError = adMobAdErrorCreator.createLoadAdError(error) + callback.onFailure(adError) + } + + private fun onContextIsNotActivityError() { + val error = adMobAdErrorCreator.createRequiresActivityError() + interstitialAdCallback?.onAdFailedToShow(error) + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialLoaderFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialLoaderFactory.kt new file mode 100644 index 000000000..a83051686 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/InterstitialLoaderFactory.kt @@ -0,0 +1,8 @@ +package com.google.ads.mediation.yandex.interstitial + +import android.content.Context +import com.yandex.mobile.ads.interstitial.InterstitialAdLoader + +internal class InterstitialLoaderFactory { + fun create(context: Context) = InterstitialAdLoader(context) +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdEventListener.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdEventListener.kt new file mode 100644 index 000000000..1f8b3fd92 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdEventListener.kt @@ -0,0 +1,33 @@ +package com.google.ads.mediation.yandex.interstitial + +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.mediation.MediationInterstitialAdCallback +import com.yandex.mobile.ads.common.AdError +import com.yandex.mobile.ads.common.ImpressionData +import com.yandex.mobile.ads.interstitial.InterstitialAdEventListener + +internal class MediationInterstitialAdEventListener( + private val interstitialAdCallback: MediationInterstitialAdCallback, + private val errorConverter: AdMobAdErrorCreator +) : InterstitialAdEventListener { + + override fun onAdClicked() { + interstitialAdCallback.reportAdClicked() + } + + override fun onAdImpression(impressionData: ImpressionData?) { + interstitialAdCallback.reportAdImpression() + } + + override fun onAdDismissed() { + interstitialAdCallback.onAdClosed() + } + + override fun onAdShown() { + interstitialAdCallback.onAdOpened() + } + + override fun onAdFailedToShow(adError: AdError) { + interstitialAdCallback.onAdFailedToShow(errorConverter.convertToAdMobError(adError)) + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdFactory.kt new file mode 100644 index 000000000..17381dac4 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/interstitial/MediationInterstitialAdFactory.kt @@ -0,0 +1,17 @@ +package com.google.ads.mediation.yandex.interstitial + +import android.app.Activity +import com.google.android.gms.ads.mediation.MediationInterstitialAd +import com.yandex.mobile.ads.interstitial.InterstitialAd + +internal class MediationInterstitialAdFactory { + + fun create( + loadedAd: InterstitialAd, + onContextIsNotActivity: () -> Unit + ) = MediationInterstitialAd { context -> + if (context is Activity) { + loadedAd.show(context) + } else onContextIsNotActivity() + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/UriGenerator.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/UriGenerator.kt new file mode 100644 index 000000000..cb8d584c0 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/UriGenerator.kt @@ -0,0 +1,14 @@ +package com.google.ads.mediation.yandex.nativeads + +import android.net.Uri + +internal class UriGenerator { + + fun createImageUri(any: Any): Uri? { + return Uri.parse(IMAGE_URI_PREFIX + any.hashCode()) + } + + companion object { + private const val IMAGE_URI_PREFIX = "admob.image.url." + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdAsset.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdAsset.kt new file mode 100644 index 000000000..0f0aeb96c --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdAsset.kt @@ -0,0 +1,12 @@ +package com.google.ads.mediation.yandex.nativeads + +object YandexNativeAdAsset { + const val AGE = "age" + const val DOMAIN = "domain" + const val FAVICON = "favicon" + const val FEEDBACK = "feedback" + const val RATING = "rating" + const val REVIEW_COUNT = "review_count" + const val SPONSORED = "sponsored" + const val WARNING = "warning" +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdEventListener.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdEventListener.kt new file mode 100644 index 000000000..887919f42 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdEventListener.kt @@ -0,0 +1,27 @@ +package com.google.ads.mediation.yandex.nativeads + +import com.google.android.gms.ads.mediation.MediationNativeAdCallback +import com.yandex.mobile.ads.common.ImpressionData +import com.yandex.mobile.ads.nativeads.NativeAdEventListener + +internal class YandexNativeAdEventListener( + private val adMobListener: MediationNativeAdCallback +) : NativeAdEventListener { + + override fun onReturnedToApplication() { + adMobListener.onAdClosed() + } + + override fun onAdClicked() { + adMobListener.reportAdClicked() + } + + override fun onLeftApplication() { + adMobListener.onAdOpened() + adMobListener.onAdLeftApplication() + } + + override fun onImpression(impressionData: ImpressionData?) { + adMobListener.reportAdImpression() + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImage.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImage.kt new file mode 100644 index 000000000..b3fe0722a --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImage.kt @@ -0,0 +1,17 @@ +package com.google.ads.mediation.yandex.nativeads + +import android.graphics.drawable.Drawable +import android.net.Uri +import com.google.android.gms.ads.formats.NativeAd + +internal class YandexNativeAdImage( + private val drawable: Drawable, + private val uri: Uri +) : NativeAd.Image() { + + override fun getDrawable(): Drawable = drawable + + override fun getUri(): Uri = uri + + override fun getScale(): Double = 1.0 +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImageFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImageFactory.kt new file mode 100644 index 000000000..b394e71a9 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdImageFactory.kt @@ -0,0 +1,29 @@ +package com.google.ads.mediation.yandex.nativeads + +import android.content.Context +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import com.yandex.mobile.ads.nativeads.NativeAdImage + +internal class YandexNativeAdImageFactory { + + private val uriGenerator: UriGenerator = UriGenerator() + + fun createYandexNativeAdImage( + context: Context, + imageData: NativeAdImage? + ): YandexNativeAdImage? { + var nativeAdImage: YandexNativeAdImage? = null + + if (imageData != null) { + val resources = context.resources + val bitmap = imageData.bitmap + val imageDrawable: Drawable = BitmapDrawable(resources, bitmap) + uriGenerator.createImageUri(imageData)?.let { + nativeAdImage = YandexNativeAdImage(imageDrawable, it) + } + } + + return nativeAdImage + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdLoadListener.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdLoadListener.kt new file mode 100644 index 000000000..fffba7ac6 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/YandexNativeAdLoadListener.kt @@ -0,0 +1,57 @@ +package com.google.ads.mediation.yandex.nativeads + +import android.content.Context +import android.os.Bundle +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.mediation.MediationAdLoadCallback +import com.google.android.gms.ads.mediation.MediationNativeAdCallback +import com.google.android.gms.ads.mediation.UnifiedNativeAdMapper +import com.yandex.mobile.ads.common.AdRequestError +import com.yandex.mobile.ads.nativeads.NativeAd +import com.yandex.mobile.ads.nativeads.NativeAdLoadListener +import com.yandex.mobile.ads.nativeads.YandexNativeAdMappersFactory +import java.lang.ref.WeakReference + +internal class YandexNativeAdLoadListener @JvmOverloads constructor( + context: Context, + private val callback: MediationAdLoadCallback, + private val extras: Bundle?, + private val adMappersFactory: YandexNativeAdMappersFactory = YandexNativeAdMappersFactory(), + private val adMobAdErrorCreator: AdMobAdErrorCreator = AdMobAdErrorCreator() +) : NativeAdLoadListener { + + private val contextReference: WeakReference = WeakReference(context) + + private var admobNativeListener: MediationNativeAdCallback? = null + + private var nativeAd: NativeAd? = null + + override fun onAdFailedToLoad(error: AdRequestError) { + val adError = adMobAdErrorCreator.createLoadAdError(error) + callback.onFailure(adError) + } + + override fun onAdLoaded(nativeAd: NativeAd) { + finishWithAdMapper(nativeAd) + } + + private fun finishWithAdMapper(nativeAd: NativeAd) { + val context = contextReference.get() + if (context != null) { + val nativeAdMapper = adMappersFactory.createAdMapper(context, nativeAd, extras) + admobNativeListener = callback.onSuccess(nativeAdMapper) + configureNativeAd(nativeAd) + } else { + val adError = adMobAdErrorCreator.createLoadAdError(AdRequest.ERROR_CODE_INTERNAL_ERROR) + callback.onFailure(adError) + } + } + + private fun configureNativeAd(nativeAd: NativeAd) { + admobNativeListener?.let { + nativeAd.setNativeAdEventListener(YandexNativeAdEventListener(it)) + } + this.nativeAd = nativeAd + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/ViewUtils.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/ViewUtils.kt new file mode 100644 index 000000000..8045a4cbc --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/ViewUtils.kt @@ -0,0 +1,18 @@ +package com.google.ads.mediation.yandex.nativeads.view + +import android.view.View + +internal object ViewUtils { + + @JvmStatic + fun castView( + view: View?, + expectedViewClass: Class + ): T? { + return if (expectedViewClass.isInstance(view)) { + expectedViewClass.cast(view) + } else { + null + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexAdAssetViewsProviderCreator.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexAdAssetViewsProviderCreator.kt new file mode 100644 index 000000000..e66f9e195 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexAdAssetViewsProviderCreator.kt @@ -0,0 +1,58 @@ +package com.google.ads.mediation.yandex.nativeads.view + +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import com.google.ads.mediation.yandex.nativeads.YandexNativeAdAsset +import com.google.ads.mediation.yandex.nativeads.view.ViewUtils.castView +import com.google.android.gms.ads.nativead.NativeAdView + +internal class YandexAdAssetViewsProviderCreator( + extras: Bundle, + private val viewsFinder: YandexNativeAdViewsFinder = YandexNativeAdViewsFinder(extras), + private val providerBuilder: YandexNativeAssetViewsProvider.Builder = + YandexNativeAssetViewsProvider.Builder() +) { + + fun createProvider(nativeAdView: NativeAdView): YandexNativeAssetViewsProvider { + val bodyView = castView(nativeAdView.bodyView, TextView::class.java) + val callToActionView = castView(nativeAdView.callToActionView, TextView::class.java) + val domainView = castView(nativeAdView.storeView, TextView::class.java) + val iconView = castView(nativeAdView.iconView, ImageView::class.java) + val imageView = castView(nativeAdView.imageView, ImageView::class.java) + val priceView = castView(nativeAdView.priceView, TextView::class.java) + val sponsoredView = castView(nativeAdView.advertiserView, TextView::class.java) + val titleView = castView(nativeAdView.headlineView, TextView::class.java) + var builder = createBuilderWithYandexSupportedViews(nativeAdView) + + builder = builder.withBodyView(bodyView) + .withCallToActionView(callToActionView) + .withDomainView(domainView) + .withIconView(iconView) + .withImageView(imageView) + .withPriceView(priceView) + .withSponsoredView(sponsoredView) + .withTitleView(titleView) + + return builder.build() + } + + private fun createBuilderWithYandexSupportedViews( + nativeAdView: View + ): YandexNativeAssetViewsProvider.Builder { + val ageView = viewsFinder.findViewByExtraKey(nativeAdView, YandexNativeAdAsset.AGE) + val faviconView = viewsFinder.findViewByExtraKey(nativeAdView, YandexNativeAdAsset.FAVICON) + val feedbackView = viewsFinder.findViewByExtraKey(nativeAdView, YandexNativeAdAsset.FEEDBACK) + val reviewCountView = viewsFinder.findViewByExtraKey(nativeAdView, YandexNativeAdAsset.REVIEW_COUNT) + val warningView = viewsFinder.findViewByExtraKey(nativeAdView, YandexNativeAdAsset.WARNING) + + return providerBuilder + .withAgeView(castView(ageView, TextView::class.java)) + .withFaviconView(castView(faviconView, ImageView::class.java)) + .withFeedbackView(castView(feedbackView, ImageView::class.java)) + .withRatingView(viewsFinder.findRatingView(nativeAdView)) + .withReviewCountView(castView(reviewCountView, TextView::class.java)) + .withWarningView(castView(warningView, TextView::class.java)) + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAdViewsFinder.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAdViewsFinder.kt new file mode 100644 index 000000000..10ae50cff --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAdViewsFinder.kt @@ -0,0 +1,30 @@ +package com.google.ads.mediation.yandex.nativeads.view + +import android.os.Bundle +import android.view.View +import com.google.ads.mediation.yandex.nativeads.YandexNativeAdAsset +import com.yandex.mobile.ads.nativeads.Rating + +internal class YandexNativeAdViewsFinder(private val extras: Bundle) { + + fun findViewByExtraKey( + nativeAdView: View, + extraKey: String + ): View? { + return if (extras.containsKey(extraKey)) { + nativeAdView.findViewById(extras.getInt(extraKey)) + } else { + null + } + } + + fun findRatingView(nativeAdView: View): T? where T : View?, T : Rating? { + try { + val view = findViewByExtraKey(nativeAdView, YandexNativeAdAsset.RATING) + return view as? Rating as? T + } catch (ignored: Exception) { + } + + return null + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAssetViewsProvider.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAssetViewsProvider.kt new file mode 100644 index 000000000..55305941a --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/nativeads/view/YandexNativeAssetViewsProvider.kt @@ -0,0 +1,160 @@ +package com.google.ads.mediation.yandex.nativeads.view + +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import com.yandex.mobile.ads.nativeads.Rating + +internal class YandexNativeAssetViewsProvider private constructor(builder: Builder) { + + val ageView: TextView? = builder.ageView + + val bodyView: TextView? = builder.bodyView + + val callToActionView: TextView? = builder.callToActionView + + val domainView: TextView? = builder.domainView + + val faviconView: ImageView? = builder.faviconView + + val feedbackView: ImageView? = builder.feedbackView + + val imageView: ImageView? = builder.imageView + + val iconView: ImageView? = builder.iconView + + val priceView: TextView? = builder.priceView + + private val ratingView: View? = builder.ratingView + + val reviewCountView: TextView? = builder.reviewCountView + + val sponsoredView: TextView? = builder.sponsoredView + + val titleView: TextView? = builder.titleView + + val warningView: TextView? = builder.warningView + + fun getRatingView(): T? where T : View?, T : Rating? { + return ratingView as T? + } + + class Builder { + + var ageView: TextView? = null + private set + + var bodyView: TextView? = null + private set + + var callToActionView: TextView? = null + private set + + var domainView: TextView? = null + private set + + var faviconView: ImageView? = null + private set + + var feedbackView: ImageView? = null + private set + + var imageView: ImageView? = null + private set + + var iconView: ImageView? = null + private set + + var priceView: TextView? = null + private set + + var ratingView: View? = null + private set + + var reviewCountView: TextView? = null + private set + + var sponsoredView: TextView? = null + private set + + var titleView: TextView? = null + private set + + var warningView: TextView? = null + private set + + fun build(): YandexNativeAssetViewsProvider { + return YandexNativeAssetViewsProvider(this) + } + + fun withAgeView(ageView: TextView?): Builder { + this.ageView = ageView + return this + } + + fun withBodyView(bodyView: TextView?): Builder { + this.bodyView = bodyView + return this + } + + fun withCallToActionView(callToActionView: TextView?): Builder { + this.callToActionView = callToActionView + return this + } + + fun withDomainView(domainView: TextView?): Builder { + this.domainView = domainView + return this + } + + fun withFaviconView(faviconView: ImageView?): Builder { + this.faviconView = faviconView + return this + } + + fun withFeedbackView(feedbackView: ImageView?): Builder { + this.feedbackView = feedbackView + return this + } + + fun withIconView(iconView: ImageView?): Builder { + this.iconView = iconView + return this + } + + fun withImageView(imageView: ImageView?): Builder { + this.imageView = imageView + return this + } + + fun withPriceView(priceView: TextView?): Builder { + this.priceView = priceView + return this + } + + fun withRatingView(ratingView: T?): Builder where T : View?, T : Rating? { + this.ratingView = ratingView + return this + } + + fun withReviewCountView(reviewCountView: TextView?): Builder { + this.reviewCountView = reviewCountView + return this + } + + fun withSponsoredView(sponsoredView: TextView?): Builder { + this.sponsoredView = sponsoredView + return this + } + + fun withTitleView(titleView: TextView?): Builder { + this.titleView = titleView + return this + } + + fun withWarningView(warningView: TextView?): Builder { + this.warningView = warningView + return this + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/AdMobReward.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/AdMobReward.kt new file mode 100644 index 000000000..b19d9c534 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/AdMobReward.kt @@ -0,0 +1,15 @@ +package com.google.ads.mediation.yandex.rewarded + +import com.google.android.gms.ads.rewarded.RewardItem +import com.yandex.mobile.ads.rewarded.Reward + +internal class AdMobReward(private val reward: Reward) : RewardItem { + + override fun getType(): String { + return reward.type + } + + override fun getAmount(): Int { + return reward.amount + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdEventListener.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdEventListener.kt new file mode 100644 index 000000000..1177f6613 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdEventListener.kt @@ -0,0 +1,42 @@ +package com.google.ads.mediation.yandex.rewarded + +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.mediation.MediationRewardedAdCallback +import com.yandex.mobile.ads.common.AdError +import com.yandex.mobile.ads.common.ImpressionData +import com.yandex.mobile.ads.rewarded.Reward +import com.yandex.mobile.ads.rewarded.RewardedAdEventListener + +internal class MediationRewardedAdEventListener( + private val rewardedAdCallback: MediationRewardedAdCallback, + private val errorConverter: AdMobAdErrorCreator +) : RewardedAdEventListener { + + override fun onAdClicked() { + rewardedAdCallback.reportAdClicked() + } + + override fun onAdFailedToShow(adError: AdError) { + rewardedAdCallback.onAdFailedToShow(errorConverter.convertToAdMobError(adError)) + } + + override fun onAdImpression(impressionData: ImpressionData?) { + rewardedAdCallback.reportAdImpression() + } + + override fun onAdDismissed() { + rewardedAdCallback.onAdClosed() + } + + override fun onAdShown() { + rewardedAdCallback.apply { + onAdOpened() + onVideoStart() + } + } + + override fun onRewarded(reward: Reward) { + val rewardItem = AdMobReward(reward) + rewardedAdCallback.onUserEarnedReward(rewardItem) + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdFactory.kt new file mode 100644 index 000000000..dd2044d42 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/MediationRewardedAdFactory.kt @@ -0,0 +1,17 @@ +package com.google.ads.mediation.yandex.rewarded + +import android.app.Activity +import com.google.android.gms.ads.mediation.MediationRewardedAd +import com.yandex.mobile.ads.rewarded.RewardedAd + +internal class MediationRewardedAdFactory { + + fun create( + loadedAd: RewardedAd, + onContextIsNotActivity: () -> Unit + ) = MediationRewardedAd { context -> + if (context is Activity) { + loadedAd.show(context) + } else onContextIsNotActivity() + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedAdLoadListenerFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedAdLoadListenerFactory.kt new file mode 100644 index 000000000..c8e4a4c2d --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedAdLoadListenerFactory.kt @@ -0,0 +1,44 @@ +package com.google.ads.mediation.yandex.rewarded + +import com.google.ads.mediation.yandex.base.AdMobAdErrorCreator +import com.google.android.gms.ads.mediation.MediationAdLoadCallback +import com.google.android.gms.ads.mediation.MediationRewardedAd +import com.google.android.gms.ads.mediation.MediationRewardedAdCallback +import com.yandex.mobile.ads.common.AdRequestError +import com.yandex.mobile.ads.rewarded.RewardedAd +import com.yandex.mobile.ads.rewarded.RewardedAdLoadListener + +internal class RewardedAdLoadListenerFactory { + + fun create( + callback: MediationAdLoadCallback, + adMobAdErrorCreator: AdMobAdErrorCreator, + mediationRewardedAdFactory: MediationRewardedAdFactory = MediationRewardedAdFactory() + ) = object : RewardedAdLoadListener { + + var rewardedAdCallback: MediationRewardedAdCallback? = null + + override fun onAdLoaded(loadedAd: RewardedAd) { + val mediationRewardedAd = mediationRewardedAdFactory.create( + loadedAd, ::onContextIsNotActivityError + ) + rewardedAdCallback = callback.onSuccess(mediationRewardedAd).also { rewardedAdCallback -> + val mediationRewardedAdEventListener = MediationRewardedAdEventListener( + rewardedAdCallback, + adMobAdErrorCreator + ) + loadedAd.setAdEventListener(mediationRewardedAdEventListener) + } + } + + override fun onAdFailedToLoad(error: AdRequestError) { + val adError = adMobAdErrorCreator.createLoadAdError(error) + callback.onFailure(adError) + } + + private fun onContextIsNotActivityError() { + val error = adMobAdErrorCreator.createRequiresActivityError() + rewardedAdCallback?.onAdFailedToShow(error) + } + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedLoaderFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedLoaderFactory.kt new file mode 100644 index 000000000..2a2211e93 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/google/ads/mediation/yandex/rewarded/RewardedLoaderFactory.kt @@ -0,0 +1,8 @@ +package com.google.ads.mediation.yandex.rewarded + +import android.content.Context +import com.yandex.mobile.ads.rewarded.RewardedAdLoader + +internal class RewardedLoaderFactory { + fun create(context: Context) = RewardedAdLoader(context) +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/MediaViewFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/MediaViewFactory.kt new file mode 100644 index 000000000..1843cf596 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/MediaViewFactory.kt @@ -0,0 +1,7 @@ +package com.yandex.mobile.ads.nativeads + +import android.content.Context + +internal class MediaViewFactory { + fun create(context: Context) = MediaView(context) +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/NativeAdViewBinderBuilderFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/NativeAdViewBinderBuilderFactory.kt new file mode 100644 index 000000000..242c58e0d --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/NativeAdViewBinderBuilderFactory.kt @@ -0,0 +1,7 @@ +package com.yandex.mobile.ads.nativeads + +import android.view.View + +internal class NativeAdViewBinderBuilderFactory { + fun create(view: View) = NativeAdViewBinder.Builder(view) +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapper.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapper.kt new file mode 100644 index 000000000..1eeee4936 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapper.kt @@ -0,0 +1,66 @@ +package com.yandex.mobile.ads.nativeads + +import android.os.Bundle +import android.util.Log +import android.view.View +import com.google.ads.mediation.yandex.nativeads.view.YandexAdAssetViewsProviderCreator +import com.google.android.gms.ads.mediation.UnifiedNativeAdMapper +import com.google.android.gms.ads.nativead.NativeAdView + +internal class YandexNativeAdMapper( + private val nativeAd: NativeAd, + extras: Bundle, + private val nativeAdViewBinderBuilderFactory: NativeAdViewBinderBuilderFactory = NativeAdViewBinderBuilderFactory(), + private val assetViewsProviderCreator: YandexAdAssetViewsProviderCreator = YandexAdAssetViewsProviderCreator(extras) +) : UnifiedNativeAdMapper() { + + private var mediaView: MediaView? = null + + override fun trackViews( + view: View, + clickableAssetViews: Map, + nonclickableAssetViews: Map + ) { + super.trackViews(view, clickableAssetViews, nonclickableAssetViews) + + if (view is NativeAdView) { + try { + val provider = assetViewsProviderCreator.createProvider(view) + + val binder = nativeAdViewBinderBuilderFactory.create(view) + .setAgeView(provider.ageView) + .setBodyView(provider.bodyView) + .setCallToActionView(provider.callToActionView) + .setDomainView(provider.domainView) + .setFaviconView(provider.faviconView) + .setFeedbackView(provider.feedbackView) + .setIconView(provider.iconView) + .setMediaView(mediaView) + .setPriceView(provider.priceView) + .setRatingView(provider.getRatingView()) + .setReviewCountView(provider.reviewCountView) + .setSponsoredView(provider.sponsoredView) + .setTitleView(provider.titleView) + .setWarningView(provider.warningView) + .build() + + nativeAd.bindNativeAd(binder) + } catch (e: Exception) { + Log.w(TAG, "Error while binding native ad. $e") + } + } else { + Log.w(TAG, "Invalid view type") + } + } + + override fun setMediaView(view: View) { + super.setMediaView(view) + if (view is MediaView) { + mediaView = view + } + } + + companion object { + private const val TAG = "Yandex AdMob Adapter" + } +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapperFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapperFactory.kt new file mode 100644 index 000000000..54ad39770 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMapperFactory.kt @@ -0,0 +1,7 @@ +package com.yandex.mobile.ads.nativeads + +import android.os.Bundle + +internal class YandexNativeAdMapperFactory { + fun create(nativeAd: NativeAd, extras: Bundle) = YandexNativeAdMapper(nativeAd, extras) +} diff --git a/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMappersFactory.kt b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMappersFactory.kt new file mode 100644 index 000000000..2d9193264 --- /dev/null +++ b/ThirdPartyAdapters/yandex/yandex/src/main/java/com/yandex/mobile/ads/nativeads/YandexNativeAdMappersFactory.kt @@ -0,0 +1,113 @@ +package com.yandex.mobile.ads.nativeads + +import android.content.Context +import android.os.Bundle +import com.google.ads.mediation.yandex.nativeads.YandexNativeAdAsset +import com.google.ads.mediation.yandex.nativeads.YandexNativeAdImageFactory +import com.google.android.gms.ads.formats.NativeAd.Image + +internal class YandexNativeAdMappersFactory( + private val adMapperFactory: YandexNativeAdMapperFactory = YandexNativeAdMapperFactory(), + private val nativeAdImageFactory: YandexNativeAdImageFactory = YandexNativeAdImageFactory(), + private val mediaViewFactory: MediaViewFactory = MediaViewFactory() +) { + + fun createAdMapper( + context: Context, + nativeAd: NativeAd, + extras: Bundle? + ): YandexNativeAdMapper { + val networkExtras = extras ?: Bundle() + val mapper = adMapperFactory.create(nativeAd, networkExtras) + + mapper.overrideClickHandling = OVERRIDE_CLICK_TRACKING + mapper.overrideImpressionRecording = OVERRIDE_IMPRESSION_RECORDING + + val assets = nativeAd.adAssets + + assets.sponsored?.let { + mapper.advertiser = it + } + + assets.body?.let { + mapper.body = it + } + + assets.callToAction?.let { + mapper.callToAction = it + } + + assets.title?.let { + mapper.headline = it + } + + assets.price?.let { + mapper.price = it + } + + assets.domain?.let { + mapper.store = it + } + + nativeAdImageFactory.createYandexNativeAdImage(context, assets.icon)?.let { + mapper.icon = it + } + + mapper.images = createNativeAdImages(context, assets.image) + + assets.rating?.let { + mapper.starRating = it.toDouble() + } + + val media = assets.media + val hasMediaContent = media != null + + mapper.setHasVideoContent(hasMediaContent) + + if (hasMediaContent) { + media?.let { + mapper.mediaContentAspectRatio = media.aspectRatio + } + } + + val mediaView = mediaViewFactory.create(context) + mapper.setMediaView(mediaView) + + val assetExtras = createAssetExtras(assets) + mapper.extras = assetExtras + + return mapper + } + + private fun createAssetExtras(assets: NativeAdAssets): Bundle { + val assetExtras = Bundle() + + with(assetExtras) { + putString(YandexNativeAdAsset.AGE, assets.age) + putString(YandexNativeAdAsset.DOMAIN, assets.domain) + putString(YandexNativeAdAsset.REVIEW_COUNT, assets.reviewCount) + putString(YandexNativeAdAsset.SPONSORED, assets.sponsored) + putString(YandexNativeAdAsset.WARNING, assets.warning) + } + + return assetExtras + } + + private fun createNativeAdImages( + context: Context, + nativeAdImage: NativeAdImage? + ): List { + val images: MutableList = ArrayList() + + if (nativeAdImage != null) { + images.add(nativeAdImageFactory.createYandexNativeAdImage(context, nativeAdImage)) + } + + return images + } + + companion object { + private const val OVERRIDE_CLICK_TRACKING = true + private const val OVERRIDE_IMPRESSION_RECORDING = true + } +}