From e9fccc0f228bdaa56a940893cbde6a7af3eb8a84 Mon Sep 17 00:00:00 2001 From: parthmittal Date: Thu, 20 Feb 2025 13:02:09 +0530 Subject: [PATCH] -updated java doc for util functions --- .../org/commcare/utils/BiometricsHelper.java | 114 ++++++++++++++---- app/src/org/commcare/utils/CrashUtil.java | 18 ++- .../org/commcare/utils/KeyboardHelper.java | 13 +- .../org/commcare/utils/PhoneNumberHelper.java | 106 ++++++++++++---- 4 files changed, 194 insertions(+), 57 deletions(-) diff --git a/app/src/org/commcare/utils/BiometricsHelper.java b/app/src/org/commcare/utils/BiometricsHelper.java index 6a2ba47b0a..4c4b73a057 100644 --- a/app/src/org/commcare/utils/BiometricsHelper.java +++ b/app/src/org/commcare/utils/BiometricsHelper.java @@ -18,42 +18,72 @@ import androidx.fragment.app.FragmentActivity; /** - * Helper class for biometric configuration and verification - * - * @author dviggiano + * Helper class for biometric configuration and verification. + * Provides methods to check biometric availability, configure biometrics, + * and perform authentication using fingerprint or PIN or Password. + * Supports both biometric strong authentication and device credentials. */ public class BiometricsHelper { + /** - * Enum simplifying the availability of a biometric method + * Enum representing the availability and configuration status of a biometric method. */ public enum ConfigurationStatus { - NotAvailable, - NotConfigured, - Configured + NotAvailable, // Biometrics not available on the device + NotConfigured, // Biometrics available but not set up + Configured // Biometrics set up and ready for authentication } private static final int StrongBiometric = BiometricManager.Authenticators.BIOMETRIC_STRONG; private static final int PinBiometric = BiometricManager.Authenticators.DEVICE_CREDENTIAL; + /** + * Checks the fingerprint authentication status. + * + * @param context The application context. + * @param biometricManager The BiometricManager instance. + * @return The fingerprint configuration status. + */ public static ConfigurationStatus checkFingerprintStatus(Context context, BiometricManager biometricManager) { return checkStatus(context, biometricManager, StrongBiometric); } + /** + * Determines if fingerprint authentication is configured on the device. + * + * @param context The application context. + * @param biometricManager The BiometricManager instance. + * @return True if fingerprint authentication is configured, false otherwise. + */ public static boolean isFingerprintConfigured(Context context, BiometricManager biometricManager) { return checkStatus(context, biometricManager, StrongBiometric) == ConfigurationStatus.Configured; } + /** + * Prompts the user to configure fingerprint authentication. + * + * @param activity The current activity. + * @return True if the configuration process starts successfully, false otherwise. + */ public static boolean configureFingerprint(Activity activity) { return configureBiometric(activity, StrongBiometric); } + /** + * Initiates fingerprint authentication. + * + * @param activity The fragment activity. + * @param biometricManager The BiometricManager instance. + * @param allowExtraOptions Whether to allow alternative authentication options (e.g., PIN). + * @param callback The callback for authentication results. + */ public static void authenticateFingerprint(FragmentActivity activity, BiometricManager biometricManager, boolean allowExtraOptions, BiometricPrompt.AuthenticationCallback callback) { if (BiometricsHelper.isFingerprintConfigured(activity, biometricManager)) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { - //For newer versions, PIN prompt will handle all unlock + // For Android 11+ (R), use PIN as an alternative unlock method authenticatePin(activity, biometricManager, callback); } else { BiometricPrompt prompt = new BiometricPrompt(activity, @@ -74,7 +104,13 @@ public static void authenticateFingerprint(FragmentActivity activity, } } - + /** + * Checks the status of PIN-based authentication. + * + * @param context The application context. + * @param biometricManager The BiometricManager instance. + * @return The PIN configuration status. + */ public static ConfigurationStatus checkPinStatus(Context context, BiometricManager biometricManager) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { return checkStatus(context, biometricManager, PinBiometric); @@ -88,29 +124,56 @@ public static ConfigurationStatus checkPinStatus(Context context, BiometricManag } } + /** + * Determines if PIN authentication is configured on the device. + * + * @param context The application context. + * @param biometricManager The BiometricManager instance. + * @return True if PIN authentication is configured, false otherwise. + */ public static boolean isPinConfigured(Context context, BiometricManager biometricManager) { return checkStatus(context, biometricManager, PinBiometric) == ConfigurationStatus.Configured; } + /** + * Prompts the user to configure PIN-based authentication. + * + * @param activity The current activity. + * @return True if the configuration process starts successfully, false otherwise. + */ public static boolean configurePin(Activity activity) { return configureBiometric(activity, PinBiometric); } private static BiometricPrompt.AuthenticationCallback biometricPromptCallbackHolder; + /** + * Initiates PIN-based authentication. + * + * @param activity The fragment activity. + * @param biometricManager The BiometricManager instance. + * @param biometricPromptCallback The callback for authentication results. + */ public static void authenticatePin(FragmentActivity activity, BiometricManager biometricManager, BiometricPrompt.AuthenticationCallback biometricPromptCallback) { if (BiometricsHelper.isPinConfigured(activity, biometricManager)) { - biometricPromptCallbackHolder = biometricPromptCallback; - KeyguardManager manager = (KeyguardManager)activity.getSystemService(Context.KEYGUARD_SERVICE); - activity.startActivityForResult( - manager.createConfirmDeviceCredentialIntent( - activity.getString(R.string.connect_unlock_title), - activity.getString(R.string.connect_unlock_message)), - ConnectConstants.CONNECT_UNLOCK_PIN); + biometricPromptCallbackHolder = biometricPromptCallback; + KeyguardManager manager = (KeyguardManager)activity.getSystemService(Context.KEYGUARD_SERVICE); + activity.startActivityForResult( + manager.createConfirmDeviceCredentialIntent( + activity.getString(R.string.connect_unlock_title), + activity.getString(R.string.connect_unlock_message)), + ConnectConstants.CONNECT_UNLOCK_PIN); } } + /** + * Handles the result of the PIN authentication activity. + * + * @param requestCode The request code for the authentication intent. + * @param resultCode The result code from the authentication activity. + * @return True if the request was handled, false otherwise. + */ public static boolean handlePinUnlockActivityResult(int requestCode, int resultCode) { if (requestCode == ConnectConstants.CONNECT_UNLOCK_PIN) { if (resultCode == Activity.RESULT_OK) { @@ -118,13 +181,19 @@ public static boolean handlePinUnlockActivityResult(int requestCode, int resultC } else { biometricPromptCallbackHolder.onAuthenticationFailed(); } - return true; } - return false; } + /** + * Checks the biometric authentication status for a specific authentication method. + * + * @param context The application context. + * @param biometricManager The BiometricManager instance. + * @param authenticator The authenticator type (e.g., fingerprint, PIN). + * @return The biometric configuration status. + */ public static ConfigurationStatus checkStatus(Context context, BiometricManager biometricManager, int authenticator) { int val = canAuthenticate(context, biometricManager, authenticator); @@ -136,7 +205,6 @@ public static ConfigurationStatus checkStatus(Context context, BiometricManager return ConfigurationStatus.NotConfigured; } } - return ConfigurationStatus.NotAvailable; } @@ -150,23 +218,17 @@ private static int canAuthenticate(Context context, BiometricManager biometricMa return isSecure ? BiometricManager.BIOMETRIC_SUCCESS : BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED; } - return biometricManager.canAuthenticate(authenticator); } private static boolean configureBiometric(Activity activity, int authenticator) { - // Prompts the user to create credentials that your app accepts. Intent enrollIntent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - //Best case, handles both fingerprint and PIN enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL); - enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, - authenticator); + enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, authenticator); } else if (authenticator == StrongBiometric && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - //An alternative for fingerprint enroll that might be available enrollIntent = new Intent(Settings.ACTION_FINGERPRINT_ENROLL); } else { - //No way to enroll, have to fail return false; } diff --git a/app/src/org/commcare/utils/CrashUtil.java b/app/src/org/commcare/utils/CrashUtil.java index bbe8cf0a14..2ffadf65dc 100644 --- a/app/src/org/commcare/utils/CrashUtil.java +++ b/app/src/org/commcare/utils/CrashUtil.java @@ -4,11 +4,12 @@ import org.commcare.android.logging.ReportingUtils; import org.commcare.connect.ConnectManager; import org.commcare.dalvik.BuildConfig; + import com.google.firebase.crashlytics.FirebaseCrashlytics; /** * Contains constants and methods used in Crashlytics reporting. - * + *

* Created by shubham on 8/09/17. */ public class CrashUtil { @@ -56,12 +57,21 @@ public static void log(String message) { } } + /** + * Registers the current Connect user with Firebase Crashlytics for error tracking. + *

+ * If Crashlytics is enabled and a Connect ID is configured, this method retrieves + * the user ID from ConnectManager and sets it as a custom key in Crashlytics. + *

+ * In case of any exceptions during this process, the exception is recorded in + * Crashlytics to aid debugging. + */ public static void registerConnectUser() { if (crashlyticsEnabled && ConnectManager.isConnectIdConfigured()) { - try{ - String userId=ConnectManager.getUser(CommCareApplication.instance()).getUserId(); + try { + String userId = ConnectManager.getUser(CommCareApplication.instance()).getUserId(); FirebaseCrashlytics.getInstance().setCustomKey(CCC_USER, userId); - }catch (Exception e){ + } catch (Exception e) { FirebaseCrashlytics.getInstance().recordException(e); } } diff --git a/app/src/org/commcare/utils/KeyboardHelper.java b/app/src/org/commcare/utils/KeyboardHelper.java index ba0e1f3433..a44e9666bf 100644 --- a/app/src/org/commcare/utils/KeyboardHelper.java +++ b/app/src/org/commcare/utils/KeyboardHelper.java @@ -6,16 +6,27 @@ import android.view.inputmethod.InputMethodManager; /** - * Helper class (single method) for showing the keyboard on an input + * Utility class for handling keyboard interactions. + * Provides a method to show the keyboard on a given input field. * * @author dviggiano */ public class KeyboardHelper { + + /** + * Displays the soft keyboard for the specified input view. + * This method ensures the view gains focus before attempting to show the keyboard. + * A slight delay is added to ensure the keyboard appears properly. + * + * @param activity The activity context used to retrieve the InputMethodManager. + * @param view The input view that should receive focus and trigger the keyboard. + */ public static void showKeyboardOnInput(Activity activity, View view) { view.requestFocus(); InputMethodManager inputMethodManager = (InputMethodManager)activity.getSystemService( Context.INPUT_METHOD_SERVICE); + view.postDelayed(new Runnable() { @Override public void run() { diff --git a/app/src/org/commcare/utils/PhoneNumberHelper.java b/app/src/org/commcare/utils/PhoneNumberHelper.java index 9e3a70d749..a178c0d2b8 100644 --- a/app/src/org/commcare/utils/PhoneNumberHelper.java +++ b/app/src/org/commcare/utils/PhoneNumberHelper.java @@ -21,8 +21,12 @@ import io.michaelrocks.libphonenumber.android.Phonenumber; /** - * Helper class for functionality related to phone numbers - * Includes frequent usage of PhoneNumberUtil + * Utility class for handling phone number-related operations. + * Provides functions for phone number validation, formatting, + * country code retrieval, and requesting phone number hints. + *

+ * This class leverages the PhoneNumberUtil library for number parsing + * and validation, and Google Identity API for phone number hint retrieval. * * @author dviggiano */ @@ -30,24 +34,27 @@ public class PhoneNumberHelper { private static final ThreadLocal utilStatic = new ThreadLocal<>(); private static ActivityResultLauncher phoneNumberHintLauncher; - //Private constructor, class should be used statically + // Private constructor to prevent instantiation private PhoneNumberHelper() { } + /** + * Sets the ActivityResultLauncher for handling phone number hint requests. + * + * @param launcher The launcher that will handle the result of the phone number hint request. + */ public static void setPhoneNumberHintLauncher(ActivityResultLauncher launcher) { phoneNumberHintLauncher = launcher; } - private static PhoneNumberUtil getUtil(Context context) { - PhoneNumberUtil util = utilStatic.get(); - if (util == null) { - util = PhoneNumberUtil.createInstance(context); - utilStatic.set(util); - } - - return util; - } - + /** + * Combines the country code and phone number into a single formatted string. + * Removes any spaces, dashes, or parentheses from the phone number. + * + * @param countryCode The country code as a string (e.g., "+1"). + * @param phone The phone number as a string. + * @return A formatted phone number string with no special characters. + */ public static String buildPhoneNumber(String countryCode, String phone) { return String.format("%s%s", countryCode, phone) .replaceAll("-", "") @@ -56,18 +63,31 @@ public static String buildPhoneNumber(String countryCode, String phone) { .replaceAll(" ", ""); } + /** + * Validates whether the given phone number is valid based on the region. + * + * @param context The application context used for retrieving the PhoneNumberUtil instance. + * @param phone The phone number to validate. + * @return True if the phone number is valid, false otherwise. + */ public static boolean isValidPhoneNumber(Context context, String phone) { PhoneNumberUtil util = getUtil(context); try { Phonenumber.PhoneNumber phoneNumber = util.parse(phone, null); return util.isValidNumber(phoneNumber); } catch (NumberParseException e) { - //Error parsing number means it isn't valid, fall-through to return false + // Error parsing number means it isn't valid } - return false; } + /** + * Extracts the country code from a given phone number. + * + * @param context The application context. + * @param phone The phone number from which to extract the country code. + * @return The country code as an integer, or -1 if extraction fails. + */ public static int getCountryCode(Context context, String phone) { PhoneNumberUtil util = getUtil(context); try { @@ -78,23 +98,32 @@ public static int getCountryCode(Context context, String phone) { } catch (NumberParseException e) { Log.d("PhoneNumberHelper", "Failed to parse number: " + e.getMessage()); } - return -1; } + /** + * Retrieves the country code for the user's current locale. + * + * @param context The application context. + * @return The country code as an integer. + */ public static int getCountryCode(Context context) { Locale locale = context.getResources().getConfiguration().locale; PhoneNumberUtil util = getUtil(context); - return util.getCountryCodeForRegion(locale.getCountry()); } + /** + * Returns the default country code formatted as a string with a "+" prefix. + * + * @param context The application context. + * @return The country code string (e.g., "+1"), or an empty string if unavailable. + */ public static String setDefaultCountryCode(Context context) { Locale locale = context.getResources().getConfiguration().locale; PhoneNumberUtil util = getUtil(context); int code = util.getCountryCodeForRegion(locale.getCountry()); - String codeText = ""; if (code > 0) { codeText = String.format(Locale.getDefault(), "%d", code); @@ -102,10 +131,15 @@ public static String setDefaultCountryCode(Context context) { codeText = "+" + codeText; } } - return codeText; } + /** + * Requests a phone number hint from Google Identity API. + * This allows the user to pick a phone number without manually entering it. + * + * @param activity The activity that initiates the request. + */ public static void requestPhoneNumberHint(Activity activity) { GetPhoneNumberHintIntentRequest hintRequest = GetPhoneNumberHintIntentRequest.builder().build(); Identity.getSignInClient(activity).getPhoneNumberHintIntent(hintRequest) @@ -123,20 +157,40 @@ public static void requestPhoneNumberHint(Activity activity) { }); } + /** + * Handles the result of a phone number picker request. + * Extracts the phone number from the returned intent if available. + * + * @param requestCode The request code used to identify the intent result. + * @param resultCode The result code indicating success or failure. + * @param intent The intent containing the selected phone number. + * @param activity The activity that initiated the request. + * @return The selected phone number as a string, or an empty string if unavailable. + */ public static String handlePhoneNumberPickerResult(int requestCode, int resultCode, Intent intent, Activity activity) { - if (requestCode == ConnectConstants.CREDENTIAL_PICKER_REQUEST && resultCode == Activity.RESULT_OK) { SignInClient signInClient = Identity.getSignInClient(activity); - String phoneNumber; try { - phoneNumber = signInClient.getPhoneNumberFromIntent(intent); - return phoneNumber; + return signInClient.getPhoneNumberFromIntent(intent); } catch (ApiException e) { Log.e("PhoneNumberHelper", "Failed to get phone number: " + e.getMessage(), e); - return null; } - } return ""; } -} \ No newline at end of file + + /** + * Retrieves a thread-local instance of PhoneNumberUtil to parse phone numbers. + * + * @param context The application context. + * @return The PhoneNumberUtil instance. + */ + private static PhoneNumberUtil getUtil(Context context) { + PhoneNumberUtil util = utilStatic.get(); + if (util == null) { + util = PhoneNumberUtil.createInstance(context); + utilStatic.set(util); + } + return util; + } +}