diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index 665b551..5cd0755 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -4,27 +4,18 @@ - - + - + - - + + - - - - - - - - - - + + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2bfae1d..e1f0009 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6780e64..4dad71a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ diff --git a/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt b/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt index 56cbc1c..b3ef37d 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/MainActivity.kt @@ -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) } } diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt new file mode 100644 index 0000000..19780b3 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/BwfManager.kt @@ -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(null) + val statePeers = mutableStateOf(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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/README.md b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/README.md new file mode 100644 index 0000000..4e0acc5 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/README.md @@ -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) diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfConnectException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfConnectException.kt new file mode 100644 index 0000000..a581c09 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfConnectException.kt @@ -0,0 +1,5 @@ +package com.faraphel.tasks_valider.connectivity.bwf.error + +class BwfConnectException( + reason: Int +) : BwfException("Cannot connect to the peer. Reason: $reason") diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfCreateGroupException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfCreateGroupException.kt new file mode 100644 index 0000000..0ce1169 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfCreateGroupException.kt @@ -0,0 +1,5 @@ +package com.faraphel.tasks_valider.connectivity.bwf.error + +class BwfCreateGroupException ( + reason: Int +) : BwfException("Could not create the group : $reason") diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfDiscoverException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfDiscoverException.kt new file mode 100644 index 0000000..a4e818a --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfDiscoverException.kt @@ -0,0 +1,5 @@ +package com.faraphel.tasks_valider.connectivity.bwf.error + +class BwfDiscoverException( + reason: Int +) : BwfException("Could not discover peers : $reason") diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfException.kt similarity index 57% rename from app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperException.kt rename to app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfException.kt index 892e2b2..7fd8810 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperException.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfException.kt @@ -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) diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfInvalidActionException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfInvalidActionException.kt new file mode 100644 index 0000000..0b690a3 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfInvalidActionException.kt @@ -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") diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt new file mode 100644 index 0000000..9f11424 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfNotSupportedException.kt @@ -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.") \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfRemoveGroupException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfRemoveGroupException.kt new file mode 100644 index 0000000..92d0789 --- /dev/null +++ b/app/src/main/java/com/faraphel/tasks_valider/connectivity/bwf/error/BwfRemoveGroupException.kt @@ -0,0 +1,5 @@ +package com.faraphel.tasks_valider.connectivity.bwf.error + +class BwfRemoveGroupException ( + reason: Int +) : BwfException("Could not remove the group : $reason") diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelper.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelper.kt deleted file mode 100644 index 574a030..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelper.kt +++ /dev/null @@ -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 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 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 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) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelperListenerInfo.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelperListenerInfo.kt deleted file mode 100644 index 3c68903..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/WifiP2pHelperListenerInfo.kt +++ /dev/null @@ -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( - val callback: CallbackType, - val once: Boolean, -) diff --git a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperInvalidActionException.kt b/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperInvalidActionException.kt deleted file mode 100644 index 26d147f..0000000 --- a/app/src/main/java/com/faraphel/tasks_valider/connectivity/wifi_p2p/error/WifiP2pHelperInvalidActionException.kt +++ /dev/null @@ -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") diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt index 681d4c8..44b1b0b 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomClientScreen.kt @@ -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(null) } +fun RoomClientScreen(bwfManager: BwfManager) { + val navController = rememberNavController() + val selectedDevice = remember { mutableStateOf(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() } \ No newline at end of file diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt index 467470b..bb9ba87 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomHostScreen.kt @@ -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") } diff --git a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt index 3e7b38a..efa95bd 100644 --- a/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt +++ b/app/src/main/java/com/faraphel/tasks_valider/ui/screen/room/RoomScreen.kt @@ -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(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) + } } } \ No newline at end of file