Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle wifi direct data sharing strategy failures #57

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ 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
import android.os.Build
import androidx.core.app.ActivityCompat
import org.smartregister.p2p.search.contract.P2PManagerListener

Expand All @@ -47,7 +47,11 @@ 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?
handleDeviceChanged(device = device)
}
}
}

Expand Down Expand Up @@ -101,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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener {
}
}
} else {
// TODO: Handle fetching device details
/** This has been handled by [WifiDirectDataSharingStrategy.onDeviceInfoChanged] */
}
}
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -450,7 +454,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()
Expand Down Expand Up @@ -493,7 +503,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) {

Expand Down Expand Up @@ -554,7 +570,6 @@ class WifiDirectDataSharingStrategy : DataSharingStrategy, P2PManagerListener {
if (isScanning) {
listenForWifiP2pIntents()
initiatePeerDiscoveryOnceAccessFineLocationGranted()
requestDeviceInfo()
requestConnectionInfo()
}
}
Expand Down Expand Up @@ -674,8 +689,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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ enum class P2PState {
TRANSFERRING_DATA,
WAITING_TO_RECEIVE_DATA,
PAIR_DEVICES_FOUND,
WIFI_AND_LOCATION_ENABLE
PAIR_DEVICES_SEARCH_FAILED,
CONNECT_TO_DEVICE_FAILED,
WIFI_AND_LOCATION_ENABLE,
RECEIVE_BASIC_DEVICE_DETAILS_FAILED
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -39,6 +40,8 @@ interface P2pModeSelectContract {
fun updateTransferProgress(transferProgress: TransferProgress)

fun notifyDataTransferStarting(deviceRole: DeviceRole)

fun showCancelTransferDialog(p2PDialogState: P2PDialogState)
}

interface SenderViewModel {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -299,8 +300,11 @@ class P2PDeviceSearchActivity : AppCompatActivity(), P2pModeSelectContract.View
p2PViewModel.showTransferCompleteDialog()
}

override fun showCancelTransferDialog(p2PDialogState: P2PDialogState) {
p2PViewModel.showCancelTransferDialog(p2PDialogState = p2PDialogState)
}

private fun logDebug(message: String) {
// Snackbar.make(rootView, message, Snackbar.LENGTH_SHORT).show()
Timber.d(message)
}

Expand Down Expand Up @@ -328,6 +332,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ 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
import org.smartregister.p2p.payload.BytePayload
import org.smartregister.p2p.payload.PayloadContract
Expand Down Expand Up @@ -65,14 +67,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")
}
}
Expand Down Expand Up @@ -136,6 +133,7 @@ class P2PReceiverViewModel(

override fun onFailure(device: DeviceInfo?, ex: Exception) {
Timber.e(ex, "Failed to receive manifest")
showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true))
}
}
)
Expand Down Expand Up @@ -179,6 +177,7 @@ class P2PReceiverViewModel(

override fun onFailure(device: DeviceInfo?, ex: Exception) {
Timber.e(ex, "Failed to receive chunk data")
showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true))
}
}
)
Expand Down Expand Up @@ -226,6 +225,7 @@ class P2PReceiverViewModel(

override fun onFailure(device: DeviceInfo?, ex: Exception) {
Timber.e(ex, "Failed to receive manifest")
showCancelTransferDialog(P2PDialogState(showCancelTransferDialog = true))
}
}
)
Expand All @@ -251,6 +251,10 @@ class P2PReceiverViewModel(
}
}

fun showCancelTransferDialog(p2PDialogState: P2PDialogState) {
view.showCancelTransferDialog(p2PDialogState = p2PDialogState)
}

class Factory(
private val context: P2PDeviceSearchActivity,
private val dataSharingStrategy: DataSharingStrategy,
Expand Down
Loading