Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

136 - Dialog with "prominent" disclosure to request location #142

Merged
merged 25 commits into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
793af9f
"prominent" disclosure dialog to request user location permissions
mrsarm Dec 17, 2020
447562c
Add 'x86' platform to the build. Fix javadoc
mrsarm Dec 17, 2020
3e13379
Fix error when form is submitted and no location perm allowed
mrsarm Dec 17, 2020
6234057
Commented the code that enables 'x86' builds
mrsarm Dec 17, 2020
4a1bb11
Fix android checkstyle error
mrsarm Dec 18, 2020
62b8e29
Localization of the location dialog (default only)
mrsarm Dec 18, 2020
e7044a1
Location disclosure refactor: change dialog by an activity / layout
mrsarm Dec 22, 2020
b3b7531
Update location disclosure title
mrsarm Dec 22, 2020
b08c7da
Fix bug when handling location permission
mrsarm Dec 22, 2020
f70398a
Disclosure of location view: reduce a bit margin top
mrsarm Dec 22, 2020
9783fe1
Remove redundant exception catch and remove trace of useless log
mrsarm Dec 22, 2020
25e923e
Disclosure of location view: camelCase for string names
mrsarm Dec 22, 2020
656106d
Fix random assignment of request codes
mrsarm Dec 22, 2020
5528555
Use GH variables for setting the version number
garethbowen Dec 22, 2020
46adb7b
Add main languages for disclosure location view. Reduce padding to be…
mrsarm Dec 28, 2020
a6f9974
Better logging of request codes
mrsarm Dec 28, 2020
d835365
Disable translation lints because are optional
mrsarm Dec 28, 2020
30e09b0
French translation fix
mrsarm Dec 29, 2020
899b4e2
Update main location disclosure message and translations
mrsarm Dec 30, 2020
72b5292
Remove unused translations strings
mrsarm Jan 5, 2021
df664ee
Add release notes
mrsarm Jan 5, 2021
9195e5a
Update README.md
mrsarm Jan 6, 2021
cfc452f
Update README.md about translations
mrsarm Jan 6, 2021
72999fc
Add Bamanankan (Bambara) translations
mrsarm Jan 7, 2021
68e7f91
Avoid result code collisions (#146)
craig-landry Jan 11, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Set release version
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Medic Mobile Android App
========================

<a href="https://travis-ci.org/medic/medic-android"><img src="https://travis-ci.org/medic/medic-android.svg"/></a>

The medic-android application is a thin wrapper to load the [CHT Core Framework](https://github.com/medic/cht-core/) web application in a webview. This allows the application to be hardcoded to a specific CHT deployment and have a partner specific logo and display name. This app also provides some deeper integration with other android apps and native phone functions that are otherwise unavailable to webapps.

# Release notes
Expand Down Expand Up @@ -64,7 +62,7 @@ To add a new brand:

1. add `productFlavors { <new_brand> { ... } }` in `build.gradle`
1. add icons, strings etc. in `src/<new_brand>`
1. to enable automated deployments, add the `new_brand` to `.travis.yml`
1. to enable automated deployments, add the `new_brand` to `.github/workflows/publish.yml`

# Releasing

Expand Down
18 changes: 12 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ def simprintsApiKey, simprintsModuleId, simprintsUserId

def getVersionCode = {
int versionCode = 1
if(System.env.TRAVIS == 'true' && System.env.TRAVIS_TAG && System.env.TRAVIS_TAG.startsWith('v')) {
def versionParts = System.env.TRAVIS_TAG.split(/[^0-9]+/)
if(System.env.CI == 'true' && System.env.RELEASE_VERSION && System.env.RELEASE_VERSION.startsWith('v')) {
def versionParts = System.env.RELEASE_VERSION.split(/[^0-9]+/)

if (versionParts.length != 4 && versionParts.length != 5)
throw new RuntimeException("Unexpected version number - should be of formatted as 'v1.2.3' or 'v1.2.3-alpha.4', but was: $System.env.TRAVIS_TAG")
throw new RuntimeException("Unexpected version number - should be of formatted as 'v1.2.3' or 'v1.2.3-alpha.4', but was: $System.env.RELEASE_VERSION")

versionParts = versionParts.drop(1).collect { Integer.parseInt(it) }
int alphaPart = versionParts.size() == 4 ? versionParts[3] : 99;
Expand All @@ -56,7 +56,7 @@ def getVersionCode = {
}

def getVersionName = {
System.env.TRAVIS_TAG ?: 'SNAPSHOT'
System.env.RELEASE_VERSION ?: 'SNAPSHOT'
}

android {
Expand Down Expand Up @@ -141,12 +141,14 @@ android {
disable 'UnusedResources' // linter can't handle static imports, so just skip this test
disable 'GradleDependency' // TODO update to latest support-v4 lib and re-enable this rule
disable 'OldTargetApi'
disable 'MissingTranslation'
disable 'StringFormatCount'

warningsAsErrors true

xmlReport false

if(System.env.TRAVIS == 'true') {
if(System.env.CI == 'true') {
abortOnError true
htmlReport false
textReport true
Expand Down Expand Up @@ -303,7 +305,11 @@ android {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a'
include(
'armeabi-v7a',
'arm64-v8a',
//'x86', //--> uncomment to be able to deploy the app in Android 10+ virtual devices
)
universalApk false
}
}
Expand Down
2 changes: 1 addition & 1 deletion fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ platform :android do
end

lane :deploy do |options|
version = ENV['TRAVIS_TAG'].empty? ? 'SNAPSHOT' : ENV['TRAVIS_TAG']
version = ENV['RELEASE_VERSION'].empty? ? 'SNAPSHOT' : ENV['RELEASE_VERSION']
package_name = options[:flavor] == 'unbranded' ? "org.medicmobile.webapp.mobile" : "org.medicmobile.webapp.mobile.#{options[:flavor]}"

supply(
Expand Down
2 changes: 2 additions & 0 deletions src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
android:screenOrientation="portrait"/>
<activity android:name="SettingsDialogActivity"
android:screenOrientation="portrait"/>
<activity android:name="RequestPermissionActivity"
android:screenOrientation="portrait"/>
<activity android:name="AppUrlIntentActivity" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.medicmobile.webapp.mobile;

import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import static org.medicmobile.webapp.mobile.MedicLog.trace;

/**
* Shows a confirmation view that displays a "prominent" disclosure about how
* the user geolocation data is used, asking to confirm whether to allow the app to
* access the location or not.
*
* If the user accepts, a request to the API to access the location is made by the main activity,
* but Android will show another confirmation dialog. If the user decline the first
* confirmation, the request to the API is omitted and the decision recorded to avoid
* requesting the same next time.
*/
public class RequestPermissionActivity extends LockableActivity {

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.request_permission);
String message = getResources().getString(R.string.locRequestMessage);
String appName = getResources().getString(R.string.app_name);
TextView field = (TextView) findViewById(R.id.locMessageText);
field.setText(String.format(message, appName));
}

public void onClickOk(View view) {
trace(this, "onClickOk() :: user accepted to share the location");
setResult(RESULT_OK);
finish();
}

public void onClickNegative(View view) {
trace(this, ":: onClickNegative() :: user denied to share the location");
setResult(RESULT_CANCELED);
finish();
}
}
21 changes: 20 additions & 1 deletion src/main/java/org/medicmobile/webapp/mobile/SettingsStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,32 @@ void updateWithUnlockCode(String unlockCode) throws SettingsException {
ed.putString("unlock-code", unlockCode);

if(!ed.commit()) throw new SettingsException(
"Failed to save to SharedPreferences.");
"Failed to save 'unlock-code' to SharedPreferences.");
}

String get(String key) {
return prefs.getString(key, null);
}

/**
* Returns true if the user has denied to provide its geolocation data.
* The rejection is taken from the first view with the "prominent" disclosure
* about the location data, not from the native dialog displayed by Android.
*/
boolean hasUserDeniedGeolocation() {
return prefs.getBoolean("denied-geolocation", false);
}

/**
* @see #hasUserDeniedGeolocation()
*/
void setUserDeniedGeolocation() throws SettingsException {
SharedPreferences.Editor ed = prefs.edit();
ed.putBoolean("denied-geolocation", true);
if(!ed.commit()) throw new SettingsException(
"Failed to save 'denied-geolocation' to SharedPreferences.");
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we should store this in the settings. I think this would be very difficult to clear if the user has changed their mind - we'd either have to add a UI to do it or wipe all app data.

Android already remembers this information and provides a UI for changing the permissions. Can we instead check that somehow and only show the dialog if it's not already set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is something discussed in the ticket, in the current master version if you regret to allow / deny the locations, you have the same problem, but it is true that it is more convenient just to remove the permission or the rejection from the app info in the Android settings than wipe all the data in order to clean this setting, but either case the user needs to go to the Android settings to do so.

Can we instead check that somehow and only show the dialog if it's not already set?

It works like that, first it checks whether the user already allowed / denied the locations permissions, and only shows the dialog if the user never did. Users that already has the app installed and already allowed the app to access the location won't see the new dialog when upgrade to this version, and the app won't store any configuration.

Anyway, I'll check later if there is a way that in case the user rejects the permission request from our dialog, store the rejection in the same permissions settings that Android uses for that purpose, but because it is a rejection, not sure whether is possible.

Copy link
Contributor Author

@mrsarm mrsarm Dec 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Back to this, I pushed a fix because a bug in the PR that was causing the form to be blocked when loc permissions were denied, and now testing again, turns out the user does not need to wipe the app data to rollback its decision to allow or deny the access to the location, it only needs to do the same that it does with the current master version: go to the app settings in the android settings and just add again or revoke the location permission, but no need to wipe the app data because the variable stored here is read after check the permissions against the Android API.

The only difference is that in case the user rejected the location permissions from the custom dialog instead of from the Android dialog, in the app settings you won't see the location permission accepted or rejected, the permission will be displayed like it was never accepted or rejected, and from there the user will be able to add the permission to access location in which case this variable stored will be ignored by the app.

Still will check later whether I can ask Android to store the negative of location access using the API like it was rejected from the native location dialog, but may be not possible.

static SettingsStore in(Context ctx) {
if(DEBUG) log("Loading settings for context %s...", ctx);

Expand Down
Binary file added src/main/res/drawable-hdpi/location_pin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/res/drawable-mdpi/location_pin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/res/drawable-xhdpi/location_pin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/res/drawable-xxhdpi/location_pin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions src/main/res/layout/request_permission.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">

<ImageView
android:id="@+id/locIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:contentDescription="@string/locRequestIconDescription"
android:scaleType="center"
android:src="@drawable/location_pin" />

<TextView
android:id="@+id/locTitleText"
style="@android:style/Widget.DeviceDefault.Light.TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/locIcon"
android:layout_marginTop="8dp"
android:gravity="center"
android:padding="10dp"
android:text="@string/locRequestTitle"
android:textSize="18sp"
android:textStyle="bold" />

<TextView
android:id="@+id/locMessageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/locTitleText"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="20dp"
android:text="@string/locRequestMessage"
android:textSize="18sp" />

<LinearLayout
android:id="@+id/locButtons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp">

<Button
android:id="@+id/locNegativeButton"
style="@style/Widget.AppCompat.Button.Borderless.Blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClickNegative"
android:text="@string/locRequestDenyButton"
tools:ignore="OnClick" />

<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />

<Button
android:id="@+id/locOkButton"
style="@style/Widget.AppCompat.Button.Borderless.Blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClickOk"
android:text="@string/locRequestOkButton"
tools:ignore="OnClick" />
</LinearLayout>

</RelativeLayout>
9 changes: 9 additions & 0 deletions src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="locRequestTitle">Acceso a la ubicación</string>
<string name="locRequestMessage">%s recolecta información de la ubicación cuando envías un formulario para analizar y mejorar resultados de salud en tu área. Selecciona \"Permitir solo con la app en uso\" en la siguiente pantalla para activar el acceso a tu ubicación.</string>
<string name="locRequestOkButton">Permitir</string>
<string name="locRequestDenyButton">No gracias</string>
<string name="locRequestIconDescription">Ícono de mi ubicación</string>
<string name="locRequestMapIconDescription">Ícono de ubicación en el mapa</string>
</resources>
9 changes: 9 additions & 0 deletions src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="locRequestTitle">Accès à la position</string>
<string name="locRequestMessage">%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 position.</string>
<string name="locRequestOkButton">Allumer</string>
<string name="locRequestDenyButton">Non merci</string>
<string name="locRequestIconDescription">Icône de mon emplacement</string>
<string name="locRequestMapIconDescription">Emplacement dans l\'icône de la carte</string>
</resources>
9 changes: 9 additions & 0 deletions src/main/res/values-hi/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="locRequestTitle">स्थान का उपयोग</string>
<string name="locRequestMessage">जब आप अपने क्षेत्र में स्वास्थ्य परिणामों का विश्लेषण और सुधार करने के लिए फ़ॉर्म सबमिट करते हैं तो यह ऐप स्थान डेटा एकत्र करता है। अपने स्थान का उपयोग चालू करने के लिए अगली स्क्रीन पर "एप्लिकेशन का उपयोग करते समय अनुमति दें" का चयन करें।</string>
<string name="locRequestOkButton">चालू करो</string>
<string name="locRequestDenyButton">जी नहीं, धन्यवाद</string>
<string name="locRequestIconDescription">मेरा स्थान आइकन</string>
<string name="locRequestMapIconDescription">मानचित्र आइकन में स्थान</string>
</resources>
9 changes: 9 additions & 0 deletions src/main/res/values-in/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="locRequestTitle">Akses lokasi</string>
<string name="locRequestMessage">%s mengumpulkan data lokasi saat Anda mengirimkan formulir untuk menganalisis dan meningkatkan hasil kesehatan di wilayah Anda. Pilih \"Izinkan hanya saat menggunakan aplikasi\" di layar berikutnya untuk mengaktifkan akses lokasi Anda.</string>
<string name="locRequestOkButton">Nyalakan</string>
<string name="locRequestDenyButton">Tidak, terima kasih</string>
<string name="locRequestIconDescription">Ikon lokasiku</string>
<string name="locRequestMapIconDescription">Lokasi di ikon peta</string>
</resources>
9 changes: 9 additions & 0 deletions src/main/res/values-ne/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="locRequestTitle">स्थान पहुँच</string>
<string name="locRequestMessage">यो अनुप्रयोगले डेटा डेटा सlects्कलन गर्दछ जब तपाईं आफ्नो क्षेत्रको स्वास्थ्य परिणामहरूको विश्लेषण र सुधार गर्न फारम बुझाउनुहुन्छ। अर्को स्क्रिनमा तपाईको स्थान पहुँच सक्रिय गर्न "अनुप्रयोग प्रयोग गर्ने बेला मात्रै अनुमति दिनुहोस्" चयन गर्नुहोस्।</string>
<string name="locRequestOkButton">खोल्नुहोस्</string>
<string name="locRequestDenyButton">धन्यबाद</string>
<string name="locRequestIconDescription">मेरो स्थान आइकन</string>
<string name="locRequestMapIconDescription">नक्शा आइकनमा स्थान</string>
</resources>
7 changes: 7 additions & 0 deletions src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@
<string name="promptChooseImage">Choose image</string>

<string name="spnCompressingImage">Compressing image…</string>

<string name="locRequestTitle">Location access</string>
<string name="locRequestMessage">%s collects location data when you submit a form to analyze and improve health outcomes in your area. Select \"Allow only while using the app\" on the next screen to turn on your location access.</string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user is not necesarily aware of what consists and doesn't consist of a form, so it would be clearer to avoid mentioning forms here.

Suggested change
<string name="locRequestMessage">%s collects location data when you submit a form to analyze and improve health outcomes in your area. Select \"Allow only while using the app\" on the next screen to turn on your location access.</string>
<string name="locRequestMessage">%s collects location data to analyze and improve health outcomes in your area. Select \"Allow only while using the app\" on the next screen to turn on your location access.</string>

<string name="locRequestOkButton">Turn on</string>
<string name="locRequestDenyButton">No thanks</string>
<string name="locRequestIconDescription">My location icon</string>
<string name="locRequestMapIconDescription">Location in map icon</string>
</resources>
4 changes: 4 additions & 0 deletions src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
<item name="android:paddingLeft">32dp</item>
<item name="android:paddingRight">32dp</item>
</style>
<style name="Widget.AppCompat.Button.Borderless.Blue" parent="Widget.AppCompat.Button.Borderless">
<item name="android:textColor">#0073cd</item>
<item name="android:textAllCaps">false</item>
</style>
</resources>
Loading