Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class MockCardReaderManagerModule {

override fun setupTapToPayUx(config: TapToPayUxConfig) {}

override fun startConnectionToReader(cardReader: CardReader, locationId: String) {}
override suspend fun startConnectionToReader(cardReader: CardReader, locationId: String) {}

override suspend fun disconnectReader(): Boolean = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ class WooPosTotalsViewModelTest {
val vm = createViewModelAndSetupForSuccessfulOrderCreation(controllerFactory = factory)

// WHEN
paymentState.value = CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment("", {})
paymentState.value = CardReaderPaymentState.PaymentCapturing.ExternalReaderPaymentCapturing("")
advanceUntilIdle()

// THEN
Expand Down Expand Up @@ -862,7 +862,7 @@ class WooPosTotalsViewModelTest {
}

@Test
fun `given order draft created and reader connected, when payment is processed, should show processing state`() =
fun `given order draft created and reader connected, when payment is processed, then should show checkout with ready for payment`() =
runTest {
// GIVEN
givenCardReaderConnectedAndNetworkAvailable()
Expand All @@ -881,12 +881,10 @@ class WooPosTotalsViewModelTest {
advanceUntilIdle()

// THEN
val processingState = vm.state.value as WooPosTotalsViewState.PaymentInProgress
assertThat(processingState).isInstanceOf(WooPosTotalsViewState.PaymentInProgress::class.java)
with(processingState) {
assertThat(title).isEqualTo("Processing payment")
assertThat(subtitle).isEqualTo("Please wait…")
}
val checkoutState = vm.state.value as WooPosTotalsViewState.Checkout
assertThat(checkoutState.readerStatus).isInstanceOf(
WooPosTotalsViewState.ReaderStatus.ReadyForPayment::class.java
)
}

@Test
Expand Down Expand Up @@ -1261,7 +1259,7 @@ class WooPosTotalsViewModelTest {
}

@Test
fun `given payment processing state, when OnBackClicked, then should ignore OnBackClicked`() = runTest {
fun `given payment in progress state with capturing payment, when OnBackClicked, then should ignore OnBackClicked`() = runTest {
// GIVEN
givenCardReaderConnectedAndNetworkAvailable()
val mockCardReaderPaymentController: CardReaderPaymentController = mock()
Expand All @@ -1275,7 +1273,7 @@ class WooPosTotalsViewModelTest {

// WHEN
val vm = createViewModelAndSetupForSuccessfulOrderCreation(controllerFactory = factory)
paymentState.value = CardReaderPaymentState.ProcessingPayment.ExternalReaderProcessingPayment("", {})
paymentState.value = CardReaderPaymentState.PaymentCapturing.ExternalReaderPaymentCapturing("")
advanceUntilIdle()

vm.onUIEvent(OnBackClicked)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface CardReaderManager {

fun setupTapToPayUx(config: TapToPayUxConfig)

fun startConnectionToReader(cardReader: CardReader, locationId: String)
suspend fun startConnectionToReader(cardReader: CardReader, locationId: String)
suspend fun disconnectReader(): Boolean
fun cancelReconnection()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ object CardReaderManagerFactory {
DiscoverReadersAction(terminal, logWrapper),
terminalListener,
application,
logWrapper,
),
SoftwareUpdateManager(
terminal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ internal class CardReaderManagerImpl(
connectionManager.setupTapToPayUx(config)
}

override fun startConnectionToReader(cardReader: CardReader, locationId: String) {
override suspend fun startConnectionToReader(cardReader: CardReader, locationId: String) {
if (!terminal.isInitialized()) error("Terminal not initialized")
connectionManager.startConnectionToReader(cardReader, locationId)
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import android.app.Application
import android.content.pm.PackageManager
import android.os.Build
import com.stripe.stripeterminal.external.callable.Callback
import com.stripe.stripeterminal.external.callable.ReaderCallback
import com.stripe.stripeterminal.external.models.ConnectionConfiguration.BluetoothConnectionConfiguration
import com.stripe.stripeterminal.external.models.ConnectionConfiguration.TapToPayConnectionConfiguration
import com.stripe.stripeterminal.external.models.DeviceType
import com.stripe.stripeterminal.external.models.Reader
import com.stripe.stripeterminal.external.models.TerminalErrorCode
import com.stripe.stripeterminal.external.models.TerminalException
import com.woocommerce.android.cardreader.CardReaderManager
import com.woocommerce.android.cardreader.LogWrapper
import com.woocommerce.android.cardreader.connection.CardReader
import com.woocommerce.android.cardreader.connection.CardReaderDiscoveryEvents
import com.woocommerce.android.cardreader.connection.CardReaderImpl
Expand All @@ -32,18 +32,19 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

private const val ARTIFICIAL_STATUS_UPDATE_DELAY_IN_MILLIS = 500L
private const val LOG_TAG = "ConnectionManager"

@Suppress("LongParameterList")
internal class ConnectionManager(
private val terminal: TerminalWrapper,
private val bluetoothReaderListener: BluetoothReaderListenerImpl,
private val tapToPayReaderListener: TapToPayReaderListenerImpl,
private val discoverReadersAction: DiscoverReadersAction,
private val terminalListenerImpl: TerminalListenerImpl,
private val application: Application,
private val logWrapper: LogWrapper,
) {
val softwareUpdateStatus = bluetoothReaderListener.updateStatusEvents
val softwareUpdateAvailability = bluetoothReaderListener.updateAvailabilityEvents
Expand Down Expand Up @@ -124,43 +125,36 @@ internal class ConnectionManager(
}
}

fun startConnectionToReader(cardReader: CardReader, locationId: String) {
suspend fun startConnectionToReader(cardReader: CardReader, locationId: String) {
(cardReader as CardReaderImpl).let {
updateReaderStatus(CardReaderStatus.Connecting)
val readerCallback = object : ReaderCallback {
override fun onSuccess(reader: Reader) {
updateReaderStatus(CardReaderStatus.Connected(CardReaderImpl(reader)))
try {
val reader = when (it.cardReader.deviceType) {
DeviceType.TAP_TO_PAY_DEVICE -> connectToBuiltInReader(cardReader, locationId)
else -> connectToExternalReader(cardReader, locationId)
}

override fun onFailure(e: TerminalException) {
updateReaderStatus(
CardReaderStatus.NotConnected(
errorCode = e.errorCode.toErrorCode(),
errorMessage = e.errorMessage,
)
updateReaderStatus(CardReaderStatus.Connected(CardReaderImpl(reader)))
} catch (e: TerminalException) {
updateReaderStatus(
CardReaderStatus.NotConnected(
errorCode = e.errorCode.toErrorCode(),
errorMessage = e.errorMessage,
)
}
}

when (it.cardReader.deviceType) {
DeviceType.TAP_TO_PAY_DEVICE -> connectToBuiltInReader(cardReader, locationId, readerCallback)
else -> connectToExternalReader(cardReader, locationId, readerCallback)
)
}
}
}

suspend fun disconnectReader() = suspendCoroutine { continuation ->
terminal.disconnectReader(object : Callback {
override fun onFailure(e: TerminalException) {
updateReaderStatus(CardReaderStatus.NotConnected())
continuation.resume(false)
}

override fun onSuccess() {
updateReaderStatus(CardReaderStatus.NotConnected())
continuation.resume(true)
}
})
suspend fun disconnectReader(): Boolean {
return try {
terminal.disconnectReader()
updateReaderStatus(CardReaderStatus.NotConnected())
true
} catch (e: TerminalException) {
logWrapper.e(LOG_TAG, "Failed to disconnect reader: ${e.errorMessage}")
updateReaderStatus(CardReaderStatus.NotConnected())
false
}
}

fun cancelReconnection() {
Expand Down Expand Up @@ -213,31 +207,27 @@ internal class ConnectionManager(
terminal.setupTapToPayUx(config)
}

private fun connectToExternalReader(
private suspend fun connectToExternalReader(
cardReader: CardReaderImpl,
locationId: String,
readerCallback: ReaderCallback
) {
terminal.connectToReader(
locationId: String
): Reader {
return terminal.connectToReader(
cardReader.cardReader,
BluetoothConnectionConfiguration(locationId, true, bluetoothReaderListener),
readerCallback
BluetoothConnectionConfiguration(locationId, true, bluetoothReaderListener)
)
}

private fun connectToBuiltInReader(
private suspend fun connectToBuiltInReader(
cardReader: CardReaderImpl,
locationId: String,
readerCallback: ReaderCallback
) {
terminal.connectToMobile(
locationId: String
): Reader {
return terminal.connectToMobile(
cardReader.cardReader,
TapToPayConnectionConfiguration(
locationId,
autoReconnectOnUnexpectedDisconnect = true,
tapToPayReaderListener
),
readerCallback
)
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
package com.woocommerce.android.cardreader.internal.connection.actions

import androidx.annotation.RequiresPermission
import com.stripe.stripeterminal.external.callable.Callback
import com.stripe.stripeterminal.external.callable.DiscoveryListener
import com.stripe.stripeterminal.external.models.DiscoveryConfiguration
import com.stripe.stripeterminal.external.models.Reader
import com.stripe.stripeterminal.external.models.TerminalException
import com.woocommerce.android.cardreader.LogWrapper
import com.woocommerce.android.cardreader.internal.LOG_TAG
import com.woocommerce.android.cardreader.internal.connection.actions.DiscoverReadersAction.DiscoverReadersStatus.Failure
import com.woocommerce.android.cardreader.internal.connection.actions.DiscoverReadersAction.DiscoverReadersStatus.FoundReaders
import com.woocommerce.android.cardreader.internal.connection.actions.DiscoverReadersAction.DiscoverReadersStatus.Started
import com.woocommerce.android.cardreader.internal.connection.actions.DiscoverReadersAction.DiscoverReadersStatus.Success
import com.woocommerce.android.cardreader.internal.sendAndLog
import com.woocommerce.android.cardreader.internal.wrappers.TerminalWrapper
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart

private const val DISCOVERY_TIMEOUT_IN_SECONDS = 60

Expand Down Expand Up @@ -55,40 +58,22 @@ internal class DiscoverReadersAction(
],
)
private fun discoverReaders(config: DiscoveryConfiguration): Flow<DiscoverReadersStatus> {
return callbackFlow {
sendAndLog(Started, logWrapper)
var foundReaders: List<Reader>? = null
val cancelable = terminal.discoverReaders(
config,
object : DiscoveryListener {
override fun onUpdateDiscoveredReaders(readers: List<Reader>) {
if (readers != foundReaders) {
foundReaders = readers
[email protected](FoundReaders(readers), logWrapper)
}
}
},
object : Callback {
override fun onFailure(e: TerminalException) {
[email protected](Failure(e), logWrapper)
[email protected]()
}

override fun onSuccess() {
[email protected](Success, logWrapper)
[email protected]()
}
return terminal.discoverReaders(config)
.distinctUntilChanged()
.map<List<Reader>, DiscoverReadersStatus> { readers -> FoundReaders(readers) }
.onStart { emit(Started) }
.onCompletion { cause ->
if (cause == null || cause is CancellationException) {
emit(Success)
}
}
.catch { e ->
if (e is TerminalException) {
emit(Failure(e))
} else {
throw e
}
)
awaitClose {
cancelable.takeIf { !it.isCompleted }?.cancel(noopCallback)
}
}
.onEach { logWrapper.d(LOG_TAG, it.toString()) }
}
}

private val noopCallback = object : Callback {
override fun onFailure(e: TerminalException) {}

override fun onSuccess() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,16 @@ internal class InteracRefundManager(
refundConfig: RefundConfig,
): Flow<CardInteracRefundStatus> = flow {
emit(CardInteracRefundStatus.CollectingInteracRefund)
processRefundAction.processRefund(
val status = processRefundAction.processRefund(
refundParameters.toStripeRefundParameters(paymentsUtils),
refundConfig.toStripeRefundConfiguration()
).collect { status ->
when (status) {
is ProcessRefundAction.ProcessRefundStatus.Success -> {
emit(CardInteracRefundStatus.InteracRefundSuccess)
}
is ProcessRefundAction.ProcessRefundStatus.Failure -> {
emit(refundErrorMapper.mapTerminalError(refundParameters, status.exception))
}
)
when (status) {
is ProcessRefundAction.ProcessRefundStatus.Success -> {
emit(CardInteracRefundStatus.InteracRefundSuccess)
}
is ProcessRefundAction.ProcessRefundStatus.Failure -> {
emit(refundErrorMapper.mapTerminalError(refundParameters, status.exception))
}
}
}
Expand Down
Loading