Skip to content

Commit

Permalink
AND-19338 Return Google Mobile Ads SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
akiriharu authored and robinshi-mega committed Aug 29, 2024
1 parent 914588d commit d192738
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 41 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ dependencies {

// Google GMS
implementation(lib.billing.client.ktx)
implementation(google.services.ads)
implementation(google.services.location)
implementation(google.services.maps)
implementation(google.services.mlkit.document.scanner)
Expand Down
36 changes: 35 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,38 @@
# Matcher #
#####################
-keep class org.hamcrest.** { *; }
-dontwarn org.hamcrest.**
-dontwarn org.hamcrest.**

#####################
# Google Ads #
#####################
-keep class com.google.android.gms.internal.ads.** { *; }
-keep public class com.google.android.gms.ads.** {
public *;
}

-keep public class com.google.ads.** {
public *;
}

# For mediation
-keepattributes *Annotation*

# Other required classes for Google Play Services
# Read more at http://developer.android.com/google/play-services/setup.html
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}

-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}

-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
@com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
7 changes: 7 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,13 @@
<activity
android:name=".presentation.tags.TagsActivity"
android:launchMode="singleTop" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-2135147798858967~2157690671"/>
<property
android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/gma_ad_services_config"
tools:replace="android:resource" />
</application>

</manifest>
8 changes: 8 additions & 0 deletions app/src/main/java/mega/privacy/android/app/MegaApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.decode.SvgDecoder
import coil.decode.VideoFrameDecoder
import com.google.android.gms.ads.MobileAds
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import com.jeremyliao.liveeventbus.LiveEventBus
Expand Down Expand Up @@ -225,6 +226,13 @@ class MegaApplication : MultiDexApplication(), DefaultLifecycleObserver,
setupMegaChatApi()
getMiscFlagsIfNeeded()
applicationScope.launch {
runCatching {
// Initialize the Google Mobile Ads SDK on a background thread.
MobileAds.initialize(this@MegaApplication) {}
Timber.i("MobileAds initialized")
}.onFailure {
Timber.e(it, "MobileAds initialization failed")
}
runCatching { updateApiServerUseCase() }
dbH.resetExtendedAccountDetailsTimestamp()
// clear the cache files stored in the external cache folder.
Expand Down
105 changes: 69 additions & 36 deletions app/src/main/java/mega/privacy/android/app/main/ManagerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.Chronometer
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
Expand Down Expand Up @@ -80,6 +81,11 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.viewpager2.widget.ViewPager2
import androidx.work.WorkManager
import com.anggrayudi.storage.file.getAbsolutePath
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.admanager.AdManagerAdRequest
import com.google.android.gms.ads.admanager.AdManagerAdView
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.bottomnavigation.BottomNavigationView
Expand Down Expand Up @@ -159,7 +165,6 @@ import mega.privacy.android.app.myAccount.MyAccountActivity
import mega.privacy.android.app.presentation.advertisements.model.AdsSlotIDs.TAB_CLOUD_SLOT_ID
import mega.privacy.android.app.presentation.advertisements.model.AdsSlotIDs.TAB_HOME_SLOT_ID
import mega.privacy.android.app.presentation.advertisements.model.AdsSlotIDs.TAB_PHOTOS_SLOT_ID
import mega.privacy.android.app.presentation.advertisements.view.AdsBannerView
import mega.privacy.android.app.presentation.backups.BackupsFragment
import mega.privacy.android.app.presentation.bottomsheet.NodeOptionsBottomSheetDialogFragment
import mega.privacy.android.app.presentation.bottomsheet.UploadBottomSheetDialogActionListener
Expand Down Expand Up @@ -521,7 +526,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
private lateinit var freePlanLimitParticipantsDialogComposeView: ComposeView
private lateinit var bottomNavigationView: BottomNavigationView
private lateinit var navigationView: NavigationView
private lateinit var adsComposeView: ComposeView
private lateinit var adsContainerView: FrameLayout

private var miniAudioPlayerController: MiniAudioPlayerController? = null
private lateinit var cameraUploadViewTypes: LinearLayout
Expand Down Expand Up @@ -635,6 +640,8 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
}
}

