Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ThirdPartyAdapters/maio/maio/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ext {
// String property to store the proper name of the mediation network adapter.
adapterName = "maio"
// String property to store version name.
stringVersion = "2.0.7.0"
stringVersion = "2.0.8.0"
// String property to store group id.
stringGroupId = "com.google.ads.mediation"
// Jacoco version to generate code coverage data
Expand All @@ -23,7 +23,7 @@ android {
defaultConfig {
minSdkVersion 23
targetSdk 33
versionCode 2000700
versionCode 2000800
versionName stringVersion
buildConfigField('String', 'ADAPTER_VERSION', "\"${stringVersion}\"")
multiDexEnabled true
Expand Down Expand Up @@ -119,7 +119,7 @@ task jacocoTestReport(type: JacocoReport,
}

dependencies {
implementation 'com.maio:android-sdk-v2:2.0.7'
implementation 'com.maio:android-sdk-v2:2.0.8'
implementation 'androidx.annotation:annotation:1.5.0'
implementation 'com.google.android.gms:play-services-ads:24.7.0'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.mediation.maio;

import static com.google.ads.mediation.maio.MaioMediationAdapter.ERROR_DOMAIN;
import static com.google.ads.mediation.maio.MaioMediationAdapter.ERROR_INVALID_SERVER_PARAMETERS;
import static com.google.ads.mediation.maio.MaioMediationAdapter.TAG;
import static com.google.ads.mediation.maio.MaioMediationAdapter.getAdError;

import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.MediationUtils;
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 java.util.ArrayList;
import java.util.List;
import jp.maio.sdk.android.mediation.admob.adapter.MaioAdsManager;
import jp.maio.sdk.android.v2.banner.MaioBannerListener;
import jp.maio.sdk.android.v2.banner.MaioBannerSize;
import jp.maio.sdk.android.v2.banner.MaioBannerView;

public class MaioBannerAd implements MediationBannerAd {
private MaioBannerView bannerView;
private final MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback>
adLoadCallback;
private MediationBannerAdCallback bannerAdCallback;

public MaioBannerAd(
MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback> adLoadCallback) {
this.adLoadCallback = adLoadCallback;
}

public void loadAd(MediationBannerAdConfiguration mediationBannerAdConfiguration) {
Context context = mediationBannerAdConfiguration.getContext();

Bundle serverParameters = mediationBannerAdConfiguration.getServerParameters();
String mediaID = serverParameters.getString(MaioAdsManager.KEY_MEDIA_ID);
if (TextUtils.isEmpty(mediaID)) {
AdError error =
new AdError(
ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Media ID.", ERROR_DOMAIN);
Log.w(TAG, error.getMessage());
adLoadCallback.onFailure(error);
return;
}

String zoneID = serverParameters.getString(MaioAdsManager.KEY_ZONE_ID);
if (TextUtils.isEmpty(zoneID)) {
AdError error =
new AdError(ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Zone ID.", ERROR_DOMAIN);
Log.w(TAG, error.getMessage());
adLoadCallback.onFailure(error);
return;
}

MaioBannerSize bannerSize =
toMaioBannerSize(context, mediationBannerAdConfiguration.getAdSize());
if (bannerSize == null) {
AdError error =
new AdError(
ERROR_INVALID_SERVER_PARAMETERS,
"The requested ad size is not supported by maio SDK.",
ERROR_DOMAIN);
Log.w(TAG, error.getMessage());
adLoadCallback.onFailure(error);
return;
}

bannerView = new MaioBannerView(context, zoneID, bannerSize);
bannerView.setListener(new MaioBannerListener() {
@Override
public void loaded(@NonNull MaioBannerView maioBannerView) {
if (adLoadCallback != null) {
bannerAdCallback = adLoadCallback.onSuccess(MaioBannerAd.this);
}
}

@Override
public void failedToLoad(@NonNull MaioBannerView maioBannerView, int errorCode) {
if (adLoadCallback != null) {
Log.w(TAG, getAdError(errorCode).getMessage());
adLoadCallback.onFailure(getAdError(errorCode));
}
}

@Override
public void impression(@NonNull MaioBannerView maioBannerView) {
if (bannerAdCallback != null) {
bannerAdCallback.reportAdImpression();
}
}

@Override
public void clicked(@NonNull MaioBannerView maioBannerView) {
if (bannerAdCallback != null) {
bannerAdCallback.reportAdClicked();
}
}

@Override
public void leftApplication(@NonNull MaioBannerView maioBannerView) {
if (bannerAdCallback != null) {
bannerAdCallback.onAdLeftApplication();
}
}

@Override
public void failedToShow(@NonNull MaioBannerView maioBannerView, int errorCode) {
if (adLoadCallback != null) {
Log.w(TAG, getAdError(errorCode).getMessage());
adLoadCallback.onFailure(getAdError(errorCode));
}
}
});
bannerView.load(mediationBannerAdConfiguration.isTestRequest());
}

@NonNull
@Override
public View getView() {
return bannerView;
}

private MaioBannerSize toMaioBannerSize(Context context, AdSize adSize) {
List<AdSize> supportedSizes = new ArrayList<>();
supportedSizes.add(new AdSize(320, 50));
supportedSizes.add(new AdSize(320, 100));
supportedSizes.add(new AdSize(300, 250));
AdSize closestSize = MediationUtils.findClosestSize(context, adSize, supportedSizes);

if (closestSize != null) {
return new MaioBannerSize(closestSize.getWidth(), closestSize.getHeight());
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
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;
Expand All @@ -34,13 +37,15 @@
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import jp.maio.sdk.android.mediation.admob.adapter.MaioAdsManager;
import jp.maio.sdk.android.v2.banner.MaioBannerView;

public class MaioMediationAdapter extends Adapter {

public static final String TAG = MaioMediationAdapter.class.getSimpleName();

private MaioInterstitialAd interstitialAd;
private MaioRewardedAd rewardedAd;
private MaioBannerAd bannerAd;

/**
* Maio adapter error domain.
Expand Down Expand Up @@ -168,4 +173,13 @@ public void loadRewardedAd(
rewardedAd = new MaioRewardedAd(mediationAdLoadCallback);
rewardedAd.loadAd(mediationRewardedAdConfiguration);
}

@Override
public void loadBannerAd(
@NonNull MediationBannerAdConfiguration adConfiguration,
@NonNull MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback>
callback) {
bannerAd = new MaioBannerAd(callback);
bannerAd.loadAd(adConfiguration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ import com.google.ads.mediation.maio.MaioMediationAdapter.ERROR_DOMAIN
import com.google.ads.mediation.maio.MaioMediationAdapter.ERROR_INVALID_SERVER_PARAMETERS
import com.google.ads.mediation.maio.MaioUtils.getVersionInfo
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.RequestConfiguration
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.MediationRewardedAd
import com.google.android.gms.ads.mediation.MediationRewardedAdCallback
import com.google.android.gms.ads.mediation.MediationRewardedAdConfiguration
Expand All @@ -33,7 +37,6 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.argThat
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.robolectric.Robolectric
Expand All @@ -52,6 +55,11 @@ class MaioMediationAdapterTest {
mock<MediationAdLoadCallback<MediationRewardedAd, MediationRewardedAdCallback>> {
on { onSuccess(any()) } doReturn mockRewardedAdCallback
}
private val mockBannerAdCallback = mock<MediationBannerAdCallback>()
private val mockMediationBannerAdLoadCallback =
mock<MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback>> {
on { onSuccess(any()) } doReturn mockBannerAdCallback
}

// region version tests
@Test
Expand Down Expand Up @@ -192,6 +200,96 @@ class MaioMediationAdapterTest {

// endregion

// region Banner ad tests

@Test
fun loadBannerAd_withNullKeyMedia_invokesOnFailure() {
val bannerAdConfiguration = createBannerAdConfiguration()

adapter.loadBannerAd(bannerAdConfiguration, mockMediationBannerAdLoadCallback)

val expectedAdError =
AdError(ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Media ID.", ERROR_DOMAIN)
verify(mockMediationBannerAdLoadCallback).onFailure(argThat(AdErrorMatcher(expectedAdError)))
}

@Test
fun loadBannerAd_withEmptyKeyMedia_invokesOnFailure() {
val serverParameters = bundleOf(KEY_MEDIA_ID to "")
val bannerAdConfiguration = createBannerAdConfiguration(serverParameters = serverParameters)

adapter.loadBannerAd(bannerAdConfiguration, mockMediationBannerAdLoadCallback)

val expectedAdError =
AdError(ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Media ID.", ERROR_DOMAIN)
verify(mockMediationBannerAdLoadCallback).onFailure(argThat(AdErrorMatcher(expectedAdError)))
}

@Test
fun loadBannerAd_withNullZoneId_invokesOnFailure() {
val serverParameters = bundleOf(KEY_MEDIA_ID to TEST_APP_ID_1)
val bannerAdConfiguration = createBannerAdConfiguration(serverParameters = serverParameters)

adapter.loadBannerAd(bannerAdConfiguration, mockMediationBannerAdLoadCallback)

val expectedAdError =
AdError(ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Zone ID.", ERROR_DOMAIN)
verify(mockMediationBannerAdLoadCallback).onFailure(argThat(AdErrorMatcher(expectedAdError)))
}

@Test
fun loadBannerAd_withEmptyZoneId_invokesOnFailure() {
val serverParameters = bundleOf(KEY_MEDIA_ID to TEST_APP_ID_1, KEY_ZONE_ID to "")
val bannerAdConfiguration = createBannerAdConfiguration(serverParameters = serverParameters)

adapter.loadBannerAd(bannerAdConfiguration, mockMediationBannerAdLoadCallback)

val expectedAdError =
AdError(ERROR_INVALID_SERVER_PARAMETERS, "Missing or Invalid Zone ID.", ERROR_DOMAIN)
verify(mockMediationBannerAdLoadCallback).onFailure(argThat(AdErrorMatcher(expectedAdError)))
}

@Test
fun loadBannerAd_withInvalidSize_invokesOnFailure() {
val serverParameters = bundleOf(KEY_MEDIA_ID to TEST_APP_ID_1, KEY_ZONE_ID to "testZoneId")
val bannerAdConfiguration =
createBannerAdConfiguration(
serverParameters = serverParameters,
adSize = AdSize(300, 50),
)

adapter.loadBannerAd(bannerAdConfiguration, mockMediationBannerAdLoadCallback)

val expectedAdError =
AdError(
ERROR_INVALID_SERVER_PARAMETERS,
"The requested ad size is not supported by maio SDK.",
ERROR_DOMAIN,
)
verify(mockMediationBannerAdLoadCallback).onFailure(argThat(AdErrorMatcher(expectedAdError)))
}

private fun createBannerAdConfiguration(
context: Context = activity,
serverParameters: Bundle = bundleOf(),
adSize: AdSize = AdSize.BANNER,
) =
MediationBannerAdConfiguration(
context,
/*bidresponse=*/ "",
serverParameters,
/*mediationExtras=*/ Bundle(),
/*isTesting=*/ true,
/*location=*/ null,
RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_UNSPECIFIED,
RequestConfiguration.TAG_FOR_UNDER_AGE_OF_CONSENT_UNSPECIFIED,
/*maxAdContentRating=*/ "",
adSize,
TEST_WATERMARK,
)

// endregion

private companion object {
const val TEST_APP_ID_1 = "testAppId1"
const val TEST_APP_ID_2 = "testAppId2"
Expand Down
Loading