MFlisar / GDPRDialog

GDPR fragment dialog implementation
Apache License 2.0
211 stars 53 forks source link

Some ideas from Google Consent SDK #4

Closed Luklek closed 6 years ago

Luklek commented 6 years ago

I tried implementing the Consent SDK and I noticed some small differences compared to the MoPub solution in the consent flow/content. Below some screenshots and video too.

In the Consent SDK: 1) Back button does not close Dialogue nor Navigate Back (have own Back button in the dialogue layout) 2) CONSENT YES: just close the dialogue without any more confirmation messages 3) CONSENT NO (non personalized ads): next dialogue asks to actually Agree to non personalized or Back (not a simple Close as MoPub) 4) link to new dialogue to show all the Links of Networks, Services and Partners. (with the main/first dialogue not referencing directly any names of Networks or Partners or Services) 5) link to the App own Privacy Policy (in the other 2 dialogues other than the main one)

Personally I think the first 3 points are good and the 4-5 are worth considering.

ezgif-5-7a9ea058d1 Image device-2018-05-23-012528 device-2018-05-23-012507

MFlisar commented 6 years ago

ad 1) I don't want to add a close button, there is no need for this I think ad 3) I prefer the soft opt in and there is defenitely no need to explicitly ask again for consent for non personalised ads ad 5) That's a good idea as well...

The problem is, AdMob dialog targets ads only, I try to keep the dialog generic though, so it's not that easy to have the same workflow... I will try to make some changes in this direction as I like the appearance of AdMob's dialog.

After seeing this dialog, I could think about following change though: 1) Change main text to something like following "We care about your privacy and keep this app cheap/free by using third party services. We use ads/cloud storage in this app. Those services may collect unique identifiers and collect personal data to provide a proper and personalised service. (<a href="...">Lern more about our partners</a>). By agreeing, you are confirming that you would like this personalised experience." 2) Optionally I will add the link to the app's own privacy policy

MFlisar commented 6 years ago

Check out the new code and demo, I've adjusted the flow to be even simplier and a little more like AdMob's... Or try the v0.5.0 release to try it out

Luklek commented 6 years ago

I just tested v0.5 Some more ideas/comments (sorry if I write too much^^):

MFlisar commented 6 years ago

1) I can make the close part optional, but imho, this is not fully GDPR conform... It does put pressure on the user to select something, there is no easy way out in this case... I can add the option, but I would not suggest to use it.

2) can be done, but is no must. I talked about the general workflow with a GDPR expert (her friend even was one of the guys responsible for GDPR) and I got her ok for the soft opt in here. Feel free to ad this as optional flag though

3) the library is general, someone may use it without ads. In the definitions of services I already have a flag that indicates if a service is an ad service. If you try the newest version, you will already see the information about what the services used do (ads, cloud database, crash reporting)

4) check out the newest layout (screenshot you posted is old). I already added the services function to the main dialog e.g. (like ads) => this also effects the point about "I would add/change: crash reporting, analytics reporting"

5) The sentence "Can we continue to use your data to tailor ads for you and as needed by the other services used in this App?" I'll add a question like this, but a shorter one probably. You can anyway override resources yourself at anytime...

6) Layout - you can also try the bottom sheet style now if you want to...

Info

Only because google is doing something, it does not mean it's correct/perfect. They may make changes to the sdk in the near future, rleasing the sdk so late is an indicator for this imho. The problem with laws like this is, that nobody really knows what is 100% save until the first courtyard has made a judgement. From then on you are a lot safer as you can always use the case as reference to back up your behaviour...

MFlisar commented 6 years ago

Try out version 0.5.2... Some points are implemented and some other changes may be solved now as well...

Luklek commented 6 years ago

I understand that of course Google may be wrong about their own implementation and may change behavior in the future. To be honest I am not even worried about GDPR itself as much as Google own policies (AdMob, Google Play). About 2. (as the https://support.google.com/admob/answer/7676680 specify it's about the ePrivacy Directive) my main concern is that AdMob policy itself now maybe requires that extra step to agree to non-personalized Ads.

About 1. it just makes me feel that if the user misclick outside of the dialogue he will think the App crashed for example. Or even pressing Back when facing a Dialog, the user doesn't expect an App to close (but to dismiss the Dialog only). Anyway it's just an idea that may be worth to have an option for.

About 3-5) are just mostly ideas to try to make the library more general as possible and then have the strings translated in many languages (I can provide Italian). Other than that of course each one can adjust as they prefer.

Luklek commented 6 years ago

v0.5.2

MFlisar commented 6 years ago

Everything should be adjusted now but following:

1) "Can we continue to use your data..." question Adding redundant information (all the info is written above already) again here makes the dialog even bigger imho... It would make it even scrollable in portrait mode on my S6 already...

2) dialog size I added a method withCustomDialogTheme. You can add a custom dialog theme there... Other than this, the dialog size should be androids default size, there is nothing in the app that changes the size or style... The app's theme is simply Theme.AppCompat.Light.DarkActionBar

Luklek commented 6 years ago

Tested latest version:

Some other ideas from MoPub and Google SDKs:

MFlisar commented 6 years ago

1) fixed 2) added this short text "and to show personalised ads" if an ad service is used 3) I don't understand what this should do; looks like checking if the user is within EAA or not, so the same as 4? 4) checkout GDPRSetup::withCheckRequestLocation => this will check following url (the one from googles sdk). Btw, I would not use this though... as written in my readme about GDPR...

