Last active
October 27, 2023 13:45
-
-
Save Josuhu/39194bcd5e6b0b14120c3e2e47613031 to your computer and use it in GitHub Desktop.
Java classes for GDPR consent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TODO For implementation see coding video series https://youtube.com/playlist?list=PLQVB-tSJSr656zCJoViyF3MYlKGljVTT7&si=4xY8dV7XkrV_7f1f | |
public class JavaConsentTracker { | |
private static final String TAG = "ConsentTracker"; | |
private final MyLogging myLogger = new MyLogging(); // TODO Log with your own logger | |
private final Context context; | |
public JavaConsentTracker(Context context) { | |
this.context = context; | |
} | |
public boolean isUserConsentValid() { | |
boolean isGdpr = isGDPR(); | |
boolean canShowPersAds = canShowPersonalizedAds(); | |
boolean canShowAds = canShowAds(); | |
boolean consentValidity = !isGdpr || canShowPersAds || canShowAds; | |
myLogger.logThis(TAG, "isUserConsentValid: " + consentValidity + ", GDPR: " + isGdpr + | |
", PersAds: " + canShowPersAds + ", Ads: " + canShowAds, Log.DEBUG); | |
return consentValidity; | |
} | |
private boolean isGDPR() { | |
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | |
int gdpr = prefs.getInt("IABTCF_gdprApplies", 0); | |
return gdpr == 1; | |
} | |
private boolean canShowAds() { | |
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | |
String purposeConsent = prefs.getString("IABTCF_PurposeConsents", ""); | |
String vendorConsent = prefs.getString("IABTCF_VendorConsents", ""); | |
String vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests", ""); | |
String purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests", ""); | |
int googleId = 755; | |
boolean hasGoogleVendorConsent = hasAttribute(vendorConsent, googleId); | |
boolean hasGoogleVendorLI = hasAttribute(vendorLI, googleId); | |
// Minimum required for at least non-personalized ads | |
return hasConsentFor(Collections.singletonList(1), purposeConsent, hasGoogleVendorConsent) | |
&& hasConsentOrLegitimateInterestFor(Arrays.asList(2, 7, 9, 10), purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); | |
} | |
private boolean canShowPersonalizedAds() { | |
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); | |
String purposeConsent = prefs.getString("IABTCF_PurposeConsents", ""); | |
String vendorConsent = prefs.getString("IABTCF_VendorConsents", ""); | |
String vendorLI = prefs.getString("IABTCF_VendorLegitimateInterests", ""); | |
String purposeLI = prefs.getString("IABTCF_PurposeLegitimateInterests", ""); | |
int googleId = 755; | |
boolean hasGoogleVendorConsent = hasAttribute(vendorConsent, googleId); | |
boolean hasGoogleVendorLI = hasAttribute(vendorLI, googleId); | |
return hasConsentFor(Arrays.asList(1, 3, 4), purposeConsent, hasGoogleVendorConsent) | |
&& hasConsentOrLegitimateInterestFor(Arrays.asList(2, 7, 9, 10), purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI); | |
} | |
// Check if a binary string has a "1" at position "index" (1-based) | |
private boolean hasAttribute(String input, int index) { | |
return input.length() >= index && input.charAt(index - 1) == '1'; | |
} | |
// Check if consent is given for a list of purposes | |
private boolean hasConsentFor( | |
List<Integer> purposes, | |
String purposeConsent, | |
boolean hasVendorConsent | |
) { | |
for (int p : purposes) { | |
if (!hasAttribute(purposeConsent, p)) { | |
return false; | |
} | |
} | |
return hasVendorConsent; | |
} | |
// Check if a vendor either has consent or legitimate interest for a list of purposes | |
private boolean hasConsentOrLegitimateInterestFor( | |
List<Integer> purposes, | |
String purposeConsent, | |
String purposeLI, | |
boolean hasVendorConsent, | |
boolean hasVendorLI | |
) { | |
for (int p : purposes) { | |
if ((hasAttribute(purposeLI, p) && hasVendorLI) || (hasAttribute(purposeConsent, p) && hasVendorConsent)) { | |
continue; | |
} else { | |
return false; | |
} | |
} | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TODO For implementation see coding video series https://youtube.com/playlist?list=PLQVB-tSJSr656zCJoViyF3MYlKGljVTT7&si=4xY8dV7XkrV_7f1f | |
public class JavaGdpr { | |
private static final String TAG = "MyGdpr"; | |
private final MyLogging myLogging = new MyLogging(); // TODO Log with your own logger | |
private final ConsentInformation consentInformation; | |
private ConsentForm consentForm; | |
private final MyToasts myToasts; // TODO Toast with your own toaster | |
private final Context context; | |
public JavaGdpr(Context context) { | |
this.context = context; | |
consentInformation = UserMessagingPlatform.getConsentInformation(context); | |
myToasts = new MyToasts(context); | |
} | |
/**IN PRODUCTION CALL AT ONCREATE FOR CONSENT FORM CHECK*/ | |
public void updateConsentInfo( | |
Activity activity, | |
boolean underAge, | |
MainViewModel viewModel, | |
JavaConsentTracker consentTracker, | |
Runnable initAds | |
) { | |
ConsentRequestParameters params = new ConsentRequestParameters.Builder() | |
.setTagForUnderAgeOfConsent(underAge) | |
.build(); | |
requestConsentInfoUpdate(activity, params, viewModel, consentTracker, initAds); | |
} | |
/**ONLY TO DEBUG EU & NONE EU GEOGRAPHICS | |
* EU: ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA | |
* NOT EU: ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_NOT_EEA | |
* DISABLED: ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_DISABLED | |
* requestConsentInfoUpdate() logs the hashed id when run*/ | |
public void updateConsentInfoWithDebugGeographics( | |
Activity activity, | |
int geography, | |
MainViewModel viewModel, | |
JavaConsentTracker consentTracker, | |
Runnable initAds | |
) { | |
ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(context) | |
.setDebugGeography(geography) | |
.addTestDeviceHashedId(/*TODO hashId string here*/) // TODO insert your test devices hashId | |
.build(); | |
ConsentRequestParameters params = new ConsentRequestParameters.Builder() | |
.setConsentDebugSettings(debugSettings) | |
.build(); | |
requestConsentInfoUpdate(activity, params, viewModel, consentTracker, initAds); | |
} | |
private void requestConsentInfoUpdate( | |
Activity activity, | |
ConsentRequestParameters params, | |
MainViewModel viewModel, | |
JavaConsentTracker consentTracker, | |
Runnable initAds | |
) { | |
consentInformation.requestConsentInfoUpdate(activity, params, () -> { | |
if (consentInformation.isConsentFormAvailable()) { | |
loadForm(activity, viewModel, consentTracker, initAds); | |
} else { | |
viewModel.getConsentPermit().setValue(isConsentObtained(consentTracker)); | |
} | |
}, | |
formError -> myLogging.logThis(TAG, "requestConsentInfoUpdate: " + formError.getMessage(), Log.ERROR) | |
); | |
} | |
private void loadForm( | |
Activity activity, | |
MainViewModel viewModel, | |
JavaConsentTracker consentTracker, | |
Runnable initAds | |
) { | |
UserMessagingPlatform.loadConsentForm(context, | |
consentForm -> { | |
this.consentForm = consentForm; | |
if (consentInformation.getConsentStatus() == REQUIRED) { | |
myLogging.logThis(TAG, "consentForm is required to show", Log.DEBUG); | |
consentForm.show(activity, formError -> { | |
if (formError != null) { | |
myLogging.logThis(TAG, "consentForm show " + formError.getMessage(), Log.ERROR); | |
} | |
if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) { | |
myLogging.logThis(TAG, "consentForm is Obtained", Log.DEBUG); | |
viewModel.getConsentPermit().setValue(isConsentObtained(consentTracker)); | |
initAds.run(); | |
} | |
loadForm(activity, viewModel, consentTracker, initAds); | |
}); | |
} else { | |
viewModel.getConsentPermit().setValue(isConsentObtained(consentTracker)); | |
} | |
}, | |
formError -> myLogging.logThis(TAG, "loadForm Failure: " + formError.getMessage(), Log.ERROR) | |
); | |
} | |
/**RETURNS TRUE IF EU/UK IS TRULY OBTAINED OR NOT REQUIRED ELSE FALSE*/ | |
public void reUseExistingConsentForm( | |
Activity activity, | |
MainViewModel viewModel, | |
JavaConsentTracker consentTracker, | |
Runnable initAds | |
) { | |
if (consentInformation.isConsentFormAvailable()) { | |
myLogging.logThis(TAG, "reUseExistingConsentForm", Log.DEBUG); | |
consentForm.show(activity, formError -> { | |
if (formError != null) { | |
myLogging.logThis(TAG, "consentForm show " + formError.getMessage(), Log.ERROR); | |
} | |
if (consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED) { | |
myLogging.logThis(TAG, "consentForm is Obtained", Log.DEBUG); | |
viewModel.getConsentPermit().setValue(isConsentObtained(consentTracker)); | |
initAds.run(); | |
} | |
loadForm(activity, viewModel, consentTracker, initAds); | |
}); | |
} else { | |
myToasts.toastText("Consent form not available, check internet connection.", Toast.LENGTH_SHORT); | |
viewModel.getConsentPermit().setValue(isConsentObtained(consentTracker)); | |
} | |
} | |
private boolean isConsentObtained(JavaConsentTracker consentTracker) { | |
boolean obtained = consentTracker.isUserConsentValid() && consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.OBTAINED; | |
boolean notRequired = consentInformation.getConsentStatus() == ConsentInformation.ConsentStatus.NOT_REQUIRED; | |
boolean isObtained = obtained || notRequired; | |
myLogging.logThis(TAG, "isConsentObtained or not required: " + isObtained, Log.DEBUG); | |
return isObtained; | |
} | |
/**RESET ONLY IF TRULY REQUIRED. E.G FOR TESTING OR USER WANTS TO RESET CONSENT SETTINGS*/ | |
public void resetConsent() { | |
consentInformation.reset(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For implementation in to Activity, see coding video series https://youtube.com/playlist?list=PLQVB-tSJSr656zCJoViyF3MYlKGljVTT7&si=4xY8dV7XkrV_7f1f