From e9253e60161b498f2528a76198b6cd57a1a0d252 Mon Sep 17 00:00:00 2001 From: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:32:19 -0600 Subject: [PATCH] [interactive_media_ads] Adds internal wrapper for Android native `AdsRenderingSettings` (#7660) --- packages/interactive_media_ads/CHANGELOG.md | 4 + .../AdsRenderingSettingsProxyApi.kt | 91 +++ .../AdsRequestProxyApi.kt | 2 +- .../InteractiveMediaAdsLibrary.g.kt | 519 ++++++++++++++++++ .../ProxyApiRegistrar.kt | 4 + .../AdsRenderingSettingsProxyApiTest.kt | 158 ++++++ .../AdsRequestProxyAPIDelegate.swift | 2 +- .../src/android/interactive_media_ads.g.dart | 515 +++++++++++++++++ .../interactive_media_ads_android.dart | 91 +++ packages/interactive_media_ads/pubspec.yaml | 2 +- 10 files changed, 1385 insertions(+), 3 deletions(-) create mode 100644 packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApi.kt create mode 100644 packages/interactive_media_ads/android/src/test/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApiTest.kt diff --git a/packages/interactive_media_ads/CHANGELOG.md b/packages/interactive_media_ads/CHANGELOG.md index 99368f39a03a..6da27d963280 100644 --- a/packages/interactive_media_ads/CHANGELOG.md +++ b/packages/interactive_media_ads/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.2+2 + +* Adds internal wrapper for Android native `AdsRenderingSettings`. + ## 0.2.2+1 * Bumps Android dependency `com.google.ads.interactivemedia.v3:interactivemedia` from `3.34.0` to diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApi.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApi.kt new file mode 100644 index 000000000000..d924ad43f783 --- /dev/null +++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApi.kt @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package dev.flutter.packages.interactive_media_ads + +import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings +import com.google.ads.interactivemedia.v3.api.UiElement + +/** + * ProxyApi implementation for [AdsRenderingSettings]. + * + *

This class may handle instantiating native object instances that are attached to a Dart + * instance or handle method calls on the associated native class or an instance of that class. + */ +class AdsRenderingSettingsProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) : + PigeonApiAdsRenderingSettings(pigeonRegistrar) { + override fun getBitrateKbps(pigeon_instance: AdsRenderingSettings): Long { + return pigeon_instance.bitrateKbps.toLong() + } + + override fun getEnableCustomTabs(pigeon_instance: AdsRenderingSettings): Boolean { + return pigeon_instance.enableCustomTabs + } + + override fun getEnablePreloading(pigeon_instance: AdsRenderingSettings): Boolean { + return pigeon_instance.enablePreloading + } + + override fun getFocusSkipButtonWhenAvailable(pigeon_instance: AdsRenderingSettings): Boolean { + return pigeon_instance.focusSkipButtonWhenAvailable + } + + override fun getMimeTypes(pigeon_instance: AdsRenderingSettings): List { + return pigeon_instance.mimeTypes + } + + override fun setBitrateKbps(pigeon_instance: AdsRenderingSettings, bitrate: Long) { + pigeon_instance.bitrateKbps = bitrate.toInt() + } + + override fun setEnableCustomTabs( + pigeon_instance: AdsRenderingSettings, + enableCustomTabs: Boolean + ) { + pigeon_instance.enableCustomTabs = enableCustomTabs + } + + override fun setEnablePreloading( + pigeon_instance: AdsRenderingSettings, + enablePreloading: Boolean + ) { + pigeon_instance.enablePreloading = enablePreloading + } + + override fun setFocusSkipButtonWhenAvailable( + pigeon_instance: AdsRenderingSettings, + enableFocusSkipButton: Boolean + ) { + pigeon_instance.focusSkipButtonWhenAvailable = enableFocusSkipButton + } + + override fun setLoadVideoTimeout(pigeon_instance: AdsRenderingSettings, loadVideoTimeout: Long) { + pigeon_instance.setLoadVideoTimeout(loadVideoTimeout.toInt()) + } + + override fun setMimeTypes(pigeon_instance: AdsRenderingSettings, mimeTypes: List) { + pigeon_instance.mimeTypes = mimeTypes + } + + override fun setPlayAdsAfterTime(pigeon_instance: AdsRenderingSettings, time: Double) { + pigeon_instance.setPlayAdsAfterTime(time) + } + + override fun setUiElements( + pigeon_instance: AdsRenderingSettings, + uiElements: List + ) { + val nativeUiElements = + uiElements.map { + when (it) { + dev.flutter.packages.interactive_media_ads.UiElement.AD_ATTRIBUTION -> + UiElement.AD_ATTRIBUTION + dev.flutter.packages.interactive_media_ads.UiElement.COUNTDOWN -> UiElement.COUNTDOWN + dev.flutter.packages.interactive_media_ads.UiElement.UNKNOWN -> + throw UnsupportedOperationException("$it is not supported.") + } + } + pigeon_instance.setUiElements(nativeUiElements.toSet()) + } +} diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt index a09099f54f24..d8c7b41b2943 100644 --- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt +++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt @@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) : * * This must match the version in pubspec.yaml. */ - const val pluginVersion = "0.2.2+1" + const val pluginVersion = "0.2.2+2" } override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) { diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.kt index 4056a3d980b6..7dfd13066256 100644 --- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.kt +++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/InteractiveMediaAdsLibrary.g.kt @@ -537,6 +537,12 @@ abstract class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar( */ abstract fun getPigeonApiAdEventListener(): PigeonApiAdEventListener + /** + * An implementation of [PigeonApiAdsRenderingSettings] used to add a new Dart instance of + * `AdsRenderingSettings` to the Dart `InstanceManager`. + */ + abstract fun getPigeonApiAdsRenderingSettings(): PigeonApiAdsRenderingSettings + fun setUp() { InteractiveMediaAdsLibraryPigeonInstanceManagerApi.setUpMessageHandlers( binaryMessenger, instanceManager) @@ -560,6 +566,8 @@ abstract class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar( binaryMessenger, getPigeonApiAdsLoadedListener()) PigeonApiAdErrorListener.setUpMessageHandlers(binaryMessenger, getPigeonApiAdErrorListener()) PigeonApiAdEventListener.setUpMessageHandlers(binaryMessenger, getPigeonApiAdEventListener()) + PigeonApiAdsRenderingSettings.setUpMessageHandlers( + binaryMessenger, getPigeonApiAdsRenderingSettings()) } fun tearDown() { @@ -580,6 +588,7 @@ abstract class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar( PigeonApiAdsLoadedListener.setUpMessageHandlers(binaryMessenger, null) PigeonApiAdErrorListener.setUpMessageHandlers(binaryMessenger, null) PigeonApiAdEventListener.setUpMessageHandlers(binaryMessenger, null) + PigeonApiAdsRenderingSettings.setUpMessageHandlers(binaryMessenger, null) } } @@ -611,6 +620,7 @@ private class InteractiveMediaAdsLibraryPigeonProxyApiBaseCodec( value is AdErrorCode || value is AdErrorType || value is AdEventType || + value is UiElement || value == null) { super.writeValue(stream, value) return @@ -669,6 +679,8 @@ private class InteractiveMediaAdsLibraryPigeonProxyApiBaseCodec( registrar.getPigeonApiAdErrorListener().pigeon_newInstance(value) {} } else if (value is com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener) { registrar.getPigeonApiAdEventListener().pigeon_newInstance(value) {} + } else if (value is com.google.ads.interactivemedia.v3.api.AdsRenderingSettings) { + registrar.getPigeonApiAdsRenderingSettings().pigeon_newInstance(value) {} } when { @@ -854,6 +866,27 @@ enum class AdEventType(val raw: Int) { } } +/** + * Describes an element of the ad UI, to be requested or rendered by the SDK. + * + * See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/UiElement.html. + */ +enum class UiElement(val raw: Int) { + /** The ad attribution UI element, for example, "Ad". */ + AD_ATTRIBUTION(0), + /** Ad attribution is required for a countdown timer to be displayed. */ + COUNTDOWN(1), + /** The element is not recognized by this wrapper. */ + UNKNOWN(2); + + companion object { + fun ofRaw(raw: Int): UiElement? { + return values().firstOrNull { it.raw == raw } + } + } +} + private open class InteractiveMediaAdsLibraryPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { @@ -866,6 +899,9 @@ private open class InteractiveMediaAdsLibraryPigeonCodec : StandardMessageCodec( 131.toByte() -> { return (readValue(buffer) as Long?)?.let { AdEventType.ofRaw(it.toInt()) } } + 132.toByte() -> { + return (readValue(buffer) as Long?)?.let { UiElement.ofRaw(it.toInt()) } + } else -> super.readValueOfType(type, buffer) } } @@ -884,6 +920,10 @@ private open class InteractiveMediaAdsLibraryPigeonCodec : StandardMessageCodec( stream.write(131) writeValue(stream, value.raw) } + is UiElement -> { + stream.write(132) + writeValue(stream, value.raw) + } else -> super.writeValue(stream, value) } } @@ -4101,3 +4141,482 @@ abstract class PigeonApiAdEventListener( } } } +/** + * Defines parameters that control the rendering of ads. + * + * See + * https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/AdsRenderingSettings.html. + */ +@Suppress("UNCHECKED_CAST") +abstract class PigeonApiAdsRenderingSettings( + open val pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar +) { + /** Maximum recommended bitrate. */ + abstract fun getBitrateKbps( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + ): Long + + /** Returns whether the click-through URL will be opened using Custom Tabs feature. */ + abstract fun getEnableCustomTabs( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + ): Boolean + + /** + * Whether the SDK will instruct the player to load the creative in response to + * `BaseManager.init()`. + */ + abstract fun getEnablePreloading( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + ): Boolean + + /** + * Whether to focus on the skip button when the skippable ad can be skipped on Android TV. + * + * This is a no-op on non-Android TV devices. + */ + abstract fun getFocusSkipButtonWhenAvailable( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + ): Boolean + + /** The SDK will prioritize the media with MIME type on the list. */ + abstract fun getMimeTypes( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + ): List + + /** + * Maximum recommended bitrate. + * + * The value is in kbit/s. Default value, -1, means the bitrate will be selected by the SDK. + */ + abstract fun setBitrateKbps( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + bitrate: Long + ) + + /** + * Notifies the SDK whether to launch the click-through URL using Custom Tabs feature. + * + * Default is false. + */ + abstract fun setEnableCustomTabs( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + enableCustomTabs: Boolean + ) + + /** + * If set, the SDK will instruct the player to load the creative in response to + * `BaseManager.init()`. + * + * This allows the player to preload the ad at any point before calling `AdsManager.start()`. + */ + abstract fun setEnablePreloading( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + enablePreloading: Boolean + ) + + /** + * Set whether to focus on the skip button when the skippable ad can be skipped on Android TV. + * + * This is a no-op on non-Android TV devices. + * + * Default is true. + */ + abstract fun setFocusSkipButtonWhenAvailable( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + enableFocusSkipButton: Boolean + ) + + /** + * Specifies a non-default amount of time to wait for media to load before timing out, in + * milliseconds. + * + * This only applies to the IMA client-side SDK. + * + * Default time is 8000 ms. + */ + abstract fun setLoadVideoTimeout( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + loadVideoTimeout: Long + ) + + /** If specified, the SDK will prioritize the media with MIME type on the list. */ + abstract fun setMimeTypes( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + mimeTypes: List + ) + + /** + * For VMAP and ad rules playlists, only play ad breaks scheduled after this time (in seconds). + */ + abstract fun setPlayAdsAfterTime( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + time: Double + ) + + /** Sets the ad UI elements to be rendered by the IMA SDK. */ + abstract fun setUiElements( + pigeon_instance: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + uiElements: List + ) + + companion object { + @Suppress("LocalVariableName") + fun setUpMessageHandlers( + binaryMessenger: BinaryMessenger, + api: PigeonApiAdsRenderingSettings? + ) { + val codec = api?.pigeonRegistrar?.codec ?: InteractiveMediaAdsLibraryPigeonCodec() + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getBitrateKbps", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val wrapped: List = + try { + listOf(api.getBitrateKbps(pigeon_instanceArg)) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getEnableCustomTabs", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val wrapped: List = + try { + listOf(api.getEnableCustomTabs(pigeon_instanceArg)) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getEnablePreloading", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val wrapped: List = + try { + listOf(api.getEnablePreloading(pigeon_instanceArg)) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getFocusSkipButtonWhenAvailable", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val wrapped: List = + try { + listOf(api.getFocusSkipButtonWhenAvailable(pigeon_instanceArg)) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getMimeTypes", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val wrapped: List = + try { + listOf(api.getMimeTypes(pigeon_instanceArg)) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setBitrateKbps", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val bitrateArg = args[1] as Long + val wrapped: List = + try { + api.setBitrateKbps(pigeon_instanceArg, bitrateArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setEnableCustomTabs", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val enableCustomTabsArg = args[1] as Boolean + val wrapped: List = + try { + api.setEnableCustomTabs(pigeon_instanceArg, enableCustomTabsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setEnablePreloading", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val enablePreloadingArg = args[1] as Boolean + val wrapped: List = + try { + api.setEnablePreloading(pigeon_instanceArg, enablePreloadingArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setFocusSkipButtonWhenAvailable", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val enableFocusSkipButtonArg = args[1] as Boolean + val wrapped: List = + try { + api.setFocusSkipButtonWhenAvailable(pigeon_instanceArg, enableFocusSkipButtonArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setLoadVideoTimeout", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val loadVideoTimeoutArg = args[1] as Long + val wrapped: List = + try { + api.setLoadVideoTimeout(pigeon_instanceArg, loadVideoTimeoutArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setMimeTypes", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val mimeTypesArg = args[1] as List + val wrapped: List = + try { + api.setMimeTypes(pigeon_instanceArg, mimeTypesArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setPlayAdsAfterTime", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val timeArg = args[1] as Double + val wrapped: List = + try { + api.setPlayAdsAfterTime(pigeon_instanceArg, timeArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setUiElements", + codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val pigeon_instanceArg = + args[0] as com.google.ads.interactivemedia.v3.api.AdsRenderingSettings + val uiElementsArg = args[1] as List + val wrapped: List = + try { + api.setUiElements(pigeon_instanceArg, uiElementsArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } + + @Suppress("LocalVariableName", "FunctionName") + /** Creates a Dart instance of AdsRenderingSettings and attaches it to [pigeon_instanceArg]. */ + fun pigeon_newInstance( + pigeon_instanceArg: com.google.ads.interactivemedia.v3.api.AdsRenderingSettings, + callback: (Result) -> Unit + ) { + if (pigeonRegistrar.ignoreCallsToDart) { + callback( + Result.failure( + FlutterError("ignore-calls-error", "Calls to Dart are being ignored.", ""))) + return + } + if (pigeonRegistrar.instanceManager.containsInstance(pigeon_instanceArg)) { + Result.success(Unit) + return + } + val pigeon_identifierArg = + pigeonRegistrar.instanceManager.addHostCreatedInstance(pigeon_instanceArg) + val binaryMessenger = pigeonRegistrar.binaryMessenger + val codec = pigeonRegistrar.codec + val channelName = + "dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.pigeon_newInstance" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(pigeon_identifierArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/ProxyApiRegistrar.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/ProxyApiRegistrar.kt index ff1190eb9fc7..57667057e68a 100644 --- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/ProxyApiRegistrar.kt +++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/ProxyApiRegistrar.kt @@ -125,4 +125,8 @@ open class ProxyApiRegistrar(binaryMessenger: BinaryMessenger, var context: Cont override fun getPigeonApiMediaPlayer(): PigeonApiMediaPlayer { return MediaPlayerProxyApi(this) } + + override fun getPigeonApiAdsRenderingSettings(): PigeonApiAdsRenderingSettings { + return AdsRenderingSettingsProxyApi(this) + } } diff --git a/packages/interactive_media_ads/android/src/test/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApiTest.kt b/packages/interactive_media_ads/android/src/test/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApiTest.kt new file mode 100644 index 000000000000..f7585858a8e4 --- /dev/null +++ b/packages/interactive_media_ads/android/src/test/kotlin/dev/flutter/packages/interactive_media_ads/AdsRenderingSettingsProxyApiTest.kt @@ -0,0 +1,158 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package dev.flutter.packages.interactive_media_ads + +import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings +import com.google.ads.interactivemedia.v3.api.UiElement +import kotlin.test.Test +import kotlin.test.assertEquals +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +class AdsRenderingSettingsProxyApiTest { + @Test + fun getBitrateKbps() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val value = 0 + whenever(instance.bitrateKbps).thenReturn(value) + + assertEquals(value.toLong(), api.getBitrateKbps(instance)) + } + + @Test + fun getEnableCustomTabs() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val value = true + whenever(instance.enableCustomTabs).thenReturn(value) + + assertEquals(value, api.getEnableCustomTabs(instance)) + } + + @Test + fun getEnablePreloading() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val value = true + whenever(instance.enablePreloading).thenReturn(value) + + assertEquals(value, api.getEnablePreloading(instance)) + } + + @Test + fun getFocusSkipButtonWhenAvailable() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val value = true + whenever(instance.focusSkipButtonWhenAvailable).thenReturn(value) + + assertEquals(value, api.getFocusSkipButtonWhenAvailable(instance)) + } + + @Test + fun getMimeTypes() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val value = listOf("myString") + whenever(instance.mimeTypes).thenReturn(value) + + assertEquals(value, api.getMimeTypes(instance)) + } + + @Test + fun setBitrateKbps() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val bitrate = 0L + api.setBitrateKbps(instance, bitrate) + + verify(instance).bitrateKbps = bitrate.toInt() + } + + @Test + fun setEnableCustomTabs() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val enableCustomTabs = true + api.setEnableCustomTabs(instance, enableCustomTabs) + + verify(instance).enableCustomTabs = enableCustomTabs + } + + @Test + fun setEnablePreloading() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val enablePreloading = true + api.setEnablePreloading(instance, enablePreloading) + + verify(instance).enablePreloading = enablePreloading + } + + @Test + fun setFocusSkipButtonWhenAvailable() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val enableFocusSkipButton = true + api.setFocusSkipButtonWhenAvailable(instance, enableFocusSkipButton) + + verify(instance).focusSkipButtonWhenAvailable = enableFocusSkipButton + } + + @Test + fun setLoadVideoTimeout() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val loadVideoTimeout = 0L + api.setLoadVideoTimeout(instance, loadVideoTimeout) + + verify(instance).setLoadVideoTimeout(loadVideoTimeout.toInt()) + } + + @Test + fun setMimeTypes() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val mimeTypes = listOf("myString") + api.setMimeTypes(instance, mimeTypes) + + verify(instance).mimeTypes = mimeTypes + } + + @Test + fun setPlayAdsAfterTime() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val time = 1.0 + api.setPlayAdsAfterTime(instance, time) + + verify(instance).setPlayAdsAfterTime(time) + } + + @Test + fun setUiElements() { + val api = TestProxyApiRegistrar().getPigeonApiAdsRenderingSettings() + + val instance = mock() + val uiElements = listOf(dev.flutter.packages.interactive_media_ads.UiElement.AD_ATTRIBUTION) + api.setUiElements(instance, uiElements) + + verify(instance).setUiElements(setOf(UiElement.AD_ATTRIBUTION)) + } +} diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift index 9c2dcbd2f1d0..50a4dcd4e307 100644 --- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift +++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift @@ -13,7 +13,7 @@ class AdsRequestProxyAPIDelegate: PigeonApiDelegateIMAAdsRequest { /// The current version of the `interactive_media_ads` plugin. /// /// This must match the version in pubspec.yaml. - static let pluginVersion = "0.2.2+1" + static let pluginVersion = "0.2.2+2" func pigeonDefaultConstructor( pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer, diff --git a/packages/interactive_media_ads/lib/src/android/interactive_media_ads.g.dart b/packages/interactive_media_ads/lib/src/android/interactive_media_ads.g.dart index 927161d0bcee..4a1dd1516c5a 100644 --- a/packages/interactive_media_ads/lib/src/android/interactive_media_ads.g.dart +++ b/packages/interactive_media_ads/lib/src/android/interactive_media_ads.g.dart @@ -189,6 +189,8 @@ class PigeonInstanceManager { pigeon_instanceManager: instanceManager); AdEventListener.pigeon_setUpMessageHandlers( pigeon_instanceManager: instanceManager); + AdsRenderingSettings.pigeon_setUpMessageHandlers( + pigeon_instanceManager: instanceManager); return instanceManager; } @@ -639,6 +641,20 @@ enum AdEventType { unknown, } +/// Describes an element of the ad UI, to be requested or rendered by the SDK. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/UiElement.html. +enum UiElement { + /// The ad attribution UI element, for example, "Ad". + adAttribution, + + /// Ad attribution is required for a countdown timer to be displayed. + countdown, + + /// The element is not recognized by this wrapper. + unknown, +} + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -655,6 +671,9 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is AdEventType) { buffer.putUint8(131); writeValue(buffer, value.index); + } else if (value is UiElement) { + buffer.putUint8(132); + writeValue(buffer, value.index); } else { super.writeValue(buffer, value); } @@ -672,6 +691,9 @@ class _PigeonCodec extends StandardMessageCodec { case 131: final int? value = readValue(buffer) as int?; return value == null ? null : AdEventType.values[value]; + case 132: + final int? value = readValue(buffer) as int?; + return value == null ? null : UiElement.values[value]; default: return super.readValueOfType(type, buffer); } @@ -4975,3 +4997,496 @@ class AdEventListener extends PigeonInternalProxyApiBaseClass { ); } } + +/// Defines parameters that control the rendering of ads. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/AdsRenderingSettings.html. +class AdsRenderingSettings extends PigeonInternalProxyApiBaseClass { + /// Constructs [AdsRenderingSettings] without creating the associated native object. + /// + /// This should only be used by subclasses created by this library or to + /// create copies for an [PigeonInstanceManager]. + @protected + AdsRenderingSettings.pigeon_detached({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + }); + + late final _PigeonInternalProxyApiBaseCodec + _pigeonVar_codecAdsRenderingSettings = + _PigeonInternalProxyApiBaseCodec(pigeon_instanceManager); + + static void pigeon_setUpMessageHandlers({ + bool pigeon_clearHandlers = false, + BinaryMessenger? pigeon_binaryMessenger, + PigeonInstanceManager? pigeon_instanceManager, + AdsRenderingSettings Function()? pigeon_newInstance, + }) { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _PigeonInternalProxyApiBaseCodec( + pigeon_instanceManager ?? PigeonInstanceManager.instance); + final BinaryMessenger? binaryMessenger = pigeon_binaryMessenger; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.pigeon_newInstance', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (pigeon_clearHandlers) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.pigeon_newInstance was null.'); + final List args = (message as List?)!; + final int? arg_pigeon_instanceIdentifier = (args[0] as int?); + assert(arg_pigeon_instanceIdentifier != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.pigeon_newInstance was null, expected non-null int.'); + try { + (pigeon_instanceManager ?? PigeonInstanceManager.instance) + .addHostCreatedInstance( + pigeon_newInstance?.call() ?? + AdsRenderingSettings.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + ), + arg_pigeon_instanceIdentifier!, + ); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } + + /// Maximum recommended bitrate. + Future getBitrateKbps() async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getBitrateKbps'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as int?)!; + } + } + + /// Returns whether the click-through URL will be opened using Custom Tabs + /// feature. + Future getEnableCustomTabs() async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getEnableCustomTabs'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Whether the SDK will instruct the player to load the creative in response + /// to `BaseManager.init()`. + Future getEnablePreloading() async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getEnablePreloading'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Whether to focus on the skip button when the skippable ad can be skipped + /// on Android TV. + /// + /// This is a no-op on non-Android TV devices. + Future getFocusSkipButtonWhenAvailable() async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getFocusSkipButtonWhenAvailable'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// The SDK will prioritize the media with MIME type on the list. + Future> getMimeTypes() async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.getMimeTypes'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)!.cast(); + } + } + + /// Maximum recommended bitrate. + /// + /// The value is in kbit/s. Default value, -1, means the bitrate will be + /// selected by the SDK. + Future setBitrateKbps(int bitrate) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setBitrateKbps'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, bitrate]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Notifies the SDK whether to launch the click-through URL using Custom Tabs + /// feature. + /// + /// Default is false. + Future setEnableCustomTabs(bool enableCustomTabs) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setEnableCustomTabs'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, enableCustomTabs]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// If set, the SDK will instruct the player to load the creative in response + /// to `BaseManager.init()`. + /// + /// This allows the player to preload the ad at any point before calling + /// `AdsManager.start()`. + Future setEnablePreloading(bool enablePreloading) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setEnablePreloading'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, enablePreloading]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Set whether to focus on the skip button when the skippable ad can be + /// skipped on Android TV. + /// + /// This is a no-op on non-Android TV devices. + /// + /// Default is true. + Future setFocusSkipButtonWhenAvailable( + bool enableFocusSkipButton) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setFocusSkipButtonWhenAvailable'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, enableFocusSkipButton]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Specifies a non-default amount of time to wait for media to load before + /// timing out, in milliseconds. + /// + /// This only applies to the IMA client-side SDK. + /// + /// Default time is 8000 ms. + Future setLoadVideoTimeout(int loadVideoTimeout) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setLoadVideoTimeout'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, loadVideoTimeout]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// If specified, the SDK will prioritize the media with MIME type on the + /// list. + Future setMimeTypes(List mimeTypes) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setMimeTypes'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, mimeTypes]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// For VMAP and ad rules playlists, only play ad breaks scheduled after this + /// time (in seconds). + Future setPlayAdsAfterTime(double time) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setPlayAdsAfterTime'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([this, time]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Sets the ad UI elements to be rendered by the IMA SDK. + Future setUiElements(List uiElements) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecAdsRenderingSettings; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.AdsRenderingSettings.setUiElements'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, uiElements]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + @override + AdsRenderingSettings pigeon_copy() { + return AdsRenderingSettings.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + ); + } +} diff --git a/packages/interactive_media_ads/pigeons/interactive_media_ads_android.dart b/packages/interactive_media_ads/pigeons/interactive_media_ads_android.dart index 4ac4afdf7e04..f16486aff2d0 100644 --- a/packages/interactive_media_ads/pigeons/interactive_media_ads_android.dart +++ b/packages/interactive_media_ads/pigeons/interactive_media_ads_android.dart @@ -207,6 +207,20 @@ enum AdEventType { unknown, } +/// Describes an element of the ad UI, to be requested or rendered by the SDK. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/UiElement.html. +enum UiElement { + /// The ad attribution UI element, for example, "Ad". + adAttribution, + + /// Ad attribution is required for a countdown timer to be displayed. + countdown, + + /// The element is not recognized by this wrapper. + unknown, +} + /// A base class for more specialized container interfaces. /// /// See https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/BaseDisplayContainer.html. @@ -743,3 +757,80 @@ abstract class AdEventListener { /// Respond to an occurrence of an AdEvent. late final void Function(AdEvent event) onAdEvent; } + +/// Defines parameters that control the rendering of ads. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/api/reference/com/google/ads/interactivemedia/v3/api/AdsRenderingSettings.html. +@ProxyApi( + kotlinOptions: KotlinProxyApiOptions( + fullClassName: + 'com.google.ads.interactivemedia.v3.api.AdsRenderingSettings', + ), +) +abstract class AdsRenderingSettings { + /// Maximum recommended bitrate. + int getBitrateKbps(); + + /// Returns whether the click-through URL will be opened using Custom Tabs + /// feature. + bool getEnableCustomTabs(); + + /// Whether the SDK will instruct the player to load the creative in response + /// to `BaseManager.init()`. + bool getEnablePreloading(); + + /// Whether to focus on the skip button when the skippable ad can be skipped + /// on Android TV. + /// + /// This is a no-op on non-Android TV devices. + bool getFocusSkipButtonWhenAvailable(); + + /// The SDK will prioritize the media with MIME type on the list. + List getMimeTypes(); + + /// Maximum recommended bitrate. + /// + /// The value is in kbit/s. Default value, -1, means the bitrate will be + /// selected by the SDK. + void setBitrateKbps(int bitrate); + + /// Notifies the SDK whether to launch the click-through URL using Custom Tabs + /// feature. + /// + /// Default is false. + void setEnableCustomTabs(bool enableCustomTabs); + + /// If set, the SDK will instruct the player to load the creative in response + /// to `BaseManager.init()`. + /// + /// This allows the player to preload the ad at any point before calling + /// `AdsManager.start()`. + void setEnablePreloading(bool enablePreloading); + + /// Set whether to focus on the skip button when the skippable ad can be + /// skipped on Android TV. + /// + /// This is a no-op on non-Android TV devices. + /// + /// Default is true. + void setFocusSkipButtonWhenAvailable(bool enableFocusSkipButton); + + /// Specifies a non-default amount of time to wait for media to load before + /// timing out, in milliseconds. + /// + /// This only applies to the IMA client-side SDK. + /// + /// Default time is 8000 ms. + void setLoadVideoTimeout(int loadVideoTimeout); + + /// If specified, the SDK will prioritize the media with MIME type on the + /// list. + void setMimeTypes(List mimeTypes); + + /// For VMAP and ad rules playlists, only play ad breaks scheduled after this + /// time (in seconds). + void setPlayAdsAfterTime(double time); + + /// Sets the ad UI elements to be rendered by the IMA SDK. + void setUiElements(List uiElements); +} diff --git a/packages/interactive_media_ads/pubspec.yaml b/packages/interactive_media_ads/pubspec.yaml index 30c607b8fffe..172c65415d5f 100644 --- a/packages/interactive_media_ads/pubspec.yaml +++ b/packages/interactive_media_ads/pubspec.yaml @@ -2,7 +2,7 @@ name: interactive_media_ads description: A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS. repository: https://github.com/flutter/packages/tree/main/packages/interactive_media_ads issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+interactive_media_ads%22 -version: 0.2.2+1 # This must match the version in +version: 0.2.2+2 # This must match the version in # `android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt` and # `ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift`