Skip to content

Commit

Permalink
REM-928 - Add the rotation to Ads provider
Browse files Browse the repository at this point in the history
  • Loading branch information
naz013 committed Jan 19, 2025
1 parent 6501083 commit 2db863c
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 133 deletions.
145 changes: 16 additions & 129 deletions app/src/free/java/com/elementary/tasks/AdsProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,18 @@ package com.elementary.tasks

import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.RatingBar
import android.widget.TextView
import androidx.annotation.LayoutRes
import com.elementary.tasks.core.utils.SuperUtil
import com.github.naz013.logging.Logger
import com.github.naz013.ui.common.view.gone
import com.github.naz013.ui.common.view.transparent
import com.github.naz013.ui.common.view.visible
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import com.google.android.gms.ads.nativead.NativeAdView
import com.google.android.ump.ConsentForm
import com.google.android.ump.ConsentInformation
import com.google.android.ump.ConsentRequestParameters
import com.google.android.ump.UserMessagingPlatform

class AdsProvider {

private var nativeAdd: NativeAd? = null
private var consentInformation: ConsentInformation? = null
private var consentForm: ConsentForm? = null

Expand Down Expand Up @@ -83,26 +65,15 @@ class AdsProvider {
bannerId: String,
failListener: (() -> Unit)? = null
) {
val adView = AdView(viewGroup.context)
adView.setAdSize(AdSize.LARGE_BANNER)
adView.adUnitId = bannerId

viewGroup.removeAllViews()
viewGroup.addView(adView)

val adRequest = AdRequest.Builder().build()
adView.loadAd(adRequest)

adView.adListener = object : AdListener() {
override fun onAdFailedToLoad(adError: LoadAdError) {
adView.gone()
failListener?.invoke()
}

override fun onAdLoaded() {
adView.visible()
RotatingBannerAdsProvider(
bannerId = bannerId,
viewGroup = viewGroup,
onAdsFailureCallback = object : OnAdsFailureCallback {
override fun onAdsFailure() {
failListener?.invoke()
}
}
}
)
}

fun showNativeBanner(
Expand All @@ -111,104 +82,20 @@ class AdsProvider {
@LayoutRes res: Int,
failListener: (() -> Unit)? = null
) {
val adLoader = AdLoader.Builder(viewGroup.context, bannerId)
.forNativeAd { ad: NativeAd ->
nativeAdd?.destroy()
nativeAdd = ad
val adView = LayoutInflater.from(viewGroup.context).inflate(res, null) as NativeAdView
populateUnifiedNativeAdView(ad, adView)
viewGroup.removeAllViews()
viewGroup.addView(adView)
}
.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
super.onAdFailedToLoad(error)
Logger.e("Failed to load native ad: ${error.message}")
RotatingNativeAdsProvider(
viewGroup = viewGroup,
bannerId = bannerId,
res = res,
onAdsFailureCallback = object : OnAdsFailureCallback {
override fun onAdsFailure() {
wasError = true
failListener?.invoke()
}
})
.withNativeAdOptions(
NativeAdOptions.Builder()
.setRequestMultipleImages(false)
.build()
)
.build()
adLoader.loadAd(AdRequest.Builder().build())
}

fun destroy() {
nativeAdd?.destroy()
}

private fun populateUnifiedNativeAdView(nativeAd: NativeAd, adView: NativeAdView) {
adView.mediaView = adView.findViewById(R.id.ad_media)

adView.headlineView = adView.findViewById(R.id.ad_headline)
adView.bodyView = adView.findViewById(R.id.ad_body)
adView.callToActionView = adView.findViewById(R.id.ad_call_to_action)
adView.iconView = adView.findViewById(R.id.ad_app_icon)
adView.priceView = adView.findViewById(R.id.ad_price)
adView.starRatingView = adView.findViewById(R.id.ad_stars)
adView.storeView = adView.findViewById(R.id.ad_store)
adView.advertiserView = adView.findViewById(R.id.ad_advertiser)

(adView.headlineView as TextView).text = nativeAd.headline
if (nativeAd.body == null) {
adView.bodyView?.transparent()
} else {
adView.bodyView?.visible()
(adView.bodyView as TextView).text = nativeAd.body
}

if (nativeAd.callToAction == null) {
adView.callToActionView?.transparent()
} else {
adView.callToActionView?.visible()
(adView.callToActionView as Button).text = nativeAd.callToAction
}

if (nativeAd.icon == null) {
adView.iconView?.gone()
} else {
(adView.iconView as ImageView).setImageDrawable(
nativeAd.icon?.drawable
)
adView.iconView?.visible()
}

if (nativeAd.price == null) {
adView.priceView?.transparent()
} else {
adView.priceView?.visible()
(adView.priceView as TextView).text = nativeAd.price
}

if (nativeAd.store == null) {
adView.storeView?.transparent()
} else {
adView.storeView?.visible()
(adView.storeView as TextView).text = nativeAd.store
}

if (nativeAd.starRating == null) {
adView.starRatingView?.transparent()
} else {
(adView.starRatingView as RatingBar).rating = nativeAd.starRating!!.toFloat()
adView.starRatingView?.visible()
}

if (nativeAd.advertiser == null) {
adView.advertiserView?.transparent()
} else {
(adView.advertiserView as TextView).text = nativeAd.advertiser
adView.advertiserView?.visible()
}
adView.setNativeAd(nativeAd)
}
)
}

companion object {
private const val ADMOB_ID = "ca-app-pub-5133908997831400~9675541050"
const val REMINDER_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/1084030852"
const val NOTE_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/4831704177"
const val BIRTHDAY_PREVIEW_BANNER_ID = "ca-app-pub-5133908997831400/1262280397"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.elementary.tasks

interface OnAdsFailureCallback {
fun onAdsFailure()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.elementary.tasks

import android.os.Handler
import android.os.Looper
import android.view.ViewGroup
import androidx.core.view.doOnDetach
import com.github.naz013.logging.Logger
import com.github.naz013.ui.common.view.gone
import com.github.naz013.ui.common.view.visible
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.LoadAdError
import java.lang.ref.WeakReference

class RotatingBannerAdsProvider(
private val bannerId: String,
viewGroup: ViewGroup,
onAdsFailureCallback: OnAdsFailureCallback
) {

private val parent = WeakReference(viewGroup)
private val callback = WeakReference(onAdsFailureCallback)

private val handler = Handler(Looper.getMainLooper())
private val runnable = Runnable { scheduleAds() }

init {
scheduleAds()
listenParent()
}

private fun listenParent() {
parent.get()?.doOnDetach {
Logger.d(TAG, "Parent view is detached, will not show ADS")
handler.removeCallbacks(runnable)
callback.clear()
parent.clear()
}
}

private fun scheduleAds() {
if (safeLoadAds()) {
Logger.d(TAG, "Scheduled ads")
handler.postDelayed(runnable, ADS_DURATION)
}
}

private fun safeLoadAds(): Boolean {
return runCatching { loadAds() }.getOrNull() ?: false
}

private fun loadAds(): Boolean {
val viewGroup = parent.get() ?: return false.also {
Logger.e(TAG, "Will not show ADS, Parent view is null")
}
val adView = AdView(viewGroup.context)
adView.setAdSize(AdSize.LARGE_BANNER)
adView.adUnitId = bannerId

viewGroup.removeAllViews()
viewGroup.addView(adView)

val adRequest = AdRequest.Builder().build()
adView.loadAd(adRequest)

adView.adListener = object : AdListener() {
override fun onAdFailedToLoad(adError: LoadAdError) {
adView.gone()
callback.get()?.onAdsFailure()
}

override fun onAdLoaded() {
adView.visible()
}
}
return true
}

companion object {
private const val TAG = "RotatingBannerAdsProvider"
private const val ADS_DURATION = 1 * 60 * 1000L // 1 minute
}
}
Loading

0 comments on commit 2db863c

Please sign in to comment.