medic / cht-android

A native Android container for Community Health Toolkit (CHT) applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add UI for prominent disclosure when requesting for permissions

derickl opened this issue · comments

#111 improved the way we request for location by doing it at the point of use rather than when the App starts. However, this still misses the mark on the Play Store's need for prominent disclosure - from my reading this could be interpreted as explicitly informing the user why we need to collect that information.

Here are some guidelines from the Play Store on how to implement prominent disclosure:
https://support.google.com/googleplay/android-developer/answer/9799150#prominent_disclosure

prominent-disclosure (1)

Google will start enforcing removal for non-compliant apps stating

  • on January 18 2021 for apps published after 18th April 2020
  • on March 29th 2021 for apps published on or before April 2020

Added to 3.11 to avoid app removal.

Does this need design work? Thinking it makes sense to reuse the same format as the privacy policy when beginning a form (perhaps with an added icon/illustration 🙂)

cc @michaelkohn

gps-permissions

Chatted with @garethbowen @MaxDiz and @mrjones-plip and aligned on this flow:

  • Form prompts location page (once)
  • If a user selects "no thanks", save this permission and take them directly to the form
  • If a user selects "turn on", they see the modal
  • If a user selects "allow only while using the app", save this permission and take them to the form
  • If a user selects "deny", save this permission and take them to the form

Let me know if I missed anything!

