From 8e438393c6cb428ebbfdfbed9b09d508433dfd7a Mon Sep 17 00:00:00 2001 From: Mihai-Cristian Condrea Date: Sun, 31 Aug 2025 13:45:26 +0300 Subject: [PATCH 1/2] Add ad load params data class --- .../java/data/model/AdLoadParams.java | 18 ++++++++++++++++++ .../data/repository/SupportRepository.java | 13 +++++++++---- .../domain/support/InitMobileAdsUseCase.java | 6 +++--- .../support/InitiatePurchaseUseCase.java | 5 ++--- .../ui/screens/support/SupportActivity.java | 6 ++++-- .../ui/screens/support/SupportViewModel.java | 14 ++++++-------- .../support/repository/SupportRepository.java | 15 ++++++++------- 7 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java new file mode 100644 index 00000000..67a55dce --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java @@ -0,0 +1,18 @@ +package com.d4rk.androidtutorials.java.data.model; + +import com.google.android.gms.ads.AdRequest; +import java.util.function.Consumer; + +/** Parameters used to load an ad without exposing view bindings. */ +public class AdLoadParams { + private final Consumer adLoader; + + public AdLoadParams(Consumer adLoader) { + this.adLoader = adLoader; + } + + public Consumer getAdLoader() { + return adLoader; + } +} + diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/SupportRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/SupportRepository.java index 0d56bf4f..3db5bef9 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/SupportRepository.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/repository/SupportRepository.java @@ -1,17 +1,22 @@ package com.d4rk.androidtutorials.java.data.repository; -import android.app.Activity; +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.ProductDetails; -import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; +import com.d4rk.androidtutorials.java.data.model.AdLoadParams; import java.util.List; public interface SupportRepository { void initBillingClient(Runnable onConnected); void queryProductDetails(List productIds, OnProductDetailsListener listener); - void initiatePurchase(Activity activity, String productId); - void initMobileAds(ActivitySupportBinding binding); + void initiatePurchase(String productId, BillingFlowLauncher launcher); + void initMobileAds(AdLoadParams params); interface OnProductDetailsListener { void onProductDetailsRetrieved(List productDetailsList); } + + interface BillingFlowLauncher { + void launch(BillingClient billingClient, BillingFlowParams params); + } } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitMobileAdsUseCase.java b/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitMobileAdsUseCase.java index e91213d6..135b5ed7 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitMobileAdsUseCase.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitMobileAdsUseCase.java @@ -1,6 +1,6 @@ package com.d4rk.androidtutorials.java.domain.support; -import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; +import com.d4rk.androidtutorials.java.data.model.AdLoadParams; import com.d4rk.androidtutorials.java.data.repository.SupportRepository; /** Initializes Google Mobile Ads. */ @@ -11,7 +11,7 @@ public InitMobileAdsUseCase(SupportRepository repository) { this.repository = repository; } - public void invoke(ActivitySupportBinding binding) { - repository.initMobileAds(binding); + public void invoke(AdLoadParams params) { + repository.initMobileAds(params); } } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitiatePurchaseUseCase.java b/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitiatePurchaseUseCase.java index 86886c4d..15070c5b 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitiatePurchaseUseCase.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/domain/support/InitiatePurchaseUseCase.java @@ -1,6 +1,5 @@ package com.d4rk.androidtutorials.java.domain.support; -import android.app.Activity; import com.d4rk.androidtutorials.java.data.repository.SupportRepository; /** Launches billing flow for a product. */ @@ -11,7 +10,7 @@ public InitiatePurchaseUseCase(SupportRepository repository) { this.repository = repository; } - public void invoke(Activity activity, String productId) { - repository.initiatePurchase(activity, productId); + public void invoke(String productId, SupportRepository.BillingFlowLauncher launcher) { + repository.initiatePurchase(productId, launcher); } } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportActivity.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportActivity.java index 8a4f1f0d..6de42255 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportActivity.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportActivity.java @@ -11,6 +11,7 @@ import androidx.lifecycle.ViewModelProvider; import com.android.billingclient.api.ProductDetails; +import com.d4rk.androidtutorials.java.data.model.AdLoadParams; import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate; @@ -41,7 +42,7 @@ protected void onCreate(Bundle savedInstanceState) { supportViewModel = new ViewModelProvider(this).get(SupportViewModel.class); - supportViewModel.initMobileAds(binding); + supportViewModel.initMobileAds(new AdLoadParams(adRequest -> binding.largeBannerAd.loadAd(adRequest))); binding.buttonWebAd.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://bit.ly/3p8bpjj")))); @@ -72,7 +73,8 @@ private void queryProductDetails() { } private void initiatePurchase(String productId) { - supportViewModel.initiatePurchase(this, productId); + supportViewModel.initiatePurchase(productId, + (billingClient, params) -> billingClient.launchBillingFlow(this, params)); } @Override diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java index f00188b1..7d2e99f2 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/SupportViewModel.java @@ -1,15 +1,13 @@ package com.d4rk.androidtutorials.java.ui.screens.support; -import android.app.Activity; - import androidx.lifecycle.ViewModel; -import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; +import com.d4rk.androidtutorials.java.data.model.AdLoadParams; +import com.d4rk.androidtutorials.java.data.repository.SupportRepository; import com.d4rk.androidtutorials.java.domain.support.InitBillingClientUseCase; import com.d4rk.androidtutorials.java.domain.support.QueryProductDetailsUseCase; import com.d4rk.androidtutorials.java.domain.support.InitiatePurchaseUseCase; import com.d4rk.androidtutorials.java.domain.support.InitMobileAdsUseCase; -import com.d4rk.androidtutorials.java.ui.screens.support.repository.SupportRepository; import dagger.hilt.android.lifecycle.HiltViewModel; import javax.inject.Inject; @@ -44,11 +42,11 @@ public void queryProductDetails(List productIds, queryProductDetailsUseCase.invoke(productIds, listener); } - public void initiatePurchase(Activity activity, String productId) { - initiatePurchaseUseCase.invoke(activity, productId); + public void initiatePurchase(String productId, SupportRepository.BillingFlowLauncher launcher) { + initiatePurchaseUseCase.invoke(productId, launcher); } - public void initMobileAds(ActivitySupportBinding binding) { - initMobileAdsUseCase.invoke(binding); + public void initMobileAds(AdLoadParams params) { + initMobileAdsUseCase.invoke(params); } } \ No newline at end of file diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java index 5553627a..6ac2d1dc 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java @@ -1,6 +1,5 @@ package com.d4rk.androidtutorials.java.ui.screens.support.repository; -import android.app.Activity; import android.content.Context; import androidx.annotation.NonNull; @@ -12,7 +11,7 @@ import com.android.billingclient.api.PendingPurchasesParams; import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.QueryProductDetailsParams; -import com.d4rk.androidtutorials.java.databinding.ActivitySupportBinding; +import com.d4rk.androidtutorials.java.data.model.AdLoadParams; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.MobileAds; @@ -120,9 +119,9 @@ public void queryProductDetails(List productIds, com.d4rk.androidtutoria /** * Launch the billing flow for a particular product. */ - public void initiatePurchase(Activity activity, String productId) { + public void initiatePurchase(String productId, com.d4rk.androidtutorials.java.data.repository.SupportRepository.BillingFlowLauncher launcher) { ProductDetails details = productDetailsMap.get(productId); - if (details != null) { + if (details != null && billingClient != null && launcher != null) { // Note: In a real app, you would select a specific offer. For simplicity, // we're assuming there's only one or we're using the base plan. // For subscriptions, this would be ProductDetails.getSubscriptionOfferDetails() @@ -144,7 +143,7 @@ public void initiatePurchase(Activity activity, String productId) { .setProductDetailsParamsList(productDetailsParamsList) .build(); - billingClient.launchBillingFlow(activity, flowParams); + launcher.launch(billingClient, flowParams); } } @@ -153,9 +152,11 @@ public void initiatePurchase(Activity activity, String productId) { * Initialize Mobile Ads (usually done once in your app, but * can be done here if needed for the support screen). */ - public void initMobileAds(ActivitySupportBinding binding) { + public void initMobileAds(AdLoadParams params) { MobileAds.initialize(context); - binding.largeBannerAd.loadAd(new AdRequest.Builder().build()); + if (params != null && params.getAdLoader() != null) { + params.getAdLoader().accept(new AdRequest.Builder().build()); + } } } \ No newline at end of file From 585b45e2a2d8ab4ce819a8fdda2a643c29abe793 Mon Sep 17 00:00:00 2001 From: Mihai-Cristian Condrea Date: Sun, 31 Aug 2025 14:05:12 +0300 Subject: [PATCH 2/2] Use custom AdLoader interface for ad requests --- .../java/data/model/AdLoadParams.java | 14 ++++++++++---- .../support/repository/SupportRepository.java | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java b/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java index 67a55dce..04c20adc 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/data/model/AdLoadParams.java @@ -1,17 +1,23 @@ package com.d4rk.androidtutorials.java.data.model; import com.google.android.gms.ads.AdRequest; -import java.util.function.Consumer; /** Parameters used to load an ad without exposing view bindings. */ public class AdLoadParams { - private final Consumer adLoader; - public AdLoadParams(Consumer adLoader) { + /** Callback to handle ad loading without exposing view bindings. */ + @FunctionalInterface + public interface AdLoader { + void load(AdRequest request); + } + + private final AdLoader adLoader; + + public AdLoadParams(AdLoader adLoader) { this.adLoader = adLoader; } - public Consumer getAdLoader() { + public AdLoader getAdLoader() { return adLoader; } } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java index 6ac2d1dc..90edefe4 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java @@ -155,7 +155,7 @@ public void initiatePurchase(String productId, com.d4rk.androidtutorials.java.da public void initMobileAds(AdLoadParams params) { MobileAds.initialize(context); if (params != null && params.getAdLoader() != null) { - params.getAdLoader().accept(new AdRequest.Builder().build()); + params.getAdLoader().load(new AdRequest.Builder().build()); } }