private var adView: AdManagerAdView? = null

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
Expand Down Expand Up @@ -921,8 +928,8 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
private fun checkForInAppAdvertisement() {
lifecycleScope.launch {
runCatching {
val isAdsEnabled = getFeatureFlagValueUseCase(ABTestFeatures.ads)
if (isAdsEnabled) {
val isAdseFlagEnabled = getFeatureFlagValueUseCase(ABTestFeatures.adse)
if (isAdseFlagEnabled) {
if (this@ManagerActivity.isPortrait()) {
setupAdsView()
} else {
Expand All @@ -932,7 +939,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
adsViewModel.getDefaultStartScreen()
}
}.onFailure {
Timber.e("Failed to fetch feature flags or ab_ads test flag with error: ${it.message}")
Timber.e("Failed to fetch ab_adse flag with error: ${it.message}")
}
}
}
Expand Down Expand Up @@ -982,7 +989,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
findViewById(R.id.document_scanning_error_dialog_compose_view)
freePlanLimitParticipantsDialogComposeView =
findViewById(R.id.free_plan_limit_dialog_compose_view)
adsComposeView = findViewById(R.id.ads_web_compose_view)
adsContainerView = findViewById(R.id.ads_web_compose_view)
fragmentLayout = findViewById(R.id.fragment_layout)
bottomNavigationView =
findViewById(R.id.bottom_navigation_view)
Expand Down Expand Up @@ -2309,7 +2316,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
*/
fun handleShowingAds(slotId: String) {
if (this.isPortrait() && adsViewModel.canConsumeAdSlot(slotId)) {
adsViewModel.fetchNewAd(slotId)
showAdsView()
} else {
hideAdsView()
}
Expand All @@ -2327,6 +2334,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
checkForInAppUpdateInstallStatus()
cookieDialogHandler.onResume()
updateTransfersWidgetVisibility()
adView?.resume()
}

private fun checkForInAppUpdateInstallStatus() {
Expand Down Expand Up @@ -2728,6 +2736,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
override fun onPause() {
Timber.d("onPause")
transfersManagement.isOnTransfersSection = false
adView?.pause()
super.onPause()
}

Expand All @@ -2739,6 +2748,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
reconnectDialog?.cancel()
dismissAlertDialogIfExists(processFileDialog)
cookieDialogHandler.onDestroy()
adView?.destroy()
super.onDestroy()
}

Expand Down Expand Up @@ -4047,7 +4057,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
val padding =
if (adsComposeView.isVisible) resources.getDimensionPixelSize(R.dimen.ads_web_view_and_bottom_navigation_view_height)
if (adsContainerView.isVisible) resources.getDimensionPixelSize(R.dimen.ads_web_view_and_bottom_navigation_view_height)
else resources.getDimensionPixelSize(R.dimen.bottom_navigation_view_height)
params.setMargins(
0, 0, 0,
Expand Down Expand Up @@ -7181,7 +7191,7 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
ViewGroup.LayoutParams.MATCH_PARENT
)
val height: Int =
if (adsComposeView.isVisible) resources.getDimensionPixelSize(R.dimen.ads_web_view_and_bottom_navigation_view_height)
if (adsContainerView.isVisible) resources.getDimensionPixelSize(R.dimen.ads_web_view_and_bottom_navigation_view_height)
else resources.getDimensionPixelSize(R.dimen.bottom_navigation_view_height)

if (hide && visibility == View.VISIBLE) {
Expand Down Expand Up @@ -7814,33 +7824,51 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
}

private fun setupAdsView() {
adsComposeView.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
setContent {
val themeMode by getThemeMode().collectAsStateWithLifecycle(initialValue = ThemeMode.System)
val isDark = themeMode.isDarkMode()
val uiState by adsViewModel.uiState.collectAsStateWithLifecycle()
OriginalTempTheme(isDark = isDark) {
AdsBannerView(uiState = uiState,
onAdsWebpageLoaded = ::onAdsWebpageLoaded,
onAdClicked = { uri ->
uri?.let {
val intent = Intent(Intent.ACTION_VIEW, it)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
onAdConsumed()
} else {
Timber.d("No Application found to can handle Ads intent")
adsViewModel.fetchNewAd()
}
}
}, onAdDismissed = {
onAdConsumed()
}
)
}
val adView = AdManagerAdView(this)
// This is a adUntiId only for testing, it should be replace with real one after testing is finished
adView.adUnitId = AD_UNIT_ID
// the size will be set manually for now, the better implementation will be provided when API and SDK are ready
adView.setAdSize(AD_SIZE)
adView.adListener = object : AdListener() {
override fun onAdClicked() {
// Code to be executed when the user clicks on an ad.
Timber.d("Ad clicked")
}

override fun onAdClosed() {
Timber.i("Ad closed")
// Code to be executed when the user is about to return
// to the app after tapping on an ad.
}

override fun onAdFailedToLoad(adError : LoadAdError) {
// Code to be executed when an ad request fails.
Timber.w("Ad failed to load: ${adError.message}")
}

override fun onAdImpression() {
Timber.i("Ad impression")
// Code to be executed when an impression is recorded
// for an ad.
}

override fun onAdLoaded() {
Timber.i("Ad loaded")
// Code to be executed when an ad finishes loading.
}

override fun onAdOpened() {
Timber.i("Ad opened")
// Code to be executed when an ad opens an overlay that
// covers the screen.
}
}
this.adView = adView
adsContainerView.removeAllViews()
adsContainerView.addView(adView)

val adRequest = AdManagerAdRequest.Builder().build()
adView.loadAd(adRequest)
}

private fun onAdConsumed() {
Expand All @@ -7851,11 +7879,14 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
}

private fun showAdsView() {
adsComposeView.isVisible = true
if (viewModel.state().adsEnabled) {
adsContainerView.isVisible = true
setupAdsView()
}
}

fun hideAdsView() {
adsComposeView.isVisible = false
adsContainerView.isVisible = false
adsViewModel.cancelFetchingAds()
}

Expand All @@ -7876,6 +7907,8 @@ class ManagerActivity : TransfersManagementActivity(), MegaRequestListenerInterf
}

companion object {
const val AD_UNIT_ID = "ca-app-pub-2135147798858967/9835644604"
val AD_SIZE = AdSize(320, 50)
const val TRANSFERS_TAB = "TRANSFERS_TAB"
private const val BOTTOM_ITEM_BEFORE_OPEN_FULLSCREEN_OFFLINE =
"BOTTOM_ITEM_BEFORE_OPEN_FULLSCREEN_OFFLINE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import kotlinx.coroutines.launch
import mega.privacy.android.app.MegaApplication
import mega.privacy.android.app.R
import mega.privacy.android.app.components.ChatManagement
import mega.privacy.android.app.featuretoggle.ABTestFeatures
import mega.privacy.android.app.featuretoggle.ApiFeatures
import mega.privacy.android.app.featuretoggle.AppFeatures
import mega.privacy.android.app.main.dialog.removelink.RemovePublicLinkResultMapper
Expand Down Expand Up @@ -532,6 +533,15 @@ class ManagerViewModel @Inject constructor(
}
}
}