Looks good. Couple of comments/questions:

  1. I assume the answer is yes, but I just want to confirm that the only time we ever (currently) try to access location information is when you are filling in a form.
  2. Just to be clear (probably doesn't change anything in the screenshots above), this will also happen for contact and action forms (not just task forms).
  3. I don't know how Android handles this, but what does the workflow look like if they later want to enable this? Do they have to go to Android settings and change this or can it be done from within the CHT app? If it's possible to re-enable in the CHT app, where / how do they do that?
  4. I assume both screens will use translation keys instead of hard coded text. I'm curious how the Play store will evaluate whether or not the text meets the "The language in the disclosure MUST include the following elements:" requirements if we use translation keys?
  5. There was something in a recent release where forms will attempt to get a location and prevent you from submitting the form before it is done trying (30s max). Just want to make sure that we don't wait for that if they have "Denied" access.
  6. We keep track of location error messages on submitted forms. Will this show up as an error (denied, for example)?

only time we ever (currently) try to access location information is when you are filling in a form

Correct. @garethbowen can set me straight if I'm wrong ;)

this will also happen for contact and action forms (not just task forms).

We (currently) gather GPS for any form. The first time you go to fill out a form, you'll get hit with this flow.

what does the workflow look like if they later want to enable this?

It looks bad 😞 . If the user has selected "Deny" in the modal, the app can not re-initiate the process. The user needs to leave Medic app and go into the app settings in android and grant permissions. Of course re-installing the app will cause our app to re-prompt.

I assume both screens will use translation keys instead of hard coded text.

Yup! We'll find out more when we go to implement this. It does beg the question if this follows OS language preferences or our app language preferences though...I'd guess the former. @garethbowen?

There was something in a recent release where forms will attempt to get a location and prevent you from submitting the form before it is done trying (30s max). Just want to make sure that we don't wait for that if they have "Denied" access.

Nope - the perm worklfow pops the moment you're on a form that wants GPS perms, not after the timeout. Specifically, timeout only happens after a user has granted our app perms. If the user hasn't granted access, there's no timeout and the form submits immediately.

We keep track of location error messages on submitted forms. Will this show up as an error (denied, for example)?

My guess is "no", but I defer to @garethbowen .

only time we ever (currently) try to access location information is when you are filling in a form

Correct!

I assume both screens will use translation keys instead of hard coded text.

Yes, but we don't have a good i18n solution for Android screens (which this will be). At the moment apps will be able to change the default text but not provide multiple languages and there is no language detection in use. (relevant issue).

I'm curious how the Play store will evaluate whether or not the text meets the "The language in the disclosure MUST include the following elements:" requirements if we use translation keys?

The Play Store is provided with test user credentials and they actually log in and start filling in a form at which point they will see whatever text the app is built with as well as how the production configuration is set up. They do this for each and every brand and will delist apps that don't meet this criteria once it's been detected (may be months later...).

Will this show up as an error (denied, for example)?

It should do, yes. It's definitely worth testing next time you have your phone out!

Recent Google rejection on this:
image

Our Covid KE update to 0.6 was rejected due to lack of prominent disclosure.
What's currently active in a 0.4.x APK linked to a 3.10 instance. So, collecting location information will be broken until this is resolved.

What's currently active in a 0.4.x APK linked to a 3.10 instance. So, collecting location information will be broken until this is resolved.

0.4.x and 3.10.x should work for gathering location information as well as it ever did. The only issue is when running 0.5.x or 0.6.x with 3.9.x or below. Have you seen a regression in this data? Is it possible you don't need to upgrade medic-android at all?

Have you seen a regression in this data?

Bad assumption on my end

Is it possible you don't need to upgrade medic-android at all?

We've been flagged before for collecting location in the background (though not using it) and lack of prominent disclosure.

From the screenshot here #136 (comment)
Google is also expecting that apps implement a prominent disclosure UI for Covid-related apps highlighting what type of data will be used/collected and how the data will be used. Users will need to provide affirmative consent.

@n-orlowski could you please attach the assets used in the mockup you uploaded ? The icon on the top and the map in the center.

First time developing for Android so not sure what would be the best format, but looks like PNG is the standard, and not sure what would be the best resolution for each one, and whether is convenient at least for the map image to provide it in the different size configurations we support today in the app: hdpi, mdpi, xhdpi, xxhdpi and xxxhdpi.

@mrsarm I was under the impression we had to include the top icon as a default and an image but knowing that isn't the case now here is a simpler mock we can use:

location

Asset in different resolutions are here

Ready for AT - 0.7.0-alpha.2 on the play store for Gamma and Unbranded apps, and also on GitHub.

Make sure that location still works as expected, that you can allow or deny, on both the crosswalk and webview versions.

@mrsarm I am seeing two issues one of which it has been hard to replicate so I reported it in the QA channel to see if anyone else has come across . The other issue is around the 'back button' when the new prompt shows: pressing the button is akin to pressing 'no thanks', the prompt goes away, the app carries on showing the form and geo data is collected. I am not entirely sure if it has to do with this work. The button seems to behave differently inside the form as well. Like, if one opens a report form, select the patient's name and press the back button, the app closes off completely (attached recording) - (tested using the Galaxy A01/ android 10, on gamma-cht

prompt-and-button.mov
back-button.mov

Thanks @ngaruko !

About the two issues reported:

The button seems to behave differently inside the form as well. Like, if one opens a report form, select the patient's name and press the back button, the app closes off completely (attached recording) - (tested using the Galaxy A01/ android 10, on gamma-cht

The master version behave the same, so not related with this PR (though I noticed it too and I thought it was a well know limitation, we should report it separately).

Going to check what you said about the geolocation data been collected after user denied it...

@ngaruko ,

About this:

The other issue is around the 'back button' when the new prompt shows: pressing the button is akin to pressing 'no thanks', the prompt goes away, the app carries on showing the form and geo data is collected.

I couldn't reproduce the error, could you give more details about the error? are you sure if not a sync issue?

Also it seems improbable the app be able to access the location data if the user didn't accept to give the permission from the native dialog shown by Android that ask whether to accept geolocation or not, because it is a native dialog from the OS, not from the App, and the decision is recorded by Android in the app settings, so in case we are accessing the location even with the user rejection, it would be a security issue in the Android OS more than app error, but something to take care off for sure.

The steps I used were:

  1. Edit a form report from a desktop browser with permission to access the geolocation. Then in the Couch DB I could see in the record the following data:

      "geolocation": {
        "latitude": 25.xxxx...,
        "longitude": -80.xxxx...,
        "altitude": null,
        "accuracy": 38,
        "altitudeAccuracy": null,
        "heading": null,
        "speed": null
      }
  2. Then I installed the app in an Android 10 device and configured the application to sync with the CHT instance

  3. Press to edit the same record

  4. The app displayed the disclosure view, I chose "No thanks"

  5. Edited some data in the record and saved

  6. Ensured the app is in sync with the DB tapping in the "Sync now" entry in the main menu

  7. Going to the CouchDB record, now the same field is:

      "geolocation": {
        "code": 2,
        "message": "application does not have sufficient geolocation permissions."
      }

What I have seen in the past is that rejecting the location permissions from the mobile app (before my PR changes) and then going to the CouchDB record, the geolocation data previously recorded from the browser didn't change. At this point I'm not sure whether it was an error in the CHT webapp (not an error in the Android app) or it was that I didn't sync the data properly (that's why in the step (6) I did sync with the instance manually to be sure the changes were sent to the CHT instance.

@ngaruko In case you get to the same error again, could you check whether the same problem does not happens with the "master" version of the app? to be sure is not a issue within the webapp accessing the location API in the webview / xwalk browser, because in that case we need to solve the problem outside the mobile app and outside this PR (maybe and error in the JS API used by the CHT webapp).

Same for the error you mentioned in the Slack channel:

...Seeing an intermittent error where a) the second prompt for location permission (android) is skipped upon pressing ‘Turn on’ on the new location access prompt. b) the submit button hangs and report is not submitted. Trying to replicate it and right up a comprehensive bug report, but thought of leaving it here in case someone else comes across the same

