diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
index 96b54a39a2..4fac7c8ddd 100644
--- a/app/AndroidManifest.xml
+++ b/app/AndroidManifest.xml
@@ -1,9 +1,9 @@
-
+
@@ -20,74 +20,64 @@
-
-
-
-
-
-
+ android:maxSdkVersion="32" />
+
+
+
+
+
+ android:maxSdkVersion="32" />
-
+
-
+
+ android:required="false" />
+ android:required="false" />
+ android:required="false" />
+ android:required="false" />
-
-
+ android:required="false" />
-
+ android:label="@string/permission_content_provider_label" />
+ android:label="@string/permission_external_action_label" />
-
-
+ android:protectionLevel="dangerous">
-
+ android:protectionLevel="dangerous">
@@ -95,12 +85,17 @@
+
-
+
+
+
@@ -108,16 +103,16 @@
+ android:usesCleartextTraffic="true"
+ tools:replace="android:label,android:icon,android:theme, android:allowBackup">
+ android:label="@string/application_name">
-
+
-
+
-
+
-
+
-
+
-
+ android:label="@string/application_name"
+ android:windowSoftInputMode="adjustResize">
@@ -188,24 +182,24 @@
+ android:authorities="${odkProvider}.forms"
+ android:exported="false" />
+ android:authorities="${odkProvider}.instances"
+ android:exported="false" />
+ android:readPermission="${applicationId}.provider.cases.read" />
+ android:readPermission="${applicationId}.provider.cases.read" />
+ android:resource="@xml/provider_paths" />
-
+ android:theme="@style/PreferenceTheme">
-
+ android:theme="@style/PreferenceTheme">
-
+ android:theme="@style/FullscreenTheme">
+ android:name="org.commcare.activities.DotsEntryActivity"
+ android:exported="false">
-
+
-
+
-
-
+
-
+
-
-
+
+
-
-
-
-
+
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
-
+
-
+
-
-
-
+
+
+
-
+
-
-
+
+
+ android:scheme="file" />
-
+
-
+
-
-
-
+
+
+
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
-
-
+ android:windowSoftInputMode="stateUnchanged|adjustResize">
+
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:name="org.commcare.services.CommCareSessionService"
+ android:enabled="true">
-
+ android:launchMode="singleTop"
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
+ android:windowSoftInputMode="adjustResize">
-
-
-
-
-
-
-
-
+ android:windowSoftInputMode="adjustResize">
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ android:required="false" />
-
-
+
-
-
+
+ android:name="org.commcare.activities.ReportProblemActivity"
+ android:label="@string/title_activity_report_problem">
+ android:value="org.commcare.activities.CommCareSetupActivity" />
-
-
-
+ android:windowSoftInputMode="adjustResize">
+
+ android:name="org.commcare.activities.KeyAccessRequestActivity"
+ android:exported="true">
-
+
-
+
+ android:name="org.commcare.android.nfc.NfcWriteActivity"
+ android:exported="false">
-
+
-
+
+ android:name="org.commcare.android.nfc.NfcReadActivity"
+ android:exported="false">
-
+
-
+
@@ -443,156 +408,144 @@
android:name="org.commcare.provider.ExternalApiReceiver"
android:exported="true">
-
-
+
+
+
-
-
-
+
+
+
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
-
+ android:windowSoftInputMode="adjustPan">
-
+ android:windowSoftInputMode="adjustResize">
-
-
-
+ android:screenOrientation="portrait">
+
-
+
-
+
-
-
-
-
+
+
+
-
+ android:windowSoftInputMode="stateVisible|adjustResize">
-
-
-
+ android:windowSoftInputMode="stateVisible|adjustResize">
+
+
+ android:label="@string/title_data_change_logs_activity">
-
+
-
-
-
-
-
+
+
+
+ android:value="${googlePlayMapsApiKey}" />
+ android:value="@integer/google_play_services_version" />
-
-
-
+ android:resource="@xml/app_restrictions" />
-
+
-
-
-
-
-
+
+
+ android:exported="true"
+ tools:node="merge" />
-
-
+
\ No newline at end of file
diff --git a/app/res/drawable/arow_icon.png b/app/res/drawable/arow_icon.png
new file mode 100644
index 0000000000..7255d45c1e
Binary files /dev/null and b/app/res/drawable/arow_icon.png differ
diff --git a/app/res/drawable/commcare_diamgi_logo.png b/app/res/drawable/commcare_diamgi_logo.png
new file mode 100644
index 0000000000..73205b4c90
Binary files /dev/null and b/app/res/drawable/commcare_diamgi_logo.png differ
diff --git a/app/res/drawable/dialpad.png b/app/res/drawable/dialpad.png
new file mode 100644
index 0000000000..cae8bacdbe
Binary files /dev/null and b/app/res/drawable/dialpad.png differ
diff --git a/app/res/drawable/grey_small_button.xml b/app/res/drawable/grey_small_button.xml
new file mode 100644
index 0000000000..0de12b63d4
--- /dev/null
+++ b/app/res/drawable/grey_small_button.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/res/drawable/lock.png b/app/res/drawable/lock.png
new file mode 100644
index 0000000000..dd2e8b48f6
Binary files /dev/null and b/app/res/drawable/lock.png differ
diff --git a/app/res/drawable/rounded_rect.xml b/app/res/drawable/rounded_rect.xml
new file mode 100644
index 0000000000..5bc899c501
--- /dev/null
+++ b/app/res/drawable/rounded_rect.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/app/res/values-fr/strings.xml b/app/res/values-fr/strings.xml
index 39db1c83c9..aaf4450a44 100644
--- a/app/res/values-fr/strings.xml
+++ b/app/res/values-fr/strings.xml
@@ -203,13 +203,10 @@ License.
Statut de vérification
Vérification en attente: %d\nNot Approved: %d\Approved: %d
Statut de paiement
- Montant gagné: %s\nMontant transféré: %s
Payé %s
Confirmé
Non confirmé
Émis %s
-
-
Mis à jour: %s
Vous ne suivez aucune formation pour un emploi pour le moment
Vous n\'avez aucun emploi actif pour le moment
diff --git a/app/res/values/colors.xml b/app/res/values/colors.xml
index 5f9214660f..dde7ec7d5d 100644
--- a/app/res/values/colors.xml
+++ b/app/res/values/colors.xml
@@ -146,4 +146,6 @@
#005ab2
#d0e3ff
+
+ #1c1b1f
diff --git a/app/res/values/strings.xml b/app/res/values/strings.xml
index 215ec6e8c0..7e9d845a25 100644
--- a/app/res/values/strings.xml
+++ b/app/res/values/strings.xml
@@ -91,7 +91,7 @@
CommCare Login Expired
Submitting Data
Submitting CommCare Logs
-
+
- 200
- 250
@@ -467,7 +467,7 @@
%1s sq m
Could not parse input coordinates
Turn on your location to receive location updates
- CommCare is still trying to get your location. Please wait or click Cancel to abort.
+ CommCare is still trying to get your location. Please wait or click Cancel to abort.
Invalid %1s, value must be 255 characters or less
This form introduces an invalid case relationship
Rooted Device Detected
@@ -786,7 +786,7 @@
Sign up for ConnectID
Sign out of ConnectID
Forget ConnectID user
-
+
App install failed due to an unknown error
App installed
Required CommCare App is not installed on device
@@ -797,4 +797,8 @@
User is Suspended. Please contact admin.
Select Phone Number
An error occurred while connecting to the server.
+ App Lock
+ Unlock with biometric
+ Setup 6 Digit PIN
+ When enabled, you’ll need to use fingerprint, face or other unique identifiers to open the CommCare App
diff --git a/app/src/org/commcare/activities/LoginActivity.java b/app/src/org/commcare/activities/LoginActivity.java
index e677c21bbb..9a0d821152 100644
--- a/app/src/org/commcare/activities/LoginActivity.java
+++ b/app/src/org/commcare/activities/LoginActivity.java
@@ -17,6 +17,8 @@
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.biometric.BiometricManager;
+import androidx.biometric.BiometricPrompt;
import androidx.core.app.ActivityCompat;
import androidx.core.util.Pair;
import androidx.preference.PreferenceManager;
@@ -51,6 +53,7 @@
import org.commcare.tasks.ManageKeyRecordTask;
import org.commcare.tasks.PullTaskResultReceiver;
import org.commcare.tasks.ResultAndError;
+import org.commcare.utils.BiometricsHelper;
import org.commcare.utils.ConsumerAppsUtil;
import org.commcare.utils.CrashUtil;
import org.commcare.utils.Permissions;
@@ -112,6 +115,10 @@ public class LoginActivity extends CommCareActivity
private String presetAppId;
private boolean appLaunchedFromConnect;
private boolean connectLaunchPerformed;
+ private BiometricPrompt.AuthenticationCallback biometricPromptCallbacks;
+ private BiometricManager biometricManager;
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -134,6 +141,8 @@ protected void onCreate(Bundle savedInstanceState) {
presetAppId = getIntent().getStringExtra(EXTRA_APP_ID);
appLaunchedFromConnect = ConnectManager.wasAppLaunchedFromConnect(presetAppId);
connectLaunchPerformed = false;
+ biometricManager = BiometricManager.from(this);
+ biometricPromptCallbacks = preparePromptCallbacks();
if (savedInstanceState == null) {
// Only restore last user on the initial creation
@@ -197,17 +206,40 @@ protected void onSaveInstanceState(Bundle savedInstanceState) {
}
}
+
+
+ private BiometricPrompt.AuthenticationCallback preparePromptCallbacks() {
+ return new BiometricPrompt.AuthenticationCallback() {
+
+
+ @Override
+ public void onAuthenticationSucceeded(
+ @NonNull BiometricPrompt.AuthenticationResult result) {
+ super.onAuthenticationSucceeded(result);
+ ConnectManager.goToConnectJobsList();
+ setResult(RESULT_OK);
+ finish();
+
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ super.onAuthenticationFailed();
+ Toast.makeText(getApplicationContext(), "Authentication failed",
+ Toast.LENGTH_SHORT)
+ .show();
+ }
+ };
+ }
+
/**
* @param restoreSession Indicates if CommCare should attempt to restore the saved session
* upon successful login
*/
protected void initiateLoginAttempt(boolean restoreSession) {
if(isConnectJobsSelected()) {
- ConnectManager.unlockConnect(this, success -> {
- if(success) {
- ConnectManager.goToConnectJobsList();
- }
- });
+ boolean allowOtherOptions = BiometricsHelper.isPinConfigured(this, biometricManager);
+ BiometricsHelper.authenticateFingerprint(this, biometricManager, allowOtherOptions, biometricPromptCallbacks);
} else {
LoginMode loginMode = uiController.getLoginMode();
@@ -469,13 +501,15 @@ private void setResultAndFinish(boolean goToJobInfo) {
public void handleConnectButtonPress() {
selectedAppIndex = -1;
- ConnectManager.unlockConnect(this, success -> {
- if(success) {
- ConnectManager.goToConnectJobsList();
- setResult(RESULT_OK);
- finish();
- }
- });
+ boolean allowOtherOptions = BiometricsHelper.isPinConfigured(this, biometricManager);
+ BiometricsHelper.authenticateFingerprint(this, biometricManager, allowOtherOptions, biometricPromptCallbacks);
+// ConnectManager.unlockConnect(this, success -> {
+// if(success) {
+// ConnectManager.goToConnectJobsList();
+// setResult(RESULT_OK);
+// finish();
+// }
+// });
}
public boolean handleConnectSignIn() {
diff --git a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java
index d04ef0a201..244c906c96 100644
--- a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java
+++ b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java
@@ -1,15 +1,24 @@
package org.commcare.activities.connect;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.biometric.BiometricManager;
+import androidx.biometric.BiometricPrompt;
import org.commcare.activities.CommCareActivity;
import org.commcare.connect.ConnectConstants;
import org.commcare.dalvik.R;
+import org.commcare.google.services.analytics.AnalyticsParamValue;
+import org.commcare.google.services.analytics.FirebaseAnalyticsUtil;
import org.commcare.interfaces.CommCareActivityUIController;
import org.commcare.interfaces.WithUIController;
import org.commcare.utils.BiometricsHelper;
import org.commcare.views.dialogs.CustomProgressDialog;
+import org.javarosa.core.services.Logger;
import androidx.biometric.BiometricManager;
@@ -24,22 +33,26 @@ public class ConnectIdBiometricConfigActivity extends CommCareActivity parent, ConnectManager.
}else if (user.shouldForcePassword()) {
requestCode = ConnectTask.CONNECT_UNLOCK_PASSWORD;
} else {
- requestCode = ConnectTask.CONNECT_UNLOCK_BIOMETRIC;
+// requestCode = ConnectTask.CONNECT_UNLOCK_BIOMETRIC;
}
}
default -> {
@@ -91,7 +91,7 @@ public static void unlockConnect(CommCareActivity> parent, ConnectManager.Conn
ConnectUserRecord user = ConnectDatabaseHelper.getUser(parentActivity);
- phase = ConnectTask.CONNECT_UNLOCK_BIOMETRIC;
+// phase = ConnectTask.CONNECT_UNLOCK_BIOMETRIC;
if (user.shouldForcePin()) {
phase = ConnectTask.CONNECT_UNLOCK_PIN;
} else if (user.shouldForcePassword()) {
@@ -218,8 +218,8 @@ private static void continueWorkflow() {
params.put(ConnectConstants.MESSAGE, R.string.connect_recovery_success_message);
params.put(ConnectConstants.BUTTON, R.string.connect_recovery_success_button);
}
- case CONNECT_UNLOCK_BIOMETRIC -> params.put(ConnectConstants.ALLOW_PASSWORD, "true");
- case CONNECT_REGISTRATION_UNLOCK_BIOMETRIC, CONNECT_RECOVERY_UNLOCK_BIOMETRIC -> params.put(ConnectConstants.ALLOW_PASSWORD, "false");
+// case CONNECT_UNLOCK_BIOMETRIC -> params.put(ConnectConstants.ALLOW_PASSWORD, "true");
+// case CONNECT_REGISTRATION_UNLOCK_BIOMETRIC, CONNECT_RECOVERY_UNLOCK_BIOMETRIC -> params.put(ConnectConstants.ALLOW_PASSWORD, "false");
case CONNECT_BIOMETRIC_ENROLL_FAIL -> {
params.put(ConnectConstants.TITLE, R.string.connect_biometric_enroll_fail_title);
params.put(ConnectConstants.MESSAGE, R.string.connect_biometric_enroll_fail_message);
@@ -297,8 +297,12 @@ public static boolean handleFinishedActivity(int requestCode, int resultCode, In
if (success) {
boolean failedEnrollment = intent.getBooleanExtra(ConnectConstants.ENROLL_FAIL, false);
nextRequestCode = failedEnrollment ? ConnectTask.CONNECT_BIOMETRIC_ENROLL_FAIL :
- ConnectTask.CONNECT_REGISTRATION_UNLOCK_BIOMETRIC;
+ ConnectTask.CONNECT_REGISTRATION_VERIFY_PRIMARY_PHONE;
+ }else{
+ nextRequestCode =
+ ConnectTask.CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS;
}
+ rememberPhase = success;
}
case CONNECT_BIOMETRIC_ENROLL_FAIL -> {
nextRequestCode = ConnectTask.CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS;
@@ -307,11 +311,11 @@ public static boolean handleFinishedActivity(int requestCode, int resultCode, In
launchSecuritySettings = true;
}
}
- case CONNECT_REGISTRATION_UNLOCK_BIOMETRIC -> {
- nextRequestCode = success ? ConnectTask.CONNECT_REGISTRATION_VERIFY_PRIMARY_PHONE :
- ConnectTask.CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS;
- rememberPhase = success;
- }
+// case CONNECT_REGISTRATION_UNLOCK_BIOMETRIC -> {
+// nextRequestCode = success ? ConnectTask.CONNECT_REGISTRATION_VERIFY_PRIMARY_PHONE :
+// ConnectTask.CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS;
+// rememberPhase = success;
+// }
case CONNECT_REGISTRATION_VERIFY_PRIMARY_PHONE -> {
nextRequestCode = ConnectTask.CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS;
if (success) {
@@ -388,15 +392,15 @@ public static boolean handleFinishedActivity(int requestCode, int resultCode, In
}
}
case CONNECT_RECOVERY_CONFIGURE_BIOMETRICS -> {
- if (success) {
- nextRequestCode = ConnectTask.CONNECT_RECOVERY_UNLOCK_BIOMETRIC;
- }
- }
- case CONNECT_RECOVERY_UNLOCK_BIOMETRIC -> {
if (success) {
nextRequestCode = ConnectTask.CONNECT_RECOVERY_VERIFY_PRIMARY_PHONE;
}
}
+// case CONNECT_RECOVERY_UNLOCK_BIOMETRIC -> {
+// if (success) {
+// nextRequestCode = ConnectTask.CONNECT_RECOVERY_VERIFY_PRIMARY_PHONE;
+// }
+// }
case CONNECT_RECOVERY_VERIFY_PRIMARY_PHONE -> {
if (success) {
if(intent.hasExtra(ConnectConstants.CONNECT_KEY_SECONDARY_PHONE)) {
@@ -484,15 +488,15 @@ public static boolean handleFinishedActivity(int requestCode, int resultCode, In
rememberPhase = true;
completeSignIn();
}
- case CONNECT_UNLOCK_BIOMETRIC -> {
- if (success) {
- nextRequestCode = completeUnlock();
- } else if (intent != null && intent.getBooleanExtra(ConnectConstants.PASSWORD, false)) {
- nextRequestCode = ConnectTask.CONNECT_UNLOCK_PASSWORD;
- } else if (intent != null && intent.getBooleanExtra(ConnectConstants.RECOVER, false)) {
- nextRequestCode = ConnectTask.CONNECT_RECOVERY_PRIMARY_PHONE;
- }
- }
+// case CONNECT_UNLOCK_BIOMETRIC -> {
+// if (success) {
+// nextRequestCode = completeUnlock();
+// } else if (intent != null && intent.getBooleanExtra(ConnectConstants.PASSWORD, false)) {
+// nextRequestCode = ConnectTask.CONNECT_UNLOCK_PASSWORD;
+// } else if (intent != null && intent.getBooleanExtra(ConnectConstants.RECOVER, false)) {
+// nextRequestCode = ConnectTask.CONNECT_RECOVERY_PRIMARY_PHONE;
+// }
+// }
case CONNECT_UNLOCK_PIN -> {
nextRequestCode = ConnectTask.CONNECT_RECOVERY_VERIFY_PRIMARY_PHONE;
if (success) {
diff --git a/app/src/org/commcare/connect/ConnectTask.java b/app/src/org/commcare/connect/ConnectTask.java
index 87b4bad680..fb4a694699 100644
--- a/app/src/org/commcare/connect/ConnectTask.java
+++ b/app/src/org/commcare/connect/ConnectTask.java
@@ -30,8 +30,7 @@ public enum ConnectTask {
ConnectIdRegistrationActivity.class),
CONNECT_REGISTRATION_CONFIGURE_BIOMETRICS(ConnectConstants.ConnectIdTaskIdOffset + 5,
ConnectIdBiometricConfigActivity.class),
- CONNECT_REGISTRATION_UNLOCK_BIOMETRIC(ConnectConstants.ConnectIdTaskIdOffset + 6,
- ConnectIdBiometricUnlockActivity.class),
+
CONNECT_REGISTRATION_VERIFY_PRIMARY_PHONE(ConnectConstants.ConnectIdTaskIdOffset + 7,
ConnectIdPhoneVerificationActivity.class),
CONNECT_REGISTRATION_CHANGE_PRIMARY_PHONE(ConnectConstants.ConnectIdTaskIdOffset + 8,
@@ -52,8 +51,8 @@ public enum ConnectTask {
ConnectIdPhoneVerificationActivity.class),
CONNECT_RECOVERY_SUCCESS(ConnectConstants.ConnectIdTaskIdOffset + 18,
ConnectIdMessageActivity.class),
- CONNECT_UNLOCK_BIOMETRIC(ConnectConstants.ConnectIdTaskIdOffset + 19,
- ConnectIdBiometricUnlockActivity.class),
+// CONNECT_UNLOCK_BIOMETRIC(ConnectConstants.ConnectIdTaskIdOffset + 19,
+// ConnectIdBiometricUnlockActivity.class),
CONNECT_UNLOCK_PASSWORD(ConnectConstants.ConnectIdTaskIdOffset + 20,
ConnectIdPasswordVerificationActivity.class),
CONNECT_UNLOCK_PIN(ConnectConstants.ConnectIdTaskIdOffset + 21,
@@ -72,8 +71,6 @@ public enum ConnectTask {
ConnectIdPinActivity.class),
CONNECT_RECOVERY_CONFIGURE_BIOMETRICS(ConnectConstants.ConnectIdTaskIdOffset + 28,
ConnectIdBiometricConfigActivity.class),
- CONNECT_RECOVERY_UNLOCK_BIOMETRIC(ConnectConstants.ConnectIdTaskIdOffset + 29,
- ConnectIdBiometricUnlockActivity.class),
CONNECT_VERIFY_ALT_PHONE_MESSAGE(ConnectConstants.ConnectIdTaskIdOffset + 30,
ConnectIdMessageActivity.class),
CONNECT_VERIFY_ALT_PHONE(ConnectConstants.ConnectIdTaskIdOffset + 31,