From 7918bbc92227ddf12ea5646e9e2a482754b6e2ec Mon Sep 17 00:00:00 2001 From: Arif Burak Demiray Date: Wed, 16 Oct 2024 12:07:50 +0300 Subject: [PATCH] feat: new way of consent removal --- .../count/android/sdk/ModuleViewsTests.java | 29 +++++++++++++++++++ .../java/ly/count/android/sdk/ModuleBase.java | 3 ++ .../ly/count/android/sdk/ModuleConsent.java | 13 +++++++-- .../ly/count/android/sdk/ModuleViews.java | 22 ++++++-------- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/sdk/src/androidTest/java/ly/count/android/sdk/ModuleViewsTests.java b/sdk/src/androidTest/java/ly/count/android/sdk/ModuleViewsTests.java index acad0e10e..4892e26c3 100644 --- a/sdk/src/androidTest/java/ly/count/android/sdk/ModuleViewsTests.java +++ b/sdk/src/androidTest/java/ly/count/android/sdk/ModuleViewsTests.java @@ -1855,6 +1855,35 @@ public void recordView_previousViewName() throws JSONException { validateView("test2", 0.0, 1, 2, false, true, TestUtils.map(), "_CLY_", "_CLY_", "test"); } + /** + * "startView" with consent removal + * Validate that all running views are stopped when the view consent is removed + * + * @throws JSONException if the JSON is not valid + */ + @Test + public void startView_consentRemoval() throws JSONException { + CountlyConfig countlyConfig = TestUtils.createBaseConfig(); + countlyConfig.setRequiresConsent(true); + countlyConfig.setLoggingEnabled(true); + countlyConfig.giveAllConsents(); + countlyConfig.setEventQueueSizeToSend(1); + + Countly countly = new Countly().init(countlyConfig); + + countly.views().startView("test"); + ModuleConsentTests.validateAllConsentRequest(TestUtils.commonDeviceId, 0); + validateView("test", 0.0, 1, 2, true, true, TestUtils.map(), "_CLY_", "_CLY_", null); + + countly.views().startView("test2"); + validateView("test2", 0.0, 2, 3, false, true, TestUtils.map(), "_CLY_", "_CLY_", null); + + countly.consent().removeConsent(new String[] { Countly.CountlyFeatureNames.views }); + validateView("test", 0.0, 3, 6, false, false, TestUtils.map(), "_CLY_", "_CLY_", null); + validateView("test2", 0.0, 4, 6, false, false, TestUtils.map(), "_CLY_", "_CLY_", null); + ModuleConsentTests.validateConsentRequest(TestUtils.commonDeviceId, 5, new boolean[] { true, true, true, true, true, true, true, true, true, true, true, true, false, true, true }); + } + static void validateView(String viewName, Double viewDuration, int idx, int size, boolean start, boolean visit, Map customSegmentation, String id, String pvid) throws JSONException { validateView(viewName, viewDuration, idx, size, start, visit, customSegmentation, id, pvid, null); } diff --git a/sdk/src/main/java/ly/count/android/sdk/ModuleBase.java b/sdk/src/main/java/ly/count/android/sdk/ModuleBase.java index 0ad6655d4..65ef158f4 100644 --- a/sdk/src/main/java/ly/count/android/sdk/ModuleBase.java +++ b/sdk/src/main/java/ly/count/android/sdk/ModuleBase.java @@ -95,6 +95,9 @@ void deviceIdChanged(boolean withoutMerge) { void onConsentChanged(@NonNull final List consentChangeDelta, final boolean newConsent, @NonNull final ModuleConsent.ConsentChangeSource changeSource) { } + void consentWillChange(@NonNull List consentThatWillChange, final boolean isConsentGiven) { + } + //notify the SDK modules that internal configuration was updated void sdkConfigurationChanged() { diff --git a/sdk/src/main/java/ly/count/android/sdk/ModuleConsent.java b/sdk/src/main/java/ly/count/android/sdk/ModuleConsent.java index be6265a27..68f410463 100644 --- a/sdk/src/main/java/ly/count/android/sdk/ModuleConsent.java +++ b/sdk/src/main/java/ly/count/android/sdk/ModuleConsent.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class ModuleConsent extends ModuleBase implements ConsentProvider { Consent consentInterface = null; @@ -213,6 +214,7 @@ void setConsentInternal(@Nullable final String[] featureNames, final boolean isC } List consentThatWillChange = new ArrayList<>(featureNames.length); + Map consentUpdateMap = new ConcurrentHashMap<>(); for (String featureName : featureNames) { if (!isValidFeatureName(featureName)) { @@ -223,12 +225,17 @@ void setConsentInternal(@Nullable final String[] featureNames, final boolean isC if (getConsentTrue(featureName) != isConsentGiven) { //if the current consent does not match the one give, add it to the list consentThatWillChange.add(featureName); - - //set new consent value - featureConsentValues.put(featureName, isConsentGiven); + //set new consent values later because some modules need to do operation before changing consent + consentUpdateMap.put(featureName, isConsentGiven); } } + for (ModuleBase module : _cly.modules) { + module.consentWillChange(consentThatWillChange, isConsentGiven); + } + + featureConsentValues.putAll(consentUpdateMap); + for (ModuleBase module : _cly.modules) { module.onConsentChanged(consentThatWillChange, isConsentGiven, changeSource); } diff --git a/sdk/src/main/java/ly/count/android/sdk/ModuleViews.java b/sdk/src/main/java/ly/count/android/sdk/ModuleViews.java index 467b360be..9902351c7 100644 --- a/sdk/src/main/java/ly/count/android/sdk/ModuleViews.java +++ b/sdk/src/main/java/ly/count/android/sdk/ModuleViews.java @@ -272,6 +272,7 @@ void stopViewWithIDInternal(@Nullable String viewID, @Nullable Map customViewSeg //only record view if the view name is not null if (vd.viewName == null) { - L.e("[ModuleViews] stopViewWithIDInternal, view has no internal name, ignoring it"); + L.e("[ModuleViews] recordViewEndEvent, view has no internal name, ignoring it"); return; } @@ -506,6 +507,13 @@ void onConfigurationChanged(Configuration newConfig) { } } + @Override + void consentWillChange(@NonNull List consentThatWillChange, final boolean isConsentGiven) { + if (consentThatWillChange.contains(Countly.CountlyFeatureNames.views) && !isConsentGiven) { + stopAllViewsInternal(null); + } + } + @Override void onActivityStopped(int updatedActivityCount) { if (autoViewTracker) { @@ -558,18 +566,6 @@ void onActivityStarted(Activity activity, int updatedActivityCount) { } } - @Override - void onConsentChanged(@NonNull final List consentChangeDelta, final boolean newConsent, @NonNull final ModuleConsent.ConsentChangeSource changeSource) { - L.d("[ModuleViews] onConsentChanged, consentChangeDelta:[" + consentChangeDelta + "], newConsent:[" + newConsent + "], changeSource:[" + changeSource + "]"); - if (consentChangeDelta.contains(Countly.CountlyFeatureNames.views)) { - if (!newConsent) { - L.d("[ModuleViews] onConsentChanged, stopping all views because consent was removed"); - - stopAllViewsInternal(null); - } - } - } - /** * Needed for mocking test result *