Because this one looks more like error in this app, but it happens after pressing the native dialog from Android that is also displayed in the master version of the app, could you please also check the behavior in the master version? I want to be sure is not an old bug already present in the master version and not related with the PR, although we can try to fix it from here.

@mrsarm

The other issue is around the 'back button' when the new prompt shows: pressing the button is akin to pressing 'no thanks', the prompt goes away, the app carries on showing the form and geo data is collected.

Also it seems improbable the app be able to access the location data if the user didn't accept to give the permission from the native dialog shown by Android that ask whether to accept geolocation or not, because it is a native dialog from the OS, not from the App, and the decision is recorded by Android in the app settings, so in case we are accessing the location even with the user rejection, it would be a security issue in the Android OS more than app error, but something to take care off for sure.

This is definitely my typo. Apology. The data is definitely NOT collected. Same as if one presses 'No Thanks'. I am also tempted to believe that this issue has more to do with the back button than this PR: we have had unexpected behavior with the back button before and a very similar issue of the button exiting the app. (though it is quite an old issue).
So, on this one, to be clear, one would expect the back button to be like a oops button in this instance, the user opens a form, gets prompted to allow permissions, decides to NOT continue with that action (ie the form submission and go back to wherever they were: the 'reports' tab). So it is less severe (minor UX issue).

Because this one looks more like error in this app, but it happens after pressing the native dialog from Android that is also displayed in the master version of the app, could you please also check the behavior in the master version? I want to be sure is not an old bug already present in the master version and not related with the PR, although we can try to fix it from here.

I saw this a couple of times and grew suspicious, attached a debugger to get the logs, but haven't been able to replicate. So I posted it in Slack to see if anyone has seen it before and/or raise some attention as we test this. If I manage to reliable reproduce it, I will check if master behaves the same.

what does the workflow look like if they later want to enable this?

It looks bad 😞 . If the user has selected "Deny" in the modal, the app can not re-initiate the process. The user needs to leave Medic app and go into the app settings in android and grant permissions. Of course re-installing the app will cause our app to re-prompt.

I think @michaelkohn's & @mrjones-plip's comments need to be properly documented/explained. It looks like a possible scenario where the user 'denies' the permission by error and decides to reinstate it quickly. The question is at what stage does the new change take effect (immediately ie with the same form the user started? after navigating to another tab? after closing and opening the app?). One such a case, the user opens the form, gets prompted to accept/ or deny, chooses deny, realises that was a mistake, opens the settings and allows the permission....then continues with the form. (in my case, I had the settings/location permissions already open in the background and used the switch apps button to switch between medic and settings. Apparently, the permission does not kick in for that particular form.
What I also see is that we have two different behaviours when toggling the permissions: if one presses allow, nothing seems to happen in the app, but when switching to deny, the app restarts.

permissions.mov

Note: Probably not related to this PR and not a blocker :)

