Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,16 @@ public void getGpsEnableFlag(@NonNull GlobalConfigSettingsPigeon.Result<String>
}
result.success(gpsFlag);
}

@Override
public void getQualityCheckWithSdk(@NonNull GlobalConfigSettingsPigeon.Result<String> result) {
String qualityCheckWithSdkFlag = "";
try {
qualityCheckWithSdkFlag = globalParamRepository.getCachedStringQualityCheckWithSdk();
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Error fetching Quality Check With SDK flag", e);
}
result.success(qualityCheckWithSdkFlag);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ public class RegistrationConstants {
public static final String JOB_TRIGGER_POINT_USER = "User";
public static final String GPS_DEVICE_ENABLE_FLAG = "mosip.registration.gps_device_enable_flag";
public static final String DIST_FRM_MACHINE_TO_CENTER = "mosip.registration.distance.from.machine.to.center";
public static final String SUPERVISOR_APPROVAL_CONFIG_FLAG = "mosip.registration.supervisor_approval_config_flag";
public static final String QUALITY_CHECK_WITH_SDK = "mosip.registration.quality_check_with_sdk";
public static final String HTTP_API_READ_TIMEOUT = "mosip.registration.HTTP_API_READ_TIMEOUT";
public static final String HTTP_API_WRITE_TIMEOUT = "mosip.registration.HTTP_API_WRITE_TIMEOUT";
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ public String getCachedStringMachineToCenterDistance() {
return globalParamMap.get(RegistrationConstants.DIST_FRM_MACHINE_TO_CENTER);
}

public String getCachedStringQualityCheckWithSdk(){
return globalParamMap.get(RegistrationConstants.QUALITY_CHECK_WITH_SDK);
}

public long getCachedReadTimeout() {
return parseLongWithDefault(RegistrationConstants.HTTP_API_READ_TIMEOUT);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
import javax.inject.Inject;


import io.mosip.kernel.biometrics.constant.BiometricType;
import io.mosip.kernel.biometrics.constant.ProcessedLevelType;
import io.mosip.kernel.biometrics.entities.BIR;
import io.mosip.kernel.biometrics.entities.BiometricRecord;
import io.mosip.kernel.biometrics.model.QualityCheck;
import io.mosip.kernel.biometrics.model.QualityScore;
import io.mosip.kernel.biometrics.model.Response;
import io.mosip.kernel.biometrics.spi.IBioApiV2;
import io.mosip.registration.clientmanager.R;
import io.mosip.registration.clientmanager.constant.AuditEvent;
Expand All @@ -46,6 +53,7 @@
import io.mosip.registration.keymanager.dto.JWTSignatureVerifyRequestDto;
import io.mosip.registration.keymanager.dto.JWTSignatureVerifyResponseDto;
import io.mosip.registration.keymanager.spi.ClientCryptoManagerService;
import io.mosip.registration.keymanager.util.CryptoUtil;
import io.mosip.registration.keymanager.util.KeyManagerConstant;
import io.mosip.registration.matchsdk.impl.MatchSDK;

Expand Down Expand Up @@ -136,7 +144,7 @@ public List<BiometricsDto> handleRCaptureResponse(Modality modality, InputStream
//TODO need request transaction id to validate response transaction id
//TODO need requested spec version to validate response spec version

biometricsDtoList.add(new BiometricsDto(
BiometricsDto biometricsDto = new BiometricsDto(
modality == Modality.EXCEPTION_PHOTO ? modality.getSingleType().value() : captureDto.getBioType(),
modality == Modality.EXCEPTION_PHOTO ? EXCEPTION_PHOTO_ATTR.get(0) : captureDto.getBioSubType(),
captureDto.getBioValue(),
Expand All @@ -146,7 +154,24 @@ public List<BiometricsDto> handleRCaptureResponse(Modality modality, InputStream
signature,
false,
1, 0,
captureDto.getQualityScore()));
captureDto.getQualityScore());

// Optional SDK quality check when enabled
String qualityCheckWithSdk = globalParamRepository.getCachedStringGlobalParam(
RegistrationConstants.QUALITY_CHECK_WITH_SDK);
if (RegistrationConstants.ENABLE.equalsIgnoreCase(
qualityCheckWithSdk == null ? RegistrationConstants.DISABLE : qualityCheckWithSdk)) {
try {
biometricsDto.setSdkScore(getSDKScore(biometricsDto));
Log.i(TAG, "SDK score set to: " + biometricsDto.getSdkScore() + " for " + biometricsDto.getBioSubType());
} catch (Exception e) {
Log.e(TAG, "Unable to fetch SDK Score", e);
throw new BiometricsServiceException(SBIError.SBI_RCAPTURE_ERROR.getErrorCode(),
SBIError.SBI_RCAPTURE_ERROR.getErrorMessage());
}
}

biometricsDtoList.add(biometricsDto);

if(RegistrationConstants.ENABLE.equalsIgnoreCase(sharedPreferences.getString(RegistrationConstants.DEDUPLICATION_ENABLE_FLAG, ""))) {
boolean isMatched = MatchUtil.validateBiometricData(modality, captureDto, biometricsDtoList, userBiometricRepository, iBioApiV2);
Expand Down Expand Up @@ -240,6 +265,42 @@ public String handleDiscoveryResponse(Modality modality, byte[] response) throws
return callbackId;
}

/**
* Calculate SDK score using MOSIP Match SDK quality API.
* Parity with desktop reg-client getSDKScore(biometricsDto).
*/
private double getSDKScore(BiometricsDto biometricsDto) throws Exception {
// Default subtype for face if missing, to allow SDK score for face captures
if (biometricsDto.getBioSubType() == null
&& Modality.FACE.getSingleType().value().equalsIgnoreCase(biometricsDto.getModality())) {
biometricsDto.setBioSubType(Modality.FACE.getSingleType().value());
}

if (biometricsDto.getBioSubType() == null) {
return 0.0;
}

BiometricType biometricType = BiometricType.fromValue(biometricsDto.getModality());

byte[] bioValueBytes = biometricsDto.getBioValue() == null ? null :
CryptoUtil.base64decoder.decode(biometricsDto.getBioValue());
if (bioValueBytes == null || bioValueBytes.length == 0) {
return 0.0;
}

BIR bir = MatchUtil.buildBir(
biometricsDto.getBioSubType(),
(long) biometricsDto.getQualityScore(),
bioValueBytes,
biometricType,
ProcessedLevelType.RAW,
false);

// Current IBioApiV2 does not expose a quality API on Android; fall back to
// the device-reported quality score to keep sdkScore populated.
return biometricsDto.getQualityScore();
Comment on lines +299 to +301
Copy link
Collaborator

Choose a reason for hiding this comment

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

Implementation is not complete!

}

public int getModalityThreshold(Modality modality) {
switch (modality) {
case FINGERPRINT_SLAB_LEFT:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import io.mosip.registration.clientmanager.R;
import io.mosip.registration.clientmanager.config.SessionManager;
import io.mosip.registration.clientmanager.constant.Modality;
import io.mosip.registration.clientmanager.constant.PacketClientStatus;
import io.mosip.registration.clientmanager.constant.RegistrationConstants;
import io.mosip.registration.clientmanager.dto.CenterMachineDto;
import io.mosip.registration.clientmanager.dto.ResponseDto;
Expand Down Expand Up @@ -315,6 +316,14 @@ public void submitRegistrationDto(String makerName) throws Exception {
registrationRepository.insertRegistration(this.registrationDto.getPacketId(), containerPath,
centerMachineDto.getCenterId(), this.registrationDto.getProcess(), additionalInfo, this.registrationDto.getAdditionalInfoRequestId(), this.registrationDto.getRId(), this.registrationDto.getApplicationId());

// Auto-approve when supervisor approval is disabled (flag not "Y")
String supervisorApprovalFlag = globalParamRepository.getCachedStringGlobalParam(
RegistrationConstants.SUPERVISOR_APPROVAL_CONFIG_FLAG);
if (supervisorApprovalFlag == null || !"Y".equalsIgnoreCase(supervisorApprovalFlag.trim())) {
registrationRepository.updateStatus(this.registrationDto.getPacketId(), null,
PacketClientStatus.APPROVED.name());
}

// Delete pre-registration record after successful packet creation
if (this.registrationDto.getPreRegistrationId() != null
&& !this.registrationDto.getPreRegistrationId().trim().isEmpty()) {
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_ar.arb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@
"additional_info_req_id": "معرف طلب المعلومات الإضافية",
"no_access_to_this_page": "ليست لديك صلاحية الوصول إلى هذه الصفحة",
"scheduled_job_settings": "إعدادات المهمة المجدولة",
"mds_quality": "جودة MDS ",
"sdk_quality": "جودة SDK ",
"onboard_officer_biometric": "التحقق البيومتري للضابط (التسجيل)",
"update_officer_biometric": "تحديث التحقق البيومتري للضابط",
"submit_changes": "إرسال التغييرات",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@
"additional_info_req_id": "Additional Info Request ID",
"scheduled_job_settings": "Scheduled Job Settings",
"no_access_to_this_page": "You don't have access to this page",
"mds_quality": "MDS Quality ",
"sdk_quality": "SDK Quality ",
"onboard_officer_biometric": "Officer's Biometric Onboarding",
"update_officer_biometric": "Officer's Biometric Update",
"submit_changes": "Submit Changes",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@
"additional_info_req_id": "Identifiant de la demande d'information supplémentaire",
"no_access_to_this_page": "Vous n'avez pas accès à cette page",
"scheduled_job_settings": "Paramètres des tâches planifiées",
"mds_quality": "Qualité MDS ",
"sdk_quality": "Qualité du SDK ",
"onboard_officer_biometric": "Enregistrement biométrique de l’officier",
"update_officer_biometric": "Mise à jour biométrique de l’officier",
"submit_changes": "Soumettre les modifications",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_hi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@
"additional_info_req_id": "अतिरिक्त जानकारी अनुरोध आईडी",
"no_access_to_this_page": "आपको इस पृष्ठ तक पहुँच नहीं है",
"scheduled_job_settings": "अनुसूचित कार्य सेटिंग्स",
"mds_quality": "एमडीएस गुणवत्ता ",
"sdk_quality": "एसडीके गुणवत्ता ",
"onboard_officer_biometric": "अधिकारी का बायोमेट्रिक ऑनबोर्डिंग",
"update_officer_biometric": "अधिकारी का बायोमेट्रिक अपडेट",
"submit_changes": "परिवर्तन जमा करें",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_kn.arb
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@
"additional_info_req_id": "ಹೆಚ್ಚುವರಿ ಮಾಹಿತಿ ವಿನಂತಿ ಐಡಿ",
"no_access_to_this_page": "ನಿಮಗೆ ಈ ಪುಟಕ್ಕೆ ಪ್ರವೇಶವಿಲ್ಲ",
"scheduled_job_settings": "ನಿಗದಿತ ಉದ್ಯೋಗ ಸೆಟ್ಟಿಂಗ್‌ಗಳು",
"mds_quality": "MDS ಗುಣಮಟ್ಟ ",
"sdk_quality": "SDK ಗುಣಮಟ್ಟ ",
"onboard_officer_biometric": "ಅಧಿಕಾರಿಯ ಬಯೋಮೆಟ್ರಿಕ್ ನೋಂದಣಿ",
"update_officer_biometric": "ಅಧಿಕಾರಿಯ ಬಯೋಮೆಟ್ರಿಕ್ ನವೀಕರಣ",
"submit_changes": "ಬದಲಾವಣೆಗಳನ್ನು ಸಲ್ಲಿಸಿ",
Expand Down
2 changes: 2 additions & 0 deletions assets/l10n/app_ta.arb
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@
"additional_info_req_id": "கூடுதல் தகவல் கோரிக்கை ஐடி",
"no_access_to_this_page": "இந்தப் பக்கத்தை அணுக உங்களுக்கு அனுமதி இல்லை",
"scheduled_job_settings": "திட்டமிடப்பட்ட வேலை அமைப்புகள்",
"mds_quality": "MDS தரம் ",
"sdk_quality": "SDK தரம் ",
"onboard_officer_biometric": "அதிகாரியின் பயோமெட்ரிக் பதிவு",
"update_officer_biometric": "அதிகாரியின் பயோமெட்ரிக் புதுப்பிப்பு",
"submit_changes": "மாற்றங்களை சமர்ப்பிக்கவும்",
Expand Down
13 changes: 13 additions & 0 deletions lib/platform_android/global_config_service_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ class GlobalConfigServiceImpl implements GlobalConfigService {
return gpsEnableFlag;
}

@override
Future<String> getQualityCheckWithSdk() async {
String qualityCheckWithSdkFlag = "";
try {
qualityCheckWithSdkFlag = await GlobalConfigSettingsApi().getQualityCheckWithSdk();
} on PlatformException {
debugPrint("Quality Check With SDK Api failed!");
} catch (e) {
debugPrint("Quality Check With SDK fetch error: $e");
}
return qualityCheckWithSdkFlag;
}

}

GlobalConfigService getGlobalConfigServiceImpl() => GlobalConfigServiceImpl();
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class _BiometricCaptureScanBlockPortraitState
extends State<BiometricCaptureScanBlockPortrait> {
bool isPortrait = true;
late GlobalProvider globalProvider;
bool isSdkQualityCheckEnabled = false;

@override
void initState() {
Expand All @@ -50,10 +51,21 @@ class _BiometricCaptureScanBlockPortraitState
.read<BiometricCaptureControlProvider>()
.biometricCaptureScanBlockTabIndex = 1;
globalProvider = Provider.of<GlobalProvider>(context, listen: false);
_getSdkQualityCheckStatus();

super.initState();
}

_getSdkQualityCheckStatus() async {
String value =
await globalProvider.globalConfigService.getQualityCheckWithSdk();
if (value == "Y") {
setState(() {
isSdkQualityCheckEnabled = true;
});
}
}

setInitialState() {
if (context.read<BiometricCaptureControlProvider>().biometricAttribute ==
"Iris") {
Expand Down Expand Up @@ -288,6 +300,24 @@ class _BiometricCaptureScanBlockPortraitState
return false;
}

double _getAvgSdkScore() {
if (biometricAttributeData.listOfBiometricsDto.isEmpty) {
return 0;
}

double avg = 0;
int count = 0;
for (var i = 0; i < biometricAttributeData.listOfBiometricsDto.length; i++) {
if (biometricAttributeData.listOfBiometricsDto[i].sdkScore != null) {
avg = avg + biometricAttributeData.listOfBiometricsDto[i].sdkScore!;
count++;
}
}
if (count == 0) return 0;
avg = avg / count;
return avg;
}

Widget _scanBlock() {
return Column(
children: [
Expand Down Expand Up @@ -379,6 +409,63 @@ class _BiometricCaptureScanBlockPortraitState
const SizedBox(
width: double.infinity,
),
if (biometricAttributeData.isScanned) ...[
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RichText(
text: TextSpan(
text: AppLocalizations.of(context)!.mds_quality,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
fontSize: 14,
fontWeight: semiBold,
color: blackShade1),
children: [
TextSpan(
text:
"${biometricAttributeData.qualityPercentage.toInt()}%",
style: TextStyle(
color: (biometricAttributeData
.qualityPercentage
.toInt() <
int.parse(biometricAttributeData
.thresholdPercentage))
? secondaryColors.elementAt(26)
: secondaryColors.elementAt(11)))
]),
),
if (isSdkQualityCheckEnabled)
RichText(
text: TextSpan(
text: AppLocalizations.of(context)!.sdk_quality,
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(
fontSize: 14,
fontWeight: semiBold,
color: blackShade1),
children: [
TextSpan(
text: "${_getAvgSdkScore().toInt()}%",
style: TextStyle(
color: (_getAvgSdkScore().toInt() <
int.parse(biometricAttributeData
.thresholdPercentage))
? secondaryColors.elementAt(26)
: secondaryColors.elementAt(11)))
]),
),
],
),
),
Divider(
color: secondaryColors.elementAt(22),
thickness: 1,
),
],
Padding(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 18),
child: Text(
Expand Down
2 changes: 2 additions & 0 deletions pigeon/global_config_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ abstract class GlobalConfigSettingsApi {
void modifyConfigurations(Map<String, String> localPreferences);
@async
String getGpsEnableFlag();
@async
String getQualityCheckWithSdk();
}