From ff8b2dccab2d6ae4d44f90394b0c6ad43775d41e Mon Sep 17 00:00:00 2001 From: parthmittal Date: Mon, 24 Jun 2024 14:49:00 +0530 Subject: [PATCH 1/2] biometric design changes --- app/AndroidManifest.xml | 528 ++++++++---------- app/res/drawable/arow_icon.png | Bin 0 -> 340 bytes app/res/drawable/commcare_diamgi_logo.png | Bin 0 -> 31942 bytes app/res/drawable/dialpad.png | Bin 0 -> 2966 bytes app/res/drawable/grey_small_button.xml | 18 + app/res/drawable/lock.png | Bin 0 -> 1878 bytes app/res/drawable/rounded_rect.xml | 13 + .../layout/activity_biometric_signup_page.xml | 167 ++++++ app/res/values/colors.xml | 2 + app/res/values/strings.xml | 12 +- .../connect/BiometricSignupPage.java | 75 +++ .../BiometricSignupPageUiController.java | 40 ++ .../ConnectIdBiometricConfigActivity.java | 118 +++- ...IdBiometricConfigActivityUiController.java | 2 +- .../commcare/connect/ConnectIdWorkflows.java | 32 +- app/src/org/commcare/connect/ConnectTask.java | 8 +- 16 files changed, 681 insertions(+), 334 deletions(-) create mode 100644 app/res/drawable/arow_icon.png create mode 100644 app/res/drawable/commcare_diamgi_logo.png create mode 100644 app/res/drawable/dialpad.png create mode 100644 app/res/drawable/grey_small_button.xml create mode 100644 app/res/drawable/lock.png create mode 100644 app/res/drawable/rounded_rect.xml create mode 100644 app/res/layout/activity_biometric_signup_page.xml create mode 100644 app/src/org/commcare/activities/connect/BiometricSignupPage.java create mode 100644 app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index a25d66b43e..5aa02d50c1 100644 --- a/app/AndroidManifest.xml +++ b/app/AndroidManifest.xml @@ -1,91 +1,80 @@ - - - - - - - - - + + + + + + + + + + - - - - - - + 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"> @@ -93,12 +82,17 @@ + - + + + @@ -106,93 +100,93 @@ + 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"> + + + + + + + + + + + + + + + + + + + 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"> - + - + @@ -430,156 +395,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 0000000000000000000000000000000000000000..7255d45c1efa95be7b6317f74a4e936a400b39b6 GIT binary patch literal 340 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 literal 0 HcmV?d00001 diff --git a/app/res/drawable/dialpad.png b/app/res/drawable/dialpad.png new file mode 100644 index 0000000000000000000000000000000000000000..cae8bacdbe5381ed4cdea370b42de1ea6526229c GIT binary patch literal 2966 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 H*w}vp0=bd0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..dd2e8b48f6f8db379faf086a1a35319c525a5ed6 GIT binary patch literal 1878 zcmai#c{mjM9>#yeFw9s+O2!sSh#^ZEyBT{6PEC?6Dj{1MvNL03DciM-Ivvbp$+2rW zQT8QWbDwkmc;EN?`TqSr&zs@mWG@bvg98A>9UW}W z>?ZL~i3sm{kA*LNH$<;HTp$3TeezF1D$FUr?mi)eGxj)8|61Y8EW(1GUCaI$&pPO#Cm@cz92IQ`#6f1t)&I`VvPo~~W z*~|a2dy-xH>}-}(vLjks^gMESn1_6Iw)CXST5D7ZOh(TFWEI;XQlddR`a7d?t4htx z?~rAzRfMSTxMI8f%`P81VX7-3=)U~Nrr>pHhtL%_n^{PzKXx{PfohICdIZ!2Z@l?c z`IVQg|Hk61nAoLLV7Rg*g^(?xb43H5ERvmSZE#auLYCUZvJfUIPHbp-u{bxlau2-P zo(av>@QSF$bEfM#@gBf9jfReS3FPyIEej9Ps6!!jua($yzZ0yeOChlhcbEIFl>mf&^& z@GJ{@;*7Zpb?yn4nyd6ZNxXz)_XOUV-J0ofV=1TL&PB?=I7OV(wZ}8ia^?17Zz}g>IJOyB$VpS z2s(JlG#op!(bJ__J05MutP~@~HMlQd^vZfV4iAtfGTW9Jd83If9f@o{xm4w#k;?ca zMU$^`6N}?9ncKQl2s#@gXBvu7h($fi+_G+cmbhavzset$^v1rsAR?S*;;AD;h2SFH zW!`Acsm$9bc^)odt7Mc~3A#hAFdLVr=a@P(kL>x}T-}lU22>nX{f)3vbxmR8=TQrA zjqAL(gA+BN%JX=V@*uy_A%sA1U-DxbjwT_LyIs5Yw3&_la89*u(6Wr2qtL9b16SoA zrw?r^-p0wsnYyL-vC;E^+k(VsB)?hYg$ptwd7O|CqtNL=^i%t~qH<*4P1x&um{o}K zEVqRzpx<>)~l_>1h(s%6>+>i&kPuJNDNgS==IjpEL=^L5;Pqpv7SHulJXT- zV?g!&XssLr(Wn6HyrBT-;Xu0|@;Bg4$-Ll-zg}$?-X--r(sv%2Rc}d&H95cIUT_Yw z5#|Cvwos}R*}OH3j(v=CnHc9lX&8ehn?JNi{}8~_G$%H$4Sbgw)X=JdpQ*|-%$i9E ziq-RwB5tyO7-R9y7{%WAv0axXxR>I=aC$ku;;IFixV&j}qsA9gCP=N$tU&8U?cW>y zF5uOiFd3x?U_EEuWQ^?&NXp8Ckp=hqt{RQ0cf+)`{s)=jo$GT0w@-{6*+)qG4J8k> zVOpL+54^kgrK~8cWB*YF2`3HO zAj@l*@JPeDBeb?zeu+>1X7++SrN181NIbR;nP<=9f49@GS>i6EdMdU)xg1a2^yvTj zakc%>@{d+DNBWmj4~Gh}yb(QAR~`E?vDV1DO$WnVzlpYnEa@C&?+Z5l%g+8!o8gkg zf6lS#gR!lTu)10o*%vMt!l8=&=GqKXNqtHTKvt>m6r%tt`!J^a z_5|j$8so)SZqr~CM8J0cI1bq-bVZvF3TWiq?aDzzrg~xo& zUhY|)meXHmG*TCG4m1gAquxynaTd>nm=^&JeW;fNR$m}~p1-Z0n?HE6Kk;>8r8M)E z?g7BJJf^W=DEH=W*|gwF1{{YWr9o*;?;FZV%CT!!Em}E+nZ;z{e^=+<*S`6So@Iyq U+vvH4yE6zJZJliDaX!ia0)EnEQvd(} literal 0 HcmV?d00001 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/layout/activity_biometric_signup_page.xml b/app/res/layout/activity_biometric_signup_page.xml new file mode 100644 index 0000000000..74daa64c80 --- /dev/null +++ b/app/res/layout/activity_biometric_signup_page.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 bb779f5520..46d54b8caa 100644 --- a/app/res/values/strings.xml +++ b/app/res/values/strings.xml @@ -90,7 +90,7 @@ CommCare Login Expired Submitting Data Submitting CommCare Logs - + 200 250 @@ -466,7 +466,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 @@ -783,11 +783,17 @@ 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 + Audio Recording Notification Today\'s Visits: %d + + 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/connect/BiometricSignupPage.java b/app/src/org/commcare/activities/connect/BiometricSignupPage.java new file mode 100644 index 0000000000..75a540ff1a --- /dev/null +++ b/app/src/org/commcare/activities/connect/BiometricSignupPage.java @@ -0,0 +1,75 @@ +package org.commcare.activities.connect; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.biometric.BiometricManager; + +import org.commcare.activities.CommCareActivity; +import org.commcare.connect.ConnectConstants; +import org.commcare.dalvik.R; +import org.commcare.interfaces.CommCareActivityUIController; +import org.commcare.interfaces.WithUIController; +import org.commcare.utils.BiometricsHelper; + +public class BiometricSignupPage extends CommCareActivity + implements WithUIController { + private BiometricSignupPageUiController uiController; + + private BiometricManager biometricManager; + + @Override + public CommCareActivityUIController getUIController() { + return this.uiController; + } + + @Override + public void initUIController() { + uiController = new BiometricSignupPageUiController(this); + } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setTitle(getString(R.string.app_lock)); + biometricManager = BiometricManager.from(this); + + uiController.setupUI(); + + BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, + biometricManager); + BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); + if (fingerprint == BiometricsHelper.ConfigurationStatus.NotAvailable && + pin == BiometricsHelper.ConfigurationStatus.NotAvailable) { +// Skip to password-only workflow + finish(true, true); + } else { +// updateState(fingerprint, pin); + } + } + + public void handleFingerprintButton() { + BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, + biometricManager); + if (fingerprint == BiometricsHelper.ConfigurationStatus.Configured) { + finish(true, false); + } else if (!BiometricsHelper.configureFingerprint(this)) { + finish(true, true); + } + } + + public void finish(boolean success, boolean failedEnrollment) { + Intent intent = new Intent(getIntent()); + + BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, + biometricManager); + BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); + boolean configured = fingerprint == BiometricsHelper.ConfigurationStatus.Configured || + pin == BiometricsHelper.ConfigurationStatus.Configured; + + intent.putExtra(ConnectConstants.ENROLL_FAIL, failedEnrollment || !configured); + + setResult(success ? RESULT_OK : RESULT_CANCELED, intent); + finish(); + } +} diff --git a/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java b/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java new file mode 100644 index 0000000000..07849cc02e --- /dev/null +++ b/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java @@ -0,0 +1,40 @@ +package org.commcare.activities.connect; + +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.Switch; + +import org.commcare.dalvik.R; +import org.commcare.interfaces.CommCareActivityUIController; +import org.commcare.views.ManagedUi; +import org.commcare.views.UiElement; + +@ManagedUi(R.layout.activity_biometric_signup_page) +public class BiometricSignupPageUiController implements CommCareActivityUIController { + @UiElement(value = R.id.switchBiometric) + private Switch fingerprintButton; + + private final BiometricSignupPage activity; + + public BiometricSignupPageUiController(BiometricSignupPage activity) { + this.activity = activity; + } + + @Override + public void setupUI() { + fingerprintButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if(isChecked){ + activity.handleFingerprintButton(); + } + } + }); + + + } + + @Override + public void refreshView() { + + } +} diff --git a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java index 75ecef475d..1817b98455 100644 --- a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java +++ b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java @@ -1,17 +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; /** * Shows the page for configuring biometrics (fingerprint and/or PIN) @@ -24,22 +31,27 @@ public class ConnectIdBiometricConfigActivity extends CommCareActivity activity.handleFingerprintButton()); - pinButton.setOnClickListener(v -> activity.handlePinButton()); +// pinButton.setOnClickListener(v -> activity.handlePinButton()); } @Override diff --git a/app/src/org/commcare/connect/ConnectIdWorkflows.java b/app/src/org/commcare/connect/ConnectIdWorkflows.java index 9769c79e0c..f3196f5262 100644 --- a/app/src/org/commcare/connect/ConnectIdWorkflows.java +++ b/app/src/org/commcare/connect/ConnectIdWorkflows.java @@ -219,9 +219,9 @@ private static void continueWorkflow() { 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_REGISTRATION_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); @@ -301,8 +301,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; @@ -311,11 +315,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) { @@ -386,15 +390,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)) { diff --git a/app/src/org/commcare/connect/ConnectTask.java b/app/src/org/commcare/connect/ConnectTask.java index 8a528d79cb..33211171e9 100644 --- a/app/src/org/commcare/connect/ConnectTask.java +++ b/app/src/org/commcare/connect/ConnectTask.java @@ -30,8 +30,8 @@ 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_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, @@ -72,8 +72,8 @@ public enum ConnectTask { ConnectIdPinActivity.class), CONNECT_RECOVERY_CONFIGURE_BIOMETRICS(ConnectConstants.ConnectIdTaskIdOffset + 28, ConnectIdBiometricConfigActivity.class), - CONNECT_RECOVERY_UNLOCK_BIOMETRIC(ConnectConstants.ConnectIdTaskIdOffset + 29, - ConnectIdBiometricUnlockActivity.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, From 1b8957f44a10d0a17a3330b9c956d970e2f1b6d3 Mon Sep 17 00:00:00 2001 From: parthmittal Date: Tue, 23 Jul 2024 19:15:00 +0530 Subject: [PATCH 2/2] -pr requested change --- app/AndroidManifest.xml | 3 - .../layout/activity_biometric_signup_page.xml | 167 ------------------ app/res/values-fr/strings.xml | 3 - app/res/values/strings.xml | 4 + .../commcare/activities/LoginActivity.java | 58 ++++-- .../connect/BiometricSignupPage.java | 75 -------- .../BiometricSignupPageUiController.java | 40 ----- .../ConnectIdBiometricConfigActivity.java | 30 ++-- ...IdBiometricConfigActivityUiController.java | 2 +- .../commcare/connect/ConnectIdWorkflows.java | 26 +-- app/src/org/commcare/connect/ConnectTask.java | 9 +- 11 files changed, 77 insertions(+), 340 deletions(-) delete mode 100644 app/res/layout/activity_biometric_signup_page.xml delete mode 100644 app/src/org/commcare/activities/connect/BiometricSignupPage.java delete mode 100644 app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml index 5d1ef916c0..4fac7c8ddd 100644 --- a/app/AndroidManifest.xml +++ b/app/AndroidManifest.xml @@ -113,9 +113,6 @@ android:theme="@style/AppBaseTheme" android:usesCleartextTraffic="true" tools:replace="android:label,android:icon,android:theme, android:allowBackup"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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/strings.xml b/app/res/values/strings.xml index b656812b39..7e9d845a25 100644 --- a/app/res/values/strings.xml +++ b/app/res/values/strings.xml @@ -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/BiometricSignupPage.java b/app/src/org/commcare/activities/connect/BiometricSignupPage.java deleted file mode 100644 index 75a540ff1a..0000000000 --- a/app/src/org/commcare/activities/connect/BiometricSignupPage.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.commcare.activities.connect; - -import android.content.Intent; -import android.os.Bundle; - -import androidx.biometric.BiometricManager; - -import org.commcare.activities.CommCareActivity; -import org.commcare.connect.ConnectConstants; -import org.commcare.dalvik.R; -import org.commcare.interfaces.CommCareActivityUIController; -import org.commcare.interfaces.WithUIController; -import org.commcare.utils.BiometricsHelper; - -public class BiometricSignupPage extends CommCareActivity - implements WithUIController { - private BiometricSignupPageUiController uiController; - - private BiometricManager biometricManager; - - @Override - public CommCareActivityUIController getUIController() { - return this.uiController; - } - - @Override - public void initUIController() { - uiController = new BiometricSignupPageUiController(this); - } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTitle(getString(R.string.app_lock)); - biometricManager = BiometricManager.from(this); - - uiController.setupUI(); - - BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, - biometricManager); - BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); - if (fingerprint == BiometricsHelper.ConfigurationStatus.NotAvailable && - pin == BiometricsHelper.ConfigurationStatus.NotAvailable) { -// Skip to password-only workflow - finish(true, true); - } else { -// updateState(fingerprint, pin); - } - } - - public void handleFingerprintButton() { - BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, - biometricManager); - if (fingerprint == BiometricsHelper.ConfigurationStatus.Configured) { - finish(true, false); - } else if (!BiometricsHelper.configureFingerprint(this)) { - finish(true, true); - } - } - - public void finish(boolean success, boolean failedEnrollment) { - Intent intent = new Intent(getIntent()); - - BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, - biometricManager); - BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); - boolean configured = fingerprint == BiometricsHelper.ConfigurationStatus.Configured || - pin == BiometricsHelper.ConfigurationStatus.Configured; - - intent.putExtra(ConnectConstants.ENROLL_FAIL, failedEnrollment || !configured); - - setResult(success ? RESULT_OK : RESULT_CANCELED, intent); - finish(); - } -} diff --git a/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java b/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java deleted file mode 100644 index 07849cc02e..0000000000 --- a/app/src/org/commcare/activities/connect/BiometricSignupPageUiController.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.commcare.activities.connect; - -import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.Switch; - -import org.commcare.dalvik.R; -import org.commcare.interfaces.CommCareActivityUIController; -import org.commcare.views.ManagedUi; -import org.commcare.views.UiElement; - -@ManagedUi(R.layout.activity_biometric_signup_page) -public class BiometricSignupPageUiController implements CommCareActivityUIController { - @UiElement(value = R.id.switchBiometric) - private Switch fingerprintButton; - - private final BiometricSignupPage activity; - - public BiometricSignupPageUiController(BiometricSignupPage activity) { - this.activity = activity; - } - - @Override - public void setupUI() { - fingerprintButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if(isChecked){ - activity.handleFingerprintButton(); - } - } - }); - - - } - - @Override - public void refreshView() { - - } -} diff --git a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java index 469ac59967..244c906c96 100644 --- a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java +++ b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivity.java @@ -46,14 +46,13 @@ protected void onCreate(Bundle savedInstanceState) { biometricManager = BiometricManager.from(this); biometricPromptCallbacks = preparePromptCallbacks(); uiController.setupUI(); - allowPassword = getIntent().hasExtra(ConnectConstants.ALLOW_PASSWORD) && getIntent().getStringExtra(ConnectConstants.ALLOW_PASSWORD).equals("true");; BiometricsHelper.ConfigurationStatus fingerprint = BiometricsHelper.checkFingerprintStatus(this, biometricManager); BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); if (fingerprint == BiometricsHelper.ConfigurationStatus.NotAvailable && pin == BiometricsHelper.ConfigurationStatus.NotAvailable) { //Skip to password-only workflow -// finish(true, true); + finish(true, true,false); } else { updateState(fingerprint, pin); } @@ -136,9 +135,7 @@ public void handleFingerprintButton() { performFingerprintUnlock(); } else if (BiometricsHelper.isPinConfigured(this, biometricManager)) { performPinUnlock(); - } else if (allowPassword) { - performPasswordUnlock(); - } else { + } else { Logger.exception("No unlock method available when trying to unlock ConnectID", new Exception("No unlock option")); } } @@ -150,10 +147,6 @@ public void performFingerprintUnlock() { BiometricsHelper.authenticateFingerprint(this, biometricManager, allowOtherOptions, biometricPromptCallbacks); } - public void performPasswordUnlock() { - finish(false, true, false); - } - public void performPinUnlock() { BiometricsHelper.authenticatePin(this, biometricManager, biometricPromptCallbacks); } @@ -171,9 +164,6 @@ public void onAuthenticationError(int errorCode, allowPassword) { //Automatically try password, it's the only option performPinUnlock(); - } else { - //Automatically try password, it's the only option - performPasswordUnlock(); } } } @@ -202,14 +192,14 @@ private void logSuccess() { FirebaseAnalyticsUtil.reportCccSignIn(method); } -// public void handlePinButton() { -// BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); -// if (pin == BiometricsHelper.ConfigurationStatus.Configured) { -// finish(true, false); -// } else if (!BiometricsHelper.configurePin(this)) { -// finish(true, true); -// } -// } + public void handlePinButton() { + BiometricsHelper.ConfigurationStatus pin = BiometricsHelper.checkPinStatus(this, biometricManager); + if (pin == BiometricsHelper.ConfigurationStatus.Configured) { + finish(true, false,false); + } else if (!BiometricsHelper.configurePin(this)) { + finish(true, true,false); + } + } private void finish(boolean success, boolean password, boolean recover) { Intent intent = new Intent(getIntent()); diff --git a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivityUiController.java b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivityUiController.java index 208c9e52db..c0fd182035 100644 --- a/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivityUiController.java +++ b/app/src/org/commcare/activities/connect/ConnectIdBiometricConfigActivityUiController.java @@ -44,7 +44,7 @@ public ConnectIdBiometricConfigActivityUiController(ConnectIdBiometricConfigActi @Override public void setupUI() { fingerprintButton.setOnClickListener(v -> activity.handleFingerprintButton()); -// pinButton.setOnClickListener(v -> activity.handlePinButton()); + pinButton.setOnClickListener(v -> activity.handlePinButton()); } @Override diff --git a/app/src/org/commcare/connect/ConnectIdWorkflows.java b/app/src/org/commcare/connect/ConnectIdWorkflows.java index ad9c2e36b5..24b7a5ee1a 100644 --- a/app/src/org/commcare/connect/ConnectIdWorkflows.java +++ b/app/src/org/commcare/connect/ConnectIdWorkflows.java @@ -60,7 +60,7 @@ public static void beginRegistration(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); @@ -488,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 a2d571525c..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,