From d5be6a9b5fe09a62a2657822441c1eafdfee47c0 Mon Sep 17 00:00:00 2001 From: maxinyu Date: Mon, 25 May 2026 17:52:19 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=B7=BB=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/WifiListAdapter.kt | 17 +- .../defenseapplication/bean/AddDeviceBean.kt | 13 + .../home/AddFamilyActivity.kt | 233 +++++------------- .../home/ConnectDeviceActivity.kt | 7 +- .../home/SetNameActivity.kt | 51 +++- .../defenseapplication/utils/ApiService.kt | 8 + 6 files changed, 157 insertions(+), 172 deletions(-) create mode 100644 app/src/main/java/com/example/defenseapplication/bean/AddDeviceBean.kt diff --git a/app/src/main/java/com/example/defenseapplication/adapter/WifiListAdapter.kt b/app/src/main/java/com/example/defenseapplication/adapter/WifiListAdapter.kt index 19a67a1..ae58248 100644 --- a/app/src/main/java/com/example/defenseapplication/adapter/WifiListAdapter.kt +++ b/app/src/main/java/com/example/defenseapplication/adapter/WifiListAdapter.kt @@ -6,10 +6,12 @@ import androidx.recyclerview.widget.RecyclerView import com.example.defenseapplication.databinding.ItemWifiBinding class WifiListAdapter( - private val wifiList: List, + wifiList: List, private val onItemClick: (String) -> Unit ) : RecyclerView.Adapter() { + private val wifiList = mutableListOf().apply { addAll(wifiList) } + inner class ViewHolder(val binding: ItemWifiBinding) : RecyclerView.ViewHolder(binding.root) { init { itemView.setOnClickListener { @@ -35,4 +37,17 @@ class WifiListAdapter( } override fun getItemCount(): Int = wifiList.size + + fun updateData(newList: List) { + wifiList.clear() + wifiList.addAll(newList) + notifyDataSetChanged() + } + + fun addData(newList: List) { + val startPosition = wifiList.size + val newItems = newList.filter { !wifiList.contains(it) } + wifiList.addAll(newItems) + notifyItemRangeInserted(startPosition, newItems.size) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/defenseapplication/bean/AddDeviceBean.kt b/app/src/main/java/com/example/defenseapplication/bean/AddDeviceBean.kt new file mode 100644 index 0000000..90c8b76 --- /dev/null +++ b/app/src/main/java/com/example/defenseapplication/bean/AddDeviceBean.kt @@ -0,0 +1,13 @@ +package com.example.defenseapplication.bean + +data class AddDeviceBean( + val deviceEm: String? = null,//设备型号 + val deviceNo: String? = null,//设备编号 + val deviceSn: String? = null,//设备序列号 + val fwVer: String? = null,//固件版本 + val status: String? = null,//状态 1-在线 0-离线 2-故障 3-到期 + val wifiName: String? = null,//WiFi名称 + val wifiPassword: String? = null,//WiFi密码 + val mac: String? = null,//邀请码 + val deviceName: String? = null,//设备名称 +) diff --git a/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt b/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt index 853ddab..fb3efef 100644 --- a/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/home/AddFamilyActivity.kt @@ -6,12 +6,8 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.pm.PackageManager -import android.net.ConnectivityManager -import android.net.Network -import android.net.NetworkCapabilities -import android.net.NetworkRequest +import android.graphics.Rect import android.net.wifi.ScanResult -import android.net.wifi.WifiConfiguration import android.net.wifi.WifiManager import android.os.Bundle import android.os.Handler @@ -26,24 +22,22 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.example.defenseapplication.R import com.example.defenseapplication.adapter.WifiListAdapter import com.example.defenseapplication.databinding.AddFamilyActivityBinding import com.example.defenseapplication.databinding.DialogWifiListBinding import com.gyf.immersionbar.ImmersionBar -//选择wifi页面 class AddFamilyActivity : AppCompatActivity() { private lateinit var binding: AddFamilyActivityBinding private lateinit var wifiManager: WifiManager - private lateinit var connectivityManager: ConnectivityManager private lateinit var wifiScanReceiver: BroadcastReceiver private var popupWindow: PopupWindow? = null private val handler = Handler(Looper.getMainLooper()) - private var isConnecting = false - private var targetWifiName: String = "" - private var networkCallback: ConnectivityManager.NetworkCallback? = null + private var wifiListAdapter: WifiListAdapter? = null + private var isLoadingMore = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -53,6 +47,7 @@ class AddFamilyActivity : AppCompatActivity() { .statusBarDarkFont(true) .titleBar(binding.topBar) .init() + binding.ivBack.setOnClickListener { finish() } @@ -70,8 +65,8 @@ class AddFamilyActivity : AppCompatActivity() { updateBottomButtonVisibility() } }) + wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager - connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager wifiScanReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -81,12 +76,8 @@ class AddFamilyActivity : AppCompatActivity() { } } } + binding.btnConfirm.setOnClickListener { - //startActivity(Intent(this, ConnectDeviceActivity::class.java)) - if (isConnecting) { - return@setOnClickListener - } - val wifiName = binding.etWifiName.text.toString().trim() val wifiPassword = binding.etWifiPassword.text.toString() @@ -100,143 +91,13 @@ class AddFamilyActivity : AppCompatActivity() { return@setOnClickListener } - isConnecting = true - binding.btnConfirm.isEnabled = false - - verifyWifiPassword(wifiName, wifiPassword) + val intent = Intent(this@AddFamilyActivity, ConnectDeviceActivity::class.java) + intent.putExtra("wifi_name", wifiName) + intent.putExtra("wifi_password", wifiPassword) + startActivity(intent) } } - private fun verifyWifiPassword(wifiName: String, wifiPassword: String) { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED || - ActivityCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE) - != PackageManager.PERMISSION_GRANTED || - ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.CHANGE_WIFI_STATE, - Manifest.permission.ACCESS_NETWORK_STATE), - 1002) - return - } - - targetWifiName = wifiName - - if (!wifiManager.isWifiEnabled) { - wifiManager.isWifiEnabled = true - } - - val existingConfig = findExistingWifiConfig(wifiName) - var netId: Int - - if (existingConfig != null) { - netId = existingConfig.networkId - existingConfig.preSharedKey = "\"$wifiPassword\"" - wifiManager.updateNetwork(existingConfig) - } else { - val wifiConfig = createWifiConfig(wifiName, wifiPassword) - netId = wifiManager.addNetwork(wifiConfig) - } - - if (netId == -1) { - isConnecting = false - binding.btnConfirm.isEnabled = true - ToastUtils.showError(this, getString(R.string.wifi_connection_failed)) - return - } - - networkCallback = object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - super.onAvailable(network) - checkWifiConnected() - } - - override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) { - super.onCapabilitiesChanged(network, capabilities) - if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - checkWifiConnected() - } - } - } - - val request = NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build() - - connectivityManager.registerNetworkCallback(request, networkCallback!!) - - wifiManager.enableNetwork(netId, true) - wifiManager.saveConfiguration() - - handler.postDelayed({ - if (isConnecting) { - isConnecting = false - binding.btnConfirm.isEnabled = true - networkCallback?.let { - try { - connectivityManager.unregisterNetworkCallback(it) - } catch (e: Exception) { - } - } - networkCallback = null - ToastUtils.showError(this, getString(R.string.wifi_connection_failed)) - } - }, 15000) - } - - private fun findExistingWifiConfig(wifiName: String): WifiConfiguration? { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - return null - } - val configuredNetworks = wifiManager.configuredNetworks - configuredNetworks?.forEach { config -> - if (config.SSID == "\"$wifiName\"") { - return config - } - } - return null - } - - private fun checkWifiConnected() { - if (!isConnecting) return - - val info = wifiManager.connectionInfo - if (info.ssid == "\"$targetWifiName\"" && info.networkId != -1) { - isConnecting = false - binding.btnConfirm.isEnabled = true - networkCallback?.let { - try { - connectivityManager.unregisterNetworkCallback(it) - } catch (e: Exception) { - } - } - networkCallback = null - runOnUiThread { - ToastUtils.showSuccess(this@AddFamilyActivity, getString(R.string.wifi_connection_success)) - val intent = Intent(this@AddFamilyActivity, ConnectDeviceActivity::class.java) - intent.putExtra("wifi_name", targetWifiName) - startActivity(intent) - } - } - } - - private fun createWifiConfig(ssid: String, password: String): WifiConfiguration { - val config = WifiConfiguration() - config.SSID = "\"$ssid\"" - config.preSharedKey = "\"$password\"" - config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK) - config.allowedProtocols.set(WifiConfiguration.Protocol.RSN) - config.allowedProtocols.set(WifiConfiguration.Protocol.WPA) - config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP) - config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP) - config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP) - config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP) - return config - } - private fun showWifiListDialog() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || @@ -255,10 +116,14 @@ class AddFamilyActivity : AppCompatActivity() { wifiManager.startScan() val dialogBinding = DialogWifiListBinding.inflate(LayoutInflater.from(this)) + + val screenHeight = getScreenHeight() + val popupHeight = (screenHeight * 2 / 3).toInt() + popupWindow = PopupWindow( dialogBinding.root, ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT + popupHeight ).apply { isFocusable = true setBackgroundDrawable(null) @@ -273,10 +138,54 @@ class AddFamilyActivity : AppCompatActivity() { dialogBinding.rvWifiList.layoutManager = LinearLayoutManager(this@AddFamilyActivity) val wifiList = getWifiList() - dialogBinding.rvWifiList.adapter = WifiListAdapter(wifiList) { wifiName -> + wifiListAdapter = WifiListAdapter(wifiList) { wifiName -> binding.etWifiName.setText(wifiName) popupWindow?.dismiss() } + dialogBinding.rvWifiList.adapter = wifiListAdapter + + dialogBinding.swipeRefreshLayout.setOnRefreshListener { + refreshWifiList(dialogBinding) + } + + dialogBinding.rvWifiList.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + val layoutManager = recyclerView.layoutManager as LinearLayoutManager + val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition() + val totalItemCount = layoutManager.itemCount + + if (lastVisibleItemPosition == totalItemCount - 1 && dy > 0 && !isLoadingMore && totalItemCount > 0) { + loadMoreWifiList() + } + } + }) + } + + private fun getScreenHeight(): Int { + val rect = Rect() + window.decorView.getWindowVisibleDisplayFrame(rect) + return rect.height() + } + + private fun refreshWifiList(dialogBinding: DialogWifiListBinding) { + dialogBinding.swipeRefreshLayout.isRefreshing = true + handler.postDelayed({ + wifiManager.startScan() + val newWifiList = getWifiList() + wifiListAdapter?.updateData(newWifiList) + dialogBinding.swipeRefreshLayout.isRefreshing = false + }, 1000) + } + + private fun loadMoreWifiList() { + isLoadingMore = true + handler.postDelayed({ + wifiManager.startScan() + val newWifiList = getWifiList() + wifiListAdapter?.addData(newWifiList) + isLoadingMore = false + }, 1000) } private fun updateBottomButtonVisibility() { @@ -315,31 +224,19 @@ class AddFamilyActivity : AppCompatActivity() { super.onStop() unregisterReceiver(wifiScanReceiver) popupWindow?.dismiss() - networkCallback?.let { - try { - connectivityManager.unregisterNetworkCallback(it) - } catch (e: Exception) { - } - } - networkCallback = null handler.removeCallbacksAndMessages(null) } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when (requestCode) { - 1002 -> { + 1001 -> { if (grantResults.isNotEmpty() && - grantResults.size >= 3 && + grantResults.size >= 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED && - grantResults[1] == PackageManager.PERMISSION_GRANTED && - grantResults[2] == PackageManager.PERMISSION_GRANTED) { - val wifiName = binding.etWifiName.text.toString().trim() - val wifiPassword = binding.etWifiPassword.text.toString() - verifyWifiPassword(wifiName, wifiPassword) + grantResults[1] == PackageManager.PERMISSION_GRANTED) { + showWifiListDialog() } else { - isConnecting = false - binding.btnConfirm.isEnabled = true Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show() } } diff --git a/app/src/main/java/com/example/defenseapplication/home/ConnectDeviceActivity.kt b/app/src/main/java/com/example/defenseapplication/home/ConnectDeviceActivity.kt index 937c78d..2e23c8d 100644 --- a/app/src/main/java/com/example/defenseapplication/home/ConnectDeviceActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/home/ConnectDeviceActivity.kt @@ -97,7 +97,12 @@ class ConnectDeviceActivity : AppCompatActivity() { // 跳转到下一个界面或关闭当前页面 // 使用 Handler 延迟跳转 Handler(Looper.getMainLooper()).postDelayed({ - startActivity(Intent(this, SetNameActivity::class.java)) + val wifiName = intent.getStringExtra("wifi_name") ?: "" + val wifiPassword = intent.getStringExtra("wifi_password") ?: "" + startActivity(Intent(this, SetNameActivity::class.java).apply { + putExtra("wifi_name", wifiName) + putExtra("wifi_password", wifiPassword) + }) finish() }, 1000) // 1秒后跳转 } diff --git a/app/src/main/java/com/example/defenseapplication/home/SetNameActivity.kt b/app/src/main/java/com/example/defenseapplication/home/SetNameActivity.kt index 23a8440..9ff24c1 100644 --- a/app/src/main/java/com/example/defenseapplication/home/SetNameActivity.kt +++ b/app/src/main/java/com/example/defenseapplication/home/SetNameActivity.kt @@ -2,14 +2,24 @@ package com.example.defenseapplication.home import android.content.Intent import android.os.Bundle +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import com.example.defenseapplication.bean.AddDeviceBean +import com.example.defenseapplication.bean.DeviceBean import com.example.defenseapplication.databinding.SetNameActivityBinding import com.example.defenseapplication.liveVideo.LiveVideoActivity +import com.example.defenseapplication.utils.RetrofitNetwork import com.gyf.immersionbar.ImmersionBar -//设置名字页面 +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + class SetNameActivity : AppCompatActivity() { private lateinit var binding: SetNameActivityBinding + private var wifiName: String = "" + private var wifiPassword: String = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -19,12 +29,49 @@ class SetNameActivity : AppCompatActivity() { .statusBarDarkFont(true) .titleBar(binding.topBar) .init() + + // 获取传递的 WiFi 名称和密码 + wifiName = intent.getStringExtra("wifi_name") ?: "" + wifiPassword = intent.getStringExtra("wifi_password") ?: "" + binding.ivBack.setOnClickListener { finish() } + binding.btnConfirm.setOnClickListener { val deviceName = binding.etName.text.toString().trim() - startActivity(Intent(this, LiveVideoActivity::class.java).apply {}) + if (deviceName.isEmpty()) { + Toast.makeText(this, "请输入设备名称", Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + addDevice(deviceName) + } + } + + private fun addDevice(deviceName: String) { + CoroutineScope(Dispatchers.IO).launch { + try { + val deviceBean = AddDeviceBean( + deviceName = deviceName, + wifiName = wifiName, + wifiPassword = wifiPassword, + status = "0" + ) + val result = RetrofitNetwork.getNetworkService().addDevice(deviceBean) + withContext(Dispatchers.Main) { + if (result.code == 200) { + Toast.makeText(this@SetNameActivity, "设备添加成功", Toast.LENGTH_SHORT).show() + startActivity(Intent(this@SetNameActivity, LiveVideoActivity::class.java)) + finish() + } else { + Toast.makeText(this@SetNameActivity, result.msg ?: "添加失败", Toast.LENGTH_SHORT).show() + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + Toast.makeText(this@SetNameActivity, "网络请求失败", Toast.LENGTH_SHORT).show() + } + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt b/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt index dd47508..5e9801f 100644 --- a/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt +++ b/app/src/main/java/com/example/defenseapplication/utils/ApiService.kt @@ -8,6 +8,7 @@ import com.example.defenseapplication.bean.GetCodeBean import bean.LoginBean import bean.LoginRequest import bean.RegisterRequest +import com.example.defenseapplication.bean.AddDeviceBean import com.example.defenseapplication.bean.AddDeviceUserRequest import com.example.defenseapplication.bean.DeleteBean import com.example.defenseapplication.bean.DeleteDeviceUserRequest @@ -73,6 +74,13 @@ interface ApiService { @GET("/app/appMessage/list") suspend fun getMessage(): GetCodeBean> + + /** + * 添加设备并绑定家庭 + */ + @POST("/app/addDevice") + suspend fun addDevice(@Body deviceBean: AddDeviceBean): GetCodeBean + /** * 修改设备信息 */