diff --git a/app/build.gradle b/app/build.gradle index 10b1c3d2..e4621720 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,6 +18,12 @@ android { vectorDrawables.useSupportLibrary = true testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' resourceConfigurations += ['en', 'de', 'es', 'fr', 'hi', 'hu', 'in', 'it', 'ja', 'ro', 'ru', 'tr', 'sv', 'bg', 'pl', 'uk'] + manifestPlaceholders = [ + analyticsStorage: true, + adStorage: true, + adUserData: true, + adPersonalization: true + ] } buildTypes { @@ -27,11 +33,23 @@ android { shrinkResources true debuggable false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + manifestPlaceholders = [ + analyticsStorage: true, + adStorage: true, + adUserData: true, + adPersonalization: true + ] } debug { multiDexEnabled true debuggable true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + manifestPlaceholders = [ + analyticsStorage: false, + adStorage: false, + adUserData: false, + adPersonalization: false + ] } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5d061c0c..50b6650b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -332,9 +332,9 @@ android:name="com.google.android.gms.ads.AD_MANAGER_APP" android:value="true" /> - - - - + + + + \ No newline at end of file diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainActivity.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainActivity.java index df28e98f..65a7f52d 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainActivity.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/main/MainActivity.java @@ -32,6 +32,7 @@ import com.d4rk.androidtutorials.java.notifications.managers.AppUsageNotificationsManager; import com.d4rk.androidtutorials.java.ui.components.navigation.BottomSheetMenuFragment; import com.d4rk.androidtutorials.java.ui.screens.startup.StartupActivity; +import com.d4rk.androidtutorials.java.ui.screens.startup.StartupViewModel; import com.d4rk.androidtutorials.java.ui.screens.support.SupportActivity; import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate; import com.google.android.gms.ads.AdRequest; @@ -47,6 +48,9 @@ import com.google.android.play.core.install.model.AppUpdateType; import com.google.android.play.core.install.model.InstallStatus; import com.google.android.play.core.install.model.UpdateAvailability; +import com.google.android.ump.ConsentInformation; +import com.google.android.ump.ConsentRequestParameters; +import com.google.android.ump.UserMessagingPlatform; public class MainActivity extends AppCompatActivity { @@ -61,6 +65,8 @@ public class MainActivity extends AppCompatActivity { ); private ActivityMainBinding mBinding; private MainViewModel mainViewModel; + private StartupViewModel startupViewModel; + private ConsentInformation consentInformation; private NavController navController; private AppUpdateNotificationsManager appUpdateNotificationsManager; private AppUpdateManager appUpdateManager; @@ -74,6 +80,21 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(mBinding.getRoot()); mainViewModel = new ViewModelProvider(this).get(MainViewModel.class); + startupViewModel = new ViewModelProvider(this).get(StartupViewModel.class); + consentInformation = UserMessagingPlatform.getConsentInformation(this); + ConsentRequestParameters params = new ConsentRequestParameters.Builder() + .setTagForUnderAgeOfConsent(false) + .build(); + startupViewModel.requestConsentInfoUpdate( + this, + params, + () -> { + if (consentInformation.isConsentFormAvailable()) { + startupViewModel.loadConsentForm(this, null); + } + }, + null + ); setupActionBar(); observeViewModel(); diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupActivity.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupActivity.java index e5c8f5b1..03d0a2b1 100644 --- a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupActivity.java +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/StartupActivity.java @@ -15,6 +15,7 @@ import com.google.android.ump.ConsentRequestParameters; import com.google.android.ump.UserMessagingPlatform; import com.google.firebase.analytics.FirebaseAnalytics; +import com.d4rk.androidtutorials.java.ui.screens.startup.dialogs.ConsentDialogFragment; import java.util.EnumMap; import java.util.Map; @@ -39,26 +40,20 @@ protected void onCreate(Bundle savedInstanceState) { .setTagForUnderAgeOfConsent(false) .build(); - consentInformation.requestConsentInfoUpdate( + startupViewModel.requestConsentInfoUpdate( this, params, () -> { if (consentInformation.isConsentFormAvailable()) { startupViewModel.loadConsentForm( this, - formError -> { - updateFirebaseConsent(false); - proceedToMainActivity(); - } + formError -> updateFirebaseConsent(false, false, false, false) ); - } else { - if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) { - updateFirebaseConsent(true); - } - proceedToMainActivity(); + } else if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) { + updateFirebaseConsent(true, true, true, true); } }, - formError -> proceedToMainActivity() + formError -> {} ); new FastScrollerBuilder(binding.scrollView) @@ -70,7 +65,14 @@ protected void onCreate(Bundle savedInstanceState) { Uri.parse("https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy"))) ); - binding.floatingButtonAgree.setOnClickListener(v -> proceedToMainActivity()); + binding.floatingButtonAgree.setOnClickListener(v -> { + ConsentDialogFragment dialog = new ConsentDialogFragment(); + dialog.setConsentListener((analytics, adStorage, adUserData, adPersonalization) -> { + updateFirebaseConsent(analytics, adStorage, adUserData, adPersonalization); + proceedToMainActivity(); + }); + dialog.show(getSupportFragmentManager(), "consent_dialog"); + }); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, 1); @@ -82,12 +84,15 @@ private void proceedToMainActivity() { finish(); } - private void updateFirebaseConsent(boolean granted) { + private void updateFirebaseConsent(boolean analytics, + boolean adStorage, + boolean adUserData, + boolean adPersonalization) { Map consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class); - consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, granted ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); - consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, granted ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); - consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, granted ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); - consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, granted ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); + consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, analytics ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); + consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, adStorage ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); + consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, adUserData ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); + consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, adPersonalization ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED); FirebaseAnalytics.getInstance(this).setConsent(consentMap); } diff --git a/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/dialogs/ConsentDialogFragment.java b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/dialogs/ConsentDialogFragment.java new file mode 100644 index 00000000..ebd15d70 --- /dev/null +++ b/app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/startup/dialogs/ConsentDialogFragment.java @@ -0,0 +1,57 @@ +package com.d4rk.androidtutorials.java.ui.screens.startup.dialogs; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.LayoutInflater; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.d4rk.androidtutorials.java.BuildConfig; +import com.d4rk.androidtutorials.java.R; +import com.d4rk.androidtutorials.java.databinding.DialogConsentBinding; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; + +public class ConsentDialogFragment extends DialogFragment { + + public interface ConsentListener { + void onConsentSet(boolean analytics, boolean adStorage, boolean adUserData, boolean adPersonalization); + } + + private ConsentListener listener; + + public void setConsentListener(ConsentListener listener) { + this.listener = listener; + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + DialogConsentBinding binding = DialogConsentBinding.inflate(LayoutInflater.from(requireContext())); + + boolean defaultChecked = !BuildConfig.DEBUG; + binding.checkAnalyticsStorage.setChecked(defaultChecked); + binding.checkAdStorage.setChecked(defaultChecked); + binding.checkAdUserData.setChecked(defaultChecked); + binding.checkAdPersonalization.setChecked(defaultChecked); + + setCancelable(false); + + return new MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.consent_dialog_title) + .setView(binding.getRoot()) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + if (listener != null) { + listener.onConsentSet( + binding.checkAnalyticsStorage.isChecked(), + binding.checkAdStorage.isChecked(), + binding.checkAdUserData.isChecked(), + binding.checkAdPersonalization.isChecked() + ); + } + }) + .create(); + } +} diff --git a/app/src/main/res/layout/dialog_consent.xml b/app/src/main/res/layout/dialog_consent.xml new file mode 100644 index 00000000..61a15a82 --- /dev/null +++ b/app/src/main/res/layout/dialog_consent.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61591577..6a33c2d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -391,4 +391,9 @@ Error loading layout Error loading code An error occurred while checking for updates + Data & Ads Consent + Analytics storage + Ad storage + Ad user data + Ad personalization \ No newline at end of file