Advertisement
androidgeek18

SecondActivity.kt

Nov 30th, 2024
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 9.53 KB | Source Code | 0 0
  1. package com.milesmarine.reeflightcontroller
  2.  
  3. import android.content.Intent
  4. import android.os.Bundle
  5. import android.util.Log
  6. import android.view.View
  7. import android.widget.LinearLayout
  8. import android.widget.TextView
  9. import androidx.appcompat.app.AppCompatActivity
  10. import androidx.recyclerview.widget.LinearLayoutManager
  11. import androidx.recyclerview.widget.RecyclerView
  12. import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
  13. import kotlinx.coroutines.CoroutineScope
  14. import kotlinx.coroutines.Dispatchers
  15. import kotlinx.coroutines.delay
  16. import kotlinx.coroutines.launch
  17. import org.json.JSONObject
  18. import java.net.DatagramPacket
  19. import java.net.DatagramSocket
  20. import java.net.HttpURLConnection
  21. import java.net.InetAddress
  22. import java.net.URL
  23.  
  24. class SecondActivity : AppCompatActivity() {
  25.  
  26.     private lateinit var recyclerView: RecyclerView
  27.     private lateinit var adapter: DeviceAdapter
  28.     private val deviceList = mutableListOf<OpenBekenDevice>()
  29.  
  30.     // UI Elements for the loading screen
  31.     private lateinit var loadingLayout: LinearLayout
  32.     private lateinit var loaderText: TextView
  33.  
  34.     // Swipe-to-refresh layout
  35.     private lateinit var swipeRefreshLayout: SwipeRefreshLayout
  36.  
  37.     // SSDP Multicast Address and Port
  38.     private val SSDP_ADDRESS = "239.255.255.250"
  39.     private val SSDP_PORT = 1900
  40.     private val SSDP_MESSAGE = """
  41.    M-SEARCH * HTTP/1.1
  42.    HOST: $SSDP_ADDRESS:$SSDP_PORT
  43.    MAN: "ssdp:discover"
  44.    MX: 3
  45.    ST: ssdp:all
  46.    """.trimIndent()
  47.  
  48.     override fun onCreate(savedInstanceState: Bundle?) {
  49.         super.onCreate(savedInstanceState)
  50.         setContentView(R.layout.activity_second)
  51.  
  52.         // Initialize RecyclerView
  53.         recyclerView = findViewById(R.id.recyclerViewDevices)
  54.         recyclerView.layoutManager = LinearLayoutManager(this)
  55.  
  56.         val onDeviceClick: (OpenBekenDevice) -> Unit = { device ->
  57.             // Save the selected device's IP to SharedPreferences
  58.             val sharedPreferences = getSharedPreferences("DevicePrefs", MODE_PRIVATE)
  59.             val editor = sharedPreferences.edit()
  60.             editor.putString("selectedDeviceIP", device.ip)
  61.             editor.apply()
  62.  
  63.             // Send selected device IP back to MainActivity
  64.             val resultIntent = Intent()
  65.             resultIntent.putExtra("selectedDeviceIP", device.ip)
  66.             setResult(RESULT_OK, resultIntent)
  67.             finish() // Close SecondActivity after selection
  68.         }
  69.  
  70.         // Set up the adapter with the onDeviceClick function
  71.         adapter = DeviceAdapter(deviceList, onDeviceClick)
  72.         recyclerView.adapter = adapter
  73.  
  74.         // Initialize loading screen elements
  75.         loadingLayout = findViewById(R.id.loadingLayout)
  76.         loaderText = findViewById(R.id.loaderText)
  77.  
  78.         // Initialize SwipeRefreshLayout
  79.         swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
  80.  
  81.         // Set up the SwipeRefreshLayout listener
  82.         swipeRefreshLayout.setOnRefreshListener {
  83.             // Reset device list and start the discovery process
  84.             deviceList.clear()
  85.             adapter.notifyDataSetChanged()  // Notify adapter to refresh RecyclerView
  86.  
  87.             Log.d("SwipeRefresh", "Swipe-to-refresh triggered")
  88.  
  89.             // Start SSDP discovery
  90.             discoverDevicesUsingSSDP()
  91.         }
  92.  
  93.         // Start SSDP discovery on initial launch
  94.         discoverDevicesUsingSSDP()
  95.     }
  96.  
  97.     private fun discoverDevicesUsingSSDP() {
  98.         Log.d("SSDP", "Starting SSDP discovery")
  99.  
  100.         // Show the loading screen
  101.         showLoadingScreen()
  102.  
  103.         // Use a Coroutine to perform the discovery in the background
  104.         CoroutineScope(Dispatchers.IO).launch {
  105.             try {
  106.                 // Open a socket to send and receive SSDP messages
  107.                 DatagramSocket().use { socket ->
  108.                     // Configure the socket to broadcast and join multicast group
  109.                     val multicastAddress = InetAddress.getByName(SSDP_ADDRESS)
  110.                     val packet = DatagramPacket(
  111.                         SSDP_MESSAGE.toByteArray(),
  112.                         SSDP_MESSAGE.length,
  113.                         multicastAddress,
  114.                         SSDP_PORT
  115.                     )
  116.  
  117.                     // Send the SSDP discovery request
  118.                     socket.send(packet)
  119.  
  120.                     // Receive responses
  121.                     val buffer = ByteArray(1024)
  122.                     while (true) {
  123.                         val responsePacket = DatagramPacket(buffer, buffer.size)
  124.                         socket.receive(responsePacket)
  125.  
  126.                         // Parse the response to extract the device details
  127.                         val response = String(responsePacket.data, 0, responsePacket.length)
  128.                         handleSSDPResponse(response, responsePacket.address.hostAddress)
  129.                     }
  130.                 }
  131.             } catch (e: Exception) {
  132.                 e.printStackTrace()
  133.             } finally {
  134.                 // Hide loading screen after discovery is done
  135.                 hideLoadingScreen()
  136.  
  137.                 // Update the RecyclerView with the devices found so far
  138.                 runOnUiThread {
  139.                     // Notify adapter about data change after the scan finishes
  140.                     adapter.notifyDataSetChanged()
  141.                     Log.d("SSDP", "Discovery completed. Devices: ${deviceList.size}")
  142.  
  143.                     // Stop the swipe refresh animation when done
  144.                     if (swipeRefreshLayout.isRefreshing) {
  145.                         swipeRefreshLayout.isRefreshing = false
  146.                     }
  147.                 }
  148.             }
  149.         }
  150.  
  151.         // Set a timeout to hide the loading screen after 5 seconds if still refreshing
  152.         CoroutineScope(Dispatchers.Main).launch {
  153.             delay(5000)
  154.             // Hide loading screen even if discovery did not complete within 10 seconds
  155.             hideLoadingScreen()
  156.  
  157.             // Stop refresh animation if still active
  158.             if (swipeRefreshLayout.isRefreshing) {
  159.                 swipeRefreshLayout.isRefreshing = false
  160.             }
  161.  
  162.             runOnUiThread {
  163.                 // Make sure the UI is updated
  164.                 adapter.notifyDataSetChanged()
  165.                 Log.d("SSDP", "Discovery timed out after 10 seconds")
  166.             }
  167.         }
  168.     }
  169.  
  170.     private fun handleSSDPResponse(response: String, ipAddress: String) {
  171.         Log.d("SSDP", "Received response: $response from $ipAddress")
  172.  
  173.         // Check if the response matches an OpenBeken device
  174.         if (response.contains("OpenBk", ignoreCase = true)) {
  175.             // Extract the LOCATION header from the response
  176.             val locationRegex = Regex("(?i)LOCATION:\\s*(http://[\\d.]+:\\d+/ssdp\\.xml)")
  177.             val locationMatch = locationRegex.find(response)
  178.             val location = locationMatch?.groups?.get(1)?.value ?: ""
  179.  
  180.             // Send HTTP request to get the MAC address
  181.             CoroutineScope(Dispatchers.IO).launch {
  182.                 val macAddress = getMacAddress(ipAddress)
  183.  
  184.                 // Create an OpenBekenDevice object with the extracted details
  185.                 val device = OpenBekenDevice(ipAddress, macAddress)
  186.  
  187.                 runOnUiThread {
  188.                     // Add the device to the list and update RecyclerView
  189.                     if (deviceList.none { it.ip == ipAddress }) { // Avoid duplicates
  190.                         deviceList.add(device)
  191.                         adapter.notifyDataSetChanged()  // Notify adapter after updating the list
  192.                     }
  193.                 }
  194.             }
  195.         }
  196.     }
  197.  
  198.     // Function to send HTTP request and get MAC address from the device's Status command
  199.     private fun getMacAddress(ipAddress: String): String {
  200.         return try {
  201.             val url = URL("http://$ipAddress/cm?cmnd=Status")
  202.             val connection = url.openConnection() as HttpURLConnection
  203.             connection.requestMethod = "GET"
  204.             connection.connect()
  205.  
  206.             // Read the response
  207.             val response = connection.inputStream.bufferedReader().readText()
  208.  
  209.             // Log the full response for debugging
  210.             Log.d("OpenBekenResponse", "Response from $ipAddress: $response")
  211.  
  212.             // Parse the JSON response
  213.             val jsonResponse = JSONObject(response)
  214.  
  215.             // Extract MAC address from the StatusNET section
  216.             if (jsonResponse.has("StatusNET")) {
  217.                 val statusNet = jsonResponse.getJSONObject("StatusNET")
  218.                 val macAddress = statusNet.getString("Mac")
  219.                 Log.d("OpenBekenResponse", "MAC Address: $macAddress")
  220.                 macAddress
  221.             } else {
  222.                 Log.d("OpenBekenResponse", "StatusNET not found in response")
  223.                 "MAC address not found"
  224.             }
  225.  
  226.         } catch (e: Exception) {
  227.             e.printStackTrace()
  228.             "Unknown MAC Address"
  229.         }
  230.     }
  231.  
  232.     // Show the loading screen
  233.     private fun showLoadingScreen() {
  234.         Log.d("UI", "Showing loading screen")
  235.         runOnUiThread {
  236.             loadingLayout.visibility = View.VISIBLE
  237.             recyclerView.visibility = View.GONE // Hide the RecyclerView during loading
  238.         }
  239.     }
  240.  
  241.     // Hide the loading screen
  242.     private fun hideLoadingScreen() {
  243.         Log.d("UI", "Hiding loading screen")
  244.         runOnUiThread {
  245.             loadingLayout.visibility = View.GONE
  246.             recyclerView.visibility = View.VISIBLE // Show the RecyclerView after loading
  247.         }
  248.     }
  249. }
  250.  
  251.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement