[WIP] use navcontroller

This commit is contained in:
Faraphel 2024-05-03 21:57:22 +02:00
parent ddb63a47ed
commit 60d5be49f7
19 changed files with 294 additions and 373 deletions

View file

@ -4,27 +4,18 @@
<value>
<entry key="app">
<State>
<multipleDevicesSelectedInDropDown value="true" />
<runningDeviceTargetsSelectedWithDialog>
<targetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="ypee7lnbpv9x7lvs" />
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Very_Small_API_34_2.avd" />
</Key>
</deviceKey>
</Target>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="2XJDU17923000406" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetsSelectedWithDialog>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-05-02T14:19:57.253897049Z" />
</State>
</entry>
</value>

View file

@ -62,6 +62,7 @@ dependencies {
implementation("androidx.compose.material3:material3")
implementation("androidx.room:room-ktx:2.6.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("androidx.navigation:navigation-compose:2.7.7")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

View file

@ -5,7 +5,7 @@
<!-- SDK -->
<uses-sdk
android:minSdkVersion="14"
android:minSdkVersion="24"
tools:ignore="GradleOverrides" />
<!-- Permissions -->

View file

@ -1,25 +1,24 @@
package com.faraphel.tasks_valider
import android.content.Context
import android.content.pm.PackageManager
import android.Manifest
import android.annotation.SuppressLint
import android.net.wifi.p2p.*
import android.content.Context
import android.content.pm.PackageManager
import android.net.wifi.p2p.WifiP2pManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import com.faraphel.tasks_valider.connectivity.packets.PacketPing
import com.faraphel.tasks_valider.connectivity.wifi_p2p.WifiP2pHelper
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
import com.faraphel.tasks_valider.connectivity.bwf.error.BwfNotSupportedException
import com.faraphel.tasks_valider.database.Database
import com.faraphel.tasks_valider.ui.screen.room.RoomScreen
class MainActivity : ComponentActivity() {
private var PERMISSION_ACCESS_FINE_LOCATION = 1001 ///< permission code for the fi
private var p2pHelper: WifiP2pHelper? = null ///< the Wi-Fi Direct helper
private var bwfManager: BwfManager? = null ///< the WiFi-Direct helper
companion object {
private lateinit var database: Database ///< the database manager
@ -29,56 +28,56 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ----- CONNECTION
// TODO(Faraphel): more check on permissions
// TOOD: more check on permissions
// check if the system support WiFi-Direct
if (!this.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
Log.e("wifi-p2p", "this device does not support the WiFi-Direct feature")
return
throw BwfNotSupportedException()
}
if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (
this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
this.checkSelfPermission(Manifest.permission.NEARBY_WIFI_DEVICES) != PackageManager.PERMISSION_GRANTED
) {
// TODO(Faraphel): should be used with shouldShowRequestPermissionRationale, with a check
this.requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), PERMISSION_ACCESS_FINE_LOCATION)
this.requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
BwfManager.PERMISSION_ACCESS_FINE_LOCATION
)
}
// get the WiFi-Direct manager
val p2pManager: WifiP2pManager? = this.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
if (p2pManager == null) {
val manager = this.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
if (manager == null) {
Log.e("wifi-p2p", "cannot access the WiFi-Direct manager")
return
throw BwfNotSupportedException()
}
// get the Wifi-Direct channel
val p2pChannel: WifiP2pManager.Channel = p2pManager.initialize(this, this.mainLooper, null)
// create a channel for the manager
val channel = manager.initialize(this, this.mainLooper, null)
// create a helper for handling the WiFi-Direct
this.p2pHelper = WifiP2pHelper(p2pManager, p2pChannel)
// create a new manager for handling the WiFi-Direct
this.bwfManager = BwfManager(manager, channel)
// open the room selection screen
this.setContent {
RoomScreen(this.p2pHelper!!)
RoomScreen(this.bwfManager!!)
}
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("UnspecifiedRegisterReceiverFlag")
override fun onResume() {
super.onResume()
// enable the WiFi-Direct events
this.registerReceiver(this.p2pHelper, WifiP2pHelper.ALL_INTENT_FILTER)
this.registerReceiver(this.bwfManager, BwfManager.ALL_INTENT_FILTER)
}
override fun onPause() {
super.onPause()
// disable the WiFi-Direct events
this.unregisterReceiver(this.p2pHelper)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// TODO(Faraphel): save the current state to reload it later
this.unregisterReceiver(this.bwfManager)
}
}

View file

@ -0,0 +1,151 @@
package com.faraphel.tasks_valider.connectivity.bwf
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.wifi.p2p.*
import androidx.compose.runtime.mutableStateOf
import com.faraphel.tasks_valider.connectivity.bwf.error.*
/**
* A helper to wrap the WiFi-Direct manager, the channel and the events.
*
* This avoids certain annoying features such as always specifying the channel as the first argument or
* handling all the events with the base event system.
*
* @param manager The WiFi-Direct manager
* @param channel The WiFi-Direct channel
*/
class BwfManager(
private var manager: WifiP2pManager,
private var channel: WifiP2pManager.Channel,
) : BroadcastReceiver() {
companion object {
var PERMISSION_ACCESS_FINE_LOCATION = 1001 ///< permission code for the fine location
var ALL_INTENT_FILTER = IntentFilter().apply {
addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
}
}
// Wrappers
/**
* Connect to another device, allowing for a communication using Sockets
* @see WifiP2pManager.connect
* @throws SecurityException if the permission has not been given
*/
@Throws(SecurityException::class)
fun connect(config: WifiP2pConfig, callback: () -> Unit = {}) =
this.manager.connect(this.channel, config, object : WifiP2pManager.ActionListener {
override fun onSuccess() { callback() }
override fun onFailure(reason: Int) = throw BwfConnectException(reason)
})
/**
* Request the list of peers after a discovery.
* @see WifiP2pManager.requestPeers
* @throws SecurityException if the permission has not been given
*/
@Throws(SecurityException::class)
fun requestPeers(callback: (WifiP2pDeviceList) -> Unit = {}) =
this.manager.requestPeers(this.channel, callback)
/**
* Start discovering peers.
* Once founds, the WIFI_P2P_PEERS_CHANGED_ACTION event will be triggered.
* @see WifiP2pManager.discoverPeers
* @throws SecurityException if the permission has not been given
*/
@Throws(SecurityException::class)
fun discoverPeers(callback: () -> Unit = {}) =
this.manager.discoverPeers(this.channel, object : WifiP2pManager.ActionListener {
override fun onSuccess() { callback() }
override fun onFailure(reason: Int) = throw BwfDiscoverException(reason)
})
/**
* Obtain information about a connection with another device.
* @see WifiP2pManager.requestConnectionInfo
*/
fun requestConnectionInfo(callback: (WifiP2pInfo) -> Unit = {}) =
this.manager.requestConnectionInfo(this.channel, callback)
/**
* Obtain information about the current group.
* @see WifiP2pManager.requestGroupInfo
* @throws SecurityException if the permission has not been given
*/
@Throws(SecurityException::class)
fun requestGroupInfo(callback: (WifiP2pGroup?) -> Unit = {}) =
this.manager.requestGroupInfo(this.channel, callback)
/**
* Create a new WiFi-Direct group.
* @see WifiP2pManager.createGroup
* @throws SecurityException if the permission has not been given
*/
@Throws(SecurityException::class)
fun createGroup(callback: () -> Unit = {}) =
this.manager.createGroup(this.channel, object : WifiP2pManager.ActionListener {
override fun onSuccess() { callback() }
override fun onFailure(reason: Int) = throw BwfCreateGroupException(reason)
})
/**
* Disconnect from the current WiFi-Direct group.
* @see WifiP2pManager.removeGroup
*/
fun removeGroup(callback: () -> Unit = {}) =
this.manager.removeGroup(this.channel, object : WifiP2pManager.ActionListener {
override fun onSuccess() { callback() }
override fun onFailure(reason: Int) = throw BwfRemoveGroupException(reason)
})
/**
* Create a new WiFi-Direct group. If already connected to a group, quit it first.
*
* Note: most of the failure on removal are caused by not having a group already created, which is checked.
*
* @param listener: the createGroup listener
* @param onRemoveFailure: error handler for the removeGroup event
*
* @see WifiP2pManager.createGroup
* @see WifiP2pManager.removeGroup
*/
fun recreateGroup(callback: () -> Unit = {}) {
// get the current group information
this.requestGroupInfo { group ->
// if a group exist, quit it
if (group != null)
this.removeGroup { this@BwfManager.createGroup(callback) }
else
// create the group
this.createGroup(callback)
}
}
// Events
val stateConnectionInfo = mutableStateOf<WifiP2pInfo?>(null)
val statePeers = mutableStateOf<WifiP2pDeviceList?>(null)
override fun onReceive(context: Context?, intent: Intent?) {
// ignore empty intent
if (intent == null)
return
// update the action corresponding state
when (intent.action) {
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> this.requestConnectionInfo {
connectionInfo -> stateConnectionInfo.value = connectionInfo
}
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> this.requestPeers {
peers -> statePeers.value = peers
}
}
// TODO(Faraphel): implement event dispatcher
}
}

View file

@ -0,0 +1,11 @@
# Better WiFi-Direct (BWD)
This package contain code to improve the base WiFi-Direct implementation.
The base have some issue, like an abusive usage of listener, error code and events that make using it
very impractical.
This improved version will instead focus on asynchronous function and exception, allowing for a
cleaner linear code instead.
(Author: https://git.faraphel.fr/Faraphel)

View file

@ -0,0 +1,5 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfConnectException(
reason: Int
) : BwfException("Cannot connect to the peer. Reason: $reason")

View file

@ -0,0 +1,5 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfCreateGroupException (
reason: Int
) : BwfException("Could not create the group : $reason")

View file

@ -0,0 +1,5 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfDiscoverException(
reason: Int
) : BwfException("Could not discover peers : $reason")

View file

@ -1,9 +1,9 @@
package com.faraphel.tasks_valider.connectivity.wifi_p2p.error
package com.faraphel.tasks_valider.connectivity.bwf.error
/**
* Base Exception for everything concerning the WifiP2pHelper class
*/
open class WifiP2pHelperException(
open class BwfException(
override val message: String?
) : Exception(message)

View file

@ -0,0 +1,5 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfInvalidActionException(
action: String
) : BwfException("This WiFi-Direct action is not supported : $action")

View file

@ -0,0 +1,4 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfNotSupportedException :
BwfException("WiFi-Direct is not supported on this device, or it is disabled.")

View file

@ -0,0 +1,5 @@
package com.faraphel.tasks_valider.connectivity.bwf.error
class BwfRemoveGroupException (
reason: Int
) : BwfException("Could not remove the group : $reason")

View file

@ -1,212 +0,0 @@
package com.faraphel.tasks_valider.connectivity.wifi_p2p
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.wifi.p2p.WifiP2pConfig
import android.net.wifi.p2p.WifiP2pDeviceList
import android.net.wifi.p2p.WifiP2pManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.faraphel.tasks_valider.connectivity.wifi_p2p.error.WifiP2pHelperInvalidActionException
/**
* A helper to wrap the WiFi-Direct manager, the channel and the events.
*
* This avoids certain annoying features such as always specifying the channel as the first argument or
* handling all the events with the base event system.
*
* @param manager: the WiFi-Direct base manager
* @param channel: the WiFi-Direct channel
*/
class WifiP2pHelper(
private val manager: WifiP2pManager,
private val channel: WifiP2pManager.Channel,
) : BroadcastReceiver() {
companion object {
/**
* This IntentFilter can be used to subscribe the helper to every supported WiFi-Direct events.
*/
val ALL_INTENT_FILTER = IntentFilter().apply {
addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
}
}
// Events
/**
* Contains the listeners to call when the peers are updated.
*/
private val listenersPeersChanged = mutableListOf<WifiP2pHelperListenerInfo<(WifiP2pDeviceList?) -> Unit>>()
/**
* Event receiver for the WiFi-Direct events.
* Should not be called manually.
* @param context: the WiFi-Direct context
* @param intent: the event information
*/
@RequiresApi(Build.VERSION_CODES.N)
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
Log.v("wifi-p2p", "Connection Changed : $context, $intent, ${intent.extras}")
}
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
Log.v("wifi-p2p", "Peers Changed : $context, $intent, ${intent.extras}")
this.requestPeers { peers ->
this@WifiP2pHelper.listenersPeersChanged.forEach { listenerInfo -> listenerInfo.callback(peers) }
this@WifiP2pHelper.listenersPeersChanged.removeIf { listenerInfo -> listenerInfo.once }
}
}
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {
Log.v("wifi-p2p", "State Changed : $context, $intent, ${intent.extras}")
}
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> {
Log.v("wifi-p2p", "This Device Changed : $context, $intent, ${intent.extras}")
}
}
}
/**
* Register a listener to a specific WiFi-Direct event.
* @param action: the name of the WiFi-Direct event
* @param callback: the callback function
* @param once: should the event be only called once ?
*/
fun <CallbackType> registerListener(action: String, callback: CallbackType, once: Boolean = false) {
when (action) {
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
@Suppress("UNCHECKED_CAST")
this.listenersPeersChanged.add(WifiP2pHelperListenerInfo(
callback as ((WifiP2pDeviceList?) -> Unit),
once
))
}
else -> {
// raise an exception if the action is invalid
throw WifiP2pHelperInvalidActionException(action)
}
}
}
@RequiresApi(Build.VERSION_CODES.N)
fun <CallbackType> unregisterListener(action: String, callback: CallbackType) {
when (action) {
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
this.listenersPeersChanged.removeIf { listenerInfo -> listenerInfo.callback == callback }
}
else -> {
// raise an exception if the action is invalid
throw WifiP2pHelperInvalidActionException(action)
}
}
}
// Wrappers
/**
* Connect to another device, allowing for a communication using Sockets
* @see WifiP2pManager.connect
*/
fun connect(config: WifiP2pConfig, listener: WifiP2pManager.ActionListener? = null) {
this.manager.connect(this.channel, config, listener)
}
/**
* Request the list of peers after a discovery.
* @see WifiP2pManager.requestPeers
*/
fun requestPeers(listener: WifiP2pManager.PeerListListener? = null) {
this.manager.requestPeers(this.channel, listener)
}
/**
* Start discovering peers.
* Once founds, the WIFI_P2P_PEERS_CHANGED_ACTION event will be triggered.
* @see WifiP2pManager.discoverPeers
*/
fun discoverPeers(listener: WifiP2pManager.ActionListener? = null) {
this.manager.discoverPeers(this.channel, listener)
}
/**
* Obtain information about a connection with another device.
* @see WifiP2pManager.requestConnectionInfo
*/
fun requestConnectionInfo(listener: WifiP2pManager.ConnectionInfoListener? = null) {
this.manager.requestConnectionInfo(this.channel, listener)
}
/**
* Obtain information about the current group.
* @see WifiP2pManager.requestGroupInfo
*/
fun requestGroupInfo(listener: WifiP2pManager.GroupInfoListener? = null) {
this.manager.requestGroupInfo(this.channel, listener)
}
/**
* Create a new WiFi-Direct group.
* @see WifiP2pManager.createGroup
*/
fun createGroup(listener: WifiP2pManager.ActionListener? = null) {
this.manager.createGroup(this.channel, listener)
}
/**
* Disconnect from the current WiFi-Direct group.
* @see WifiP2pManager.removeGroup
*/
fun removeGroup(listener: WifiP2pManager.ActionListener? = null) {
this.manager.removeGroup(this.channel, listener)
}
// Shortcuts
/**
* Create a new WiFi-Direct group. If already connected to a group, quit it first.
*
* Note: most of the failure on removal are caused by not having a group already created, which is checked.
*
* @param listener: the createGroup listener
* @param onRemoveFailure: error handler for the removeGroup event
*
* @see WifiP2pManager.createGroup
* @see WifiP2pManager.removeGroup
*/
fun recreateGroup(
listener: WifiP2pManager.ActionListener? = null,
onRemoveFailure: ((Int) -> Unit)? = null
) {
// get the current group information
this.requestGroupInfo { group ->
// if a group exist, quit it
if (group != null)
this.removeGroup(object : WifiP2pManager.ActionListener {
override fun onSuccess() {
// once left, create the group
this@WifiP2pHelper.createGroup(listener)
}
override fun onFailure(reason: Int) {
// call the handler
onRemoveFailure?.invoke(reason)
}
})
else
// create the group
this.createGroup(listener)
}
}
}