Luklek commented 6 years ago
  1. to see if we are allowed to collect user data. It first check if the EEA applies (by the user location) Then it checks the consent status (and if the user didn't turn on Limited Ad Tracking on the phone settings... but maybe this doesn't really make sense) It may be useful when passing consent to other Ad Networks not integrated directly (for example with MoPub mediation, in each Netowrk Adapter file): // Pass the user consent from the MoPub SDK to AppLovin as per GDPR boolean canCollectPersonalInfo = MoPub.canCollectPersonalInformation(); AppLovinPrivacySettings.setHasUserConsent(canCollectPersonalInfo, context);

  2. is mostly used within 3. to check location and see if GDPR apply to user.

MFlisar commented 6 years ago
  1. so you want to use other sdks functions? Then simply do this before asking for consent with this library, not sure if I understand you here (I've never used MoPub). E.g.:

    @Override
    public void onConsentNeedsToBeRequested() {
    
         // my library says you should ask the user for consent
        // if you use withCheckRequestLocation(true), googles url did report that you are in the EAA
        // otherwise the location check was not done yet, but the user did not give his consent yet
    
        // make additional checks here via other API calls, e.g.
        if (!MoPub.shouldGetConsent()) {
            // oh, MoPub says we do not need to get consent here
            return;
        }
    
        // show dialog
        GDPR.getInstance().showDialog(this, mSetup);
    }
  2. as the comments above show, use it via the builder. The call is done asynchronously and the library is talking care for this. You can use the CheckLocationAsyncTask yourself. I can make the inner function public as well, than you can use it in a Rx chain or elsewehere manually as well if you want to...

Luklek commented 6 years ago

No sorry. I meant to have a similar public boolean canCollectPersonalInformation() in your Library too.

So when I need to pass consent to other Netowks I can use it easily in something like canCollectPersonalInfo = GDPR.canCollectPersonalInformation(); AppLovinPrivacySettings.setHasUserConsent(canCollectPersonalInfo, context);

Also for AdMob itself without any mediation, having maybe multiple Banner/Interstial/Native Ads to load in multiple activities etc: If !canCollectPersonalInfo will create AdRequest with extras (to pass non personalized ads) Bundle extras = new Bundle(); extras.putString("npa", "1"); AdRequest request = new AdRequest.Builder() .addNetworkExtrasBundle(AdMobAdapter.class, extras) .build(); If canCollectPersonalInfo will create AdRequest without extras

MFlisar commented 6 years ago

so your canCollectPersonalInformation() should return if the user have given consent for personal data usage with my library?

This can be done like this:

GDPRConsent consent = GDPR.getInstance().getConsent();
boolean canCollectPersonalInformation = consent != null && consent == GDPRConsent.PERSONAL_CONSENT;
Luklek commented 6 years ago

It should also check if it's an EEA location or not. canCollectPersonalInformation should be true if consent == GDPRConsent.PERSONAL_CONSENT but also if isRequestLocationInEeaOrUnknown is false (and so consent == GDPRConsent.UNKNOWN in the case that we show consent dialog only in EEA location)

MFlisar commented 6 years ago

Ok, the library will now save the location of the last request as well. Checkout GDPR.getInstance().getRequestLocation(). You will get GDPRLocation.UNKNOWN if the request times out or if you do not enable the location check via GDPR.withCheckRequestLocation(true).

Hope this helps...

MFlisar commented 6 years ago

EDIT

I replaced GDPRConsent with GDPRConsentState which is a class holding the GDPRConsent now (and additionally it holds the date, app version and request location)

Luklek commented 6 years ago

I was trying the version before your EDIT (1h ago) and I was getting GDPRLocation.UNKNOWN even with GDPR.withCheckRequestLocation(true) and my IP outisde of EEA. When I was using IP inside EEA, I was instead getting GDPRLocation.EAA

Maybe I was doing something wrong, I will test again the new version. Thanks!

MFlisar commented 6 years ago

Checkout what you get from this url: http://adservice.google.com/getconfig/pubvendors This is what I use in this library, no fallback method though...

I get following answer from within the EAA (but have not tried it anywhere else):

{"is_request_in_eea_or_unknown":true}
Luklek commented 6 years ago

At my real IP (out of Europe), I get {"is_request_in_eea_or_unknown":false}

MFlisar commented 6 years ago

you're right, there was a bug... fixed it now, it should work now

Luklek commented 6 years ago

Thanks, seem to be working fine now.

So can maybe also add something like this now? to get consent + location anywhere in the app

boolean canCollectPersonalInformation() { GDPRConsentState consentState = GDPR.getInstance().getConsent(); GDPRConsent consent = consentState.getConsent(); // the given constent GDPRLocation location = consentState.getLocation(); // where has the given consent been given // If we don't know whether or not GDPR applies, then we haven't synced, so we cannot // collect personal information. if (location.equals(GDPRLocation.EAA) || location.equals(GDPRLocation.UNKNOWN)) { return false; } // If we are not in a GDPR region, we can freely collect user data. if (location.equals(GDPRLocation.NOT_IN_EAA)) { return true; } // Return whether or not we have consent. return consent.equals(GDPRConsent.PERSONAL_CONSENT); }

MFlisar commented 6 years ago

check out this function I've just added:

https://github.com/MFlisar/GDPRDialog/blob/9480b03294685ba9745ffa7518c7017a8c0491c7/library/src/main/java/com/michaelflisar/gdprdialog/GDPR.java#L123-L147

MFlisar commented 6 years ago

I think the method fulfills your requirements as well, so I'll close this.