From a24f9f8519f837cb01d64d8f37476f16ea9c8ee0 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 25 Mar 2026 10:56:18 +0100 Subject: [PATCH 1/3] Fix return types when view is null --- .../src/main/java/com/theoplayer/ads/AdsModule.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/android/src/main/java/com/theoplayer/ads/AdsModule.kt b/android/src/main/java/com/theoplayer/ads/AdsModule.kt index 88684fc49..e6a5a099d 100644 --- a/android/src/main/java/com/theoplayer/ads/AdsModule.kt +++ b/android/src/main/java/com/theoplayer/ads/AdsModule.kt @@ -68,11 +68,7 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun currentAds(tag: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - if (view == null) { - promise.resolve(Arguments.createMap()) - } else { - promise.resolve(AdAdapter.fromAds(view.adsApi.currentAds)) - } + promise.resolve(if (view == null) Arguments.createArray() else AdAdapter.fromAds(view.adsApi.currentAds)) } } @@ -80,11 +76,7 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun scheduledAdBreaks(tag: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - if (view == null) { - promise.resolve(Arguments.createMap()) - } else { - promise.resolve(AdAdapter.fromAdBreaks(view.adsApi.scheduledAdBreaks)) - } + promise.resolve(if (view == null) Arguments.createArray() else AdAdapter.fromAdBreaks(view.adsApi.scheduledAdBreaks)) } } From c60e815e8d94d1911d978265c78cac2f2ba31add Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 25 Mar 2026 11:01:01 +0100 Subject: [PATCH 2/3] Restructure code --- .../main/java/com/theoplayer/ads/AdsModule.kt | 62 +++++++------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/android/src/main/java/com/theoplayer/ads/AdsModule.kt b/android/src/main/java/com/theoplayer/ads/AdsModule.kt index e6a5a099d..fa47a941f 100644 --- a/android/src/main/java/com/theoplayer/ads/AdsModule.kt +++ b/android/src/main/java/com/theoplayer/ads/AdsModule.kt @@ -16,6 +16,8 @@ private const val PROP_OMID_VIEW = "view" private const val PROP_OMID_PURPOSE = "purpose" private const val PROP_OMID_REASON = "reason" +private const val ERR_SCHEDULE_AD = "Error scheduling ad" + @Suppress("unused") @ReactModule(name = AdsModule.NAME) class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(context) { @@ -42,12 +44,10 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun schedule(tag: Int, ad: ReadableMap) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - if (view != null) { - try { - view.adsApi.schedule(sourceHelper.parseAdFromJS(ad)) - } catch (exception: THEOplayerException) { - Log.e(NAME, exception.message!!) - } + try { + view?.adsApi?.schedule(sourceHelper.parseAdFromJS(ad)) + } catch (exception: THEOplayerException) { + Log.e(NAME, exception.message ?: ERR_SCHEDULE_AD) } } } @@ -56,11 +56,7 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun currentAdBreak(tag: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - if (view == null) { - promise.resolve(Arguments.createMap()) - } else { - promise.resolve(AdAdapter.fromAdBreak(view.adsApi.currentAdBreak)) - } + promise.resolve(if (view == null) Arguments.createMap() else AdAdapter.fromAdBreak(view.adsApi.currentAdBreak)) } } @@ -84,16 +80,12 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun playing(tag: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - if (view == null) { - promise.resolve(false) - } else { - promise.resolve(view.adsApi.isPlaying) - } + promise.resolve(view?.adsApi?.isPlaying ?: false) } } // Skip the current linear ad. - // NOTE: This will have no effect when the current linear ad is (not yet) skippable. + // NOTE: This will have no effect when the current linear ad is not (yet) skippable. @ReactMethod fun skip(tag: Int) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> view?.adsApi?.skip() } @@ -102,21 +94,15 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun daiSnapback(tag: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - val daiIntegration = view?.playerContext?.daiIntegration - if (daiIntegration == null) { - promise.resolve(false) - } else { - promise.resolve(daiIntegration.enableSnapback) - } + promise.resolve(view?.playerContext?.daiIntegration?.enableSnapback ?: false) } } @ReactMethod fun daiSetSnapback(tag: Int, enabled: Boolean?) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - val daiIntegration = view?.playerContext?.daiIntegration - if (daiIntegration != null) { - daiIntegration.enableSnapback = enabled!! + view?.playerContext?.daiIntegration?.let { integration -> + integration.enableSnapback = enabled ?: false } } } @@ -124,24 +110,20 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c @ReactMethod fun daiContentTimeForStreamTime(tag: Int, time: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - val daiIntegration = view?.playerContext?.daiIntegration - if (daiIntegration == null) { - promise.resolve(time) - } else { - promise.resolve((1e03 * daiIntegration.contentTimeForStreamTime(1e-03 * time)).toInt()) - } + val contentTime = view?.playerContext?.daiIntegration?.let { integration -> + (1e03 * integration.contentTimeForStreamTime(1e-03 * time)).toInt() + } ?: time + promise.resolve(contentTime) } } @ReactMethod fun daiStreamTimeForContentTime(tag: Int, time: Int, promise: Promise) { viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> - val daiIntegration = view?.playerContext?.daiIntegration - if (daiIntegration == null) { - promise.resolve(time) - } else { - promise.resolve((1e03 * daiIntegration.streamTimeForContentTime(1e-03 * time)).toInt()) - } + val streamTime = view?.playerContext?.daiIntegration?.let { integration -> + (1e03 * integration.streamTimeForContentTime(1e-03 * time)).toInt() + } ?: time + promise.resolve(streamTime) } } @@ -173,9 +155,7 @@ class AdsModule(context: ReactApplicationContext) : ReactContextBaseJavaModule(c purpose: OmidFriendlyObstructionPurpose?, reason: String? ) { - if (obsView == null || purpose == null) { - return - } + if (obsView == null || purpose == null) return viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? -> view?.player?.ads?.omid?.addFriendlyObstruction( OmidFriendlyObstruction(obsView, purpose, reason) From e6eb6b076d1d5e86c129926a4f07086e84a20c81 Mon Sep 17 00:00:00 2001 From: Tom Van Laerhoven Date: Wed, 25 Mar 2026 11:03:23 +0100 Subject: [PATCH 3/3] Add changelog entry --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3067b367a..52b305bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +- Fixed an issue on Android where the Ads API would sometimes return an empty map instead of an array when querying the list of current ads or scheduled ad breaks. + ## [10.12.1] - 26-03-19 ### Fixed