# Android SDK

The Metica Ads SDK for Android enables developers to integrate advertising into Android applications with support for interstitial, rewarded, banner, and MREC ad formats.

## Requirements

* Android API 21 (Android 5.0) or higher
* Kotlin 1.8+
* AppLovinSDK dependency (version 13.0.0 or higher, managed by Metica SDK)
* Valid Metica API credentials (API key, App ID)
* AppLovin SDK Key from [AppLovin Dashboard](https://dash.applovin.com/o/account?r=3#keys) under "SDK Key"

{% hint style="warning" %}
Do not call, reference, or initialize the AppLovin SDK directly in your code. The Metica SDK manages all AppLovin integration internally. Direct usage may cause version conflicts and unexpected behavior.
{% endhint %}

## Download

The Metica Android SDK is distributed via Maven Central. You can find the latest version and version history at:

[**Maven Central - com.metica:metica-sdk**](https://central.sonatype.com/artifact/com.metica/metica-sdk/versions)

## Installation

Add the Metica SDK dependency to your app's `build.gradle.kts` or `build.gradle`

{% code title="build.gradle.kts" %}

```kotlin
dependencies {
    implementation("com.metica:metica-sdk:<version>")
}
```

{% endcode %}

Make sure you have Maven Central in your repositories:

{% code title="repositories" %}

```kotlin
repositories {
    mavenCentral()
}
```

{% endcode %}

## Callback Interfaces

The SDK uses callback interfaces to communicate events back to your application.

### MeticaInitCallback

Triggered when SDK initialization completes.

```kotlin
fun interface MeticaInitCallback {
    fun onInit(initResponse: MeticaInitResponse)
}
```

### MeticaAdsLoadCallback

Handles ad loading events.

```kotlin
interface MeticaAdsLoadCallback {
    fun onAdLoadSuccess(meticaAd: MeticaAd)
    fun onAdLoadFailed(meticaAdError: MeticaAdError)
}
```

### MeticaAdsShowCallback

Manages display lifecycle events for fullscreen ads.

```kotlin
interface MeticaAdsShowCallback {
    fun onAdShowSuccess(meticaAd: MeticaAd)
    fun onAdShowFailed(meticaAd: MeticaAd, meticaAdError: MeticaAdError)
    fun onAdHidden(meticaAd: MeticaAd)
    fun onAdClicked(meticaAd: MeticaAd)
    fun onAdRevenuePaid(meticaAd: MeticaAd)
    fun onAdRewarded(meticaAd: MeticaAd)  // Only called for rewarded ads
}
```

### MeticaAdsAdViewCallback

Handles banner and MREC ad view events. Extends `MeticaAdsLoadCallback`.

```kotlin
interface MeticaAdsAdViewCallback : MeticaAdsLoadCallback {
    fun onAdClicked(meticaAd: MeticaAd)
    fun onAdRevenuePaid(meticaAd: MeticaAd)
}
```

## Privacy Configuration

Set privacy controls **before** initialization for GDPR and CCPA compliance:

{% code title="Privacy settings" %}

```kotlin
import com.metica.ads.MeticaAds

// GDPR - User consent for personalized ads
MeticaAds.PrivacySettings.setHasUserConsent(true, context)

// CCPA - Do Not Sell user data
MeticaAds.PrivacySettings.setDoNotSell(false, context)
```

{% endcode %}

## Supported Ad Formats

| Format       | Enum     | Dimensions        |
| ------------ | -------- | ----------------- |
| Interstitial | `INTER`  | Full-screen       |
| Rewarded     | `REWARD` | Full-screen video |
| Banner       | `BANNER` | 320x50 (adaptive) |
| MREC         | `MREC`   | 300x250           |

***

## SDK Initialization

Initialize the SDK once during application startup, before loading any ads.

{% code title="Initialize Metica SDK" %}

```kotlin
import android.app.Activity
import android.os.Bundle
import com.metica.MeticaInitCallback
import com.metica.MeticaInitConfig
import com.metica.MeticaInitResponse
import com.metica.MeticaSdk
import com.metica.ads.MeticaAds
import com.metica.ads.MeticaMediationInfo
import com.metica.ads.MeticaMediationInfo.MeticaMediationType

class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initializeMeticaSdk()
    }

    private fun initializeMeticaSdk() {
        // Set privacy settings BEFORE initialization
        MeticaAds.PrivacySettings.setHasUserConsent(true, this)
        MeticaAds.PrivacySettings.setDoNotSell(false, this)

        val initConfig = MeticaInitConfig(
            apiKey = "YOUR_API_KEY",
            appId = "YOUR_APP_ID",
            userId = "unique-user-id"  // Optional - SDK generates one if empty
        )

        val mediationInfo = MeticaMediationInfo(
            mediationType = MeticaMediationType.MAX,
            key = "YOUR_APPLOVIN_SDK_KEY"
        )

        MeticaSdk.initialize(
            context = this,
            initConfig = initConfig,
            mediationInfo = mediationInfo,
            callback = object : MeticaInitCallback {
                override fun onInit(initResponse: MeticaInitResponse) {
                    println("Current user is part of ${initResponse.smartFloors?.userGroup}")
                    println("Metica initialization completed")

                    // SDK ready - start loading ads
                    loadAds()
                }
            }
        )
    }

    private fun loadAds() {
        // Load your ads here
    }
}
```

{% endcode %}

### Initialization Response

The `MeticaInitResponse` contains a `smartFloors` object with two properties:

* `userGroup` – The experiment group assigned to the current user: either `TRIAL` or `HOLDOUT`. This determines which cohort the user belongs to for A/B testing purposes.
* `isForcedHoldout` – A boolean indicating whether the current user has been forcefully assigned to the holdout group because of an issue, i.e. for a connection problem.

{% hint style="info" %}
These values are provided solely for analytics and logging. You do not need to implement any fallback logic, the SDK handles group assignment internally regardless of initialization outcome.
{% endhint %}

### Using Kotlin Lambda

```kotlin
MeticaSdk.initialize(
    context = this,
    initConfig = initConfig,
    mediationInfo = mediationInfo
) { initResponse ->
    println("Current user is part of ${initResponse.smartFloors?.userGroup}")
    println("Metica initialization completed")
}
```

***

## Interstitial Ads

Full-screen ads that cover the app interface.

{% code title="InterstitialAdManager.kt" %}

```kotlin
import android.app.Activity
import com.metica.MeticaSdk
import com.metica.ads.MeticaAd
import com.metica.ads.MeticaAdError
import com.metica.ads.MeticaAdsLoadCallback
import com.metica.ads.MeticaAdsShowCallback

class InterstitialAdManager(private val activity: Activity) :
    MeticaAdsLoadCallback, MeticaAdsShowCallback {

    private val adUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID"
    private var retryAttempt = 0
    private val maxRetryDelay = 64.0

    fun loadAd() {
        MeticaSdk.Ads.loadInterstitial(adUnitId, this)
    }

    fun showAd() {
        if (MeticaSdk.Ads.isInterstitialReady(adUnitId)) {
            MeticaSdk.Ads.showInterstitial(
                activity = activity,
                adUnitId = adUnitId,
                placementId = "main_menu",      // Optional - for analytics
                customData = "level_complete",  // Optional - for analytics
                callback = this
            )
        } else {
            println("Interstitial not ready")
        }
    }

    // Load callbacks
    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        retryAttempt = 0
        println("Interstitial loaded: ${meticaAd.adUnitId}")
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        println("Interstitial load failed: ${meticaAdError.message}")

        // Exponential backoff retry
        retryAttempt++
        val delaySeconds = minOf(Math.pow(2.0, retryAttempt.toDouble()), maxRetryDelay)

        activity.window.decorView.postDelayed({
            println("Retrying interstitial load in ${delaySeconds}s")
            loadAd()
        }, (delaySeconds * 1000).toLong())
    }

    // Show callbacks
    override fun onAdShowSuccess(meticaAd: MeticaAd) {
        println("Interstitial shown")
    }

    override fun onAdShowFailed(meticaAd: MeticaAd, meticaAdError: MeticaAdError) {
        println("Interstitial show failed: ${meticaAdError.message}")
    }

    override fun onAdHidden(meticaAd: MeticaAd) {
        println("Interstitial hidden")
        // Preload next ad
        loadAd()
    }

    override fun onAdClicked(meticaAd: MeticaAd) {
        println("Interstitial clicked")
    }

    override fun onAdRevenuePaid(meticaAd: MeticaAd) {
        println("Interstitial revenue: ${meticaAd.revenue} from ${meticaAd.networkName}")
    }

    override fun onAdRewarded(meticaAd: MeticaAd) {
        // Not called for interstitials
    }
}
```

{% endcode %}

***

## Rewarded Ads

Full-screen video ads that reward users upon completion.

{% code title="RewardedAdManager.kt" %}

```kotlin
import android.app.Activity
import com.metica.MeticaSdk
import com.metica.ads.MeticaAd
import com.metica.ads.MeticaAdError
import com.metica.ads.MeticaAdsLoadCallback
import com.metica.ads.MeticaAdsShowCallback

class RewardedAdManager(private val activity: Activity) :
    MeticaAdsLoadCallback, MeticaAdsShowCallback {

    private val adUnitId = "YOUR_REWARDED_AD_UNIT_ID"
    private var retryAttempt = 0
    private val maxRetryDelay = 64.0

    fun loadAd() {
        MeticaSdk.Ads.loadRewarded(adUnitId, this)
    }

    fun showAd() {
        if (MeticaSdk.Ads.isRewardedReady(adUnitId)) {
            MeticaSdk.Ads.showRewarded(
                activity = activity,
                adUnitId = adUnitId,
                placementId = "shop",         // Optional - for analytics
                customData = "extra_coins",   // Optional - for analytics
                callback = this
            )
        } else {
            println("Rewarded ad not ready")
        }
    }

    // Load callbacks
    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        retryAttempt = 0
        println("Rewarded ad loaded")
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        println("Rewarded ad load failed: ${meticaAdError.message}")

        // Exponential backoff retry
        retryAttempt++
        val delaySeconds = minOf(Math.pow(2.0, retryAttempt.toDouble()), maxRetryDelay)

        activity.window.decorView.postDelayed({
            println("Retrying rewarded load in ${delaySeconds}s")
            loadAd()
        }, (delaySeconds * 1000).toLong())
    }

    // Show callbacks
    override fun onAdShowSuccess(meticaAd: MeticaAd) {
        println("Rewarded ad shown")
    }

    override fun onAdShowFailed(meticaAd: MeticaAd, meticaAdError: MeticaAdError) {
        println("Rewarded ad show failed: ${meticaAdError.message}")
    }

    override fun onAdHidden(meticaAd: MeticaAd) {
        println("Rewarded ad hidden")
        // Preload next ad
        loadAd()
    }

    override fun onAdClicked(meticaAd: MeticaAd) {
        println("Rewarded ad clicked")
    }

    override fun onAdRevenuePaid(meticaAd: MeticaAd) {
        println("Rewarded ad revenue: ${meticaAd.revenue} from ${meticaAd.networkName}")
    }

    override fun onAdRewarded(meticaAd: MeticaAd) {
        println("User earned reward!")
        grantRewardToUser()
    }

    private fun grantRewardToUser() {
        // Grant in-game currency, extra lives, etc.
        println("Granting reward to user!")
    }
}
```

{% endcode %}

***

## Banner Ads

Small rectangular ads (320x50) that remain on screen.

{% code title="BannerActivity.kt" %}

```kotlin
import android.app.Activity
import android.os.Bundle
import android.view.Gravity
import android.widget.FrameLayout
import com.metica.MeticaSdk
import com.metica.ads.MeticaAd
import com.metica.ads.MeticaAdError
import com.metica.ads.MeticaAdView
import com.metica.ads.MeticaAdsAdViewCallback

class BannerActivity : Activity(), MeticaAdsAdViewCallback {

    private val adUnitId = "YOUR_BANNER_AD_UNIT_ID"
    private var bannerAdView: MeticaAdView? = null
    private lateinit var bannerContainer: FrameLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Assuming you have a FrameLayout in your layout with id "banner_container"
        bannerContainer = findViewById(R.id.banner_container)
        loadBanner()
    }

    private fun loadBanner() {
        // Clean up existing banner
        bannerAdView?.destroy()
        bannerAdView = null
        bannerContainer.removeAllViews()

        // Create banner ad view
        bannerAdView = MeticaSdk.Ads.createBannerAdView(adUnitId).apply {
            setListener(this@BannerActivity)
            setPlacement("home_screen")  // Optional - for analytics
        }

        // Add to container with layout params
        val layoutParams = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
        ).apply {
            gravity = Gravity.CENTER
        }

        bannerContainer.addView(bannerAdView, layoutParams)

        // Load the ad
        bannerAdView?.load()
    }

    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        println("Banner loaded: ${meticaAd.adUnitId}")
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        println("Banner load failed: ${meticaAdError.message}")
    }

    override fun onAdClicked(meticaAd: MeticaAd) {
        println("Banner clicked")
    }

    override fun onAdRevenuePaid(meticaAd: MeticaAd) {
        println("Banner revenue: ${meticaAd.revenue}")
    }

    override fun onPause() {
        super.onPause()
        bannerAdView?.stopAutoRefresh()
    }

    override fun onResume() {
        super.onResume()
        bannerAdView?.startAutoRefresh()
    }

    override fun onDestroy() {
        super.onDestroy()
        bannerAdView?.destroy()
    }
}
```

{% endcode %}

### Banner Auto-Refresh Control

```kotlin
// Stop auto-refresh (e.g., when navigating away or during gameplay)
bannerAdView?.stopAutoRefresh()

// Resume auto-refresh
bannerAdView?.startAutoRefresh()

// Manual refresh (after stopping auto-refresh)
bannerAdView?.load()
```

***

## MREC Ads

Medium Rectangle ads (300x250).

{% code title="MrecActivity.kt" %}

```kotlin
import android.app.Activity
import android.os.Bundle
import android.view.Gravity
import android.widget.FrameLayout
import com.metica.MeticaSdk
import com.metica.ads.MeticaAd
import com.metica.ads.MeticaAdError
import com.metica.ads.MeticaAdView
import com.metica.ads.MeticaAdsAdViewCallback

class MrecActivity : Activity(), MeticaAdsAdViewCallback {

    private val adUnitId = "YOUR_MREC_AD_UNIT_ID"
    private var mrecAdView: MeticaAdView? = null
    private lateinit var mrecContainer: FrameLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mrecContainer = findViewById(R.id.mrec_container)
        loadMrec()
    }

    private fun loadMrec() {
        // Clean up existing MREC
        mrecAdView?.destroy()
        mrecAdView = null
        mrecContainer.removeAllViews()

        // Create MREC ad view
        mrecAdView = MeticaSdk.Ads.createMrecAdView(adUnitId).apply {
            setListener(this@MrecActivity)
            setPlacement("game_over_screen")  // Optional - for analytics
        }

        // Add to container - MREC is 300x250
        val layoutParams = FrameLayout.LayoutParams(
            dpToPx(300),
            dpToPx(250)
        ).apply {
            gravity = Gravity.CENTER
        }

        mrecContainer.addView(mrecAdView, layoutParams)

        // Load the ad
        mrecAdView?.load()
    }

    private fun dpToPx(dp: Int): Int {
        return (dp * resources.displayMetrics.density).toInt()
    }

    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        println("MREC loaded: ${meticaAd.adUnitId}")
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        println("MREC load failed: ${meticaAdError.message}")
    }

    override fun onAdClicked(meticaAd: MeticaAd) {
        println("MREC clicked")
    }

    override fun onAdRevenuePaid(meticaAd: MeticaAd) {
        println("MREC revenue: ${meticaAd.revenue}")
    }

    override fun onPause() {
        super.onPause()
        mrecAdView?.stopAutoRefresh()
    }

    override fun onResume() {
        super.onResume()
        mrecAdView?.startAutoRefresh()
    }

    override fun onDestroy() {
        super.onDestroy()
        mrecAdView?.destroy()
    }
}
```

{% endcode %}

***

## Revenue Tracking

Track ad revenue for analytics and attribution.

{% code title="onAdRevenuePaid example" %}

```kotlin
override fun onAdRevenuePaid(meticaAd: MeticaAd) {
    // Revenue in USD
    val revenue = meticaAd.revenue ?: 0.0
    val networkName = meticaAd.networkName ?: "unknown"
    val adUnitId = meticaAd.adUnitId
    val adFormat = meticaAd.adFormat

    println("Ad revenue: $${"%.4f".format(revenue)}")
    println("Network: $networkName")
    println("Ad Unit: $adUnitId")
    println("Format: $adFormat")

    // Send to your analytics
    trackRevenue(revenue, networkName, adUnitId)
}
```

{% endcode %}

### MeticaAd Properties

| Property       | Type      | Description                               |
| -------------- | --------- | ----------------------------------------- |
| `adUnitId`     | `String`  | Unique identifier for the ad unit         |
| `revenue`      | `Double?` | Revenue in USD                            |
| `networkName`  | `String?` | Ad network that served the ad             |
| `placementTag` | `String?` | Placement identifier (if set)             |
| `adFormat`     | `String`  | Format type (INTER, REWARD, BANNER, MREC) |
| `creativeId`   | `String?` | Creative identifier                       |
| `latency`      | `Long?`   | Load latency in milliseconds              |

***

## AppLovin Consent Utilities

Access AppLovin-specific consent information via `MeticaSdk.Ads.Max`:

```kotlin
// Check if user has provided consent
val hasConsent = MeticaSdk.Ads.Max.hasUserConsent()

// Check if consent status has been set
val isConsentSet = MeticaSdk.Ads.Max.isUserConsentSet()

// Get user's geographical category for consent purposes
val geography = MeticaSdk.Ads.Max.getConsentFlowUserGeography()
```

***

## Debug Logging

Enable logging for development and debugging:

{% code title="Enable Metica logs" %}

```kotlin
import com.metica.internal.util.MeticaLogger

// Enable before initialization
MeticaLogger.enableLogs = true
```

{% endcode %}

Or via ADB:

{% code title="ADB command" %}

```bash
adb shell setprop debug.metica.internal_logging true
```

{% endcode %}

Look for "Metica" tag in Logcat.

***

## Best Practices

{% stepper %}
{% step %}

### Initialize Early

Call `MeticaSdk.initialize()` as early as possible, ideally in `Application.onCreate()` or `MainActivity.onCreate()`.
{% endstep %}

{% step %}

### Set Privacy Before Init

Always configure privacy settings before calling initialize:

```kotlin
MeticaAds.PrivacySettings.setHasUserConsent(hasConsent, context)
MeticaAds.PrivacySettings.setDoNotSell(doNotSell, context)
MeticaSdk.initialize(...)
```

{% endstep %}

{% step %}

### Preload Ads

Load the next ad immediately after showing:

```kotlin
override fun onAdHidden(meticaAd: MeticaAd) {
    loadAd()  // Preload next ad
}
```

{% endstep %}

{% step %}

### Check Readiness Before Showing

```kotlin
if (MeticaSdk.Ads.isInterstitialReady(adUnitId)) {
    MeticaSdk.Ads.showInterstitial(activity, adUnitId, null, null, callback)
}
```

{% endstep %}

{% step %}

### Pass Activity Context

Always pass the current Activity when showing fullscreen ads:

```kotlin
// Correct
MeticaSdk.Ads.showInterstitial(activity, adUnitId, null, null, callback)

// Wrong - don't use application context
MeticaSdk.Ads.showInterstitial(applicationContext, adUnitId, null, null, callback)  // Won't work
```

{% endstep %}

{% step %}

### Clean Up Banner/MREC Views

```kotlin
override fun onDestroy() {
    super.onDestroy()
    bannerAdView?.destroy()
}
```

{% endstep %}

{% step %}

### Handle Lifecycle for Ad Views

```kotlin
override fun onPause() {
    super.onPause()
    bannerAdView?.stopAutoRefresh()
}

override fun onResume() {
    super.onResume()
    bannerAdView?.startAutoRefresh()
}
```

{% endstep %}

{% step %}

### Implement Retry with Backoff

Use exponential backoff for failed loads to avoid overwhelming the network:

```kotlin
val delaySeconds = minOf(Math.pow(2.0, retryAttempt.toDouble()), 64.0)
```

{% endstep %}
{% endstepper %}

***

## Thread Safety

All callbacks are delivered on the same thread that made the original call. If you call from the main thread, callbacks arrive on the main thread - safe for UI updates:

{% code title="Thread safety example" %}

```kotlin
// Called from main thread
MeticaSdk.Ads.loadInterstitial(adUnitId, object : MeticaAdsLoadCallback {
    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        // Safe to update UI directly
        showButton.isEnabled = true
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        // Safe to update UI directly
        statusText.text = "Load failed: ${meticaAdError.message}"
    }
})
```

{% endcode %}

***

## Complete Example

A complete activity demonstrating all features.

{% code title="CompleteExampleActivity.kt" %}

```kotlin
import android.app.Activity
import android.os.Bundle
import android.view.Gravity
import android.widget.Button
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import com.metica.MeticaInitCallback
import com.metica.MeticaInitConfig
import com.metica.MeticaInitResponse
import com.metica.MeticaSdk
import com.metica.ads.*

class CompleteExampleActivity : Activity(),
    MeticaAdsLoadCallback, MeticaAdsShowCallback, MeticaAdsAdViewCallback {

    private val interstitialAdUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID"
    private val rewardedAdUnitId = "YOUR_REWARDED_AD_UNIT_ID"
    private val bannerAdUnitId = "YOUR_BANNER_AD_UNIT_ID"

    private var bannerAdView: MeticaAdView? = null
    private lateinit var statusText: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupUI()
        initializeSdk()
    }

    private fun setupUI() {
        val layout = LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            gravity = Gravity.CENTER_HORIZONTAL
            setPadding(32, 32, 32, 32)
        }

        statusText = TextView(this).apply {
            text = "Initializing..."
            textSize = 16f
        }
        layout.addView(statusText)

        Button(this).apply {
            text = "Load Interstitial"
            setOnClickListener { loadInterstitial() }
        }.also { layout.addView(it) }

        Button(this).apply {
            text = "Show Interstitial"
            setOnClickListener { showInterstitial() }
        }.also { layout.addView(it) }

        Button(this).apply {
            text = "Load Rewarded"
            setOnClickListener { loadRewarded() }
        }.also { layout.addView(it) }

        Button(this).apply {
            text = "Show Rewarded"
            setOnClickListener { showRewarded() }
        }.also { layout.addView(it) }

        // Banner container at bottom
        val bannerContainer = FrameLayout(this).apply {
            id = android.R.id.content + 1000
            layoutParams = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            ).apply { weight = 1f }
        }
        layout.addView(bannerContainer)

        setContentView(layout)
    }

    private fun initializeSdk() {
        // Privacy settings first
        MeticaAds.PrivacySettings.setHasUserConsent(true, this)
        MeticaAds.PrivacySettings.setDoNotSell(false, this)

        MeticaSdk.initialize(
            context = this,
            initConfig = MeticaInitConfig(
                apiKey = "YOUR_API_KEY",
                appId = "YOUR_APP_ID",
                userId = ""
            ),
            mediationInfo = MeticaMediationInfo(
                mediationType = MeticaMediationInfo.MeticaMediationType.MAX,
                key = "YOUR_APPLOVIN_SDK_KEY"
            )
        ) { response ->
            // For analytics/logging only - no action needed
            println("Current user is part of ${response.smartFloors?.userGroup}")
            println("Metica initialization completed")

            statusText.text = "SDK Initialized"

            // Preload ads
            loadInterstitial()
            loadRewarded()
            loadBanner()
        }
    }

    private fun loadInterstitial() {
        MeticaSdk.Ads.loadInterstitial(interstitialAdUnitId, this)
    }

    private fun showInterstitial() {
        if (MeticaSdk.Ads.isInterstitialReady(interstitialAdUnitId)) {
            MeticaSdk.Ads.showInterstitial(this, interstitialAdUnitId, null, null, this)
        }
    }

    private fun loadRewarded() {
        MeticaSdk.Ads.loadRewarded(rewardedAdUnitId, this)
    }

    private fun showRewarded() {
        if (MeticaSdk.Ads.isRewardedReady(rewardedAdUnitId)) {
            MeticaSdk.Ads.showRewarded(this, rewardedAdUnitId, null, null, this)
        }
    }

    private fun loadBanner() {
        bannerAdView?.destroy()
        bannerAdView = MeticaSdk.Ads.createBannerAdView(bannerAdUnitId).apply {
            setListener(this@CompleteExampleActivity)
        }
        // Add to your banner container and call load()
        bannerAdView?.load()
    }

    // Callbacks
    override fun onAdLoadSuccess(meticaAd: MeticaAd) {
        statusText.text = "${meticaAd.adFormat} loaded"
    }

    override fun onAdLoadFailed(meticaAdError: MeticaAdError) {
        statusText.text = "Load failed: ${meticaAdError.message}"
    }

    override fun onAdShowSuccess(meticaAd: MeticaAd) {
        statusText.text = "${meticaAd.adFormat} shown"
    }

    override fun onAdShowFailed(meticaAd: MeticaAd, meticaAdError: MeticaAdError) {
        statusText.text = "Show failed: ${meticaAdError.message}"
    }

    override fun onAdHidden(meticaAd: MeticaAd) {
        // Preload next ad
        when (meticaAd.adFormat) {
            "INTER" -> loadInterstitial()
            "REWARD" -> loadRewarded()
        }
    }

    override fun onAdClicked(meticaAd: MeticaAd) {}
    override fun onAdRevenuePaid(meticaAd: MeticaAd) {}
    override fun onAdRewarded(meticaAd: MeticaAd) {
        statusText.text = "User earned reward!"
    }

    override fun onDestroy() {
        super.onDestroy()
        bannerAdView?.destroy()
    }
}
```

{% endcode %}

***

## API Reference

### MeticaSdk

| Method                                                     | Description                |
| ---------------------------------------------------------- | -------------------------- |
| `initialize(context, initConfig, mediationInfo, callback)` | Initialize the SDK         |
| `Ads`                                                      | Access to ad functionality |

### MeticaSdk.Ads

| Method                                                                      | Description                    |
| --------------------------------------------------------------------------- | ------------------------------ |
| `loadInterstitial(adUnitId, callback)`                                      | Load an interstitial ad        |
| `showInterstitial(activity, adUnitId, placementId?, customData?, callback)` | Show an interstitial ad        |
| `isInterstitialReady(adUnitId): Boolean`                                    | Check if interstitial is ready |
| `loadRewarded(adUnitId, callback)`                                          | Load a rewarded ad             |
| `showRewarded(activity, adUnitId, placementId?, customData?, callback)`     | Show a rewarded ad             |
| `isRewardedReady(adUnitId): Boolean`                                        | Check if rewarded is ready     |
| `createBannerAdView(adUnitId): MeticaAdView`                                | Create a banner ad view        |
| `createMrecAdView(adUnitId): MeticaAdView`                                  | Create an MREC ad view         |
| `Max`                                                                       | AppLovin-specific functions    |

### MeticaAds.PrivacySettings

| Method                                  | Description          |
| --------------------------------------- | -------------------- |
| `setHasUserConsent(isConsent, context)` | Set GDPR consent     |
| `setDoNotSell(isDoNotSell, context)`    | Set CCPA do-not-sell |

### MeticaAdView

| Method                     | Description                    |
| -------------------------- | ------------------------------ |
| `setListener(callback)`    | Set the callback for ad events |
| `setPlacement(placement?)` | Set placement for analytics    |
| `load()`                   | Load the ad                    |
| `startAutoRefresh()`       | Start auto-refresh             |
| `stopAutoRefresh()`        | Stop auto-refresh              |
| `destroy()`                | Clean up resources             |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.metica.com/api/android-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