Thanks @ngaruko !

I think these issues are not related with the PR and moreover the user may have same experiences with these changes or not because the current master version already access the location and if the user wants to change the permission settings the workflow is the same (only from the android settings is possible).

@abbyad @michaelkohn , we leaved the translations for the partners in next PRs if needed, and the "generic" translations to be added in this other ticket: #125 (that is not in development yet).

I recall however that the new view won't be displayed just to partners like the main settings view (displayed when the user opens for the first time the app to setup some configurations like the CHT instance URL). This view will be shown to CHWs the first time they try to edit a form, and may be confusing for those that don't speak English, so I think we should add at least the generic translations for the main languages in this PR, like French.

Here are the french translations using the Google Translator, and I ensured that the right translations is used for the phrase "Allow while using the app" looking for screenshots in french for that dialog on internet ("Autoriser seulement si l'appli est en cours d'utilisation"):

English: French (%s is the name of the app)

Location access: Accès à la localisation

%s collects location data when you submit a form to analyze and improve health outcomes in your area. Select "Allow while using the app" on the next screen to turn on your location access.: %s recueille des données de localisation lorsque vous soumettez un formulaire pour analyser et améliorer les résultats de santé dans votre région. Sélectionnez "Autoriser seulement si l'appli est en cours d'utilisation" sur l'écran suivant pour activer votre accès à la localisation.

Turn on: Allumer

No thanks: Non merci

Do you think is OK these translations ☝️ for French? What other languages can we add? I'm thinking to add the same languages that appears in the login page:

CHT_Languages

I'll use Google Translate, but if somebody has a better tool for a particular language or can provide the translations would be great.

@ngaruko ,

I have drafted a new version: v0.7.0-alpha.3 with the translations for the main languages (except Bamankan and Kiswahili), and a minor improvement in logging that does not affect the workflow. Could you please test it and discard whether the issues mentioned in your last comment are related with this PR or not?

Thanks @mrsarm . The issues above are definitely not related to this PR. One last little thing, is the 'prominent disclosure' hard coded? I am thinking of devices running Android 9 and below. The prompt suggests the user to select " Allow while using the app" on the next screen. This particular feature is only available from Android 10 (API level 29), Android nine displays a different permission pop up (it is a matter of wording not function)
image
Or we are only concerned about Android 10?

@ngaruko ,

I have drafted a new version: v0.7.0-alpha.3 with the translations for the main languages (except Bamankan and Kiswahili), and a minor improvement in logging that does not affect the workflow. Could you please test it and discard whether the issues mentioned in your last comment are related with this PR or not?

It looks good to me @mrsarm . However, it is probably worth noting (and preferably adding to the documentation) that the translation follows the phone OS language and NOT our app's language settings, which by the way would be ideal if that was technically possible, imo.

English: French (%s is the name of the app)

Location access: Accès à la localisation

%s collects location data when you submit a form to analyze and improve health outcomes in your area. Select "Allow while using the app" on the next screen to turn on your location access.: %s recueille des données de localisation lorsque vous soumettez un formulaire pour analyser et améliorer les résultats de santé dans votre région. Sélectionnez "Autoriser seulement si l'appli est en cours d'utilisation" sur l'écran suivant pour activer votre accès à la localisation.

Turn on: Allumer

No thanks: Non merci

The French translations look ok, although for 'location' the next screen use 'position' instead of 'localisation', which looks a little inconsistent
image
With 'allumer' for 'Turn on', I haven't used any electronics in French but it sounds a little different - Google uses activer/désactiver for ON/OFF (though in this case we are not activating/turning on anything yet), but I will let @abbyad suggest better translations.

@ngaruko , good point about the differences between Android 10+ and bellow, I checked in the official documentation and yes the messages to access to the location just when the app is in use comes from Android 10+, what I'm not sure is how much differ the message between different flavors of Android, but we can change the message regarding is Android 10+ or not, in next comment I'll suggest the message, that should be the same except the literal part of the message about the next dialog from Android.

The French translations look ok, although for 'location' the next screen use 'position' instead of 'localisation', which looks a little inconsistent

