From 5f9a759407fd702447b93cf98f2537f8237b8729 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Thu, 6 Aug 2026 00:03:24 +0200 Subject: [PATCH] Show the banner when consent is cached but the consent call fails The consent flow decided whether an ad may be requested from whether the UMP call came back clean, rather than from canRequestAds(). Both error paths hid the banner outright: - requestConsentInfoUpdate failing hid it and returned. Its own comment notes this fires for the mundane offline case, when a device that was asleep times out against fundingchoicesmessages.google.com. - a non-null FormError from loadAndShowConsentFormIfRequired hid it even when canRequestAds() was true. Neither is a refusal. The SDK caches the user's decision, so a form that fails to show or an update that times out still leaves an earlier consent standing, and outside the regions where a form is required at all there is no decision to fail in the first place. A single timeout therefore blanked the banner for the whole session, for users who had already said yes and for users who were never going to be asked. Decide on canRequestAds() alone in both callbacks, and keep logging the errors as breadcrumbs rather than acting on them. showGoogleAds() runs at billing setup and again on every onConfigurationChanged, so this path is hit on every launch and every rotation. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PafKp4GDZk7AYPbSNLTiti --- .../opendocument/droid/nonfree/AdManager.kt | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/app/opendocument/droid/nonfree/AdManager.kt b/app/src/main/java/app/opendocument/droid/nonfree/AdManager.kt index 2bee420b1e03..65afdaafa5e8 100644 --- a/app/src/main/java/app/opendocument/droid/nonfree/AdManager.kt +++ b/app/src/main/java/app/opendocument/droid/nonfree/AdManager.kt @@ -8,6 +8,7 @@ import com.google.android.gms.ads.AdSize import com.google.android.gms.ads.AdView import com.google.android.gms.ads.MobileAds import com.google.android.gms.ads.RequestConfiguration +import com.google.android.ump.ConsentInformation import com.google.android.ump.ConsentRequestParameters import com.google.android.ump.FormError import com.google.android.ump.UserMessagingPlatform @@ -95,23 +96,12 @@ class AdManager { { UserMessagingPlatform.loadAndShowConsentFormIfRequired(activity) { loadAndShowError -> - if (loadAndShowError != null || !consentInformation.canRequestAds()) { - // without this the banner just silently stays hidden, - // and the ump sdk only logs an unspecific "Error - // making request." - crashManager.log( - "consent form failed: " + - describe(loadAndShowError) + - ", canRequestAds=" + - consentInformation.canRequestAds() - ) - - hideGoogleAds() - - return@loadAndShowConsentFormIfRequired + if (loadAndShowError != null) { + // the ump sdk only logs an unspecific "Error making request." + crashManager.log("consent form failed: " + describe(loadAndShowError)) } - activity.runOnUiThread { showAdaptiveBanner() } + showAdsIfConsented(consentInformation) } }, { requestConsentError -> @@ -119,11 +109,33 @@ class AdManager { // times out against fundingchoicesmessages.google.com crashManager.log("consent info update failed: " + describe(requestConsentError)) - hideGoogleAds() + showAdsIfConsented(consentInformation) }, ) } + /** + * Whether we may load an ad is [ConsentInformation.canRequestAds] and nothing else - never + * whether the consent call itself came back clean. + * + * The sdk caches the user's decision, so a form that fails to show, or an update that times out + * because the device is offline, still leaves an earlier consent standing, and outside the + * regions where a form is required at all there is no decision to fail in the first place. + * Treating those errors as a refusal hid the banner for the rest of the session for users who + * had already said yes. + */ + private fun showAdsIfConsented(consentInformation: ConsentInformation) { + if (!consentInformation.canRequestAds()) { + crashManager.log("consent does not allow requesting ads") + + hideGoogleAds() + + return + } + + activity.runOnUiThread { showAdaptiveBanner() } + } + // https://developers.google.com/admob/android/banner/adaptive // the anchored adaptive size is deprecated in favour of the inline one, which sizes the // banner differently - a change to make on its own rather than in passing