viewModelScope.launch {
runCatching {
val isAdseFlagEnabled = getFeatureFlagValueUseCase(ABTestFeatures.adse)
_state.update { it.copy(adsEnabled = isAdseFlagEnabled) }
}.onFailure {
Timber.e(it, "Failed to get the adse feature flag")
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import mega.privacy.android.domain.entity.node.RestoreNodeResult
* @property uploadEvent Event to trigger upload actions
* @property handleScanDocumentResult Decides if the legacy or modern Document Scanner should be used
* @property documentScanningErrorTypeUiItem The specific Error return when using the modern Document Scanner
* @property isAndroidSyncWorkManagerFeatureFlagEnabled Feature flag to use Android Sync Work Manager instead of SyncBackgroundService
* @property adsEnabled Boolean to determine if ads are enabled
*/
data class ManagerState(
val isFirstNavigationLevel: Boolean = true,
Expand Down Expand Up @@ -73,4 +75,6 @@ data class ManagerState(
val uploadEvent: StateEventWithContent<TransferTriggerEvent.StartUpload> = consumed(),
val handleScanDocumentResult: HandleScanDocumentResult? = null,
val documentScanningErrorTypeUiItem: DocumentScanningErrorTypeUiItem? = null,
val isAndroidSyncWorkManagerFeatureFlagEnabled: Boolean = false,
val adsEnabled: Boolean = false,
)
4 changes: 2 additions & 2 deletions app/src/main/res/layout/activity_manager.xml
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@
app:labelVisibilityMode="unlabeled"
app:menu="@menu/bottom_navigation_items" />

<androidx.compose.ui.platform.ComposeView
<FrameLayout
android:id="@+id/ads_web_compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:visibility="gone"
tools:visibility="gone" />
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
<dimen name="default_thumbnail_margin_start">12dp</dimen>

<dimen name="bottom_navigation_view_height">56dp</dimen>
<dimen name="ads_web_view_and_bottom_navigation_view_height">146dp</dimen>
<dimen name="ads_web_view_and_bottom_navigation_view_height">110dp</dimen>

<dimen name="cu_view_type_button_height">36dp</dimen>
<dimen name="cu_view_type_button_vertical_margin">8dp</dimen>
Expand Down
2 changes: 2 additions & 0 deletions gradle/catalogs/google.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ maps-compose = "6.1.0"
play-review = "2.0.1"
play-update = "2.1.0"
protobuff = "3.22.3"
services-ads = "23.3.0"
services-location = "21.3.0"
services-maps = "18.2.0"
services-mlkit-document-scanner = "16.0.0-beta1"
Expand Down Expand Up @@ -54,6 +55,7 @@ play-review-ktx = { module = "com.google.android.play:review-ktx", version.ref =
play-update = { module = "com.google.android.play:app-update", version.ref = "play-update" }
play-update-ktx = { module = "com.google.android.play:app-update-ktx", version.ref = "play-update" }
protobuff = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuff" }
services-ads = { module = "com.google.android.gms:play-services-ads", version.ref = "services-ads" }
services-location = { module = "com.google.android.gms:play-services-location", version.ref = "services-location" }
services-maps = { module = "com.google.android.gms:play-services-maps", version.ref = "services-maps" }
services-mlkit-document-scanner = { module = "com.google.android.gms:play-services-mlkit-document-scanner", version.ref = "services-mlkit-document-scanner"}
Expand Down
Loading

0 comments on commit d192738

Please sign in to comment.