Right, I'll replace localisation with position.

Any other improvement in translations wording is welcome. CC @abbyad

Thinking what could be the message for Android 9 and above, this is my proposal (almost the same):

%s collects location data when you submit a form to analyze and improve health outcomes in your area. Press "Allow" on the next screen to turn on your location access.

Remember next screen on these devices is:

Allow location

Waiting for opinions before making the change @abbyad @ngaruko

It would be nice for the prompt to make sense for different Android versions, and wonder if a generic form would be sufficient and allow for other variants. It could be something like "confirm the next prompt". This will also work better for translations where it is hard to know what will be shown (eg I am having trouble confirming what the exact Android prompt would be in French across Android versions).

As noted in PR, I think we should remove "when you submit a form" from the generic message because it is not necessarily evident to a user what a "form" actually is, and from my reading of the docs it is not required. Here are the resulting English and French messages:

English

%s collects location data to analyze and improve health outcomes in your area. To permit location access select "Turn On", and then confirm the next prompt.

French

%s collecte votre position pour analyser et améliorer les services de santé dans votre région. Pour permettre l'accès aux données de position, sélectionnez "Activer" et confirmez à l'écran qui suivra.

Also note that Activer is more appropriate for Turn on for this and the standalone string.

@ngaruko the CI pipeline just published the new release to test: v0.7.0-alpha.4

Today I was trying to reproduce the error reported by @ngaruko and I got something similar in Android 11, with the difference that in the end the form is submitted, but without the geolocation data because after press "Turn on" in the disclosure, the Android dialog to authorize the location is skipped.

The error persisted in my installation until I cleared the data, but I couldn't figure out what was the problem and I couldn't reproduce the error again.

The reason may be related with Android counting too many times the requests to access the location and me rejecting the permission over and over in the Android Dialog while performing tests, a case that shouldn't happen in normal usage.

Moreover, the API we are using to request permission is not wrong but the Android documentation recommend to request permissions allowing the system to manage the request code, while we manage the permission request code ourself.

Quote from the documentation: "Because using the RequestPermission contract simplifies your logic, it's recommended that you use it when possible.".

So maybe in a next iteration we can use the recommended way to request the permission code just for Webview (Android 10+), and check whether the erratic error persist.

So at this point I recommend to move forward with the release of the new version, unless we can wait until Monday for a last review from Gareth.

CC @craig-landry

After today's stand up I did some testing on latest build (0.7.0 alpha 5) on Android 10 against gamma-dev with Bede's user bede. Following the happy path (GPS on, accept on new prompt from this issue, accept on second prompt native android), I got this JSON below (also see this record), in which I expected the location field to be populated, but it wasn't:

  "fields": {
    "inputs": {
      "meta": {
        "location": {
          "lat": "",
          "long": "",
          "error": "",
          "message": ""
        },
        "deprecatedID": ""
      },

However, the geolocation_log and geolocation fields were populated (lat long whole numbers changed to protect the innocent):

  "geolocation_log": [
    {
      "timestamp": 1610062385639,
      "recording": {
        "latitude": 2.9950467,
        "longitude": -15.0982067,
        "altitude": 696.3,
        "accuracy": 11.300000190734863,
        "altitudeAccuracy": null,
        "heading": null,
        "speed": 0
      }
    }
  ],
  "geolocation": {
    "latitude": 2.9950467,
    "longitude": -15.0982067,
    "altitude": 696.3,
    "accuracy": 11.300000190734863,
    "altitudeAccuracy": null,
    "heading": null,
    "speed": 0
  },

Reviewing medic/cht-docs#326 I believe the location field should be populated in this record above as it's not hidden? I suggest it's worth checking in the GA 0.6.x release if this is a regression, but I defer to @ngaruko and @brad1905 .

Thanks @mrjones-plip for your input and the investigation. I am wondering if the fields and the geolocation schemas are for the same purpose but with different app versions and configs as in this conversation on another ticket ?

As for the form submission hanging and locking the app, there is a less fatal work around (which does not involve clearing data), but rather using the force stop option in app info.
image

Merged.