From 52374b37952aa292d55d74d213780beb31b198b4 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Thu, 8 Dec 2022 06:58:31 +0300 Subject: [PATCH 01/14] Handle device search error --- .../org/smartregister/p2p/model/P2PState.kt | 1 + .../p2p/search/ui/p2p/BottomSheetScreen.kt | 34 +++++++++++++++---- .../p2p/search/ui/p2p/P2PViewModel.kt | 2 +- p2p-lib/src/main/res/values/strings.xml | 2 ++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt index 4c249e2f..43d5bf8c 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt @@ -27,5 +27,6 @@ enum class P2PState { TRANSFERRING_DATA, WAITING_TO_RECEIVE_DATA, PAIR_DEVICES_FOUND, + PAIR_DEVICES_SEARCH_FAILED, WIFI_AND_LOCATION_ENABLE } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt index 419ab088..6c2425d5 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt @@ -64,6 +64,7 @@ import org.smartregister.p2p.search.ui.p2p.components.PairDeviceRow import org.smartregister.p2p.search.ui.p2p.components.ProgressStatusIndicator import org.smartregister.p2p.search.ui.p2p.components.ProgressStatusText import org.smartregister.p2p.search.ui.p2p.components.SelectPairDeviceRow +import org.smartregister.p2p.search.ui.theme.DangerColor import org.smartregister.p2p.search.ui.theme.DefaultColor import org.smartregister.p2p.search.ui.theme.WhiteColor import org.smartregister.p2p.utils.annotation.ExcludeFromJacocoGeneratedReport @@ -123,8 +124,13 @@ fun BottomSheet( var transferCompleteMsg = "" when (deviceRole) { DeviceRole.SENDER -> { + if (p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED) { + progressStatusTitle = stringResource(id = R.string.searching_failed) + progressStatusMsg = stringResource(id = R.string.searching_failed_msg) + } else { + progressStatusMsg = stringResource(id = R.string.searching_nearby_device_as) + } bottomSheetTitle = stringResource(id = R.string.searching_for_nearby_recipient) - progressStatusMsg = stringResource(id = R.string.searching_nearby_device_as) transferCompleteMsg = stringResource( id = R.string.x_records_sent, @@ -192,10 +198,23 @@ fun BottomSheet( if (p2PState != P2PState.PAIR_DEVICES_FOUND) { Spacer(modifier = Modifier.size(5.dp)) - ProgressStatusIndicator( - showCircularProgressIndicator = showCircularProgressIndicator, - p2PUiState = p2PUiState - ) + if (p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED) { + ProgressStatusIndicator( + p2PUiState = + p2PUiState.copy( + progressIndicator = + ProgressIndicator( + backgroundColor = DangerColor.copy(alpha = 0.2f), + icon = Icons.Filled.Clear + ) + ) + ) + } else { + ProgressStatusIndicator( + showCircularProgressIndicator = showCircularProgressIndicator, + p2PUiState = p2PUiState + ) + } Spacer(modifier = Modifier.size(5.dp)) ProgressStatusText(title = progressStatusTitle, message = progressStatusMsg) @@ -226,7 +245,8 @@ fun BottomSheet( Spacer(modifier = Modifier.size(5.dp)) - if (p2PState == P2PState.TRANSFER_COMPLETE) { + if (p2PState == P2PState.TRANSFER_COMPLETE || p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED + ) { Button( onClick = { onEvent(P2PEvent.DataTransferCompleteConfirmed) }, modifier @@ -251,6 +271,6 @@ fun PreviewBottomSheetScreen() { p2PUiState = P2PUiState(), deviceName = "John", deviceRole = DeviceRole.SENDER, - p2PState = P2PState.RECEIVING_DATA + p2PState = P2PState.PAIR_DEVICES_SEARCH_FAILED ) } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 34d20b21..1f9a7752 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -105,7 +105,7 @@ class P2PViewModel( view.keepScreenOn(false) Timber.e("Devices searching failed") Timber.e(ex) - view.showToast(view.getString(R.string.device_searching_failed)) + _p2PState.postValue(P2PState.PAIR_DEVICES_SEARCH_FAILED) } } diff --git a/p2p-lib/src/main/res/values/strings.xml b/p2p-lib/src/main/res/values/strings.xml index e188da36..878bb77f 100644 --- a/p2p-lib/src/main/res/values/strings.xml +++ b/p2p-lib/src/main/res/values/strings.xml @@ -81,4 +81,6 @@ Preparing to send data to %1$s Waiting for sender to initiate data sync Please turn on Wifi connection for P2P to work + Searching failed + Sorry, could not find devices to pair with \ No newline at end of file From 33c2a651b25251ca08ff929b0430c1bca1f4685b Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Fri, 9 Dec 2022 11:12:27 +0300 Subject: [PATCH 02/14] Handle device connecting error --- .../org/smartregister/p2p/model/P2PState.kt | 1 + .../p2p/search/ui/p2p/BottomSheetScreen.kt | 72 +++++++++++++------ .../p2p/search/ui/p2p/P2PViewModel.kt | 5 +- p2p-lib/src/main/res/values/strings.xml | 4 +- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt index 43d5bf8c..a1059b3e 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt @@ -28,5 +28,6 @@ enum class P2PState { WAITING_TO_RECEIVE_DATA, PAIR_DEVICES_FOUND, PAIR_DEVICES_SEARCH_FAILED, + CONNECT_TO_DEVICE_FAILED, WIFI_AND_LOCATION_ENABLE } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt index 6c2425d5..7ebbf72e 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt @@ -124,12 +124,20 @@ fun BottomSheet( var transferCompleteMsg = "" when (deviceRole) { DeviceRole.SENDER -> { - if (p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED) { - progressStatusTitle = stringResource(id = R.string.searching_failed) - progressStatusMsg = stringResource(id = R.string.searching_failed_msg) - } else { - progressStatusMsg = stringResource(id = R.string.searching_nearby_device_as) + when (p2PState) { + P2PState.PAIR_DEVICES_SEARCH_FAILED -> { + progressStatusTitle = stringResource(id = R.string.searching_failed) + progressStatusMsg = stringResource(id = R.string.searching_failed_msg) + } + P2PState.CONNECT_TO_DEVICE_FAILED -> { + progressStatusTitle = stringResource(id = R.string.pairing_failed) + progressStatusMsg = stringResource(id = R.string.pairing_failed_msg) + } + else -> { + progressStatusMsg = stringResource(id = R.string.searching_nearby_device_as) + } } + bottomSheetTitle = stringResource(id = R.string.searching_for_nearby_recipient) transferCompleteMsg = stringResource( @@ -198,22 +206,38 @@ fun BottomSheet( if (p2PState != P2PState.PAIR_DEVICES_FOUND) { Spacer(modifier = Modifier.size(5.dp)) - if (p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED) { - ProgressStatusIndicator( - p2PUiState = - p2PUiState.copy( - progressIndicator = - ProgressIndicator( - backgroundColor = DangerColor.copy(alpha = 0.2f), - icon = Icons.Filled.Clear - ) - ) - ) - } else { - ProgressStatusIndicator( - showCircularProgressIndicator = showCircularProgressIndicator, - p2PUiState = p2PUiState - ) + + when (p2PState) { + P2PState.PAIR_DEVICES_SEARCH_FAILED -> { + ProgressStatusIndicator( + p2PUiState = + p2PUiState.copy( + progressIndicator = + ProgressIndicator( + backgroundColor = DangerColor.copy(alpha = 0.2f), + icon = Icons.Filled.Clear + ) + ) + ) + } + P2PState.CONNECT_TO_DEVICE_FAILED -> { + ProgressStatusIndicator( + p2PUiState = + p2PUiState.copy( + progressIndicator = + ProgressIndicator( + backgroundColor = DangerColor.copy(alpha = 0.2f), + icon = Icons.Filled.Clear + ) + ) + ) + } + else -> { + ProgressStatusIndicator( + showCircularProgressIndicator = showCircularProgressIndicator, + p2PUiState = p2PUiState + ) + } } Spacer(modifier = Modifier.size(5.dp)) @@ -245,7 +269,9 @@ fun BottomSheet( Spacer(modifier = Modifier.size(5.dp)) - if (p2PState == P2PState.TRANSFER_COMPLETE || p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED + if (p2PState == P2PState.TRANSFER_COMPLETE || + p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED || + p2PState == P2PState.CONNECT_TO_DEVICE_FAILED ) { Button( onClick = { onEvent(P2PEvent.DataTransferCompleteConfirmed) }, @@ -271,6 +297,6 @@ fun PreviewBottomSheetScreen() { p2PUiState = P2PUiState(), deviceName = "John", deviceRole = DeviceRole.SENDER, - p2PState = P2PState.PAIR_DEVICES_SEARCH_FAILED + p2PState = P2PState.CONNECT_TO_DEVICE_FAILED ) } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 1f9a7752..7e2fe580 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.viewModelScope import java.util.Timer import kotlin.concurrent.schedule import kotlinx.coroutines.launch -import org.smartregister.p2p.R import org.smartregister.p2p.authentication.model.DeviceRole import org.smartregister.p2p.data_sharing.DataSharingStrategy import org.smartregister.p2p.data_sharing.DeviceInfo @@ -169,8 +168,8 @@ class P2PViewModel( override fun onFailure(device: DeviceInfo?, ex: Exception) { Timber.d("Connecting to device %s failure", device?.getDisplayName() ?: "Unknown") Timber.e(ex) - - view.showToast(view.getString(R.string.connecting_to_device_failed)) + _p2PState.postValue(P2PState.CONNECT_TO_DEVICE_FAILED) + // view.showToast(view.getString(R.string.connecting_to_device_failed)) } } ) diff --git a/p2p-lib/src/main/res/values/strings.xml b/p2p-lib/src/main/res/values/strings.xml index 878bb77f..e6381d18 100644 --- a/p2p-lib/src/main/res/values/strings.xml +++ b/p2p-lib/src/main/res/values/strings.xml @@ -82,5 +82,7 @@ Waiting for sender to initiate data sync Please turn on Wifi connection for P2P to work Searching failed - Sorry, could not find devices to pair with + Sorry could not find devices to pair with + Pairing failed + Sorry could not pair with device \ No newline at end of file From a8f4d4770ba7b155be6d65dcbe3e2718b314f8ba Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Thu, 5 Jan 2023 05:06:30 +0300 Subject: [PATCH 03/14] Close wifi direct connection when exiting P2P screen --- .../p2p/search/ui/p2p/P2PViewModel.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 7e2fe580..9c724ef8 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -211,7 +211,27 @@ class P2PViewModel( } fun closeP2PScreen() { - view.finish() + if (dataSharingStrategy.getCurrentDevice() == null) { + view.finish() + return + } + + viewModelScope.launch { + dataSharingStrategy.disconnect( + dataSharingStrategy.getCurrentDevice()!!, + object : DataSharingStrategy.OperationListener { + override fun onSuccess(device: DeviceInfo?) { + Timber.i("Diconnection successful") + view.finish() + } + + override fun onFailure(device: DeviceInfo?, ex: Exception) { + view.finish() + Timber.e(ex, "P2P diconnection failed") + } + } + ) + } } fun setCurrentConnectedDevice(device: DeviceInfo?) { From b7cd326e7722135b0dd395e6b9845c94595b09c8 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Thu, 5 Jan 2023 06:45:36 +0300 Subject: [PATCH 04/14] Show error when receiving basic device details fails --- .../org/smartregister/p2p/model/P2PState.kt | 3 +- .../p2p/search/ui/P2PDeviceSearchActivity.kt | 4 +++ .../p2p/search/ui/P2PReceiverViewModel.kt | 10 ++---- .../p2p/search/ui/p2p/BottomSheetScreen.kt | 33 ++++++++++++++++--- .../p2p/search/ui/p2p/P2PScreen.kt | 3 ++ .../p2p/search/ui/p2p/P2PViewModel.kt | 1 - p2p-lib/src/main/res/values/strings.xml | 2 ++ 7 files changed, 42 insertions(+), 14 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt index a1059b3e..428bdd0e 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PState.kt @@ -29,5 +29,6 @@ enum class P2PState { PAIR_DEVICES_FOUND, PAIR_DEVICES_SEARCH_FAILED, CONNECT_TO_DEVICE_FAILED, - WIFI_AND_LOCATION_ENABLE + WIFI_AND_LOCATION_ENABLE, + RECEIVE_BASIC_DEVICE_DETAILS_FAILED } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt index 5511972f..617bf01c 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt @@ -328,6 +328,10 @@ class P2PDeviceSearchActivity : AppCompatActivity(), P2pModeSelectContract.View } } + fun updateP2PState(p2PState: P2PState) { + p2PViewModel.updateP2PState(p2PState) + } + /** * Enables or disables the keep screen on flag to avoid the device going to sleep while there is a * sync happening diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt index e8160b8e..776cf00a 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt @@ -29,6 +29,7 @@ import org.smartregister.p2p.data_sharing.DeviceInfo import org.smartregister.p2p.data_sharing.Manifest import org.smartregister.p2p.data_sharing.SyncReceiverHandler import org.smartregister.p2p.model.P2PReceivedHistory +import org.smartregister.p2p.model.P2PState import org.smartregister.p2p.model.TransferProgress import org.smartregister.p2p.payload.BytePayload import org.smartregister.p2p.payload.PayloadContract @@ -65,14 +66,9 @@ class P2PReceiverViewModel( checkIfDeviceKeyHasChanged( deviceDetails[Constants.BasicDeviceDetails.KEY_APP_LIFETIME_KEY]!! ) - - viewModelScope.launch { - withContext(dispatcherProvider.main()) { - // TODO update to use compose - // view.showTransferProgressDialog() - } - } } else { + // Show error msg + view.updateP2PState(P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED) Timber.e("An error occurred and the APP-LIFETIME-KEY was not sent") } } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt index 7ebbf72e..201d9fbb 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt @@ -147,8 +147,18 @@ fun BottomSheet( ) } DeviceRole.RECEIVER -> { - bottomSheetTitle = stringResource(id = R.string.waiting_to_pair) - progressStatusMsg = stringResource(id = R.string.waiting_to_pair_with_sender) + when (p2PState) { + P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED -> { + bottomSheetTitle = stringResource(id = R.string.receiving) + progressStatusTitle = stringResource(id = R.string.receive_device_details_failed) + progressStatusMsg = stringResource(id = R.string.receive_device_details_failed_msg) + } + else -> { + bottomSheetTitle = stringResource(id = R.string.waiting_to_pair) + progressStatusMsg = stringResource(id = R.string.waiting_to_pair_with_sender) + } + } + transferCompleteMsg = stringResource( id = R.string.x_records_received, @@ -232,6 +242,18 @@ fun BottomSheet( ) ) } + P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED -> { + ProgressStatusIndicator( + p2PUiState = + p2PUiState.copy( + progressIndicator = + ProgressIndicator( + backgroundColor = DangerColor.copy(alpha = 0.2f), + icon = Icons.Filled.Clear + ) + ) + ) + } else -> { ProgressStatusIndicator( showCircularProgressIndicator = showCircularProgressIndicator, @@ -271,7 +293,8 @@ fun BottomSheet( if (p2PState == P2PState.TRANSFER_COMPLETE || p2PState == P2PState.PAIR_DEVICES_SEARCH_FAILED || - p2PState == P2PState.CONNECT_TO_DEVICE_FAILED + p2PState == P2PState.CONNECT_TO_DEVICE_FAILED || + p2PState == P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED ) { Button( onClick = { onEvent(P2PEvent.DataTransferCompleteConfirmed) }, @@ -296,7 +319,7 @@ fun PreviewBottomSheetScreen() { modalBottomSheetState = ModalBottomSheetState(ModalBottomSheetValue.HalfExpanded), p2PUiState = P2PUiState(), deviceName = "John", - deviceRole = DeviceRole.SENDER, - p2PState = P2PState.CONNECT_TO_DEVICE_FAILED + deviceRole = DeviceRole.RECEIVER, + p2PState = P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED ) } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt index 2b5e485e..e7fb549d 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt @@ -191,6 +191,9 @@ fun P2PScreen( ) ) } + P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED -> { + coroutineScope.launch { modalBottomSheetState.show() } + } P2PState.RECEIVING_DATA -> { coroutineScope.launch { modalBottomSheetState.hide() } TransferProgressScreen( diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 9c724ef8..91ab000f 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -169,7 +169,6 @@ class P2PViewModel( Timber.d("Connecting to device %s failure", device?.getDisplayName() ?: "Unknown") Timber.e(ex) _p2PState.postValue(P2PState.CONNECT_TO_DEVICE_FAILED) - // view.showToast(view.getString(R.string.connecting_to_device_failed)) } } ) diff --git a/p2p-lib/src/main/res/values/strings.xml b/p2p-lib/src/main/res/values/strings.xml index e6381d18..79c5870d 100644 --- a/p2p-lib/src/main/res/values/strings.xml +++ b/p2p-lib/src/main/res/values/strings.xml @@ -85,4 +85,6 @@ Sorry could not find devices to pair with Pairing failed Sorry could not pair with device + Receiving device details failed + Sorry could not receive device details \ No newline at end of file From c3d9f8deebed8b0eb4e7a63af019f4fceaeef98e Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Sat, 7 Jan 2023 15:23:41 +0300 Subject: [PATCH 05/14] Initiate sending of device details when pairing is successful --- .../p2p/search/ui/p2p/P2PViewModel.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 91ab000f..3cf07b59 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -21,8 +21,6 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import java.util.Timer -import kotlin.concurrent.schedule import kotlinx.coroutines.launch import org.smartregister.p2p.authentication.model.DeviceRole import org.smartregister.p2p.data_sharing.DataSharingStrategy @@ -121,10 +119,14 @@ class P2PViewModel( currentConnectedDevice = device - // find better way to track this - if (deviceRole == DeviceRole.RECEIVER) { - _p2PState.postValue(P2PState.WAITING_TO_RECEIVE_DATA) - view.processSenderDeviceDetails() + when (deviceRole) { + DeviceRole.RECEIVER -> { + _p2PState.postValue(P2PState.WAITING_TO_RECEIVE_DATA) + view.processSenderDeviceDetails() + } + DeviceRole.SENDER -> { + view.sendDeviceDetails() + } } } @@ -161,8 +163,6 @@ class P2PViewModel( currentConnectedDevice = device Timber.d("Connecting to device %s success", device?.getDisplayName() ?: "Unknown") _p2PState.postValue(P2PState.PREPARING_TO_SEND_DATA) - - Timer().schedule(START_DATA_TRANSFER_DELAY) { view.sendDeviceDetails() } } override fun onFailure(device: DeviceInfo?, ex: Exception) { From ecb964078dc4e19170be4e42761de887ac8683c6 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Sun, 8 Jan 2023 13:37:47 +0300 Subject: [PATCH 06/14] Update unit tests --- .../search/ui/P2PDeviceSearchActivityTest.kt | 6 +++ .../p2p/search/ui/P2PViewModelTest.kt | 40 +++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivityTest.kt b/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivityTest.kt index ab7b3982..e7e18bcd 100644 --- a/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivityTest.kt +++ b/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivityTest.kt @@ -385,6 +385,12 @@ class P2PDeviceSearchActivityTest : ActivityRobolectricTest() { verify { p2PViewModel.showTransferCompleteDialog() } } + @Test + fun `updateP2PState() should call p2PViewModel#updateP2PState() with correct value`() { + p2PDeviceSearchActivity.updateP2PState(P2PState.RECEIVING_DATA) + verify { p2PViewModel.updateP2PState(P2PState.RECEIVING_DATA) } + } + fun Dialog.isCancellable(): Boolean { return ReflectionHelpers.getField(this, "mCancelable") } diff --git a/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PViewModelTest.kt b/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PViewModelTest.kt index 4566494d..048c43fe 100644 --- a/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PViewModelTest.kt +++ b/p2p-lib/src/test/java/org/smartregister/p2p/search/ui/P2PViewModelTest.kt @@ -144,10 +144,11 @@ class P2PViewModelTest : RobolectricTest() { } @Test - fun `startScanning() should call view#keepScreenOn() and view#showToast when onDeviceFound#failed is called`() { + fun `startScanning() should call view#keepScreenOn() and update p2pState to PAIR_DEVICES_SEARCH_FAILED when onDeviceFound#failed is called`() { every { view.keepScreenOn(false) } just runs val onDeviceFoundSlot = slot() every { dataSharingStrategy.searchDevices(capture(onDeviceFoundSlot), any()) } just runs + Assert.assertNull(p2PViewModel.p2PState.value) Assert.assertNull(p2PViewModel.p2PState.value) p2PViewModel.startScanning() @@ -155,7 +156,10 @@ class P2PViewModelTest : RobolectricTest() { onDeviceFoundSlot.captured.failed(java.lang.Exception()) verify { view.keepScreenOn(false) } - verify { view.showToast(any()) } + Assert.assertEquals( + P2PState.PAIR_DEVICES_SEARCH_FAILED, + p2PViewModel.p2PState.getOrAwaitValue() + ) } @Test @@ -179,7 +183,7 @@ class P2PViewModelTest : RobolectricTest() { } @Test - fun `startScanning() should update currentConnectedDevice when pairing#onSuccess is called and device role is sender`() { + fun `startScanning() should update currentConnectedDevice and call view#sendDeviceDetails() when pairing#onSuccess is called and device role is sender`() { every { view.keepScreenOn(true) } just runs every { dataSharingStrategy.getCurrentDevice() } returns deviceInfo val pairingListenerSlot = slot() @@ -195,6 +199,7 @@ class P2PViewModelTest : RobolectricTest() { Assert.assertEquals(deviceInfo, p2PViewModel.getCurrentConnectedDevice()) Assert.assertNull(p2PViewModel.p2PState.value) + verify { view.sendDeviceDetails() } verify(exactly = 0) { view.processSenderDeviceDetails() } } @@ -303,9 +308,36 @@ class P2PViewModelTest : RobolectricTest() { } @Test - fun `closeP2PScreen() calls view#finish()`() { + fun `closeP2PScreen() calls view#finish() when dataSharingStrategy#getCurrentDevice() is null`() { + every { dataSharingStrategy.getCurrentDevice() } returns null + p2PViewModel.closeP2PScreen() + + verify { view.finish() } + } + + @Test + fun `closeP2PScreen() calls view#finish() dataSharingStrategy#disconnect() is successful`() { + every { dataSharingStrategy.disconnect(any(), any()) } just runs + every { dataSharingStrategy.getCurrentDevice() } returns deviceInfo + p2PViewModel.closeP2PScreen() + + val operationalListenerSlot = slot() + verify { dataSharingStrategy.disconnect(any(), capture(operationalListenerSlot)) } + + operationalListenerSlot.captured.onSuccess(deviceInfo) + verify { view.finish() } + } + + @Test + fun `closeP2PScreen() calls view#finish() dataSharingStrategy#disconnect() fails`() { + every { dataSharingStrategy.disconnect(any(), any()) } just runs + every { dataSharingStrategy.getCurrentDevice() } returns deviceInfo p2PViewModel.closeP2PScreen() + val operationalListenerSlot = slot() + verify { dataSharingStrategy.disconnect(any(), capture(operationalListenerSlot)) } + + operationalListenerSlot.captured.onFailure(deviceInfo, java.lang.Exception()) verify { view.finish() } } } From cc352d6afb927a568e425ddbc1dca2d6eae81cfd Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Mon, 9 Jan 2023 07:37:38 +0300 Subject: [PATCH 07/14] Add bottom sheet screen tests Fix display of cancel connection dialog --- .../search/ui/p2p/BottomSheetScreenTest.kt | 99 +++++++++++++++++++ .../p2p/search/ui/p2p/P2PScreen.kt | 7 +- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/p2p-lib/src/androidTest/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreenTest.kt b/p2p-lib/src/androidTest/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreenTest.kt index fb29b85c..62ef4f09 100644 --- a/p2p-lib/src/androidTest/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreenTest.kt +++ b/p2p-lib/src/androidTest/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreenTest.kt @@ -134,4 +134,103 @@ class BottomSheetScreenTest { .assertExists() .assertIsDisplayed() } + + @Test + @OptIn(ExperimentalMaterialApi::class) + fun bottomSheetScreenRendersCorrectlyForReceiveBasicDeviceDetailsFailedStatus() { + composeRule.setContent { + BottomSheet( + deviceList = emptyList(), + onEvent = {}, + modalBottomSheetState = ModalBottomSheetState(ModalBottomSheetValue.HalfExpanded), + p2PUiState = P2PUiState(), + deviceName = "John", + deviceRole = DeviceRole.RECEIVER, + p2PState = P2PState.RECEIVE_BASIC_DEVICE_DETAILS_FAILED + ) + } + + composeRule.onNodeWithText("OKay").assertExists().assertIsDisplayed() + composeRule.onNodeWithText("Receiving device details failed").assertExists().assertIsDisplayed() + composeRule + .onNodeWithText("Sorry could not receive device details") + .assertExists() + .assertIsDisplayed() + composeRule + .onNodeWithTag(BOTTOM_SHEET_BUTTON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + composeRule + .onNodeWithTag(BOTTOM_SHEET_CANCEL_ICON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + } + + @Test + @OptIn(ExperimentalMaterialApi::class) + fun bottomSheetScreenRendersCorrectlyForPairDevicesSearchFailedStatus() { + composeRule.setContent { + BottomSheet( + deviceList = emptyList(), + onEvent = {}, + modalBottomSheetState = ModalBottomSheetState(ModalBottomSheetValue.HalfExpanded), + p2PUiState = P2PUiState(), + deviceName = "John", + deviceRole = DeviceRole.SENDER, + p2PState = P2PState.PAIR_DEVICES_SEARCH_FAILED + ) + } + + composeRule.onNodeWithText("OKay").assertExists().assertIsDisplayed() + composeRule.onNodeWithText("Searching failed").assertExists().assertIsDisplayed() + composeRule + .onNodeWithText("Sorry could not find devices to pair with") + .assertExists() + .assertIsDisplayed() + composeRule + .onNodeWithTag(BOTTOM_SHEET_BUTTON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + composeRule + .onNodeWithTag(BOTTOM_SHEET_CANCEL_ICON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + } + + @Test + @OptIn(ExperimentalMaterialApi::class) + fun bottomSheetScreenRendersCorrectlyForConnectToDeviceFailedStatus() { + composeRule.setContent { + BottomSheet( + deviceList = emptyList(), + onEvent = {}, + modalBottomSheetState = ModalBottomSheetState(ModalBottomSheetValue.HalfExpanded), + p2PUiState = P2PUiState(), + deviceName = "John", + deviceRole = DeviceRole.SENDER, + p2PState = P2PState.CONNECT_TO_DEVICE_FAILED + ) + } + + composeRule.onNodeWithText("OKay").assertExists().assertIsDisplayed() + composeRule.onNodeWithText("Pairing failed").assertExists().assertIsDisplayed() + composeRule + .onNodeWithText("Sorry could not pair with device") + .assertExists() + .assertIsDisplayed() + composeRule + .onNodeWithTag(BOTTOM_SHEET_BUTTON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + composeRule + .onNodeWithTag(BOTTOM_SHEET_CANCEL_ICON_TEST_TAG) + .assertExists() + .assertIsDisplayed() + .performClick() + } } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt index e7fb549d..4d495bad 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt @@ -297,10 +297,6 @@ fun DefaultScreen( } ) Spacer(modifier = modifier.height(20.dp)) - - if (p2PUiState.showP2PDialog) { - P2PDialog(onEvent = onEvent) - } } } } @@ -330,6 +326,9 @@ fun TransferProgressScreen( modifier = modifier.testTag(CANCEL_BUTTON_TEST_TAG) ) { Text(text = stringResource(id = R.string.cancel)) } } + if (p2PUiState.showP2PDialog) { + P2PDialog(onEvent = onEvent) + } } } From 0805dc2e73b4c4286a9734550643a2eb51079c78 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Tue, 10 Jan 2023 07:52:00 +0300 Subject: [PATCH 08/14] Handle retrieval of current device details --- .../smartregister/p2p/WifiP2pBroadcastReceiver.kt | 8 +++++++- .../data_sharing/WifiDirectDataSharingStrategy.kt | 13 ++++++++++++- .../p2p/search/contract/P2PManagerListener.kt | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt b/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt index e4bf8e28..47b9d667 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.pm.PackageManager +import android.net.wifi.p2p.WifiP2pDevice import android.net.wifi.p2p.WifiP2pGroup import android.net.wifi.p2p.WifiP2pInfo import android.net.wifi.p2p.WifiP2pManager @@ -47,7 +48,12 @@ class WifiP2pBroadcastReceiver( WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> handlePeersChanged() WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> handleStateChanged(intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)) - WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> handleDeviceChanged() + WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { + val device = + intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE) as WifiP2pDevice? + listener.onDeviceInfoChanged(device = device) + handleDeviceChanged() + } } } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt index 48bbf13a..0a0b429e 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt @@ -203,7 +203,7 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { } } } else { - // TODO: Handle fetching device details + /** This has been handled by [WifiDirectDataSharingStrategy.onDeviceInfoChanged] */ } } } @@ -646,6 +646,10 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { override fun onConnectionInfoAvailable(info: WifiP2pInfo) { this@WifiDirectDataSharingStrategy.onConnectionInfoAvailable(info, null) } + + override fun onDeviceInfoChanged(device: WifiP2pDevice?) { + this@WifiDirectDataSharingStrategy.onDeviceInfoChanged(device) + } }, context ) @@ -732,6 +736,13 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { this.onConnectionInfoAvailable(info, null) } + override fun onDeviceInfoChanged(device: WifiP2pDevice?) { + if (device != null) { + currentDevice = device + handleWifiP2pDevice(device = device) + } + } + override fun stopSearchingDevices(operationListener: DataSharingStrategy.OperationListener?) { if (isSearchingDevices) { wifiP2pManager.stopPeerDiscovery( diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt index 3d5d40db..375e26c8 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt @@ -45,4 +45,6 @@ interface P2PManagerListener : WifiP2pManager.ConnectionInfoListener { fun handleMinimumSDKVersionNotMet(minimumSdkVersion: Int) fun onConnectionInfoAvailable(info: WifiP2pInfo, wifiP2pGroup: WifiP2pGroup?) + + fun onDeviceInfoChanged(device: WifiP2pDevice?) } From 3a2783e6d53d9ad9c4ef61dc03e80202ff26027d Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Tue, 10 Jan 2023 12:42:26 +0300 Subject: [PATCH 09/14] Refactor logic for retrieving current device info --- .../p2p/WifiP2pBroadcastReceiver.kt | 33 +++---------------- .../WifiDirectDataSharingStrategy.kt | 17 ++-------- .../p2p/search/contract/P2PManagerListener.kt | 2 -- 3 files changed, 8 insertions(+), 44 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt b/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt index 47b9d667..2270efe9 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/WifiP2pBroadcastReceiver.kt @@ -24,7 +24,6 @@ import android.net.wifi.p2p.WifiP2pDevice import android.net.wifi.p2p.WifiP2pGroup import android.net.wifi.p2p.WifiP2pInfo import android.net.wifi.p2p.WifiP2pManager -import android.os.Build import androidx.core.app.ActivityCompat import org.smartregister.p2p.search.contract.P2PManagerListener @@ -51,8 +50,7 @@ class WifiP2pBroadcastReceiver( WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { val device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE) as WifiP2pDevice? - listener.onDeviceInfoChanged(device = device) - handleDeviceChanged() + handleDeviceChanged(device = device) } } } @@ -107,32 +105,11 @@ class WifiP2pBroadcastReceiver( /** * https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#WIFI_P2P_THIS_DEVICE_CHANGED_ACTION */ - private fun handleDeviceChanged() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != - PackageManager.PERMISSION_GRANTED - ) { - // TODO: Consider calling - // ActivityCompat#requestPermissions - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - listener.handleAccessFineLocationNotGranted() - return - } - manager.requestDeviceInfo(channel) { - if (it == null) { - listener.handleWifiP2pDisabled() - } else { - listener.handleWifiP2pDevice(it) - } - } + private fun handleDeviceChanged(device: WifiP2pDevice?) { + if (device == null) { + listener.handleWifiP2pDisabled() } else { - listener.handleMinimumSDKVersionNotMet( - Build.VERSION_CODES.Q, - ) + listener.handleWifiP2pDevice(device) } } } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt index 0a0b429e..4e103a04 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt @@ -554,7 +554,6 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { if (isScanning) { listenForWifiP2pIntents() initiatePeerDiscoveryOnceAccessFineLocationGranted() - requestDeviceInfo() requestConnectionInfo() } } @@ -646,10 +645,6 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { override fun onConnectionInfoAvailable(info: WifiP2pInfo) { this@WifiDirectDataSharingStrategy.onConnectionInfoAvailable(info, null) } - - override fun onDeviceInfoChanged(device: WifiP2pDevice?) { - this@WifiDirectDataSharingStrategy.onDeviceInfoChanged(device) - } }, context ) @@ -678,8 +673,9 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { } override fun handleWifiP2pDevice(device: WifiP2pDevice) { - // TODO: Handle the issue here - // This is a new p2p device + if (device != null) { + currentDevice = device + } } override fun handleP2pDiscoveryStarted() { @@ -736,13 +732,6 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { this.onConnectionInfoAvailable(info, null) } - override fun onDeviceInfoChanged(device: WifiP2pDevice?) { - if (device != null) { - currentDevice = device - handleWifiP2pDevice(device = device) - } - } - override fun stopSearchingDevices(operationListener: DataSharingStrategy.OperationListener?) { if (isSearchingDevices) { wifiP2pManager.stopPeerDiscovery( diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt index 375e26c8..3d5d40db 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2PManagerListener.kt @@ -45,6 +45,4 @@ interface P2PManagerListener : WifiP2pManager.ConnectionInfoListener { fun handleMinimumSDKVersionNotMet(minimumSdkVersion: Int) fun onConnectionInfoAvailable(info: WifiP2pInfo, wifiP2pGroup: WifiP2pGroup?) - - fun onDeviceInfoChanged(device: WifiP2pDevice?) } From 9c5f7e0cb51170fc11d4803b410f3dbde6d7a210 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Wed, 11 Jan 2023 07:30:58 +0300 Subject: [PATCH 10/14] Handle socket connection errors when connection breaks --- .../WifiDirectDataSharingStrategy.kt | 16 ++++++++++++++-- .../p2p/search/contract/P2pModeSelectContract.kt | 2 ++ .../p2p/search/ui/P2PDeviceSearchActivity.kt | 5 ++++- .../p2p/search/ui/P2PReceiverViewModel.kt | 4 ++++ .../p2p/search/ui/p2p/P2PViewModel.kt | 7 ++++++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt index 4e103a04..285cd3d9 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt @@ -450,7 +450,13 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { if (socket != null) { dataInputStream?.run { - val dataType = readUTF() + val dataType = + try { + readUTF() + } catch (e: Exception) { + operationListener.onFailure(getCurrentDevice(), e) + return@makeSocketConnections + } if (dataType == SyncPayloadType.STRING.name) { val stringPayload = readUTF() @@ -493,7 +499,13 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { // Check if this is the receiver/sender return dataInputStream?.run { - val dataType = readUTF() + val dataType = + try { + readUTF() + } catch (e: Exception) { + operationListener.onFailure(device = device, e) + return null + } if (dataType == MANIFEST) { diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt index d72f0c9f..e9d30793 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt @@ -39,6 +39,8 @@ interface P2pModeSelectContract { fun updateTransferProgress(transferProgress: TransferProgress) fun notifyDataTransferStarting(deviceRole: DeviceRole) + + fun showCancelTransferDialog() } interface SenderViewModel { diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt index 617bf01c..5b2bd236 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt @@ -299,8 +299,11 @@ class P2PDeviceSearchActivity : AppCompatActivity(), P2pModeSelectContract.View p2PViewModel.showTransferCompleteDialog() } + override fun showCancelTransferDialog() { + p2PViewModel.showCancelTransferDialog() + } + private fun logDebug(message: String) { - // Snackbar.make(rootView, message, Snackbar.LENGTH_SHORT).show() Timber.d(message) } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt index 776cf00a..c935e620 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt @@ -247,6 +247,10 @@ class P2PReceiverViewModel( } } + fun showCancelTransferDialog() { + viewModelScope.launch(dispatcherProvider.main()) { view.showCancelTransferDialog() } + } + class Factory( private val context: P2PDeviceSearchActivity, private val dataSharingStrategy: DataSharingStrategy, diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 3cf07b59..6354567c 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -64,7 +64,7 @@ class P2PViewModel( } is P2PEvent.CancelDataTransfer -> { // show cancel transfer dialog - p2PUiState.value = p2PUiState.value.copy(showP2PDialog = true) + showCancelTransferDialog() } P2PEvent.ConnectionBreakConfirmed -> { // cancel data transfer @@ -244,6 +244,11 @@ class P2PViewModel( return requestDisconnection } + fun showCancelTransferDialog() { + // show cancel transfer dialog + p2PUiState.value = p2PUiState.value.copy(showP2PDialog = true) + } + class Factory( private val context: P2PDeviceSearchActivity, private val dataSharingStrategy: DataSharingStrategy, From d96b5ac174972792b3ab95298cd19b11e8699e7c Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Wed, 11 Jan 2023 09:05:12 +0300 Subject: [PATCH 11/14] Fix failling test --- .../p2p/data_sharing/WifiDirectDataSharingStrategyTest.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/p2p-lib/src/test/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategyTest.kt b/p2p-lib/src/test/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategyTest.kt index 512b3762..466d9416 100644 --- a/p2p-lib/src/test/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategyTest.kt +++ b/p2p-lib/src/test/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategyTest.kt @@ -805,13 +805,12 @@ class WifiDirectDataSharingStrategyTest : RobolectricTest() { } @Test - fun `onResume() calls listenForWifiP2pIntents(), initiatePeerDiscoveryOnceAccessFineLocationGranted(), requestDeviceInfo() and requestConnectionInfo() when isScanning is true`() { + fun `onResume() calls listenForWifiP2pIntents(), initiatePeerDiscoveryOnceAccessFineLocationGranted(), requestConnectionInfo() when isScanning is true`() { every { wifiDirectDataSharingStrategy invokeNoArgs "listenForWifiP2pIntents" } returns null every { wifiDirectDataSharingStrategy invokeNoArgs "initiatePeerDiscoveryOnceAccessFineLocationGranted" } returns null - every { wifiDirectDataSharingStrategy invokeNoArgs "requestDeviceInfo" } returns null every { wifiDirectDataSharingStrategy invokeNoArgs "requestConnectionInfo" } returns null wifiDirectDataSharingStrategy.onResume(isScanning = true) @@ -821,7 +820,6 @@ class WifiDirectDataSharingStrategyTest : RobolectricTest() { wifiDirectDataSharingStrategy invokeNoArgs "initiatePeerDiscoveryOnceAccessFineLocationGranted" } - verify { wifiDirectDataSharingStrategy invokeNoArgs "requestDeviceInfo" } verify { wifiDirectDataSharingStrategy invokeNoArgs "requestConnectionInfo" } } From c715cebf3e6d20bbcc16a8d69f496f9160631cae Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Thu, 12 Jan 2023 19:07:49 +0300 Subject: [PATCH 12/14] handle exception thrown when writing data --- .../p2p/data_sharing/WifiDirectDataSharingStrategy.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt index 285cd3d9..a65b48ab 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/data_sharing/WifiDirectDataSharingStrategy.kt @@ -418,8 +418,12 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener { dataOutputStream?.apply { val manifestString = Gson().toJson(manifest) - writeUTF(MANIFEST) - writeUTF(manifestString) + try { + writeUTF(MANIFEST) + writeUTF(manifestString) + } catch (e: Exception) { + operationListener.onFailure(device = device, ex = e) + } flush() operationListener.onSuccess(device = device) } From ce506b9d4945fb2b25f2d5df5163b6bdc5112d9e Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Fri, 13 Jan 2023 07:48:06 +0300 Subject: [PATCH 13/14] Return to default P2P screen when bottom sheet dialog is closed --- .../org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt index 201d9fbb..f372eb84 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/BottomSheetScreen.kt @@ -209,6 +209,7 @@ fun BottomSheet( coroutineScope.launch { if (modalBottomSheetState.isVisible) modalBottomSheetState.hide() } + onEvent(P2PEvent.DataTransferCompleteConfirmed) } .testTag(BOTTOM_SHEET_CANCEL_ICON_TEST_TAG) ) From 47293bc3e764140d985c351c6d9bc6104ea90b97 Mon Sep 17 00:00:00 2001 From: Richard Kareko Date: Mon, 16 Jan 2023 08:11:24 +0300 Subject: [PATCH 14/14] Add connection break dialog --- .../smartregister/p2p/model/P2PDialogState.kt | 31 +++++++++++++++++++ .../search/contract/P2pModeSelectContract.kt | 3 +- .../p2p/search/ui/P2PDeviceSearchActivity.kt | 5 +-- .../p2p/search/ui/P2PReceiverViewModel.kt | 8 +++-- .../p2p/search/ui/P2PSenderViewModel.kt | 5 ++- .../p2p/search/ui/p2p/P2PScreen.kt | 2 +- .../p2p/search/ui/p2p/P2PUiState.kt | 7 +++-- .../p2p/search/ui/p2p/P2PViewModel.kt | 23 ++++++++++---- 8 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 p2p-lib/src/main/java/org/smartregister/p2p/model/P2PDialogState.kt diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PDialogState.kt b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PDialogState.kt new file mode 100644 index 00000000..e5e9cb7c --- /dev/null +++ b/p2p-lib/src/main/java/org/smartregister/p2p/model/P2PDialogState.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.smartregister.p2p.model + +class P2PDialogState( + val showCancelTransferDialog: Boolean = false, + val closeConnection: Boolean = true +) + +fun p2PDialogStateOf( + showTransferDialog: Boolean = false, + closeConnection: Boolean = true +): P2PDialogState { + return P2PDialogState( + showCancelTransferDialog = showTransferDialog, + closeConnection = closeConnection + ) +} diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt index e9d30793..95f09723 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/contract/P2pModeSelectContract.kt @@ -18,6 +18,7 @@ package org.smartregister.p2p.search.contract import org.smartregister.p2p.authentication.model.DeviceRole import org.smartregister.p2p.data_sharing.DeviceInfo import org.smartregister.p2p.data_sharing.Manifest +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.P2PReceivedHistory import org.smartregister.p2p.model.TransferProgress import org.smartregister.p2p.payload.PayloadContract @@ -40,7 +41,7 @@ interface P2pModeSelectContract { fun notifyDataTransferStarting(deviceRole: DeviceRole) - fun showCancelTransferDialog() + fun showCancelTransferDialog(p2PDialogState: P2PDialogState) } interface SenderViewModel { diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt index 5b2bd236..fd337f87 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PDeviceSearchActivity.kt @@ -44,6 +44,7 @@ import org.smartregister.p2p.R import org.smartregister.p2p.authentication.model.DeviceRole import org.smartregister.p2p.data_sharing.DataSharingStrategy import org.smartregister.p2p.data_sharing.DeviceInfo +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.P2PState import org.smartregister.p2p.model.TransferProgress import org.smartregister.p2p.search.contract.P2pModeSelectContract @@ -299,8 +300,8 @@ class P2PDeviceSearchActivity : AppCompatActivity(), P2pModeSelectContract.View p2PViewModel.showTransferCompleteDialog() } - override fun showCancelTransferDialog() { - p2PViewModel.showCancelTransferDialog() + override fun showCancelTransferDialog(p2PDialogState: P2PDialogState) { + p2PViewModel.showCancelTransferDialog(p2PDialogState = p2PDialogState) } private fun logDebug(message: String) { diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt index c935e620..5c3fcb5c 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PReceiverViewModel.kt @@ -28,6 +28,7 @@ import org.smartregister.p2p.data_sharing.DataSharingStrategy import org.smartregister.p2p.data_sharing.DeviceInfo import org.smartregister.p2p.data_sharing.Manifest import org.smartregister.p2p.data_sharing.SyncReceiverHandler +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.P2PReceivedHistory import org.smartregister.p2p.model.P2PState import org.smartregister.p2p.model.TransferProgress @@ -132,6 +133,7 @@ class P2PReceiverViewModel( override fun onFailure(device: DeviceInfo?, ex: Exception) { Timber.e(ex, "Failed to receive manifest") + showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true)) } } ) @@ -175,6 +177,7 @@ class P2PReceiverViewModel( override fun onFailure(device: DeviceInfo?, ex: Exception) { Timber.e(ex, "Failed to receive chunk data") + showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true)) } } ) @@ -222,6 +225,7 @@ class P2PReceiverViewModel( override fun onFailure(device: DeviceInfo?, ex: Exception) { Timber.e(ex, "Failed to receive manifest") + showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true)) } } ) @@ -247,8 +251,8 @@ class P2PReceiverViewModel( } } - fun showCancelTransferDialog() { - viewModelScope.launch(dispatcherProvider.main()) { view.showCancelTransferDialog() } + fun showCancelTransferDialog(p2PDialogState: P2PDialogState) { + view.showCancelTransferDialog(p2PDialogState = p2PDialogState) } class Factory( diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PSenderViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PSenderViewModel.kt index 79961b4f..ccd29e55 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PSenderViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/P2PSenderViewModel.kt @@ -30,6 +30,7 @@ import org.smartregister.p2p.data_sharing.DataSharingStrategy import org.smartregister.p2p.data_sharing.DeviceInfo import org.smartregister.p2p.data_sharing.Manifest import org.smartregister.p2p.data_sharing.SyncSenderHandler +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.P2PReceivedHistory import org.smartregister.p2p.model.TransferProgress import org.smartregister.p2p.payload.PayloadContract @@ -88,7 +89,9 @@ class P2PSenderViewModel( object : DataSharingStrategy.OperationListener { override fun onSuccess(device: DeviceInfo?) {} - override fun onFailure(device: DeviceInfo?, ex: Exception) {} + override fun onFailure(device: DeviceInfo?, ex: Exception) { + view.showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true)) + } } ) } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt index 4d495bad..ab73097e 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PScreen.kt @@ -326,7 +326,7 @@ fun TransferProgressScreen( modifier = modifier.testTag(CANCEL_BUTTON_TEST_TAG) ) { Text(text = stringResource(id = R.string.cancel)) } } - if (p2PUiState.showP2PDialog) { + if (p2PUiState.p2PDialogState.showCancelTransferDialog) { P2PDialog(onEvent = onEvent) } } diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PUiState.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PUiState.kt index ad99176d..6f9d64b4 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PUiState.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PUiState.kt @@ -16,13 +16,14 @@ package org.smartregister.p2p.search.ui.p2p import org.smartregister.p2p.authentication.model.DeviceRole +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.ProgressIndicator import org.smartregister.p2p.model.TransferProgress data class P2PUiState( val state: String = "", val deviceRole: DeviceRole = DeviceRole.SENDER, - val showP2PDialog: Boolean = false, + val p2PDialogState: P2PDialogState = P2PDialogState(), val progressIndicator: ProgressIndicator = ProgressIndicator(), val transferProgress: TransferProgress = TransferProgress() ) @@ -30,14 +31,14 @@ data class P2PUiState( fun p2PUiStateOf( state: String = "", deviceRole: DeviceRole = DeviceRole.SENDER, - showP2PDialog: Boolean = true, + p2PDialogState: P2PDialogState = P2PDialogState(), progressIndicator: ProgressIndicator, transferProgress: TransferProgress ): P2PUiState { return P2PUiState( state = state, deviceRole = deviceRole, - showP2PDialog = showP2PDialog, + p2PDialogState = p2PDialogState, progressIndicator = progressIndicator, transferProgress = transferProgress ) diff --git a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt index 6354567c..e3b844b7 100644 --- a/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt +++ b/p2p-lib/src/main/java/org/smartregister/p2p/search/ui/p2p/P2PViewModel.kt @@ -26,6 +26,7 @@ import org.smartregister.p2p.authentication.model.DeviceRole import org.smartregister.p2p.data_sharing.DataSharingStrategy import org.smartregister.p2p.data_sharing.DeviceInfo import org.smartregister.p2p.data_sharing.OnDeviceFound +import org.smartregister.p2p.model.P2PDialogState import org.smartregister.p2p.model.P2PState import org.smartregister.p2p.model.TransferProgress import org.smartregister.p2p.search.ui.P2PDeviceSearchActivity @@ -64,7 +65,7 @@ class P2PViewModel( } is P2PEvent.CancelDataTransfer -> { // show cancel transfer dialog - showCancelTransferDialog() + showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true)) } P2PEvent.ConnectionBreakConfirmed -> { // cancel data transfer @@ -72,7 +73,8 @@ class P2PViewModel( setRequestDisconnection(true) } P2PEvent.DismissConnectionBreakDialog -> { - p2PUiState.value = p2PUiState.value.copy(showP2PDialog = false) + p2PUiState.value = + p2PUiState.value.copy(p2PDialogState = P2PDialogState(showCancelTransferDialog = false)) } P2PEvent.DataTransferCompleteConfirmed -> { _p2PState.postValue(P2PState.PROMPT_NEXT_TRANSFER) @@ -145,9 +147,12 @@ class P2PViewModel( Timber.e("Successful on disconnect") Timber.e("isSenderSyncComplete $view.isSenderSyncComplete") - // But use a flag to determine if sync was completed + // But use a flag to determine if sync was + showCancelTransferDialog( + P2PDialogState(showCancelTransferDialog = true, closeConnection = false) + ) } - _p2PState.postValue(P2PState.TRANSFER_COMPLETE) + // _p2PState.postValue(P2PState.TRANSFER_COMPLETE) } } @@ -180,6 +185,10 @@ class P2PViewModel( fun cancelTransfer(p2PState: P2PState = P2PState.TRANSFER_CANCELLED) { Timber.e("Connection terminated by user") + if (!p2PUiState.value.p2PDialogState.closeConnection) { + _p2PState.postValue(P2PState.PROMPT_NEXT_TRANSFER) + return + } viewModelScope.launch { dataSharingStrategy.disconnect( dataSharingStrategy.getCurrentDevice()!!, @@ -195,6 +204,8 @@ class P2PViewModel( } ) } + // close connection already handled + p2PUiState.value.copy(p2PDialogState = P2PDialogState(closeConnection = false)) } fun updateTransferProgress(transferProgress: TransferProgress) { @@ -244,9 +255,9 @@ class P2PViewModel( return requestDisconnection } - fun showCancelTransferDialog() { + fun showCancelTransferDialog(p2PDialogState: P2PDialogState) { // show cancel transfer dialog - p2PUiState.value = p2PUiState.value.copy(showP2PDialog = true) + p2PUiState.value = p2PUiState.value.copy(p2PDialogState = p2PDialogState) } class Factory(