diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/ConstantTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/ConstantTest.kt index 340f851e4..c87250030 100644 --- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/ConstantTest.kt +++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/ConstantTest.kt @@ -44,7 +44,6 @@ class ConstantTest { assertEquals("signing_route", Constant.Routes.SIGNING_SCREEN) assertEquals("encrypt_route", Constant.Routes.ENCRYPT_SCREEN) assertEquals("decrypt_route", Constant.Routes.DECRYPT_SCREEN) - assertEquals("decrypt_method_route", Constant.Routes.DECRYPT_METHOD_SCREEN) assertEquals("accessibility_route", Constant.Routes.ACCESSIBILITY_SCREEN) assertEquals("info_route", Constant.Routes.INFO_SCREEN) assertEquals("diagnostics_route", Constant.Routes.DIAGNOSTICS_SCREEN) @@ -66,7 +65,6 @@ class ConstantTest { assertEquals("proxy_services_route", Constant.Routes.PROXY_SERVICES_SCREEN) assertEquals("container_notifications_route", Constant.Routes.CONTAINER_NOTIFICATIONS_SCREEN) assertEquals("myeid_identification_route", Constant.Routes.MYEID_IDENTIFICATION_SCREEN) - assertEquals("myeid_identification_method_route", Constant.Routes.MYEID_IDENTIFICATION_METHOD_SCREEN) assertEquals("myeid_screen_route", Constant.Routes.MYEID_SCREEN) assertEquals("myeid_pin_screen_route", Constant.Routes.MYEID_PIN_SCREEN) } diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/RouteTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/RouteTest.kt index 2c4c81a4b..8eeb954ac 100644 --- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/RouteTest.kt +++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/RouteTest.kt @@ -27,7 +27,6 @@ import ee.ria.DigiDoc.utils.Constant.Routes.CERTIFICATE_DETAIL_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CONTAINER_NOTIFICATIONS_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CRYPTO_FILE_CHOOSING_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CRYPTO_SCREEN -import ee.ria.DigiDoc.utils.Constant.Routes.DECRYPT_METHOD_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.DECRYPT_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.DIAGNOSTICS_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.EID_SCREEN @@ -37,7 +36,6 @@ import ee.ria.DigiDoc.utils.Constant.Routes.ENCRYPT_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.HOME_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.INFO_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.INIT_SCREEN -import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_IDENTIFICATION_METHOD_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_IDENTIFICATION_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_PIN_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_SCREEN @@ -75,7 +73,6 @@ class RouteTest { assertEquals(SIGNING_SCREEN, Route.Signing.route) assertEquals(ENCRYPT_SCREEN, Route.Encrypt.route) assertEquals(DECRYPT_SCREEN, Route.DecryptScreen.route) - assertEquals(DECRYPT_METHOD_SCREEN, Route.DecryptMethodScreen.route) assertEquals(ACCESSIBILITY_SCREEN, Route.Accessibility.route) assertEquals(INFO_SCREEN, Route.Info.route) assertEquals(DIAGNOSTICS_SCREEN, Route.Diagnostics.route) @@ -98,7 +95,6 @@ class RouteTest { assertEquals(PROXY_SERVICES_SCREEN, Route.ProxyServicesScreen.route) assertEquals(CONTAINER_NOTIFICATIONS_SCREEN, Route.ContainerNotificationsScreen.route) assertEquals(MYEID_IDENTIFICATION_SCREEN, Route.MyEidIdentificationScreen.route) - assertEquals(MYEID_IDENTIFICATION_METHOD_SCREEN, Route.MyEidIdentificationMethodScreen.route) assertEquals(MYEID_SCREEN, Route.MyEidScreen.route) assertEquals(MYEID_PIN_SCREEN, Route.MyEidPinScreen.route) } diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModelTest.kt deleted file mode 100644 index 377195801..000000000 --- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModelTest.kt +++ /dev/null @@ -1,969 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName") - -package ee.ria.DigiDoc.viewmodel - -import android.content.Context -import android.content.res.Resources -import androidx.activity.ComponentActivity -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.Observer -import androidx.test.platform.app.InstrumentationRegistry -import ee.ria.DigiDoc.IdCardDataCreator.Companion.createMockIdCardData -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.common.certificate.CertificateService -import ee.ria.DigiDoc.common.model.EIDType -import ee.ria.DigiDoc.common.model.ExtendedCertificate -import ee.ria.DigiDoc.common.testfiles.asset.AssetFile -import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository -import ee.ria.DigiDoc.cryptolib.CDOC2Settings -import ee.ria.DigiDoc.cryptolib.CryptoContainer -import ee.ria.DigiDoc.domain.model.IdCardData -import ee.ria.DigiDoc.domain.service.IdCardService -import ee.ria.DigiDoc.idcard.CodeType -import ee.ria.DigiDoc.idcard.CodeVerificationException -import ee.ria.DigiDoc.idcard.PersonalData -import ee.ria.DigiDoc.idcard.Token -import ee.ria.DigiDoc.libdigidoclib.SignedContainer -import ee.ria.DigiDoc.libdigidoclib.init.Initialization -import ee.ria.DigiDoc.libdigidoclib.init.LibdigidocLibraryLoader -import ee.ria.DigiDoc.smartcardreader.SmartCardReader -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus -import io.reactivex.rxjava3.core.Observable -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.flow.take -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.runTest -import kotlinx.coroutines.yield -import org.bouncycastle.asn1.x509.ExtendedKeyUsage -import org.bouncycastle.asn1.x509.KeyUsage -import org.bouncycastle.cert.X509CertificateHolder -import org.bouncycastle.util.encoders.Hex -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue -import org.junit.Assert.fail -import org.junit.Before -import org.junit.BeforeClass -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito.mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` -import org.mockito.MockitoAnnotations -import org.mockito.junit.MockitoJUnitRunner -import org.mockito.kotlin.any -import org.mockito.kotlin.anyOrNull -import org.mockito.kotlin.atLeastOnce -import org.mockito.kotlin.eq -import java.io.File - -@RunWith(MockitoJUnitRunner::class) -class IdCardViewModelTest { - @get:Rule - val instantExecutorRule = InstantTaskExecutorRule() - - @Mock - private lateinit var mockContext: Context - - @Mock - private lateinit var resources: Resources - - @Mock - private lateinit var idCardService: IdCardService - - @Mock - private lateinit var certificateService: CertificateService - - @Mock - private lateinit var smartCardReaderManager: SmartCardReaderManager - - @Mock - private lateinit var x509CertificateHolder: X509CertificateHolder - - @Mock - private lateinit var token: Token - - @Mock - private lateinit var mockSmartCardReader: SmartCardReader - - @Mock - private lateinit var mockComponentActivity: ComponentActivity - - private lateinit var container: File - - private lateinit var context: Context - - private lateinit var viewModel: IdCardViewModel - - private lateinit var cdoc2Settings: CDOC2Settings - - private lateinit var configurationRepository: ConfigurationRepository - - companion object { - @JvmStatic - @BeforeClass - fun setupOnce() { - runBlocking { - try { - val context = InstrumentationRegistry.getInstrumentation().targetContext - val configurationRepository = mock(ConfigurationRepository::class.java) - LibdigidocLibraryLoader().init(context) - Initialization(configurationRepository).init(context) - } catch (_: Exception) { - } - } - } - } - - @Before - fun setUp() { - MockitoAnnotations.openMocks(this) - context = InstrumentationRegistry.getInstrumentation().targetContext - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.IDLE)) - `when`(mockContext.resources).thenReturn(resources) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - configurationRepository = mock(ConfigurationRepository::class.java) - cdoc2Settings = CDOC2Settings(context, configurationRepository) - viewModel = IdCardViewModel(smartCardReaderManager, idCardService, cdoc2Settings, configurationRepository) - - container = - AssetFile.getResourceFileAsFile( - context, - "example.asice", - ee.ria.DigiDoc.common.R.raw.example, - ) - } - - @Test - fun idCardViewModel_idCardStatus_success() { - runTest { - val idCardStatus = viewModel.idCardStatus.value - - assertEquals(SmartCardReaderStatus.IDLE, idCardStatus) - } - } - - @Test - fun idCardViewModel_loadPersonalData_success() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val mockIdCardData = createMockIdCardData() - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockIdCardData.personalData) - - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockIdCardData.personalData, - mockIdCardData.authCertificate, - mockIdCardData.signCertificate, - 3, - 3, - 3, - true, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - - viewModel.loadPersonalData() - - val userDataValue = viewModel.userData.value - assertEquals(mockIdCardData, userDataValue) - } - - @Test - fun idCardViewModel_loadPersonalData_resetValuesAfterException() = - runTest { - viewModel.loadPersonalData() - - assertNull(viewModel.signStatus.value) - assertNull(viewModel.dialogError.value) - assertEquals(SmartCardReaderStatus.IDLE, viewModel.idCardStatus.value) - assertNull(viewModel.userData.value) - assertNull(viewModel.errorState.value) - assertNull(viewModel.pinErrorState.value) - assertNull(viewModel.signStatus.value) - assertNull(viewModel.signedContainer.value) - } - - @Test - fun idCardViewModel_sign_success() = - runBlocking { - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - `when`(resources.getString(any())).thenReturn("Mocked String") - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val mockPersonalData = mock(PersonalData::class.java) - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`( - idCardService.signContainer(any(), eq(signedContainer), eq(pin2), eq(null)), - ).thenReturn(signedContainer) - - val testData = byteArrayOf(1, 2, 3) - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - - val certificate = ExtendedCertificate.create(testData, certificateService) - - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockPersonalData, - certificate, - certificate, - 3, - 3, - 3, - true, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - val signStatus = viewModel.signStatus.value - - if (signStatus != null) { - assertTrue(signStatus) - } else { - fail("signStatus is null") - } - - assertNotNull(viewModel.signedContainer.value) - } - - @Test - fun idCardViewModel_sign_handleWrongPin2Exception2Retries() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val mockPersonalData = mock(PersonalData::class.java) - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - val testData = byteArrayOf(1, 2, 3) - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - - val certificate = ExtendedCertificate.create(testData, certificateService) - - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockPersonalData, - certificate, - certificate, - 3, - 2, - 3, - true, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - CodeVerificationException(CodeType.PIN2, 2), - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - val signStatusValue = viewModel.signStatus.value - if (signStatusValue != null) { - assertFalse(signStatusValue) - } else { - fail("signStatusValue is null") - } - assertNull(viewModel.signedContainer.value) - assertEquals( - Triple(R.string.id_card_sign_pin_invalid, CodeType.PIN2.name, 2), - viewModel.pinErrorState.value, - ) - } - - @Test - fun idCardViewModel_sign_handleWrongPin2Exception1Retry() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val mockPersonalData = mock(PersonalData::class.java) - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - val testData = byteArrayOf(1, 2, 3) - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - - val certificate = ExtendedCertificate.create(testData, certificateService) - - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockPersonalData, - certificate, - certificate, - 3, - 1, - 3, - true, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - CodeVerificationException(CodeType.PIN2, 1), - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - val signStatusValue = viewModel.signStatus.value - if (signStatusValue != null) { - assertFalse(signStatusValue) - } else { - fail("signStatusValue is null") - } - assertNull(viewModel.signedContainer.value) - assertEquals( - Triple(R.string.id_card_sign_pin_invalid_final, CodeType.PIN2.name, null), - viewModel.pinErrorState.value, - ) - } - - @Test - fun idCardViewModel_sign_handleWrongPin2ExceptionPinLocked() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val mockPersonalData = mock(PersonalData::class.java) - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - val testData = byteArrayOf(1, 2, 3) - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - - val certificate = ExtendedCertificate.create(testData, certificateService) - - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockPersonalData, - certificate, - certificate, - 3, - 0, - 3, - true, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - CodeVerificationException(CodeType.PIN2, 0), - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - val signStatusValue = viewModel.signStatus.value - if (signStatusValue != null) { - assertFalse(signStatusValue) - } else { - fail("signStatusValue is null") - } - assertNull(viewModel.signedContainer.value) - assertEquals( - Triple(R.string.id_card_sign_pin_locked, CodeType.PIN2.name, null), - viewModel.pinErrorState.value, - ) - } - - @Test - fun idCardViewModel_sign_handlePin2NotChangedException() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("PIN2 has not been changed") - - val mockPersonalData = mock(PersonalData::class.java) - val keyUsage = mock(KeyUsage::class.java) - val extendedKeyUsage = mock(ExtendedKeyUsage::class.java) - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - val testData = byteArrayOf(1, 2, 3) - val testName = "Test name" - - `when`(certificateService.parseCertificate(anyOrNull())) - .thenReturn(x509CertificateHolder) - `when`(certificateService.extractEIDType(any())) - .thenReturn(EIDType.ID_CARD) - `when`(certificateService.extractFriendlyName(anyOrNull())).thenReturn(testName) - `when`(certificateService.isEllipticCurve(anyOrNull())).thenReturn(true) - `when`(certificateService.extractKeyUsage(any())).thenReturn(keyUsage) - `when`(certificateService.extractExtendedKeyUsage(any())).thenReturn(extendedKeyUsage) - val certificate = ExtendedCertificate.create(testData, certificateService) - val idCardData = - IdCardData( - EIDType.ID_CARD, - mockPersonalData, - certificate, - certificate, - 3, - 0, - 3, - false, - ) - - `when`(idCardService.data(anyOrNull())).thenReturn(idCardData) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.dialogError.value) - assertEquals(exception.message, viewModel.dialogError.value) - } - - @Test - fun idCardViewModel_sign_handleWrongPin2ExceptionWhenUnableToGetPinRetryCount() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - CodeVerificationException(CodeType.PIN2, 0), - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertFalse(viewModel.signStatus.value == true) - assertNull(viewModel.signedContainer.value) - assertEquals( - Triple(R.string.id_card_sign_pin_locked, CodeType.PIN2.name, null), - viewModel.pinErrorState.value, - ) - } - - @Test - fun idCardViewModel_sign_handleTooManyRequests() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("Too Many Requests") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.dialogError.value) - assertEquals(exception.message, viewModel.dialogError.value) - } - - @Test - fun idCardViewModel_sign_handleOcspResponseNotInValidTimeSlot() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("OCSP response not in valid time slot") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.dialogError.value) - assertEquals(exception.message, viewModel.dialogError.value) - } - - @Test - fun idCardViewModel_sign_handleCertificateStatusRevoked() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("Certificate status: revoked") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.errorState.value) - assertEquals( - Triple(R.string.signature_update_signature_error_message_certificate_revoked, null, null), - viewModel.errorState.value, - ) - } - - @Test - fun idCardViewModel_sign_handleFailedToConnect() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("Failed to connect") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.errorState.value) - assertEquals(Triple(R.string.no_internet_connection, null, null), viewModel.errorState.value) - } - - @Test - fun idCardViewModel_sign_handleFailedToCreateConnectionWithHost() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("Failed to create connection with host") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.errorState.value) - assertEquals(Triple(R.string.no_internet_connection, null, null), viewModel.errorState.value) - } - - @Test - fun idCardViewModel_sign_handleFailedToCreateProxyConnectionWithHost() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("Failed to create proxy connection with host") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.errorState.value) - assertEquals(Triple(R.string.main_settings_proxy_invalid_settings, null, null), viewModel.errorState.value) - } - - @Test - fun idCardViewModel_sign_handleGeneralError() = - runTest { - `when`(smartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.CARD_DETECTED)) - - val pin2 = byteArrayOf(1, 2, 3) - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - val exception = Exception("General error") - - val mockPersonalData = mock(PersonalData::class.java) - - val mockSmartCardReader = mock(SmartCardReader::class.java) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - `when`(smartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - - `when`(token.personalData()).thenReturn(mockPersonalData) - - `when`(mockComponentActivity.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(context.resources.configuration) - - `when`(idCardService.data(anyOrNull())).thenThrow(Exception()) - `when`(idCardService.signContainer(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())).thenThrow( - exception, - ) - - viewModel.sign(mockComponentActivity, signedContainer, pin2, null) - - assertNotNull(viewModel.errorState.value) - assertEquals(Triple(R.string.error_general_client, null, null), viewModel.errorState.value) - } - - @Test - fun idCardViewModel_removePendingSignature_success() = - runTest { - val container = - AssetFile.getResourceFileAsFile( - context, - "example.asice", - ee.ria.DigiDoc.common.R.raw.example, - ) - - val signedContainer = SignedContainer.openOrCreate(context, container, listOf(container), true) - - viewModel.removePendingSignature(signedContainer) - - assertEquals(1, signedContainer.getSignatures(Main).size) - } - - @Test - fun idCardViewModel_resetSignStatus_success() = - runTest { - val resetSignStatusObserver: Observer = mock() - viewModel.signStatus.observeForever(resetSignStatusObserver) - - viewModel.resetSignStatus() - verify(resetSignStatusObserver, atLeastOnce()).onChanged(null) - - viewModel.signStatus.removeObserver(resetSignStatusObserver) - } - - @Test - fun idCardViewModel_resetDecryptStatus_success() = - runTest { - val resetDecryptStatusObserver: Observer = mock() - viewModel.decryptStatus.observeForever(resetDecryptStatusObserver) - - viewModel.resetDecryptStatus() - verify(resetDecryptStatusObserver, atLeastOnce()).onChanged(null) - - viewModel.decryptStatus.removeObserver(resetDecryptStatusObserver) - } - - @Test - fun idCardViewModel_resetErrorState_success() = - runTest { - val errorStateObserver: Observer?> = mock() - viewModel.errorState.observeForever(errorStateObserver) - - viewModel.resetErrorState() - verify(errorStateObserver, atLeastOnce()).onChanged(null) - - viewModel.errorState.removeObserver(errorStateObserver) - } - - @Test - fun idCardViewModel_resetDialogErrorState_success() = - runTest { - val dialogErrorObserver: Observer = mock() - viewModel.dialogError.observeForever(dialogErrorObserver) - - viewModel.resetDialogErrorState() - verify(dialogErrorObserver, atLeastOnce()).onChanged(null) - - viewModel.dialogError.removeObserver(dialogErrorObserver) - } - - @Test - fun idCardViewModel_resetSignedContainer_success() = - runTest { - val signedContainerObserver: Observer = mock() - viewModel.signedContainer.observeForever(signedContainerObserver) - - viewModel.resetSignedContainer() - verify(signedContainerObserver, atLeastOnce()).onChanged(null) - - viewModel.signedContainer.removeObserver(signedContainerObserver) - } - - @Test - fun idCardViewModel_resetCryptoContainer_success() = - runTest { - val cryptoContainerObserver: Observer = mock() - viewModel.cryptoContainer.observeForever(cryptoContainerObserver) - - viewModel.resetCryptoContainer() - verify(cryptoContainerObserver, atLeastOnce()).onChanged(null) - - viewModel.cryptoContainer.removeObserver(cryptoContainerObserver) - } - - @Test - fun idCardViewModel_resetPersonalUserData_success() = - runTest { - val userDataObserver: Observer = mock() - viewModel.userData.observeForever(userDataObserver) - - viewModel.resetPersonalUserData() - verify(userDataObserver, atLeastOnce()).onChanged(null) - - viewModel.userData.removeObserver(userDataObserver) - } - - @Test - fun idCardViewModel_resetPINErrorState_success() = - runTest { - val pinErrorStateObserver: Observer?> = mock() - viewModel.pinErrorState.observeForever(pinErrorStateObserver) - - viewModel.resetPINErrorState() - verify(pinErrorStateObserver, atLeastOnce()).onChanged(null) - - viewModel.pinErrorState.removeObserver(pinErrorStateObserver) - } - - @Test - fun idCardViewModel_resetShouldHandleError_success() = - runTest { - val emittedValues = mutableListOf() - val job = - launch { - viewModel.shouldHandleError - .take(1) - .toList(emittedValues) - } - - yield() - viewModel.resetShouldHandleError() - - job.join() - - assertEquals(listOf(false), emittedValues) - } - - @Test - fun idCardViewModel_setShouldHandleError_success() = - runTest { - val emittedValues = mutableListOf() - val job = - launch { - viewModel.shouldHandleError - .take(2) - .toList(emittedValues) - } - - yield() - viewModel.setShouldHandleError(true) - - job.join() - - assertEquals(listOf(false, true), emittedValues) - } -} diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModelTest.kt index 18b666ed6..2cb073703 100644 --- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModelTest.kt +++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModelTest.kt @@ -32,33 +32,26 @@ import ee.ria.DigiDoc.MainActivity import ee.ria.DigiDoc.R import ee.ria.DigiDoc.common.Constant import ee.ria.DigiDoc.domain.model.IdCardData -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting import ee.ria.DigiDoc.domain.model.pin.PinChangeVariant import ee.ria.DigiDoc.domain.preferences.DataStore import ee.ria.DigiDoc.domain.service.IdCardService import ee.ria.DigiDoc.idcard.CodeType import ee.ria.DigiDoc.idcard.CodeVerificationException import ee.ria.DigiDoc.idcard.Token -import ee.ria.DigiDoc.smartcardreader.SmartCardReader import ee.ria.DigiDoc.smartcardreader.SmartCardReaderException -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus import ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader import ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReaderManager import ee.ria.DigiDoc.ui.component.myeid.pinandcertificate.PinChangeContent import ee.ria.DigiDoc.utilsLib.date.DateUtil -import io.reactivex.rxjava3.core.Observable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain -import org.bouncycastle.util.encoders.Hex import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before @@ -91,9 +84,6 @@ class SharedMyEidViewModelTest { @Mock lateinit var errorStateObserver: Observer?> - @Mock - lateinit var idCardStatusObserver: Observer - @Mock lateinit var idCardDataObserver: Observer @@ -103,15 +93,6 @@ class SharedMyEidViewModelTest { @Mock lateinit var isPinBlockedObserver: Observer - @Mock - lateinit var identificationMethodObserver: Observer - - @Mock - lateinit var mockSmartCardReaderManager: SmartCardReaderManager - - @Mock - lateinit var mockSmartCardReader: SmartCardReader - @Mock lateinit var mockNfcSmartCardReader: NfcSmartCardReader @@ -137,11 +118,8 @@ class SharedMyEidViewModelTest { dataStore = DataStore(context) nfcSmartCardReaderManager = NfcSmartCardReaderManager() - `when`(mockSmartCardReaderManager.status()).thenReturn(Observable.just(SmartCardReaderStatus.IDLE)) - viewModel = SharedMyEidViewModel( - mockSmartCardReaderManager, mockIdCardService, nfcSmartCardReaderManager, dataStore, @@ -150,8 +128,6 @@ class SharedMyEidViewModelTest { viewModel.idCardData.observeForever(idCardDataObserver) viewModel.pinChangingState.observeForever(pinChangingStateObserver) viewModel.isPinBlocked.observeForever(isPinBlockedObserver) - viewModel.identificationMethod.observeForever(identificationMethodObserver) - viewModel.idCardStatus.observeForever(idCardStatusObserver) viewModel.errorState.observeForever(errorStateObserver) } @@ -160,14 +136,6 @@ class SharedMyEidViewModelTest { Dispatchers.resetMain() } - @Test - fun sharedMyEidViewModel_setIdentificationMethod_success() { - val identificationMethod = MyEidIdentificationMethodSetting.ID_CARD - viewModel.setIdentificationMethod(identificationMethod) - - assertEquals(identificationMethod, viewModel.identificationMethod.value) - } - @Test fun sharedMyEidViewModel_setIdCardData_success() { val idCardData = createMockIdCardData() @@ -609,48 +577,6 @@ class SharedMyEidViewModelTest { assertEquals("", result) } - @Test - fun sharedMyEidViewModel_getToken_success() { - viewModel.setIdentificationMethod(MyEidIdentificationMethodSetting.ID_CARD) - - `when`(mockSmartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - `when`(mockSmartCardReader.atr()).thenReturn(Hex.decode("3bdb960080b1fe451f830012233f536549440f9000f1")) - - var resultToken: Token? = null - var resultError: Exception? = null - - activityRule.scenario.onActivity { activity -> - viewModel.getToken(activity) { token, error -> - resultToken = token - resultError = error - } - } - - assertNotNull(resultToken) - assertNull(resultError) - } - - @Test - fun sharedMyEidViewModel_getToken_returnsSmartCardReaderException() { - viewModel.setIdentificationMethod(MyEidIdentificationMethodSetting.ID_CARD) - - `when`(mockSmartCardReaderManager.connectedReader()).thenReturn(mockSmartCardReader) - `when`(mockSmartCardReader.atr()).thenReturn(byteArrayOf(49, 50, 51, 52)) - - var resultToken: Token? = null - var resultError: Exception? = null - - activityRule.scenario.onActivity { activity -> - viewModel.getToken(activity) { token, error -> - resultToken = token - resultError = error - } - } - - assertNull(resultToken) - assertNotNull(resultError) - } - @Test fun sharedMyEidViewModel_resetScreenContent_success() = runTest { @@ -686,13 +612,6 @@ class SharedMyEidViewModelTest { assertFalse(viewModel.isPinBlocked.value == true) } - @Test - fun sharedMyEidViewModel_resetIdentificationMethod_success() = - runTest { - viewModel.resetIdentificationMethod() - assertNull(viewModel.identificationMethod.value) - } - @Test fun sharedMyEidViewModel_resetValues_success() = runTest { @@ -700,11 +619,9 @@ class SharedMyEidViewModelTest { viewModel.resetIsPinBlocked() viewModel.resetScreenContent() viewModel.resetPinChangingState() - viewModel.resetIdentificationMethod() assertNull(viewModel.errorState.value) assertFalse(viewModel.isPinBlocked.value == true) assertNull(viewModel.pinScreenContent.value) assertFalse(viewModel.pinChangingState.value == true) - assertNull(viewModel.identificationMethod.value) } } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/RIADigiDocAppNavigation.kt b/app/src/main/kotlin/ee/ria/DigiDoc/RIADigiDocAppNavigation.kt index a98320d0a..81f356ac6 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/RIADigiDocAppNavigation.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/RIADigiDocAppNavigation.kt @@ -37,7 +37,6 @@ import ee.ria.DigiDoc.fragment.AccessibilityFragment import ee.ria.DigiDoc.fragment.AdvancedSettingsFragment import ee.ria.DigiDoc.fragment.CryptoFileOpeningFragment import ee.ria.DigiDoc.fragment.DecryptFragment -import ee.ria.DigiDoc.fragment.DecryptMethodChooserFragment import ee.ria.DigiDoc.fragment.DiagnosticsFragment import ee.ria.DigiDoc.fragment.EncryptFragment import ee.ria.DigiDoc.fragment.EncryptRecipientFragment @@ -49,7 +48,6 @@ import ee.ria.DigiDoc.fragment.InitFragment import ee.ria.DigiDoc.fragment.LanguageChooserFragment import ee.ria.DigiDoc.fragment.MyEidFragment import ee.ria.DigiDoc.fragment.MyEidIdentificationFragment -import ee.ria.DigiDoc.fragment.MyEidIdentificationMethodChooserFragment import ee.ria.DigiDoc.fragment.MyEidPinFragment import ee.ria.DigiDoc.fragment.ProxyServicesSettingsFragment import ee.ria.DigiDoc.fragment.RecentDocumentsFragment @@ -190,14 +188,6 @@ fun RIADigiDocAppScreen(externalFileUris: List) { sharedContainerViewModel = sharedContainerViewModel, ) } - composable(route = Route.DecryptMethodScreen.route) { - DecryptMethodChooserFragment( - modifier = Modifier.safeDrawingPadding(), - navController = navController, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedMenuViewModel = sharedMenuViewModel, - ) - } composable(route = Route.Accessibility.route) { AccessibilityFragment( modifier = Modifier.safeDrawingPadding(), @@ -343,14 +333,6 @@ fun RIADigiDocAppScreen(externalFileUris: List) { sharedMyEidViewModel = sharedMyEidViewModel, ) } - composable(route = Route.MyEidIdentificationMethodScreen.route) { - MyEidIdentificationMethodChooserFragment( - modifier = Modifier.safeDrawingPadding(), - navController = navController, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedMenuViewModel = sharedMenuViewModel, - ) - } composable(route = Route.ContainerNotificationsScreen.route) { ContainerNotificationsFragment( modifier = Modifier.safeDrawingPadding(), diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/crypto/DecryptMethodSetting.kt b/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/crypto/DecryptMethodSetting.kt deleted file mode 100644 index 7fa684c65..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/crypto/DecryptMethodSetting.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName") - -package ee.ria.DigiDoc.domain.model.crypto - -import androidx.annotation.StringRes -import ee.ria.DigiDoc.R - -enum class DecryptMethodSetting( - val methodName: String, - @param:StringRes val label: Int, -) { - NFC("NFC", R.string.signature_update_signature_add_method_nfc), - ID_CARD("IDCard", R.string.signature_update_signature_add_method_id_card), - ; - - companion object { - fun fromMethod(mode: String): DecryptMethodSetting = entries.find { it.methodName == mode } ?: NFC - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/methods/SigningMethod.kt b/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/methods/SigningMethod.kt index 0714fcbf7..715cc35da 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/methods/SigningMethod.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/methods/SigningMethod.kt @@ -29,7 +29,6 @@ enum class SigningMethod( @param:StringRes val label: Int, ) { NFC("NFC", R.string.signature_update_signature_add_method_nfc), - ID_CARD("IDCard", R.string.signature_update_signature_add_method_id_card), MOBILE_ID("MobileId", R.string.signature_update_signature_add_method_mobile_id), SMART_ID("SmartId", R.string.signature_update_signature_add_method_smart_id), } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/myeid/MyEidIdentificationMethodSetting.kt b/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/myeid/MyEidIdentificationMethodSetting.kt deleted file mode 100644 index 29bfc23c3..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/domain/model/myeid/MyEidIdentificationMethodSetting.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName") - -package ee.ria.DigiDoc.domain.model.myeid - -import androidx.annotation.StringRes -import ee.ria.DigiDoc.R - -enum class MyEidIdentificationMethodSetting( - val methodName: String, - @param:StringRes val label: Int, -) { - NFC("NFC", R.string.signature_update_signature_add_method_nfc), - ID_CARD("IDCard", R.string.signature_update_signature_add_method_id_card), - ; - - companion object { - fun fromMethod(mode: String): MyEidIdentificationMethodSetting = entries.find { it.methodName == mode } ?: NFC - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/domain/preferences/DataStore.kt b/app/src/main/kotlin/ee/ria/DigiDoc/domain/preferences/DataStore.kt index ca29ff3a4..f9b142dc7 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/domain/preferences/DataStore.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/domain/preferences/DataStore.kt @@ -27,16 +27,12 @@ import android.content.res.Resources import androidx.core.content.edit import androidx.preference.PreferenceManager import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.common.Constant.Crypto.DECRYPT_METHOD_SETTING import ee.ria.DigiDoc.common.Constant.Defaults.DEFAULT_UUID_VALUE import ee.ria.DigiDoc.common.Constant.IS_CRASH_SENDING_ALWAYS_ENABLED import ee.ria.DigiDoc.common.Constant.KEY_LOCALE -import ee.ria.DigiDoc.common.Constant.MyEID.IDENTIFICATION_METHOD_SETTING import ee.ria.DigiDoc.common.Constant.Theme.THEME_SETTING import ee.ria.DigiDoc.common.preferences.EncryptedPreferences -import ee.ria.DigiDoc.domain.model.crypto.DecryptMethodSetting import ee.ria.DigiDoc.domain.model.methods.SigningMethod -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting import ee.ria.DigiDoc.domain.model.settings.CDOCSetting import ee.ria.DigiDoc.domain.model.settings.TSASetting import ee.ria.DigiDoc.domain.model.settings.UUIDSetting @@ -74,7 +70,6 @@ class DataStore arrayOf( SigningMethod.MOBILE_ID.methodName, SigningMethod.SMART_ID.methodName, - SigningMethod.ID_CARD.methodName, SigningMethod.NFC.methodName, ) if (!listOf(*signatureAddMethods).contains(signatureAddMethod)) { @@ -752,26 +747,6 @@ class DataStore preferences.edit { putString(THEME_SETTING, themeSetting.mode) } } - fun getDecryptMethodSetting(): DecryptMethodSetting = - DecryptMethodSetting.fromMethod( - preferences.getString(DECRYPT_METHOD_SETTING, DecryptMethodSetting.NFC.methodName) - ?: DecryptMethodSetting.NFC.methodName, - ) - - fun setDecryptMethodSetting(decryptMethodSetting: DecryptMethodSetting) { - preferences.edit { putString(DECRYPT_METHOD_SETTING, decryptMethodSetting.methodName) } - } - - fun getIdentificationMethodSetting(): MyEidIdentificationMethodSetting = - MyEidIdentificationMethodSetting.fromMethod( - preferences.getString(IDENTIFICATION_METHOD_SETTING, MyEidIdentificationMethodSetting.NFC.methodName) - ?: MyEidIdentificationMethodSetting.NFC.methodName, - ) - - fun setIdentificationMethodSetting(myEidIdentificationMethodSetting: MyEidIdentificationMethodSetting) { - preferences.edit { putString(IDENTIFICATION_METHOD_SETTING, myEidIdentificationMethodSetting.methodName) } - } - private fun getEncryptedPreferences(context: Context): SharedPreferences? = try { EncryptedPreferences.getEncryptedPreferences(context) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/DecryptMethodChooserFragment.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/DecryptMethodChooserFragment.kt deleted file mode 100644 index 0fd4de9b0..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/DecryptMethodChooserFragment.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.fragment - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import ee.ria.DigiDoc.fragment.screen.DecryptMethodChooserScreen -import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun DecryptMethodChooserFragment( - modifier: Modifier = Modifier, - navController: NavHostController, - sharedSettingsViewModel: SharedSettingsViewModel, - sharedMenuViewModel: SharedMenuViewModel, -) { - Surface( - modifier = - modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) - .semantics { - testTagsAsResourceId = true - }.testTag("decryptMethodChooserFragment"), - color = MaterialTheme.colorScheme.background, - ) { - DecryptMethodChooserScreen( - modifier = modifier, - navController = navController, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedMenuViewModel = sharedMenuViewModel, - ) - } -} - -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun DecryptMethodFragmentPreview() { - RIADigiDocTheme { - DecryptMethodChooserFragment( - navController = rememberNavController(), - sharedSettingsViewModel = hiltViewModel(), - sharedMenuViewModel = hiltViewModel(), - ) - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/MyEidIdentificationMethodChooserFragment.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/MyEidIdentificationMethodChooserFragment.kt deleted file mode 100644 index efdda93f4..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/MyEidIdentificationMethodChooserFragment.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.fragment - -import android.content.res.Configuration -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import ee.ria.DigiDoc.fragment.screen.MyEidIdentificationMethodChooserScreen -import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun MyEidIdentificationMethodChooserFragment( - modifier: Modifier = Modifier, - navController: NavHostController, - sharedSettingsViewModel: SharedSettingsViewModel, - sharedMenuViewModel: SharedMenuViewModel, -) { - Surface( - modifier = - modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) - .semantics { - testTagsAsResourceId = true - }.testTag("identificationMethodChooserFragment"), - color = MaterialTheme.colorScheme.background, - ) { - MyEidIdentificationMethodChooserScreen( - modifier = modifier, - navController = navController, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedMenuViewModel = sharedMenuViewModel, - ) - } -} - -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun MyEidIdentificationMethodFragmentPreview() { - RIADigiDocTheme { - MyEidIdentificationMethodChooserFragment( - navController = rememberNavController(), - sharedSettingsViewModel = hiltViewModel(), - sharedMenuViewModel = hiltViewModel(), - ) - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptMethodChooserScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptMethodChooserScreen.kt deleted file mode 100644 index 718110143..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptMethodChooserScreen.kt +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.fragment.screen - -import android.content.res.Configuration -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.heading -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.domain.model.crypto.DecryptMethodSetting -import ee.ria.DigiDoc.ui.component.crypto.DecryptMethodChoiceButtonItem -import ee.ria.DigiDoc.ui.component.shared.TopBar -import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager -import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun DecryptMethodChooserScreen( - modifier: Modifier = Modifier, - navController: NavHostController, - sharedMenuViewModel: SharedMenuViewModel, - sharedSettingsViewModel: SharedSettingsViewModel, -) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - - val currentDecryptMethod = sharedSettingsViewModel.dataStore.getDecryptMethodSetting() - var selectedOption by remember { - mutableStateOf( - DecryptMethodSetting.entries.find { it.methodName == currentDecryptMethod.methodName }, - ) - } - - val identificationMethodText = stringResource(id = R.string.crypto_decrypt_method) - val identificationMethodSelectedText = stringResource(id = R.string.crypto_decrypt_method_selected) - - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, - topBar = { - TopBar( - modifier = modifier, - sharedMenuViewModel = sharedMenuViewModel, - title = null, - onLeftButtonClick = { - navController.navigateUp() - }, - ) - }, - ) { paddingValues -> - Column( - modifier = - modifier - .fillMaxSize() - .padding(paddingValues) - .padding(SPadding) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(MSPadding), - ) { - Text( - modifier = - modifier - .padding(XSPadding) - .padding(bottom = SPadding) - .semantics { - heading() - }, - text = stringResource(R.string.crypto_decrypt_method_title), - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.headlineMedium, - ) - - DecryptMethodChoiceButtonItem().radioItems().forEachIndexed { _, option -> - Row( - modifier = - modifier - .fillMaxWidth() - .padding(start = XSPadding) - .clickable { selectedOption = option.setting }, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(id = option.label), - modifier = - modifier - .weight(1f) - .notAccessible(), - ) - RadioButton( - modifier = - modifier - .semantics { - testTagsAsResourceId = true - this.contentDescription = - if (option.setting == selectedOption) { - "${option.contentDescription} $identificationMethodSelectedText" - } else { - "$identificationMethodText ${option.contentDescription}" - } - }.testTag(option.testTag), - selected = selectedOption == option.setting, - onClick = { selectedOption = option.setting }, - ) - } - HorizontalDivider() - } - - Button( - onClick = { - sharedSettingsViewModel.dataStore.setDecryptMethodSetting( - selectedOption ?: DecryptMethodSetting.NFC, - ) - navController.navigateUp() - }, - modifier = - modifier - .fillMaxWidth() - .padding(vertical = MSPadding), - colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary), - ) { - Text( - text = stringResource(R.string.signature_update_method_save_button), - color = MaterialTheme.colorScheme.surface, - ) - } - } - } -} - -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun DecryptMethodChooserScreenPreview() { - RIADigiDocTheme { - DecryptMethodChooserScreen( - navController = rememberNavController(), - sharedMenuViewModel = hiltViewModel(), - sharedSettingsViewModel = hiltViewModel(), - ) - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt index 2f12b3365..a46a5ae65 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt @@ -24,24 +24,18 @@ package ee.ria.DigiDoc.fragment.screen import android.app.Activity import android.content.res.Configuration import androidx.activity.compose.LocalActivity -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost @@ -51,7 +45,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -59,11 +52,8 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics @@ -74,19 +64,15 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.domain.model.IdentityAction -import ee.ria.DigiDoc.domain.model.crypto.DecryptMethodSetting import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.TopBar -import ee.ria.DigiDoc.ui.component.signing.IdCardView import ee.ria.DigiDoc.ui.component.signing.NFCView import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.extensions.notAccessible import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -105,29 +91,20 @@ fun DecryptScreen( val context = LocalActivity.current as Activity val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } var rememberMe by rememberSaveable { mutableStateOf(true) } - var isIdCardProcessStarted by rememberSaveable { mutableStateOf(false) } var isDecrypting by rememberSaveable { mutableStateOf(false) } - val chosenMethod by remember { - mutableStateOf( - DecryptMethodSetting.entries.find { - it.methodName == sharedSettingsViewModel.dataStore.getDecryptMethodSetting().methodName - } ?: DecryptMethodSetting.NFC, - ) - } - val chosenMethodName by remember { mutableIntStateOf(chosenMethod.label) } var isValidToDecrypt by remember { mutableStateOf(false) } var decryptAction by remember { mutableStateOf<() -> Unit>({}) } var cancelDecryptAction by remember { mutableStateOf<() -> Unit>({}) } + var nfcSupported by remember { mutableStateOf(false) } val snackBarHostState = remember { SnackbarHostState() } val snackBarScope = rememberCoroutineScope() val messages by SnackBarManager.messages.collectAsState(emptyList()) - val chosenMethodNameText = stringResource(chosenMethodName) val identificationMethodText = stringResource(R.string.crypto_decrypt_method) + val chosenMethodNameText = stringResource(R.string.signature_update_signature_add_method_nfc) val rememberMeText = stringResource(R.string.signature_update_remember_me) - var nfcSupported by remember { mutableStateOf(false) } LaunchedEffect(messages) { messages.forEach { message -> @@ -195,13 +172,14 @@ fun DecryptScreen( style = MaterialTheme.typography.headlineMedium, ) - if (!isDecrypting && !isIdCardProcessStarted) { + if (!isDecrypting) { Column( modifier = modifier .fillMaxWidth() .padding(vertical = XSPadding), horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(XSPadding), ) { Text( text = identificationMethodText, @@ -215,146 +193,69 @@ fun DecryptScreen( style = MaterialTheme.typography.labelLarge, ) - Row( + Text( modifier = modifier - .fillMaxWidth() - .background(Color.Transparent) - .clickable { - navController.navigate( - Route.DecryptMethodScreen.route, - ) + .semantics { + contentDescription = "$identificationMethodText $chosenMethodNameText" }, - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - modifier = - modifier - .semantics { - contentDescription = "$identificationMethodText $chosenMethodNameText" - }, - text = chosenMethodNameText, - color = MaterialTheme.colorScheme.onSurface, - textAlign = TextAlign.Start, - ) - - Spacer(modifier = modifier.weight(1f)) - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ic_m3_arrow_right_48dp_wght400), - contentDescription = null, - modifier = - modifier - .padding(MSPadding) - .size(iconSizeXXS) - .wrapContentHeight(align = Alignment.CenterVertically) - .notAccessible(), - ) - } + text = chosenMethodNameText, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Start, + ) } } - when (chosenMethod) { - DecryptMethodSetting.ID_CARD -> - IdCardView( - modifier = modifier, - activity = context, - onError = { - isDecrypting = false - isIdCardProcessStarted = false - cancelDecryptAction() - navController.navigateUp() - }, - onSuccess = { - isDecrypting = false - navController.navigateUp() - }, - isStarted = { started -> - if (started) { - isIdCardProcessStarted = true - } - }, - isSigning = false, - isDecrypting = isDecrypting, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - isValidToDecrypt = { isValid -> - isValidToDecrypt = isValid - }, - decryptAction = { action -> - decryptAction = { - isDecrypting = true - action() - } - }, - cancelAction = { action -> - isDecrypting = false - cancelDecryptAction = action - }, - isAddingRoleAndAddress = false, - isAuthenticated = { _, _ -> {} }, - identityAction = IdentityAction.DECRYPT, - ) + NFCView( + modifier = modifier, + activity = context, + onError = { + isDecrypting = false + cancelDecryptAction() + }, + onSuccess = { + isDecrypting = false + navController.navigateUp() + }, + isDecrypting = isDecrypting, + rememberMe = rememberMe, + sharedSettingsViewModel = sharedSettingsViewModel, + sharedContainerViewModel = sharedContainerViewModel, + isSupported = { supported -> + nfcSupported = supported + }, + isValidToDecrypt = { isValid -> + isValidToDecrypt = isValid + }, + decryptAction = { action -> + decryptAction = action + }, + cancelDecryptAction = { action -> + cancelDecryptAction = action + }, + identityAction = IdentityAction.DECRYPT, + ) - DecryptMethodSetting.NFC -> - NFCView( - modifier = modifier, - activity = context, - onError = { - isDecrypting = false - cancelDecryptAction() - }, - onSuccess = { - isDecrypting = false - navController.navigateUp() - }, - isSigning = false, - isDecrypting = isDecrypting, - rememberMe = rememberMe, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - isSupported = { supported -> - nfcSupported = supported - }, - isValidToDecrypt = { isValid -> - isValidToDecrypt = isValid - }, - decryptAction = { action -> - decryptAction = action - }, - cancelDecryptAction = { action -> - cancelDecryptAction = action - }, - isAddingRoleAndAddress = false, - identityAction = IdentityAction.DECRYPT, - isAuthenticating = false, - isAuthenticated = { _, _ -> {} }, - isValidToAuthenticate = {}, - ) - } + if (!isDecrypting && nfcSupported) { + SettingsSwitchItem( + modifier = modifier, + checked = rememberMe, + onCheckedChange = { + rememberMe = it + }, + title = rememberMeText, + contentDescription = rememberMeText, + testTag = "myEidRememberMeSwitch", + ) - if (!isDecrypting && (chosenMethod != DecryptMethodSetting.NFC || nfcSupported)) { - if (chosenMethod != DecryptMethodSetting.ID_CARD) { - SettingsSwitchItem( - modifier = modifier, - checked = rememberMe, - onCheckedChange = { - rememberMe = it - }, - title = rememberMeText, - contentDescription = rememberMeText, - testTag = "myEidRememberMeSwitch", + if (rememberMe) { + Text( + text = stringResource(R.string.signature_update_remember_me_message), ) - - if (rememberMe) { - Text( - text = stringResource(R.string.signature_update_remember_me_message), - ) - } - - Spacer(modifier = modifier.height(SPadding)) } + Spacer(modifier = modifier.height(SPadding)) + Button( onClick = { isDecrypting = true diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationMethodChooserScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationMethodChooserScreen.kt deleted file mode 100644 index 6f850f2fa..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationMethodChooserScreen.kt +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.fragment.screen - -import android.content.res.Configuration -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.heading -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.navigation.NavHostController -import androidx.navigation.compose.rememberNavController -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting -import ee.ria.DigiDoc.ui.component.myeid.MyEidIdentificationMethodChoiceButtonItem -import ee.ria.DigiDoc.ui.component.shared.TopBar -import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager -import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun MyEidIdentificationMethodChooserScreen( - modifier: Modifier = Modifier, - navController: NavHostController, - sharedMenuViewModel: SharedMenuViewModel, - sharedSettingsViewModel: SharedSettingsViewModel, -) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - - val currentIdentificationMethod = sharedSettingsViewModel.dataStore.getIdentificationMethodSetting() - var selectedOption by remember { - mutableStateOf( - MyEidIdentificationMethodSetting.entries.find { it.methodName == currentIdentificationMethod.methodName }, - ) - } - - val identificationMethodText = stringResource(id = R.string.myeid_identification_method) - val identificationMethodSelectedText = stringResource(id = R.string.myeid_identification_method_selected) - - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, - topBar = { - TopBar( - modifier = modifier, - sharedMenuViewModel = sharedMenuViewModel, - title = null, - onLeftButtonClick = { - navController.navigateUp() - }, - ) - }, - ) { paddingValues -> - Column( - modifier = - modifier - .fillMaxSize() - .padding(paddingValues) - .padding(SPadding) - .verticalScroll(rememberScrollState()), - verticalArrangement = Arrangement.spacedBy(MSPadding), - ) { - Text( - modifier = - modifier - .padding(XSPadding) - .padding(bottom = SPadding) - .semantics { - heading() - }, - text = stringResource(R.string.myeid_identification_method_title), - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.headlineMedium, - ) - - MyEidIdentificationMethodChoiceButtonItem().radioItems().forEachIndexed { _, option -> - Row( - modifier = - modifier - .fillMaxWidth() - .padding(start = XSPadding) - .clickable { selectedOption = option.setting }, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(id = option.label), - modifier = - modifier - .weight(1f) - .notAccessible(), - ) - RadioButton( - modifier = - modifier - .semantics { - testTagsAsResourceId = true - this.contentDescription = - if (option.setting == selectedOption) { - "${option.contentDescription} $identificationMethodSelectedText" - } else { - "$identificationMethodText ${option.contentDescription}" - } - }.testTag(option.testTag), - selected = selectedOption == option.setting, - onClick = { selectedOption = option.setting }, - ) - } - HorizontalDivider() - } - - Button( - onClick = { - sharedSettingsViewModel.dataStore.setIdentificationMethodSetting( - selectedOption ?: MyEidIdentificationMethodSetting.NFC, - ) - navController.navigateUp() - }, - modifier = - modifier - .fillMaxWidth() - .padding(vertical = MSPadding), - colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.primary), - ) { - Text( - text = stringResource(R.string.signature_update_method_save_button), - color = MaterialTheme.colorScheme.surface, - ) - } - } - } -} - -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun MyEidIdentificationMethodChooserScreenPreview() { - RIADigiDocTheme { - MyEidIdentificationMethodChooserScreen( - navController = rememberNavController(), - sharedMenuViewModel = hiltViewModel(), - sharedSettingsViewModel = hiltViewModel(), - ) - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt index c4f133c16..fdf121202 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt @@ -24,24 +24,18 @@ package ee.ria.DigiDoc.fragment.screen import android.app.Activity import android.content.res.Configuration import androidx.activity.compose.LocalActivity -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost @@ -51,7 +45,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -61,11 +54,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics @@ -77,20 +67,16 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.domain.model.IdentityAction -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.TopBar -import ee.ria.DigiDoc.ui.component.signing.IdCardView import ee.ria.DigiDoc.ui.component.signing.NFCView import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.Route -import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBackEnabled import ee.ria.DigiDoc.utils.extensions.notAccessible import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -112,28 +98,19 @@ fun MyEidIdentificationScreen( val context = LocalActivity.current as Activity val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } var rememberMe by rememberSaveable { mutableStateOf(true) } - var isIdCardProcessStarted by rememberSaveable { mutableStateOf(false) } var isAuthenticating by rememberSaveable { mutableStateOf(false) } - val chosenMethod by remember { - mutableStateOf( - MyEidIdentificationMethodSetting.entries.find { - it.methodName == sharedSettingsViewModel.dataStore.getIdentificationMethodSetting().methodName - } ?: MyEidIdentificationMethodSetting.NFC, - ) - } - val chosenMethodName by remember { mutableIntStateOf(chosenMethod.label) } var isValidToAuthenticate by remember { mutableStateOf(false) } var cancelAction by remember { mutableStateOf<() -> Unit>({}) } + var nfcSupported by remember { mutableStateOf(false) } val snackBarHostState = remember { SnackbarHostState() } val snackBarScope = rememberCoroutineScope() val messages by SnackBarManager.messages.collectAsState(emptyList()) - val chosenMethodNameText = stringResource(chosenMethodName) val identificationMethodText = stringResource(R.string.myeid_identification_method) + val chosenMethodNameText = stringResource(R.string.signature_update_signature_add_method_nfc) val rememberMeText = stringResource(R.string.signature_update_remember_me) - var nfcSupported by remember { mutableStateOf(false) } LaunchedEffect(messages) { messages.forEach { message -> @@ -144,10 +121,6 @@ fun MyEidIdentificationScreen( } } - LaunchedEffect(chosenMethod) { - sharedMyEidViewModel.setIdentificationMethod(chosenMethod) - } - Scaffold( snackbarHost = { SnackbarHost( @@ -211,14 +184,9 @@ fun MyEidIdentificationScreen( modifier .fillMaxWidth() .padding(vertical = XSPadding) - .alpha( - if (!isAuthenticating && !isIdCardProcessStarted) { - 1f - } else { - 0.001f - }, - ), + .alpha(if (!isAuthenticating) 1f else 0.001f), horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.spacedBy(XSPadding), ) { Text( text = identificationMethodText, @@ -232,144 +200,57 @@ fun MyEidIdentificationScreen( style = MaterialTheme.typography.labelLarge, ) - Row( + Text( modifier = modifier - .fillMaxWidth() - .background(Color.Transparent) - .clickable( - enabled = !isAuthenticating && !isIdCardProcessStarted, - ) { - navController.navigate( - Route.MyEidIdentificationMethodScreen.route, - ) - }.then( - if (isAuthenticating || isIdCardProcessStarted && isTalkBackEnabled(context)) { - modifier.notAccessible() - } else { - modifier - }, - ), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - modifier = - modifier - .semantics { - contentDescription = "$identificationMethodText $chosenMethodNameText" - testTagsAsResourceId = true - }.testTag("myEidChosenMethodNameTitle"), - text = chosenMethodNameText, - color = MaterialTheme.colorScheme.onSurface, - textAlign = TextAlign.Start, - ) - - Spacer(modifier = modifier.weight(1f)) - Icon( - imageVector = ImageVector.vectorResource(R.drawable.ic_m3_arrow_right_48dp_wght400), - contentDescription = null, - modifier = - modifier - .padding(MSPadding) - .size(iconSizeXXS) - .wrapContentHeight(align = Alignment.CenterVertically) - .notAccessible(), - ) - } + .semantics { + contentDescription = "$identificationMethodText $chosenMethodNameText" + testTagsAsResourceId = true + }.testTag("myEidChosenMethodNameTitle"), + text = chosenMethodNameText, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Start, + ) } - when (chosenMethod) { - MyEidIdentificationMethodSetting.ID_CARD -> - IdCardView( - modifier = modifier, - activity = context, - onError = { - isAuthenticating = false - isIdCardProcessStarted = false - cancelAction() - }, - onSuccess = { - isAuthenticating = false - navController.navigateUp() - }, - isStarted = { started -> - if (started) { - isIdCardProcessStarted = true - } - }, - isSigning = false, - isAuthenticating = true, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - isValidToSign = { isValid -> - isValidToAuthenticate = isValid - }, - signAction = {}, - cancelAction = { action -> - isAuthenticating = false - cancelAction = action - }, - isAddingRoleAndAddress = false, - isAuthenticated = { authenticated, personalData -> - if (authenticated) { - sharedMyEidViewModel.setIdCardData(personalData) - - navController.navigate( - Route.MyEidScreen.route, - ) - } - }, - identityAction = IdentityAction.AUTH, - ) - - MyEidIdentificationMethodSetting.NFC -> - NFCView( - modifier = modifier, - activity = context, - onError = { - isAuthenticating = false - cancelAction() - }, - onSuccess = { - isAuthenticating = false - navController.navigateUp() - }, - isSigning = false, - isAuthenticating = isAuthenticating, - rememberMe = rememberMe, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - showPinField = false, - isSupported = { supported -> - nfcSupported = supported - }, - isValidToSign = {}, - signAction = {}, - cancelAction = { action -> - cancelAction = action - }, - isAddingRoleAndAddress = false, - isAuthenticated = { authenticated, idCardData -> - if (authenticated) { - sharedMyEidViewModel.setIdCardData(idCardData) + NFCView( + modifier = modifier, + activity = context, + onError = { + isAuthenticating = false + cancelAction() + }, + onSuccess = { + isAuthenticating = false + navController.navigateUp() + }, + isAuthenticating = isAuthenticating, + rememberMe = rememberMe, + sharedSettingsViewModel = sharedSettingsViewModel, + sharedContainerViewModel = sharedContainerViewModel, + showPinField = false, + isSupported = { supported -> + nfcSupported = supported + }, + cancelAction = { action -> + cancelAction = action + }, + isAuthenticated = { authenticated, idCardData -> + if (authenticated) { + sharedMyEidViewModel.setIdCardData(idCardData) - navController.navigate( - Route.MyEidScreen.route, - ) - } - }, - isValidToAuthenticate = { isValid -> - isValidToAuthenticate = isValid - }, - identityAction = IdentityAction.AUTH, - ) - } + navController.navigate( + Route.MyEidScreen.route, + ) + } + }, + isValidToAuthenticate = { isValid -> + isValidToAuthenticate = isValid + }, + identityAction = IdentityAction.AUTH, + ) - if (!isAuthenticating && - chosenMethod != MyEidIdentificationMethodSetting.ID_CARD && - (chosenMethod != MyEidIdentificationMethodSetting.NFC || nfcSupported) - ) { + if (!isAuthenticating && nfcSupported) { SettingsSwitchItem( modifier = modifier, checked = rememberMe, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt index 2173c468a..41eaeb286 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt @@ -84,7 +84,6 @@ import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.notificationPermissionRequester -import ee.ria.DigiDoc.ui.component.signing.IdCardView import ee.ria.DigiDoc.ui.component.signing.MobileIdView import ee.ria.DigiDoc.ui.component.signing.NFCView import ee.ria.DigiDoc.ui.component.signing.SmartIdView @@ -121,7 +120,6 @@ fun SignatureInputScreen( val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val getIsAskRoleAndAddressRequested = sharedSettingsViewModel.dataStore::getSettingsAskRoleAndAddress var rememberMe by rememberSaveable { mutableStateOf(true) } - var isIdCardProcessStarted by rememberSaveable { mutableStateOf(false) } var isSigning by rememberSaveable { mutableStateOf(false) } var isAddingRoleAndAddress by rememberSaveable { mutableStateOf(false) } val chosenMethod by remember { @@ -216,7 +214,7 @@ fun SignatureInputScreen( style = MaterialTheme.typography.headlineMedium, ) - if (!isSigning && !isIdCardProcessStarted && !isAddingRoleAndAddress) { + if (!isSigning && !isAddingRoleAndAddress) { Column( modifier = modifier @@ -341,48 +339,6 @@ fun SignatureInputScreen( }, ) - SigningMethod.ID_CARD -> - IdCardView( - modifier = modifier, - activity = context, - onError = { - isSigning = false - isAddingRoleAndAddress = false - cancelAction() - }, - onSuccess = { - isSigning = false - isAddingRoleAndAddress = false - navController.navigateUp() - }, - isStarted = { started -> - if (started) { - isIdCardProcessStarted = true - } - }, - isSigning = isSigning, - isAddingRoleAndAddress = isAddingRoleAndAddress, - isAuthenticating = false, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - isValidToSign = { isValid -> - isValidToSign = isValid - }, - signAction = { action -> - signAction = { - isSigning = true - action() - } - }, - cancelAction = { action -> - isSigning = false - isAddingRoleAndAddress = false - cancelAction = action - }, - isAuthenticated = { _, _ -> {} }, - identityAction = IdentityAction.SIGN, - ) - SigningMethod.NFC -> NFCView( modifier = modifier, @@ -423,7 +379,7 @@ fun SignatureInputScreen( } if (!isSigning && (chosenMethod != SigningMethod.NFC || nfcSupported)) { - if (chosenMethod != SigningMethod.ID_CARD && !isAddingRoleAndAddress) { + if (!isAddingRoleAndAddress) { SettingsSwitchItem( modifier = modifier, checked = rememberMe, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/DecryptMethodChoiceButtonItem.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/DecryptMethodChoiceButtonItem.kt deleted file mode 100644 index 4b81d52b9..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/DecryptMethodChoiceButtonItem.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.ui.component.crypto - -import androidx.annotation.StringRes -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.domain.model.crypto.DecryptMethodSetting - -data class DecryptMethodChoiceButtonItem( - @param:StringRes val label: Int = 0, - val setting: DecryptMethodSetting = DecryptMethodSetting.NFC, - val contentDescription: String = "", - val testTag: String = "", -) { - @Composable - fun radioItems(): List = - listOf( - DecryptMethodChoiceButtonItem( - label = R.string.signature_update_signature_add_method_nfc, - setting = DecryptMethodSetting.NFC, - contentDescription = - stringResource( - id = R.string.signature_update_signature_add_method_nfc_accessibility, - ).lowercase(), - testTag = "decryptMethodNFCSetting", - ), - DecryptMethodChoiceButtonItem( - label = R.string.signature_update_signature_add_method_id_card, - setting = DecryptMethodSetting.ID_CARD, - contentDescription = - stringResource( - id = R.string.signature_update_signature_add_method_id_card_accessibility, - ).lowercase(), - testTag = "decryptMethodIdCardSetting", - ), - ) -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidIdentificationMethodChoiceButtonItem.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidIdentificationMethodChoiceButtonItem.kt deleted file mode 100644 index 44bfb45fe..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidIdentificationMethodChoiceButtonItem.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.ui.component.myeid - -import androidx.annotation.StringRes -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting - -data class MyEidIdentificationMethodChoiceButtonItem( - @param:StringRes val label: Int = 0, - val setting: MyEidIdentificationMethodSetting = MyEidIdentificationMethodSetting.NFC, - val contentDescription: String = "", - val testTag: String = "", -) { - @Composable - fun radioItems(): List = - listOf( - MyEidIdentificationMethodChoiceButtonItem( - label = R.string.signature_update_signature_add_method_nfc, - setting = MyEidIdentificationMethodSetting.NFC, - contentDescription = - stringResource( - id = R.string.signature_update_signature_add_method_nfc_accessibility, - ).lowercase(), - testTag = "identificationMethodNFCSetting", - ), - MyEidIdentificationMethodChoiceButtonItem( - label = R.string.signature_update_signature_add_method_id_card, - setting = MyEidIdentificationMethodSetting.ID_CARD, - contentDescription = - stringResource( - id = R.string.signature_update_signature_add_method_id_card_accessibility, - ).lowercase(), - testTag = "identificationMethodIdCardSetting", - ), - ) -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt index 5f0510438..a4060d57b 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt @@ -72,7 +72,6 @@ import ee.ria.DigiDoc.domain.model.pin.PinChangeVariant import ee.ria.DigiDoc.idcard.CardType import ee.ria.DigiDoc.idcard.CodeType import ee.ria.DigiDoc.idcard.DateOfBirthUtil -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.myeid.mydata.MyEidMyDataView import ee.ria.DigiDoc.ui.component.myeid.pinandcertificate.MyEidPinAndCertificateView @@ -109,8 +108,6 @@ fun MyEidScreen( val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } - val idCardStatus by sharedMyEidViewModel.idCardStatus.asFlow().collectAsState(SmartCardReaderStatus.IDLE) - val idCardData by sharedMyEidViewModel.idCardData.asFlow().collectAsState(null) val isPin1Blocked = idCardData?.pin1RetryCount == 0 @@ -226,24 +223,6 @@ fun MyEidScreen( } } - LaunchedEffect(idCardStatus) { - idCardStatus?.let { status -> - if (idCardData?.personalData != null) { - when (status) { - SmartCardReaderStatus.CARD_DETECTED -> {} - else -> { - navController.navigate(Route.MyEidIdentificationScreen.route) { - popUpTo(Route.Home.route) { - inclusive = false - } - launchSingleTop = true - } - } - } - } - } - } - Scaffold( snackbarHost = { SnackbarHost( diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt index ba56162a0..fc9b84ace 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt @@ -81,11 +81,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.common.Constant -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting import ee.ria.DigiDoc.idcard.CodeType import ee.ria.DigiDoc.idcard.PaceTunnelException import ee.ria.DigiDoc.smartcardreader.ApduResponseException -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.PrimaryOutlinedButton import ee.ria.DigiDoc.ui.component.shared.SecurePinTextField @@ -96,7 +94,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeM import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS -import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBackEnabled import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent @@ -133,12 +130,8 @@ fun MyEidPinScreen( val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } - val idCardStatus by sharedMyEidViewModel.idCardStatus.asFlow().collectAsState(SmartCardReaderStatus.IDLE) - val idCardData by sharedMyEidViewModel.idCardData.asFlow().collectAsState(null) - val identificationMethod by sharedMyEidViewModel.identificationMethod.asFlow().collectAsState(null) - val content by sharedMyEidViewModel.pinScreenContent.collectAsState() val currentPinState = remember { mutableStateOf(byteArrayOf()) } @@ -370,24 +363,6 @@ fun MyEidPinScreen( } } - LaunchedEffect(idCardStatus) { - idCardStatus?.let { status -> - if (idCardData?.personalData != null) { - when (status) { - SmartCardReaderStatus.CARD_DETECTED -> {} - else -> { - navController.navigate(Route.MyEidIdentificationScreen.route) { - popUpTo(Route.Home.route) { - inclusive = false - } - launchSingleTop = true - } - } - } - } - } - } - BackHandler { if (showNewRepeatPinField.value) { newPinRepeatedState.value = byteArrayOf() @@ -472,9 +447,7 @@ fun MyEidPinScreen( contentColor = MaterialTheme.colorScheme.surface, enabled = isNewRepeatedPinValid, ) { - if (identificationMethod == MyEidIdentificationMethodSetting.NFC) { - showNFCScreen.value = true - } + showNFCScreen.value = true scope.launch(IO) { if (activity == null) { diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/IdCardView.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/IdCardView.kt deleted file mode 100644 index 8282cbf71..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/IdCardView.kt +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName", "FunctionName") - -package ee.ria.DigiDoc.ui.component.signing - -import android.app.Activity -import android.content.res.Configuration -import androidx.activity.compose.BackHandler -import androidx.activity.compose.LocalActivity -import androidx.compose.foundation.background -import androidx.compose.foundation.focusable -import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.BasicAlertDialog -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.res.vectorResource -import androidx.compose.ui.semantics.LiveRegionMode -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.liveRegion -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId -import androidx.compose.ui.semantics.traversalIndex -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.zIndex -import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel -import androidx.lifecycle.asFlow -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.common.Constant.NFCConstants.PIN1_MIN_LENGTH -import ee.ria.DigiDoc.common.Constant.NFCConstants.PIN2_MIN_LENGTH -import ee.ria.DigiDoc.common.Constant.NFCConstants.PIN_MAX_LENGTH -import ee.ria.DigiDoc.domain.model.IdCardData -import ee.ria.DigiDoc.domain.model.IdentityAction -import ee.ria.DigiDoc.idcard.CodeType -import ee.ria.DigiDoc.libdigidoclib.domain.model.RoleData -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus -import ee.ria.DigiDoc.ui.component.shared.CancelAndOkButtonRow -import ee.ria.DigiDoc.ui.component.shared.HrefMessageDialog -import ee.ria.DigiDoc.ui.component.shared.InvisibleElement -import ee.ria.DigiDoc.ui.component.shared.RoleDataView -import ee.ria.DigiDoc.ui.component.shared.SecurePinTextField -import ee.ria.DigiDoc.ui.theme.Dimensions.LPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXL -import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS -import ee.ria.DigiDoc.ui.theme.Dimensions.loadingBarSize -import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.ui.theme.buttonRoundCornerShape -import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.formatNumbers -import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBackEnabled -import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.pin.PinCodeUtil.shouldShowPINCodeError -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage -import ee.ria.DigiDoc.utilsLib.container.NameUtil.formatName -import ee.ria.DigiDoc.viewmodel.IdCardViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel -import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) -@Composable -fun IdCardView( - activity: Activity, - modifier: Modifier = Modifier, - identityAction: IdentityAction, - isSigning: Boolean = false, - isDecrypting: Boolean = false, - isAuthenticating: Boolean = false, - isStarted: (Boolean) -> Unit = {}, - onError: () -> Unit = {}, - onSuccess: () -> Unit = {}, - isAddingRoleAndAddress: Boolean = false, - sharedContainerViewModel: SharedContainerViewModel, - sharedSettingsViewModel: SharedSettingsViewModel, - idCardViewModel: IdCardViewModel = hiltViewModel(), - isValidToSign: (Boolean) -> Unit = {}, - isAuthenticated: (Boolean, IdCardData) -> Unit, - isValidToDecrypt: (Boolean) -> Unit = {}, - signAction: (() -> Unit) -> Unit = {}, - decryptAction: (() -> Unit) -> Unit = {}, - cancelAction: (() -> Unit) -> Unit = {}, - cancelDecryptAction: (() -> Unit) -> Unit = {}, -) { - val context = LocalContext.current - val scope = rememberCoroutineScope() - - val loading by remember { mutableStateOf(true) } - - val idCardStatus by idCardViewModel.idCardStatus.asFlow().collectAsState(SmartCardReaderStatus.IDLE) - val idCardData by idCardViewModel.userData.asFlow().collectAsState(null) - val dialogError by idCardViewModel.dialogError.asFlow().collectAsState(null) - - val idCardStatusInitialMessage = stringResource(id = R.string.id_card_status_initial_message) - val idCardStatusMessage = remember { mutableStateOf(idCardStatusInitialMessage) } - val idCardStatusReaderDetectedMessage = stringResource(id = R.string.id_card_status_reader_detected_message) - val idCardStatusCardDetectedMessage = stringResource(id = R.string.id_card_status_card_detected_message) - val idCardStatusSigningMessage = - if (identityAction == IdentityAction.SIGN) { - stringResource(id = R.string.id_card_progress_message_signing) - } else if (identityAction == IdentityAction.DECRYPT) { - stringResource(id = R.string.id_card_progress_message_decrypt) - } else { - "" - } - val idCardStatusReadyToSignMessage = - if (identityAction == IdentityAction.SIGN) { - stringResource(R.string.id_card_sign_message) - } else if (identityAction == IdentityAction.DECRYPT) { - stringResource(R.string.id_card_decrypt_message) - } else { - "" - } - - val idCardStatusReadyToSign = idCardData?.personalData != null && !isSigning && !isAuthenticating && !isDecrypting - - val shouldHandleError by idCardViewModel.shouldHandleError.collectAsState() - val showErrorDialog = rememberSaveable { mutableStateOf(false) } - var isDataLoadingStarted by rememberSaveable { mutableStateOf(false) } - var showLoadingIndicator by rememberSaveable { mutableStateOf(false) } - - val signedContainer by sharedContainerViewModel.signedContainer.asFlow().collectAsState(null) - val cryptoContainer by sharedContainerViewModel.cryptoContainer.asFlow().collectAsState(null) - - val codeType = - if (identityAction == IdentityAction.SIGN) { - CodeType.PIN2 - } else { - CodeType.PIN1 - } - - val pinTypeMessage = - if (codeType == CodeType.PIN2) { - stringResource(id = R.string.signature_id_card_pin2) - } else { - stringResource(id = R.string.signature_id_card_pin1) - } - - val pinMinLength = - if (identityAction == IdentityAction.SIGN) { - PIN2_MIN_LENGTH - } else { - PIN1_MIN_LENGTH - } - - val pinText = stringResource(R.string.id_card_identity_pin, pinTypeMessage) - val pinCode = remember { mutableStateOf(byteArrayOf()) } - - var roleDataRequest: RoleData? by remember { mutableStateOf(null) } - val getSettingsAskRoleAndAddress = sharedSettingsViewModel.dataStore::getSettingsAskRoleAndAddress - var errorText by remember { mutableStateOf("") } - var pinErrorText by remember { mutableStateOf("") } - val pinCodeTextEdited = rememberSaveable { mutableStateOf(false) } - val pinCodeLengthErrorText = - if (pinCodeTextEdited.value && pinCode.value.isNotEmpty()) { - if (shouldShowPINCodeError( - pinCode.value, - codeType, - ) - ) { - String.format( - stringResource(id = R.string.id_card_sign_pin_invalid_length), - pinTypeMessage, - pinMinLength, - PIN_MAX_LENGTH.toString(), - ) - } else { - "" - } - } else { - "" - } - val focusManager = LocalFocusManager.current - val statusMessageFocusRequester = remember { FocusRequester() } - val readyToSignFocusRequester = remember { FocusRequester() } - val pinCodeFocusRequester = remember { FocusRequester() } - - var isValid by rememberSaveable { mutableStateOf(false) } - - val clearButtonText = stringResource(R.string.clear_text) - val buttonName = stringResource(id = R.string.button_name) - - BackHandler { - if (isSigning || isDecrypting || isAuthenticating) { - isDataLoadingStarted = false - showLoadingIndicator = false - onError() - } else { - onSuccess() - } - } - - LaunchedEffect(Unit) { - pinCode.value = byteArrayOf() - idCardViewModel.resetPINErrorState() - idCardViewModel.resetPersonalUserData() - } - - LaunchedEffect(idCardStatus) { - idCardStatus?.let { status -> - when (status) { - SmartCardReaderStatus.IDLE -> { - showLoadingIndicator = false - isDataLoadingStarted = false - idCardStatusMessage.value = idCardStatusInitialMessage - } - - SmartCardReaderStatus.READER_DETECTED -> { - showLoadingIndicator = false - isDataLoadingStarted = false - idCardStatusMessage.value = idCardStatusReaderDetectedMessage - } - - SmartCardReaderStatus.CARD_DETECTED -> { - showLoadingIndicator = true - isDataLoadingStarted = true - withContext(IO) { - idCardViewModel.loadPersonalData() - } - idCardStatusMessage.value = idCardStatusCardDetectedMessage - } - } - - if (idCardStatus != SmartCardReaderStatus.CARD_DETECTED) { - idCardViewModel.resetPersonalUserData() - pinCode.value.fill(0) - } - } ?: run { - idCardStatusMessage.value = idCardStatusInitialMessage - } - } - - LaunchedEffect(idCardViewModel.signStatus) { - idCardViewModel.signStatus - .asFlow() - .filterNotNull() - .collect { signStatus -> - sharedContainerViewModel.setSignedIDCardStatus(signStatus) - idCardViewModel.resetSignStatus() - pinCode.value.fill(0) - idCardViewModel.resetPINErrorState() - pinCode.value = byteArrayOf() - } - } - - LaunchedEffect(idCardViewModel.decryptStatus) { - idCardViewModel.decryptStatus - .asFlow() - .filterNotNull() - .collect { decryptStatus -> - sharedContainerViewModel.setDecryptIDCardStatus(decryptStatus) - idCardViewModel.resetDecryptStatus() - pinCode.value.fill(0) - idCardViewModel.resetPINErrorState() - pinCode.value = byteArrayOf() - } - } - - LaunchedEffect(idCardViewModel.errorState) { - idCardViewModel.errorState - .asFlow() - .filterNotNull() - .collect { errorState -> - withContext(IO) { - idCardViewModel.resetPersonalUserData() - idCardViewModel.resetErrorState() - } - withContext(Main) { - if (errorState.first != 0) { - errorText = - context.getString( - errorState.first, - errorState.second, - errorState.third, - ) - } - - pinCode.value = byteArrayOf() - - isDataLoadingStarted = false - showLoadingIndicator = true - // Navigating away dismisses the notification. - // Waiting to show message before dismissing. - delay(4000L) - idCardStatusMessage.value = idCardStatusInitialMessage - isValidToSign(false) - isValidToDecrypt(false) - showLoadingIndicator = false - onError() - } - } - } - - LaunchedEffect(idCardViewModel.pinErrorState) { - idCardViewModel.pinErrorState - .asFlow() - .filterNotNull() - .collect { pinErrorState -> - withContext(IO) { - idCardViewModel.resetErrorState() - idCardViewModel.resetDialogErrorState() - } - withContext(Main) { - pinCode.value = byteArrayOf() - pinErrorText = - context.getString( - pinErrorState.first, - pinErrorState.second, - pinErrorState.third, - ) - - if (pinErrorText.isNotEmpty()) { - showMessage(pinErrorText) - } - - if (shouldHandleError) { - // Navigating away dismisses the notification. - // Waiting to show message before dismissing. - delay(4000L) - onError() - } - } - } - } - - LaunchedEffect(idCardViewModel.dialogError) { - idCardViewModel.dialogError - .asFlow() - .filterNotNull() - .collect { - withContext(Main) { - pinCode.value.fill(0) - idCardViewModel.resetErrorState() - idCardViewModel.resetPINErrorState() - pinCode.value = byteArrayOf() - showErrorDialog.value = true - } - } - } - - LaunchedEffect(idCardViewModel.signedContainer) { - idCardViewModel.signedContainer - .asFlow() - .filterNotNull() - .collect { signedContainer -> - sharedContainerViewModel.setSignedContainer(signedContainer) - idCardViewModel.resetSignedContainer() - onSuccess() - } - } - - LaunchedEffect(idCardViewModel.cryptoContainer) { - idCardViewModel.cryptoContainer - .asFlow() - .filterNotNull() - .collect { cryptoContainer -> - sharedContainerViewModel.setCryptoContainer(cryptoContainer, true) - idCardViewModel.resetCryptoContainer() - onSuccess() - } - } - - LaunchedEffect(Unit, idCardData, isValid, isSigning, isDecrypting, isAuthenticating, idCardStatusMessage) { - if (idCardData?.personalData == null || - (isValid && isSigning) || - (isValid && isDecrypting) || - isAuthenticating - ) { - statusMessageFocusRequester.requestFocus() - } - } - - LaunchedEffect(Unit, idCardData, isSigning, isAuthenticating, isDecrypting) { - if (idCardData?.personalData != null && !isSigning && !isAuthenticating && !isDecrypting) { - delay(500) - readyToSignFocusRequester.requestFocus() - } - } - - LaunchedEffect(Unit, idCardData, isAuthenticating) { - if (idCardData?.personalData != null && isAuthenticating && !isSigning) { - idCardData?.let { data -> - isAuthenticated(true, data) - idCardViewModel.resetPersonalUserData() - } - } - } - - if (errorText.isNotEmpty()) { - showMessage(errorText) - errorText = "" - } - - if (showErrorDialog.value) { - var text1 = 0 - var text1Arg: Int? = null - val text2 = null - var linkText = 0 - var linkUrl = 0 - if (dialogError?.contains("Too Many Requests") == true) { - text1 = R.string.too_many_requests_message - text1Arg = R.string.id_card_conditional_speech - linkText = R.string.additional_information - linkUrl = R.string.too_many_requests_url - } else if (dialogError?.contains("OCSP response not in valid time slot") == true) { - text1 = R.string.invalid_time_slot_message - linkText = R.string.additional_information - linkUrl = R.string.invalid_time_slot_url - } else if (dialogError?.contains("PIN2 has not been changed") == true) { - text1 = R.string.sign_blocked_pin2_unchanged_message - linkText = R.string.additional_information - linkUrl = R.string.sign_blocked_pin2_unchanged_url - } - Box(modifier = modifier.fillMaxSize()) { - BasicAlertDialog( - modifier = - modifier - .clip(buttonRoundCornerShape) - .background(MaterialTheme.colorScheme.surface), - onDismissRequest = { - showErrorDialog.value = false - idCardViewModel.resetDialogErrorState() - }, - ) { - Surface( - modifier = - modifier - .padding(SPadding) - .wrapContentHeight() - .wrapContentWidth() - .verticalScroll(rememberScrollState()), - ) { - Column( - modifier = - modifier - .semantics { - testTagsAsResourceId = true - }.testTag("idCardErrorContainer"), - ) { - HrefMessageDialog( - modifier = modifier, - text1 = text1, - text1Arg = text1Arg, - text2 = text2, - linkText = linkText, - linkUrl = linkUrl, - newLineBeforeLink = true, - ) - - CancelAndOkButtonRow( - okButtonTestTag = "hrefMessageDialogOkButton", - cancelButtonTestTag = "hrefMessageDialogCancelButton", - cancelButtonClick = {}, - okButtonClick = { - showErrorDialog.value = false - idCardViewModel.resetDialogErrorState() - }, - cancelButtonTitle = R.string.cancel_button, - okButtonTitle = R.string.ok_button, - cancelButtonContentDescription = stringResource(id = R.string.cancel_button).lowercase(), - okButtonContentDescription = stringResource(id = R.string.ok_button).lowercase(), - showCancelButton = false, - ) - } - } - } - InvisibleElement(modifier = modifier) - } - } - - Column( - modifier = - modifier - .fillMaxHeight() - .imePadding() - .pointerInput(Unit) { - detectTapGestures(onTap = { - focusManager.clearFocus() - }) - }.semantics { - testTagsAsResourceId = true - }.testTag("signatureUpdateIdCard"), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - if (isAddingRoleAndAddress) { - RoleDataView(modifier, sharedSettingsViewModel, onError) - } else { - isValid = pinCode.value.size in pinMinLength..PIN_MAX_LENGTH - - LaunchedEffect(isValid) { - isValidToSign(isValid) - } - - LaunchedEffect(isValid) { - isValidToDecrypt(isValid) - } - - LaunchedEffect(Unit, isValid) { - if (isValid) { - signAction { - if (getSettingsAskRoleAndAddress()) { - val roles = sharedSettingsViewModel.dataStore.getRoles() - val rolesList = - roles - .split(",") - .map { it.trim() } - .filter { it.isNotEmpty() } - .toList() - val city = sharedSettingsViewModel.dataStore.getRoleCity() - val state = sharedSettingsViewModel.dataStore.getRoleState() - val country = sharedSettingsViewModel.dataStore.getRoleCountry() - val zip = sharedSettingsViewModel.dataStore.getRoleZip() - - roleDataRequest = - RoleData( - roles = rolesList, - city = city, - state = state, - country = country, - zip = zip, - ) - } - - scope.launch(IO) { - idCardViewModel.sign( - activity, - signedContainer!!, - pinCode.value, - roleDataRequest, - ) - pinCode.value.fill(0) - } - } - decryptAction { - scope.launch(IO) { - idCardViewModel.decrypt( - activity, - context, - cryptoContainer!!, - pinCode.value, - ) - pinCode.value.fill(0) - } - } - } - cancelAction { - scope.launch(IO) { - signedContainer?.let { idCardViewModel.removePendingSignature(it) } - } - } - cancelDecryptAction { - scope.launch(IO) { - signedContainer?.let { idCardViewModel.removePendingSignature(it) } - } - } - } - - LaunchedEffect(isDataLoadingStarted) { - if (isDataLoadingStarted) { - isStarted(true) - } - } - - if (idCardData?.personalData != null && isSigning) { - idCardStatusMessage.value = idCardStatusSigningMessage - } - - if (idCardData?.personalData != null && isDecrypting) { - idCardStatusMessage.value = idCardStatusSigningMessage - } - - if (idCardData?.personalData == null || - (isValid && isSigning) || - (isValid && isDecrypting) || - isAuthenticating - ) { - if (!showLoadingIndicator) { - Icon( - modifier = - modifier - .fillMaxWidth() - .size(iconSizeXXL) - .notAccessible(), - imageVector = ImageVector.vectorResource(R.drawable.ic_m3_smart_card_reader_48dp_wght400), - contentDescription = null, - ) - } else { - CircularProgressIndicator( - modifier = - modifier - .padding(vertical = LPadding) - .size(loadingBarSize) - .testTag("activityIndicator") - .notAccessible(), - color = MaterialTheme.colorScheme.secondary, - trackColor = MaterialTheme.colorScheme.surfaceVariant, - ) - } - - Row( - modifier = - modifier - .fillMaxWidth() - .padding(vertical = SPadding), - horizontalArrangement = Arrangement.Center, - ) { - Text( - text = idCardStatusMessage.value, - style = MaterialTheme.typography.titleLarge, - modifier = - modifier - .focusRequester(statusMessageFocusRequester) - .focusable() - .semantics { - liveRegion = LiveRegionMode.Assertive - }.testTag("idCardStatusMessage"), - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurface, - ) - } - } - - if (idCardStatusReadyToSign) { - Column( - modifier = - modifier - .fillMaxWidth() - .padding(top = SPadding) - .semantics { - testTagsAsResourceId = true - }.testTag("signatureUpdateIdCardContainer"), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(SPadding), - ) { - Text( - modifier = - modifier - .zIndex(1f) - .focusRequester(readyToSignFocusRequester) - .focusable() - .semantics { - traversalIndex = 1f - testTagsAsResourceId = true - }.testTag("idCardReadyToSignMessage"), - text = idCardStatusReadyToSignMessage, - textAlign = TextAlign.Start, - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - - val personalData = idCardData?.personalData - - val nameText = - formatName( - "${personalData?.surname()},${personalData?.givenNames()},${personalData?.personalCode()}", - ) - - StyledNameText( - modifier = - modifier - .zIndex(2f) - .focusable(false) - .semantics { - traversalIndex = 2f - testTagsAsResourceId = true - contentDescription = formatNumbers(nameText) - }.testTag("idCardSignerNameText"), - nameText, - ) - - Column( - modifier = - modifier - .fillMaxWidth() - .semantics { - testTagsAsResourceId = true - }.testTag("idCardContainer"), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(MSPadding), - ) { - Row( - modifier = - modifier - .fillMaxWidth() - .padding(top = MSPadding), - horizontalArrangement = Arrangement.Start, - verticalAlignment = Alignment.CenterVertically, - ) { - SecurePinTextField( - modifier = - modifier - .weight(1f) - .zIndex(3f) - .semantics { - traversalIndex = 3f - testTagsAsResourceId = true - }.testTag("idCardPinTextField"), - pin = pinCode, - pinCodeLabel = pinText, - pinNumberFocusRequester = pinCodeFocusRequester, - previousFocusRequester = readyToSignFocusRequester, - pinCodeTextEdited = pinCodeTextEdited, - trailingIconContentDescription = "$clearButtonText $buttonName", - isError = - pinCodeTextEdited.value && - shouldShowPINCodeError( - pinCode.value, - codeType, - ), - ) - if (isTalkBackEnabled(context) && pinCode.value.isNotEmpty()) { - IconButton( - modifier = - modifier - .zIndex(4f) - .align(Alignment.CenterVertically) - .semantics { - traversalIndex = 4f - testTagsAsResourceId = true - }.testTag("idCardPinRemoveButton"), - onClick = { - pinCode.value = byteArrayOf() - scope.launch(Main) { - pinCodeFocusRequester.requestFocus() - focusManager.clearFocus() - delay(200) - pinCodeFocusRequester.requestFocus() - } - }, - ) { - Icon( - modifier = - modifier - .size(iconSizeXXS) - .semantics { - testTagsAsResourceId = true - }.testTag("idCardPinRemoveIconButton"), - imageVector = ImageVector.vectorResource(R.drawable.ic_icon_remove), - contentDescription = "$clearButtonText $buttonName", - ) - } - } - } - - if (pinCodeLengthErrorText.isNotEmpty()) { - Text( - modifier = - modifier - .padding(bottom = MSPadding) - .fillMaxWidth() - .focusable(true) - .semantics { contentDescription = pinCodeLengthErrorText } - .testTag("idCardPinError"), - text = pinCodeLengthErrorText, - textAlign = TextAlign.Start, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.error, - ) - } - } - } - } - } - } - - InvisibleElement(modifier = modifier) - - if (!loading) return -} - -@Preview(showBackground = true) -@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun IdCardViewPreview() { - RIADigiDocTheme { - val sharedContainerViewModel: SharedContainerViewModel = hiltViewModel() - val sharedSettingsViewModel: SharedSettingsViewModel = hiltViewModel() - IdCardView( - activity = LocalActivity.current as Activity, - sharedSettingsViewModel = sharedSettingsViewModel, - sharedContainerViewModel = sharedContainerViewModel, - identityAction = IdentityAction.SIGN, - isAuthenticating = false, - isAuthenticated = { _, _ -> {} }, - ) - } -} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/NFCView.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/NFCView.kt index 70f8f0142..ce57f793d 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/NFCView.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/NFCView.kt @@ -138,7 +138,7 @@ fun NFCView( identityAction: IdentityAction, isSigning: Boolean = false, isDecrypting: Boolean = false, - isAuthenticating: Boolean, + isAuthenticating: Boolean = false, onError: () -> Unit = {}, onSuccess: () -> Unit = {}, isAddingRoleAndAddress: Boolean = false, @@ -150,12 +150,12 @@ fun NFCView( isValidToSign: (Boolean) -> Unit = {}, isValidToDecrypt: (Boolean) -> Unit = {}, showPinField: Boolean = true, - isValidToAuthenticate: (Boolean) -> Unit, + isValidToAuthenticate: (Boolean) -> Unit = {}, signAction: (() -> Unit) -> Unit = {}, decryptAction: (() -> Unit) -> Unit = {}, cancelAction: (() -> Unit) -> Unit = {}, cancelDecryptAction: (() -> Unit) -> Unit = {}, - isAuthenticated: (Boolean, IdCardData) -> Unit, + isAuthenticated: (Boolean, IdCardData) -> Unit = { _, _ -> }, ) { val context = LocalContext.current val scope = rememberCoroutineScope() diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SignatureAddRadioItem.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SignatureAddRadioItem.kt index 67bc36c38..c9e3ae300 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SignatureAddRadioItem.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SignatureAddRadioItem.kt @@ -49,15 +49,6 @@ data class SignatureAddRadioItem( ).lowercase(), testTag = "signatureUpdateSignatureAddMethodNFC", ), - SignatureAddRadioItem( - label = R.string.signature_update_signature_add_method_id_card, - method = SigningMethod.ID_CARD, - contentDescription = - stringResource( - id = R.string.signature_update_signature_add_method_id_card_accessibility, - ).lowercase(), - testTag = "signatureUpdateSignatureAddMethodIdCard", - ), SignatureAddRadioItem( label = R.string.signature_update_signature_add_method_mobile_id, method = SigningMethod.MOBILE_ID, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/Constant.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/Constant.kt index ca77097ce..fb08e9940 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/utils/Constant.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/Constant.kt @@ -41,7 +41,6 @@ object Constant { const val SIGNING_SCREEN = "signing_route" const val ENCRYPT_SCREEN = "encrypt_route" const val DECRYPT_SCREEN = "decrypt_route" - const val DECRYPT_METHOD_SCREEN = "decrypt_method_route" const val ACCESSIBILITY_SCREEN = "accessibility_route" const val INFO_SCREEN = "info_route" const val DIAGNOSTICS_SCREEN = "diagnostics_route" @@ -64,7 +63,6 @@ object Constant { const val PROXY_SERVICES_SCREEN = "proxy_services_route" const val CONTAINER_NOTIFICATIONS_SCREEN = "container_notifications_route" const val MYEID_IDENTIFICATION_SCREEN = "myeid_identification_route" - const val MYEID_IDENTIFICATION_METHOD_SCREEN = "myeid_identification_method_route" const val MYEID_SCREEN = "myeid_screen_route" const val MYEID_PIN_SCREEN = "myeid_pin_screen_route" } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/Route.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/Route.kt index e416c9bb8..710146a06 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/utils/Route.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/Route.kt @@ -27,7 +27,6 @@ import ee.ria.DigiDoc.utils.Constant.Routes.CERTIFICATE_DETAIL_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CONTAINER_NOTIFICATIONS_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CRYPTO_FILE_CHOOSING_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.CRYPTO_SCREEN -import ee.ria.DigiDoc.utils.Constant.Routes.DECRYPT_METHOD_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.DECRYPT_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.DIAGNOSTICS_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.EID_SCREEN @@ -37,7 +36,6 @@ import ee.ria.DigiDoc.utils.Constant.Routes.ENCRYPT_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.HOME_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.INFO_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.INIT_SCREEN -import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_IDENTIFICATION_METHOD_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_IDENTIFICATION_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_PIN_SCREEN import ee.ria.DigiDoc.utils.Constant.Routes.MYEID_SCREEN @@ -84,8 +82,6 @@ sealed class Route( data object DecryptScreen : Route(DECRYPT_SCREEN) - data object DecryptMethodScreen : Route(DECRYPT_METHOD_SCREEN) - data object Accessibility : Route(ACCESSIBILITY_SCREEN) data object Info : Route(INFO_SCREEN) @@ -130,8 +126,6 @@ sealed class Route( data object MyEidIdentificationScreen : Route(MYEID_IDENTIFICATION_SCREEN) - data object MyEidIdentificationMethodScreen : Route(MYEID_IDENTIFICATION_METHOD_SCREEN) - data object MyEidScreen : Route(MYEID_SCREEN) data object MyEidPinScreen : Route(MYEID_PIN_SCREEN) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModel.kt b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModel.kt deleted file mode 100644 index efba76a66..000000000 --- a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/IdCardViewModel.kt +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName") - -package ee.ria.DigiDoc.viewmodel - -import android.app.Activity -import android.content.Context -import android.content.pm.ActivityInfo -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import ee.ria.DigiDoc.R -import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository -import ee.ria.DigiDoc.cryptolib.CDOC2Settings -import ee.ria.DigiDoc.cryptolib.CryptoContainer -import ee.ria.DigiDoc.domain.model.IdCardData -import ee.ria.DigiDoc.domain.service.IdCardService -import ee.ria.DigiDoc.idcard.CodeVerificationException -import ee.ria.DigiDoc.idcard.Token -import ee.ria.DigiDoc.libdigidoclib.SignedContainer -import ee.ria.DigiDoc.libdigidoclib.domain.model.RoleData -import ee.ria.DigiDoc.libdigidoclib.domain.model.ValidatorInterface -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus -import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.debugLog -import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.launch -import kotlinx.coroutines.rx3.asFlow -import kotlinx.coroutines.withContext -import java.util.Arrays -import java.util.Base64 -import javax.inject.Inject - -@HiltViewModel -class IdCardViewModel - @Inject - constructor( - private val smartCardReaderManager: SmartCardReaderManager, - private val idCardService: IdCardService, - private val cdoc2Settings: CDOC2Settings, - private val configurationRepository: ConfigurationRepository, - ) : ViewModel() { - private val logTag = javaClass.simpleName - - private val _idCardStatus = MutableLiveData(SmartCardReaderStatus.IDLE) - val idCardStatus: LiveData = _idCardStatus - - private val _userData = MutableLiveData(null) - val userData: LiveData = _userData - - private val _signStatus = MutableLiveData(null) - val signStatus: LiveData = _signStatus - - private val _decryptStatus = MutableLiveData(null) - val decryptStatus: LiveData = _decryptStatus - - private val _signedContainer = MutableLiveData(null) - val signedContainer: LiveData = _signedContainer - - private val _cryptoContainer = MutableLiveData(null) - val cryptoContainer: LiveData = _cryptoContainer - - private val _errorState = MutableLiveData?>(null) - val errorState: LiveData?> = _errorState - - private val _pinErrorState = MutableLiveData?>(null) - val pinErrorState: LiveData?> = _pinErrorState - - private val _shouldHandleError = MutableStateFlow(false) - val shouldHandleError: StateFlow = _shouldHandleError - - private val _dialogError = MutableLiveData(null) - val dialogError: LiveData = _dialogError - - init { - CoroutineScope(Main).launch { - smartCardReaderManager.status().asFlow().distinctUntilChanged().collect { status -> - _idCardStatus.postValue(status) - } - } - } - - suspend fun loadPersonalData() = - withContext(IO) { - try { - val token = - withContext(IO) { - Token.create(smartCardReaderManager.connectedReader()) - } - - val data = idCardService.data(token) - - _userData.postValue(data) - } catch (e: Exception) { - _signStatus.postValue(false) - _decryptStatus.postValue(false) - - showGeneralError(e) - errorLog(logTag, "Unable to get ID-card personal data: ${e.message}", e) - - resetValues() - } - } - - suspend fun sign( - activity: Activity, - signedContainer: SignedContainer, - pin2Code: ByteArray, - roleData: RoleData?, - ) { - activity.requestedOrientation = activity.resources.configuration.orientation - - try { - val token: Token = - withContext(Main) { - Token.create(smartCardReaderManager.connectedReader()) - } - - val signedContainerResult: SignedContainer = - idCardService.signContainer(token, signedContainer, pin2Code, roleData) - - if (pin2Code.isNotEmpty()) { - Arrays.fill(pin2Code, 0.toByte()) - } - - withContext(Main) { - _signStatus.postValue(true) - _signedContainer.postValue(signedContainerResult) - } - } catch (e: Exception) { - handleSigningError(e, signedContainer) - } finally { - activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } - } - - suspend fun decrypt( - activity: Activity, - context: Context, - container: CryptoContainer?, - pin1Code: ByteArray, - ) { - activity.requestedOrientation = activity.resources.configuration.orientation - if (container != null) { - try { - val token: Token = - withContext(Main) { - Token.create(smartCardReaderManager.connectedReader()) - } - - val authCert = idCardService.data(token).authCertificate.data - - debugLog( - logTag, - "Auth certificate: " + Base64.getEncoder().encodeToString(authCert), - ) - val decryptedContainer = - CryptoContainer.decrypt( - context, - container.file, - container.recipients, - authCert, - pin1Code, - token, - cdoc2Settings, - configurationRepository, - ) - if (pin1Code.isNotEmpty()) { - Arrays.fill(pin1Code, 0.toByte()) - } - - withContext(Main) { - _decryptStatus.postValue(true) - _cryptoContainer.postValue(decryptedContainer) - } - } catch (e: Exception) { - handleDecryptError(e) - } finally { - activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } - } else { - withContext(Main) { - _decryptStatus.postValue(false) - _errorState.postValue(Triple(R.string.error_general_client, null, null)) - errorLog(logTag, "Unable to get container value. Container is 'null'") - } - } - } - - suspend fun removePendingSignature(signedContainer: SignedContainer) { - val signatures = signedContainer.getSignatures(Main) - if (signatures.isNotEmpty()) { - val lastSignatureStatus = signatures.last().validator.status - if (lastSignatureStatus == ValidatorInterface.Status.Invalid || - lastSignatureStatus == ValidatorInterface.Status.Unknown - ) { - signedContainer.removeSignature(signatures.last()) - } - } - } - - private fun handleIdentityError(e: Exception) { - val message = e.message ?: "" - - when { - e is CodeVerificationException -> handlePinError(e) - message.contains("PIN2 has not been changed") -> - showErrorDialog( - e, - "Unable to sign with ID-card - PIN2 has not been changed", - ) - message.contains("Too Many Requests") -> - showErrorDialog( - e, - "Unable to sign with ID-card - Too Many Requests", - ) - message.contains("OCSP response not in valid time slot") -> - showErrorDialog( - e, - "Unable to sign with ID-card - OCSP response not in valid time slot", - ) - message.contains("Certificate status: revoked") -> showRevokedCertificateError(e) - message.contains("Certificate status: unknown") -> showUnknownCertificateError(e) - message.contains("Failed to connect") || - message.contains("Failed to create connection with host") -> - showNetworkError(e) - message.contains("Failed to create proxy connection with host") -> showProxyError(e) - message.contains("No lock found with certificate key") -> showNoLockFoundError(e) - else -> showGeneralError(e) - } - } - - private fun handleDecryptError(e: Exception) { - _decryptStatus.postValue(false) - - handleIdentityError(e) - } - - private suspend fun handleSigningError( - e: Exception, - signedContainer: SignedContainer, - ) { - removePendingSignature(signedContainer) - _signStatus.postValue(false) - - handleIdentityError(e) - } - - private fun handlePinError(e: CodeVerificationException) { - val pinRetryCount = e.retries - val pinErrorMessage = - when (pinRetryCount) { - 2 -> Triple(R.string.id_card_sign_pin_invalid, e.type.name, pinRetryCount) - 1 -> Triple(R.string.id_card_sign_pin_invalid_final, e.type.name, null) - 0 -> Triple(R.string.id_card_sign_pin_locked, e.type.name, null) - else -> Triple(R.string.id_card_sign_pin_wrong, e.type.name, null) - } - setShouldHandleError(pinRetryCount == 0) - _pinErrorState.postValue(pinErrorMessage) - errorLog(logTag, "Unable to sign / decrypt with ID-card: ${e.message}", e) - } - - private fun showErrorDialog( - e: Exception, - logMessage: String, - ) { - _dialogError.postValue(e.message) - errorLog(logTag, logMessage, e) - } - - private fun showRevokedCertificateError(e: Exception) { - _errorState.postValue( - Triple( - R.string.signature_update_signature_error_message_certificate_revoked, - null, - null, - ), - ) - errorLog(logTag, "Unable to sign with ID-card - Certificate status: revoked", e) - } - - private fun showUnknownCertificateError(e: Exception) { - _errorState.postValue( - Triple( - R.string.signature_update_signature_error_message_certificate_unknown, - null, - null, - ), - ) - errorLog(logTag, "Unable to sign with ID-card - Certificate status: unknown", e) - } - - private fun showNetworkError(e: Exception) { - _errorState.postValue(Triple(R.string.no_internet_connection, null, null)) - errorLog(logTag, "Unable to sign with ID-card - Unable to connect to Internet", e) - } - - private fun showProxyError(e: Exception) { - _errorState.postValue(Triple(R.string.main_settings_proxy_invalid_settings, null, null)) - errorLog(logTag, "Unable to sign with ID-card - Unable to create proxy connection with host", e) - } - - private fun showGeneralError(e: Exception) { - _errorState.postValue(Triple(R.string.error_general_client, null, null)) - errorLog(logTag, "Unable to sign with ID-card: ${e.message}", e) - } - - fun setShouldHandleError(value: Boolean) { - _shouldHandleError.value = value - } - - private fun showNoLockFoundError(e: Exception) { - _errorState.postValue(Triple(R.string.no_lock_found, null, null)) - errorLog(logTag, "Unable to decrypt with ID-card - No lock found with certificate key", e) - } - - fun resetSignStatus() { - _signStatus.postValue(null) - } - - fun resetDecryptStatus() { - _decryptStatus.postValue(null) - } - - fun resetErrorState() { - _errorState.postValue(null) - } - - fun resetDialogErrorState() { - _dialogError.postValue(null) - } - - fun resetSignedContainer() { - _signedContainer.postValue(null) - } - - fun resetCryptoContainer() { - _cryptoContainer.postValue(null) - } - - fun resetPersonalUserData() { - _userData.postValue(null) - } - - private fun resetIdCardStatus() { - _idCardStatus.postValue(null) - } - - fun resetPINErrorState() { - _pinErrorState.postValue(null) - } - - fun resetShouldHandleError() { - _shouldHandleError.value = false - } - - private fun resetValues() { - resetDialogErrorState() - resetIdCardStatus() - resetPersonalUserData() - resetErrorState() - resetPINErrorState() - resetSignStatus() - resetSignedContainer() - resetShouldHandleError() - } - } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModel.kt b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModel.kt index 1bc5b77cd..d22737647 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModel.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedMyEidViewModel.kt @@ -25,12 +25,10 @@ import android.app.Activity import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import ee.ria.DigiDoc.R import ee.ria.DigiDoc.common.Constant import ee.ria.DigiDoc.domain.model.IdCardData -import ee.ria.DigiDoc.domain.model.myeid.MyEidIdentificationMethodSetting import ee.ria.DigiDoc.domain.model.pin.PinChangeVariant import ee.ria.DigiDoc.domain.preferences.DataStore import ee.ria.DigiDoc.domain.service.IdCardService @@ -40,19 +38,13 @@ import ee.ria.DigiDoc.idcard.DateOfBirthUtil import ee.ria.DigiDoc.idcard.Token import ee.ria.DigiDoc.idcard.TokenWithPace import ee.ria.DigiDoc.smartcardreader.SmartCardReaderException -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderStatus import ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReader import ee.ria.DigiDoc.smartcardreader.nfc.NfcSmartCardReaderManager import ee.ria.DigiDoc.ui.component.myeid.pinandcertificate.PinChangeContent import ee.ria.DigiDoc.utilsLib.date.DateUtil import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog -import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.launch -import kotlinx.coroutines.rx3.asFlow import java.security.cert.X509Certificate import java.text.SimpleDateFormat import java.time.ZoneId @@ -66,7 +58,6 @@ import kotlin.math.abs class SharedMyEidViewModel @Inject constructor( - private val smartCardReaderManager: SmartCardReaderManager, private val idCardService: IdCardService, private val nfcSmartCardReaderManager: NfcSmartCardReaderManager, private val dataStore: DataStore, @@ -76,9 +67,6 @@ class SharedMyEidViewModel private val _pinScreenContent = MutableStateFlow(null) val pinScreenContent: StateFlow = _pinScreenContent - private val _idCardStatus = MutableLiveData(SmartCardReaderStatus.IDLE) - val idCardStatus: LiveData = _idCardStatus - private val _idCardData = MutableLiveData(null) val idCardData: LiveData = _idCardData @@ -91,21 +79,6 @@ class SharedMyEidViewModel private val _isPinBlocked = MutableLiveData(false) val isPinBlocked: LiveData = _isPinBlocked - private val _identificationMethod = MutableLiveData(null) - val identificationMethod: LiveData = _identificationMethod - - init { - viewModelScope.launch(Main) { - smartCardReaderManager.status().asFlow().distinctUntilChanged().collect { status -> - _idCardStatus.postValue(status) - } - } - } - - fun setIdentificationMethod(identificationMethod: MyEidIdentificationMethodSetting) { - _identificationMethod.postValue(identificationMethod) - } - fun setIdCardData(idCardData: IdCardData) { _idCardData.postValue(idCardData) } @@ -355,37 +328,23 @@ class SharedMyEidViewModel onResult: (Token?, Exception?) -> Unit, ) { try { - when (identificationMethod.value) { - MyEidIdentificationMethodSetting.NFC -> { - nfcSmartCardReaderManager.startDiscovery(activity) { reader, error -> - if (error != null) { - onResult(null, error) - return@startDiscovery - } - - if (reader == null) { - onResult( - null, - SmartCardReaderException( - activity.getString(R.string.error_general_client), - ), - ) - return@startDiscovery - } - - handleNfcToken(reader, onResult) - } + nfcSmartCardReaderManager.startDiscovery(activity) { reader, error -> + if (error != null) { + onResult(null, error) + return@startDiscovery } - else -> { - try { - val reader = smartCardReaderManager.connectedReader() - val token = Token.create(reader) - onResult(token, null) - } catch (e: Exception) { - onResult(null, e) - } + if (reader == null) { + onResult( + null, + SmartCardReaderException( + activity.getString(R.string.error_general_client), + ), + ) + return@startDiscovery } + + handleNfcToken(reader, onResult) } } catch (e: Exception) { onResult(null, e) @@ -424,10 +383,6 @@ class SharedMyEidViewModel _isPinBlocked.postValue(false) } - fun resetIdentificationMethod() { - _identificationMethod.postValue(null) - } - fun resetValues() { resetErrorState() resetIsPinBlocked() @@ -437,7 +392,6 @@ class SharedMyEidViewModel fun handleBackButton() { resetValues() - resetIdentificationMethod() resetIdCardData() } } diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index bb14e4803..fe8481bab 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -198,8 +198,6 @@ mobiil-ID Smart-ID - ID-kaart kaardilugeja abil - ID-kaart kaardilugeja abil ID-kaart NFC abil ID-kaart N F C abil Allkiri lisatud diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf64e3f8b..802e6abc5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -198,8 +198,6 @@ mobile-ID Smart-ID - ID-card via USB - ID-card via U S B ID-card via NFC ID-card via N F C Signature added diff --git a/id-card-lib/id-lib/id-card-lib-debug.aar b/id-card-lib/id-lib/id-card-lib-debug.aar index c3df9294a..74738850e 100644 Binary files a/id-card-lib/id-lib/id-card-lib-debug.aar and b/id-card-lib/id-lib/id-card-lib-debug.aar differ diff --git a/id-card-lib/id-lib/id-card-lib-release.aar b/id-card-lib/id-lib/id-card-lib-release.aar index 9ae349e84..fb6de8e05 100644 Binary files a/id-card-lib/id-lib/id-card-lib-release.aar and b/id-card-lib/id-lib/id-card-lib-release.aar differ diff --git a/id-card-lib/smart-lib/smart-card-reader-lib-debug.aar b/id-card-lib/smart-lib/smart-card-reader-lib-debug.aar index ac27fd4f2..eb63dc4d3 100644 Binary files a/id-card-lib/smart-lib/smart-card-reader-lib-debug.aar and b/id-card-lib/smart-lib/smart-card-reader-lib-debug.aar differ diff --git a/id-card-lib/smart-lib/smart-card-reader-lib-release.aar b/id-card-lib/smart-lib/smart-card-reader-lib-release.aar index c65d9600e..f0c86dce4 100644 Binary files a/id-card-lib/smart-lib/smart-card-reader-lib-release.aar and b/id-card-lib/smart-lib/smart-card-reader-lib-release.aar differ diff --git a/id-card-lib/src/main/AndroidManifest.xml b/id-card-lib/src/main/AndroidManifest.xml index 3d2e21e5a..8bdb7e14b 100644 --- a/id-card-lib/src/main/AndroidManifest.xml +++ b/id-card-lib/src/main/AndroidManifest.xml @@ -1,8 +1,4 @@ - - - \ No newline at end of file + diff --git a/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/di/AppModules.kt b/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/di/AppModules.kt deleted file mode 100644 index 7f1a0ad49..000000000 --- a/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/di/AppModules.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2017 - 2026 Riigi Infosüsteemi Amet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -@file:Suppress("PackageName") - -package ee.ria.DigiDoc.domain.di - -import android.app.Application -import android.content.Context -import android.hardware.usb.UsbManager -import com.google.common.collect.ImmutableList -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import ee.ria.DigiDoc.smartcardreader.SmartCardReaderManager -import ee.ria.DigiDoc.smartcardreader.usb.AcsUsbSmartCardReader -import ee.ria.DigiDoc.smartcardreader.usb.IdentivUsbSmartCardReader -import ee.ria.DigiDoc.smartcardreader.usb.UsbSmartCardReader -import ee.ria.DigiDoc.smartcardreader.usb.UsbSmartCardReaderManager -import javax.inject.Qualifier -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -class AppModules { - @Provides - @Singleton - fun provideUsbSmartCardReaderManager( - @ApplicationContext context: Context, - usbManager: UsbManager, - readers: ImmutableList, - ): SmartCardReaderManager = UsbSmartCardReaderManager(context, usbManager, readers) - - @Provides - @Singleton - fun provideUsbManager( - @ApplicationContext context: Context, - ): UsbManager = (context.getSystemService(Context.USB_SERVICE) as UsbManager) - - @Provides - fun provideUsbSmartCardReaderList( - acsSmartCardReader: AcsUsbSmartCardReader, - identivSmartCardReader: IdentivUsbSmartCardReader, - ): ImmutableList = ImmutableList.of(acsSmartCardReader, identivSmartCardReader) - - @Provides - @Singleton - fun provideAcsUsbSmartCardReader(usbManager: UsbManager): AcsUsbSmartCardReader = AcsUsbSmartCardReader(usbManager) - - @Provides - @Singleton - fun provideIdentivUsbSmartCardReader( - application: Application, - usbManager: UsbManager, - ): IdentivUsbSmartCardReader = IdentivUsbSmartCardReader(application, usbManager) -} - -@Module -@InstallIn(SingletonComponent::class) -abstract class SmartCardReaderModule { - @Qualifier - @Retention(AnnotationRetention.BINARY) - annotation class AcsReader - - @Qualifier - @Retention(AnnotationRetention.BINARY) - annotation class IdentivReader - - @Binds - @Singleton - @AcsReader - abstract fun bindAcsUsbSmartCardReader(acsSmartCardReader: AcsUsbSmartCardReader): UsbSmartCardReader - - @Binds - @Singleton - @IdentivReader - abstract fun bindIdentivUsbSmartCardReader(identivSmartCardReader: IdentivUsbSmartCardReader): UsbSmartCardReader -} diff --git a/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImpl.kt b/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImpl.kt index 734c785fd..bd2796da8 100644 --- a/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImpl.kt +++ b/id-card-lib/src/main/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImpl.kt @@ -73,7 +73,7 @@ class IdCardServiceImpl val pin1RetryCounter = token.codeRetryCounter(CodeType.PIN1) val pin2RetryCounter = token.codeRetryCounter(CodeType.PIN2) val pukRetryCounter = token.codeRetryCounter(CodeType.PUK) - val pin2CodeChanged = token.pinChangedFlag() + val pin2CodeChanged = token.pinChangedFlag(CodeType.PIN2) val authCertificate = ExtendedCertificate.create(authenticationCertificateData, certificateService) val signCertificate = ExtendedCertificate.create(signingCertificateData, certificateService) @@ -126,7 +126,7 @@ class IdCardServiceImpl val signer = ExternalSigner(signCertificateData) signer.setProfile(SIGNATURE_PROFILE_TS) - signer.setUserAgent(UserAgentUtil.getUserAgent(context, SendDiagnostics.Devices)) + signer.setUserAgent(UserAgentUtil.getUserAgent(context, SendDiagnostics.NFC)) dataToSign = containerWrapper.prepareSignature( diff --git a/networking-lib/src/main/kotlin/ee/ria/DigiDoc/network/utils/UserAgentUtil.kt b/networking-lib/src/main/kotlin/ee/ria/DigiDoc/network/utils/UserAgentUtil.kt index e1170fbe3..b1849491c 100644 --- a/networking-lib/src/main/kotlin/ee/ria/DigiDoc/network/utils/UserAgentUtil.kt +++ b/networking-lib/src/main/kotlin/ee/ria/DigiDoc/network/utils/UserAgentUtil.kt @@ -33,7 +33,6 @@ import ee.ria.DigiDoc.common.BuildVersionProvider import ee.ria.DigiDoc.common.BuildVersionProviderImpl import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog import java.util.Locale -import java.util.Objects import java.util.stream.Collectors enum class SendDiagnostics { @@ -90,18 +89,12 @@ object UserAgentUtil { deviceNameFilters .stream() .anyMatch { charSequence: String -> - Objects - .requireNonNull(value.productName) - .contains( - charSequence, - ) + value.productName?.contains(charSequence) == true } || deviceNameFilters .stream() .anyMatch { charSequence: String -> - value.deviceName.contains( - charSequence, - ) + value.deviceName.contains(charSequence) } }.collect( Collectors.toMap, String, UsbDevice>(