View file

@ -1,15 +0,0 @@
package com.faraphel.tasks_valider.connectivity.wifi_p2p
import java.util.concurrent.Callable
/**
* This class contain the information required to store a listener in the WifiP2pHelper class to correctly handle events.
* @param CallbackType: the type of the callback function
* @param callback: the function to call when the event is triggered
* @param once: should the listener be called only once ?
*/
class WifiP2pHelperListenerInfo<CallbackType>(
val callback: CallbackType,
val once: Boolean,
)

View file

@ -1,5 +0,0 @@
package com.faraphel.tasks_valider.connectivity.wifi_p2p.error
class WifiP2pHelperInvalidActionException(
action: String
) : WifiP2pHelperException("This WiFi-Direct action is not supported : $action")

View file

@ -3,32 +3,50 @@ package com.faraphel.tasks_valider.ui.screen.room
import android.net.wifi.p2p.WifiP2pConfig
import android.net.wifi.p2p.WifiP2pDevice
import android.net.wifi.p2p.WifiP2pDeviceList
import android.net.wifi.p2p.WifiP2pInfo
import android.net.wifi.p2p.WifiP2pManager
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
import com.faraphel.tasks_valider.connectivity.room.RoomClient
import com.faraphel.tasks_valider.connectivity.wifi_p2p.WifiP2pHelper
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
import com.faraphel.tasks_valider.ui.widgets.connectivity.WifiP2pDeviceListWidget
import kotlinx.coroutines.runBlocking
/**
* This screen allow the user to join a room
*/
@Composable
fun RoomClientScreen(wifiP2pHelper: WifiP2pHelper) {
val peers = remember { mutableStateOf<WifiP2pDeviceList?>(null) }
fun RoomClientScreen(bwfManager: BwfManager) {
val navController = rememberNavController()
val selectedDevice = remember { mutableStateOf<WifiP2pDevice?>(null) }
val connected = remember { mutableStateOf(false) }
// if the device is connected to a host, display the main screen
if (connected.value) {
TaskGroupScreen()
NavHost(navController = navController, startDestination = "roomSearch") {
composable(route = "roomSearch") {
// let the user pick which host he wishes to connect to
Column {
Text(text = "Find a Server")
// display all the devices that are owner of their group
WifiP2pDeviceListWidget(
peers = bwfManager.statePeers.value,
filter = { device: WifiP2pDevice -> device.isGroupOwner },
selectedDevice,
)
}
// update the list when a new device is detected
}
composable(route = "taskGroup") {
TaskGroupScreen()
}
}
// if a device is selected, connect to it
@ -37,53 +55,17 @@ fun RoomClientScreen(wifiP2pHelper: WifiP2pHelper) {
val config = WifiP2pConfig().apply {
deviceAddress = selectedDevice.value!!.deviceAddress
}
// try to connect
wifiP2pHelper.connect(config, object : WifiP2pManager.ActionListener {
override fun onSuccess() {
Log.i("room", "Connection successful to the host !")
// request additional information about the connection to obtain the host IP
wifiP2pHelper.registerListener(
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION,
{ connectionInfo: WifiP2pInfo ->
val client = RoomClient(
connectionInfo.groupOwnerAddress,
9876 // TODO(Faraphel): port should be a settings
)
Thread {
client.start()
}.start()
connected.value = true
},
once = true
)
// try to connect to the host
bwfManager.connect(config) {
Log.i("room", "Connection successful to the host !")
bwfManager.requestConnectionInfo { connectionInfo ->
val client = RoomClient(connectionInfo.groupOwnerAddress, 9876) // TODO(Faraphel): port should be a settings
Thread { client.start() }.start()
connected.value = true
}
override fun onFailure(reason: Int) {
// TODO(Faraphel): for most of theses messages, shouldn't a toast be used instead ?
Log.e("room", "Could not connect to this host. Reason: $reason")
}
})
return
}
}
// let the user pick which host he wishes to connect to
Column {
Text(text = "Find a Server")
// display all the devices that are owner of their group
WifiP2pDeviceListWidget(
peers = peers.value,
filter = { device: WifiP2pDevice -> device.isGroupOwner },
selectedDevice,
)
}
// TODO(Faraphel): might be doubtful. Test with more phones, should it only run once ? refresh button ?
// update the list when a new device is detected
wifiP2pHelper.registerListener(
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION,
{ newPeers: WifiP2pDeviceList? -> peers.value = newPeers },
)
wifiP2pHelper.discoverPeers()
}

View file

@ -1,6 +1,5 @@
package com.faraphel.tasks_valider.ui.screen.room
import android.net.wifi.p2p.WifiP2pManager
import android.util.Log
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
@ -10,8 +9,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import com.faraphel.tasks_valider.connectivity.wifi_p2p.WifiP2pHelper
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
import com.faraphel.tasks_valider.ui.screen.tasks.TaskGroupScreen
import kotlinx.coroutines.runBlocking
import java.net.ServerSocket
@ -22,7 +22,7 @@ var DEFAULT_SERVER_PORT: Int = 9876
* This screen allow the user to create a room
*/
@Composable
fun RoomHostScreen(wifiP2pHelper: WifiP2pHelper) {
fun RoomHostScreen(bwfManager: BwfManager) {
val expanded = remember { mutableStateOf(false) }
val serverPort = remember { mutableStateOf(DEFAULT_SERVER_PORT) }
val isCreated = remember { mutableStateOf(false) }
@ -65,23 +65,19 @@ fun RoomHostScreen(wifiP2pHelper: WifiP2pHelper) {
Button(onClick = {
// create a new WiFi-Direct group
wifiP2pHelper.recreateGroup(object : WifiP2pManager.ActionListener {
override fun onSuccess() {
Log.i("room", "group created !")
bwfManager.recreateGroup {
Log.i("room", "group created !")
val server = ServerSocket(serverPort.value) // TODO(Faraphel): should the port be a settings ?
Thread {
val client = server.accept() // TODO(Faraphel): should run in a thread
client.getInputStream()
}
// open a new server
val server = ServerSocket(serverPort.value)
Thread {
val client = server.accept() // TODO(Faraphel): should run in a thread
client.getInputStream()
}
// mark the group as created
isCreated.value = true
}
override fun onFailure(reason: Int) {
Log.e("room", "error while creating group. Reason: $reason")
}
})
// mark the group as created
isCreated.value = true
}
}) {
Text("Create")
}

View file

@ -6,42 +6,35 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import com.faraphel.tasks_valider.connectivity.wifi_p2p.WifiP2pHelper
enum class RoomScreenType {
HOST,
CLIENT
}
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
/**
* This screen will allow the user to choose which room is he connecting to, or let him create one.
*/
@Composable
fun RoomScreen(wifiP2pHelper: WifiP2pHelper) {
val roomMode = remember { mutableStateOf<RoomScreenType?>(null) }
fun RoomScreen(bwfManager: BwfManager) {
val navController = rememberNavController()
when (roomMode.value) {
RoomScreenType.CLIENT -> {
// Client mode
RoomClientScreen(wifiP2pHelper)
}
RoomScreenType.HOST -> {
// Host mode
RoomHostScreen(wifiP2pHelper)
}
null -> {
// let the user decide which room mode he which to use
NavHost(navController = navController, startDestination = "pickMode") {
composable(route = "pickMode") {
Column {
Button(onClick = { roomMode.value = RoomScreenType.CLIENT }) {
Button(onClick = { navController.navigate("client") }) {
Text(text = "Join a room")
}
Button(onClick = { roomMode.value = RoomScreenType.HOST }) {
Button(onClick = { navController.navigate("host") }) {
Text(text = "Create a room")
}
}
}
composable(route = "client") {
RoomClientScreen(bwfManager)
}
composable(route = "host") {
RoomHostScreen(bwfManager)
}
}
}