Skip to content

Commit

Permalink
feat: enable interstitial ads, add gdpr dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
mopsalarm committed Sep 6, 2023
1 parent 4c79d7f commit a951c94
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 57 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ dependencies {
// implementation 'com.google.guava:listenablefuture:1.0'
implementation 'androidx.paging:paging-runtime:3.2.0'
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation 'com.google.android.ump:user-messaging-platform:2.1.0'

implementation 'androidx.activity:activity-ktx:1.7.2'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
Expand Down
7 changes: 1 addition & 6 deletions app/src/main/java/com/pr0gramm/app/ApplicationClass.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import com.pr0gramm.app.services.Track
import com.pr0gramm.app.sync.SyncStatsWorker
import com.pr0gramm.app.sync.SyncWorker
import com.pr0gramm.app.ui.ActivityErrorHandler
import com.pr0gramm.app.ui.AdService
import com.pr0gramm.app.ui.dialogs.ErrorDialogFragment.Companion.GlobalErrorDialogHandler
import com.pr0gramm.app.util.AndroidUtility
import com.pr0gramm.app.util.AndroidUtility.buildVersionCode
Expand All @@ -25,7 +24,7 @@ import com.pr0gramm.app.util.debugOnly
import com.pr0gramm.app.util.di.InjectorAware
import com.pr0gramm.app.util.doInBackground
import kotlinx.coroutines.runBlocking
import java.util.*
import java.util.WeakHashMap
import java.util.concurrent.TimeUnit
import java.util.logging.Level
import java.util.logging.LogManager
Expand Down Expand Up @@ -106,10 +105,6 @@ open class ApplicationClass : Application(), InjectorAware {
log?.handlers?.forEach { it.level = Level.INFO }
}

logger.time("Initializing MobileAds") {
AdService.initializeMobileAds(this)
}

// wait for firebase setup to finish
runBlocking {
firebaseJob.join()
Expand Down
44 changes: 22 additions & 22 deletions app/src/main/java/com/pr0gramm/app/services/Track.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ object Track : InjectorAware {

fun loginSuccessful() {
send("login") {
putBoolean("success", true)
putBoolean(FirebaseAnalytics.Param.SUCCESS, true)
}

Stats().increment("login.succeeded")
}

fun loginFailed(type: String) {
send("login") {
putBoolean("success", false)
putString("type", type)
putBoolean(FirebaseAnalytics.Param.SUCCESS, false)
putString(FirebaseAnalytics.Param.VALUE, type)
}

Stats().increment("login.failed", "reason:$type")
Expand All @@ -65,7 +65,7 @@ object Track : InjectorAware {

fun writeComment(root: Boolean) {
send("write_comment") {
putBoolean("root", root)
putBoolean(FirebaseAnalytics.Param.VALUE, root)
}
}

Expand All @@ -79,22 +79,22 @@ object Track : InjectorAware {

fun votePost(vote: Vote) {
send("vote") {
putString("vote_type", vote.name)
putString("content_type", "post")
putString(FirebaseAnalytics.Param.VALUE, vote.name)
putString(FirebaseAnalytics.Param.CONTENT_TYPE, "post")
}
}

fun voteTag(vote: Vote) {
send("vote") {
putString("vote_type", vote.name)
putString("content_type", "tag")
putString(FirebaseAnalytics.Param.VALUE, vote.name)
putString(FirebaseAnalytics.Param.CONTENT_TYPE, "tag")
}
}

fun voteComment(vote: Vote) {
send("vote") {
putString("vote_type", vote.name)
putString("content_type", "comment")
putString(FirebaseAnalytics.Param.VALUE, vote.name)
putString(FirebaseAnalytics.Param.CONTENT_TYPE, "comment")
}
}

Expand All @@ -104,7 +104,7 @@ object Track : InjectorAware {

fun openBrowser(type: String) {
send("open_browser") {
putString("type", type)
putString(FirebaseAnalytics.Param.VALUE, type)
}
}

Expand All @@ -115,8 +115,8 @@ object Track : InjectorAware {
val sizeCategory = "%d-%d kb".format(categoryStart, categoryStart + 512)

send("upload") {
putLong("size", size)
putString("size_category", sizeCategory)
putLong(FirebaseAnalytics.Param.VALUE, size)
putString(FirebaseAnalytics.Param.ITEM_CATEGORY, sizeCategory)
}
}

Expand All @@ -126,13 +126,13 @@ object Track : InjectorAware {

fun inboxNotificationClosed(method: String) {
send("inbox_notification_close") {
putString("method", method)
putString(FirebaseAnalytics.Param.METHOD, method)
}
}

fun preloadCurrentFeed(size: Int) {
send("preload_feed") {
putInt("item_count", size)
putInt(FirebaseAnalytics.Param.VALUE, size)
}
}

Expand Down Expand Up @@ -162,7 +162,7 @@ object Track : InjectorAware {

fun specialMenuActionClicked(uri: Uri) {
send("special_menu_item") {
putString("uri", uri.toString())
putString(FirebaseAnalytics.Param.VALUE, uri.toString())
}
}

Expand All @@ -178,15 +178,15 @@ object Track : InjectorAware {

fun openFeed(filter: FeedFilter) {
send("view_feed") {
filter.tags?.let { putBoolean("tags", true) }
filter.collection?.let { putBoolean("collection", true) }
filter.username?.let { putBoolean("username", true) }
filter.tags?.let { putBoolean(FirebaseAnalytics.Param.TERM, true) }
filter.collection?.let { putBoolean(FirebaseAnalytics.Param.GROUP_ID, true) }
filter.username?.let { putBoolean(FirebaseAnalytics.Param.AFFILIATION, true) }
}
}

fun viewItem(itemId: Long) {
send("view_item") {
putLong("id", itemId)
putLong(FirebaseAnalytics.Param.ITEM_ID, itemId)
}
}

Expand All @@ -202,7 +202,7 @@ object Track : InjectorAware {

fun openZoomView(itemId: Long) {
send("zoom_view") {
putLong("id", itemId)
putLong(FirebaseAnalytics.Param.ITEM_ID, itemId)
}
}

Expand All @@ -215,7 +215,7 @@ object Track : InjectorAware {
installerTracked = true

send("installer") {
putString("package", name.toString())
putString(FirebaseAnalytics.Param.VALUE, name.toString())
}
}
}
Expand Down
30 changes: 20 additions & 10 deletions app/src/main/java/com/pr0gramm/app/services/config/ConfigService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ import android.content.Context
import android.content.SharedPreferences
import android.provider.Settings
import androidx.core.content.edit
import com.pr0gramm.app.*
import com.pr0gramm.app.BuildConfig
import com.pr0gramm.app.Duration.Companion.minutes
import com.pr0gramm.app.Instant
import com.pr0gramm.app.Logger
import com.pr0gramm.app.MoshiInstance
import com.pr0gramm.app.api.pr0gramm.Api
import com.pr0gramm.app.model.config.Config
import com.pr0gramm.app.util.*
import com.pr0gramm.app.util.AndroidUtility
import com.pr0gramm.app.util.debugOnly
import com.pr0gramm.app.util.di.injector
import com.pr0gramm.app.util.doInBackground
import com.pr0gramm.app.util.getStringOrNull
import com.pr0gramm.app.util.runEvery
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.adapter
import kotlinx.coroutines.flow.Flow
Expand Down Expand Up @@ -104,14 +111,17 @@ class ConfigService(context: Application,
debugOnly {
// update config for development.
return configState.copy(
adTypesLoggedIn = listOf(Config.AdType.FEED),
adTypesLoggedOut = listOf(Config.AdType.FEED, Config.AdType.FEED_TO_POST_INTERSTITIAL),
interstitialAdIntervalInSeconds = 10,
specialMenuItems = configState.specialMenuItems.takeIf { it.isNotEmpty() }
?: listOf(Config.MenuItem(
name = "Wichteln",
icon = "https://materialdesignicons.com/api/download/22D0C782-CD05-4FEB-845F-BBA7126C7326/000000/1/FFFFFF/0/48",
link = "https://pr0gramm.com/new/wichteln")))
adTypesLoggedIn = listOf(Config.AdType.FEED),
adTypesLoggedOut = listOf(Config.AdType.FEED, Config.AdType.FEED_TO_POST_INTERSTITIAL),
interstitialAdIntervalInSeconds = 600,
specialMenuItems = configState.specialMenuItems.takeIf { it.isNotEmpty() }
?: listOf(
Config.MenuItem(
name = "Wichteln",
icon = "https://materialdesignicons.com/api/download/22D0C782-CD05-4FEB-845F-BBA7126C7326/000000/1/FFFFFF/0/48",
link = "https://pr0gramm.com/new/wichteln"
)
))
}

return configState
Expand Down
46 changes: 28 additions & 18 deletions app/src/main/java/com/pr0gramm/app/ui/AdService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.pr0gramm.app.model.config.Config
import com.pr0gramm.app.services.Track
import com.pr0gramm.app.services.UserService
import com.pr0gramm.app.services.config.ConfigService
import com.pr0gramm.app.time
import com.pr0gramm.app.util.AndroidUtility
import com.pr0gramm.app.util.Holder
import com.pr0gramm.app.util.ignoreAllExceptions
Expand All @@ -43,7 +44,6 @@ class AdService(
private val userService: UserService,
) {

private val logger = Logger("AdService")
private var lastInterstitialAdShown: Instant? = null

/**
Expand Down Expand Up @@ -128,9 +128,6 @@ class AdService(
}

fun buildInterstitialAd(context: Context): Holder<InterstitialAd?> {
return Holder { null }
// currently not available

return if (enabledForTypeNow(Config.AdType.FEED_TO_POST_INTERSTITIAL)) {
val value = CompletableDeferred<InterstitialAd?>()

Expand Down Expand Up @@ -178,6 +175,8 @@ class AdService(
}

companion object {
private val logger = Logger("AdService")

private val interstitialUnitId: String = if (BuildConfig.DEBUG) {
"ca-app-pub-3940256099942544/1033173712"
} else {
Expand All @@ -190,21 +189,32 @@ class AdService(
"/61585078/pr0gramm.com_a_sticky-top"
}

private var initialized: Boolean = false

fun initializeMobileAds(context: Context) {
// for some reason an internal getVersionString returns null,
// and the result is not checked. We ignore the error in that case
ignoreAllExceptions {
val listener = OnInitializationCompleteListener { }
MobileAds.initialize(context, listener)

MobileAds.setAppVolume(0f)
MobileAds.setAppMuted(true)

MobileAds.setRequestConfiguration(
RequestConfiguration.Builder()
.setTestDeviceIds(listOf("D5DDF82D7F630F71AB2E7699408B1429"))
.build()
)
if (initialized) {
return
}

// run initialization code only once
initialized = true

logger.time("Initializing MobileAds") {
// for some reason an internal getVersionString returns null,
// and the result is not checked. We ignore the error in that case
ignoreAllExceptions {
val listener = OnInitializationCompleteListener { }
MobileAds.initialize(context, listener)

MobileAds.setAppVolume(0f)
MobileAds.setAppMuted(true)

MobileAds.setRequestConfiguration(
RequestConfiguration.Builder()
.setTestDeviceIds(listOf("D5DDF82D7F630F71AB2E7699408B1429"))
.build()
)
}
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions app/src/main/java/com/pr0gramm/app/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.google.android.material.snackbar.Snackbar
import com.google.android.ump.ConsentInformation
import com.google.android.ump.ConsentRequestParameters
import com.google.android.ump.FormError
import com.google.android.ump.UserMessagingPlatform
import com.pr0gramm.app.*
import com.pr0gramm.app.Duration.Companion.seconds
import com.pr0gramm.app.api.pr0gramm.MessageType
Expand Down Expand Up @@ -62,6 +66,7 @@ class MainActivity : BaseAppCompatActivity("MainActivity"),
PermissionHelperActivity,
RecyclerViewPoolProvider by RecyclerViewPoolMap() {

private var consentInfo: ConsentInformation? = null
private val handler = Handler(Looper.getMainLooper())
private var permissionHelper = PermissionHelperDelegate(this)

Expand Down Expand Up @@ -170,6 +175,49 @@ class MainActivity : BaseAppCompatActivity("MainActivity"),
invalidateRecyclerViewPool()
}
}

askConsent()
}

private fun askConsent() {
val params = ConsentRequestParameters.Builder()
.setTagForUnderAgeOfConsent(false)
.build()

consentInfo = UserMessagingPlatform.getConsentInformation(this).also { consentInfo ->
consentInfo.requestConsentInfoUpdate(
this,
params,
this::onConsentInfoUpdateSuccess,
this::onConsentInfoUpdateFailure
)
}

// try to initialize mobile adds in parallel, we might already have
// consent from a previous form
initializeMobileAdsSdk()
}

private fun onConsentInfoUpdateSuccess() {
UserMessagingPlatform.loadAndShowConsentFormIfRequired(this) { err ->
if (err != null) {
logger.warn { "Failed to get consent: $err" }
return@loadAndShowConsentFormIfRequired
}

// we have consent, try to initialize mobile sdk
initializeMobileAdsSdk()
}
}

private fun onConsentInfoUpdateFailure(err: FormError) {
logger.warn { "Failed to update consent form: $err" }
}

private fun initializeMobileAdsSdk() {
launchWhenCreated {
AdService.initializeMobileAds(this@MainActivity)
}
}

private fun buildDrawerArrowDrawable(): DrawerArrowDrawable {
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath 'com.android.tools.build:gradle:8.1.1'
}
}

Expand Down

0 comments on commit a951c94

Please sign in to comment.