WiFi管理

This commit is contained in:
2026-05-11 09:43:31 +08:00
parent 2c94ba767d
commit c91b646857
13 changed files with 501 additions and 35 deletions

View File

@@ -25,6 +25,9 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication"> android:theme="@style/Theme.DefenseApplication">
<activity
android:name=".liveVideo.AddLinkedUserActivity"
android:exported="false" />
<activity <activity
android:name=".liveVideo.WiFiManagementActivity" android:name=".liveVideo.WiFiManagementActivity"
android:exported="false" /> android:exported="false" />

View File

@@ -17,7 +17,7 @@ class AddDeviceAdapter(private val devices: List<Device>, private val onItemClic
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2) val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2)
val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2) // 注意:ID 要和布局中一致 val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2) // ID 要和布局中一致
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

View File

@@ -0,0 +1,37 @@
package com.example.defenseapplication.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.databinding.ItemAddLinkedUserBinding
data class UserItem(val name: String, val phone: String)
class AddLinkedUserAdapter(
private val data: List<UserItem>,
private val selectedIds: MutableSet<String>,
private val onItemClick: (String, Boolean) -> Unit
) : RecyclerView.Adapter<AddLinkedUserAdapter.ViewHolder>() {
inner class ViewHolder(val binding: ItemAddLinkedUserBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: UserItem) {
binding.tvUserName.text = "${item.name}-${item.phone}"
binding.cbSelect.isChecked = selectedIds.contains(item.phone)
binding.cbSelect.setOnClickListener {
val isChecked = binding.cbSelect.isChecked
onItemClick(item.phone, isChecked)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemAddLinkedUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(data[position])
}
override fun getItemCount(): Int = data.size
}

View File

@@ -0,0 +1,61 @@
package com.example.defenseapplication.liveVideo
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.defenseapplication.R
import com.example.defenseapplication.adapter.AddLinkedUserAdapter
import com.example.defenseapplication.adapter.UserItem
import com.example.defenseapplication.databinding.AddLinkedUserActivityBinding
import com.gyf.immersionbar.ImmersionBar
class AddLinkedUserActivity : AppCompatActivity() {
private lateinit var binding: AddLinkedUserActivityBinding
private val selectedPhoneSet = mutableSetOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = AddLinkedUserActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
.init()
initRecyclerView()
initListener()
}
private fun initRecyclerView() {
val mockData = listOf(
UserItem("王五", "13566666666"),
UserItem("赵六", "15733333333")
)
binding.rvAddLinkedUser.layoutManager = LinearLayoutManager(this)
binding.rvAddLinkedUser.adapter =
AddLinkedUserAdapter(mockData, selectedPhoneSet) { phone, isChecked ->
if (isChecked) {
selectedPhoneSet.add(phone)
} else {
selectedPhoneSet.remove(phone)
}
}
}
private fun initListener() {
binding.btnAddLinkedUser.setOnClickListener {
if (selectedPhoneSet.isEmpty()) {
Toast.makeText(this, getString(R.string.please_select_at_least_one_user), Toast.LENGTH_SHORT).show()
} else {
val message = getString(R.string.selected_users_voice, selectedPhoneSet.size)
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
binding.ivBack.setOnClickListener {
finish()
}
}
}

View File

@@ -12,7 +12,7 @@ import com.example.defenseapplication.adapter.LinkedUserAdapter
import com.example.defenseapplication.databinding.LinkedUserActivityBinding import com.example.defenseapplication.databinding.LinkedUserActivityBinding
import com.example.defenseapplication.view.CustomDialogFragmentText import com.example.defenseapplication.view.CustomDialogFragmentText
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
//关联用户页面
class LinkedUserActivity : AppCompatActivity() { class LinkedUserActivity : AppCompatActivity() {
private lateinit var binding: LinkedUserActivityBinding private lateinit var binding: LinkedUserActivityBinding
@@ -176,8 +176,8 @@ class LinkedUserActivity : AppCompatActivity() {
} }
binding.btnAddLinkedUser.setOnClickListener { binding.btnAddLinkedUser.setOnClickListener {
val intent = Intent(this, LinkedUserSearchActivity::class.java) val intent = Intent(this, AddLinkedUserActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SEARCH) startActivity(intent)
} }
} }

View File

@@ -78,8 +78,10 @@ class SettingsActivity : BaseActivity() {
val intent = Intent(this, LinkedUserActivity::class.java) val intent = Intent(this, LinkedUserActivity::class.java)
startActivity( intent) startActivity( intent)
} }
binding.itemWifiManage.setOnClickListener {
val intent = Intent(this, WiFiManagementActivity::class.java)
startActivity(intent)
}
} }
} }

View File

@@ -1,18 +1,36 @@
package com.example.defenseapplication.liveVideo package com.example.defenseapplication.liveVideo
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.net.wifi.ScanResult
import android.net.wifi.WifiManager
import android.os.Bundle import android.os.Bundle
import androidx.activity.enableEdgeToEdge import android.text.Editable
import android.text.TextWatcher
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.app.ActivityCompat
import androidx.core.view.WindowInsetsCompat import androidx.recyclerview.widget.LinearLayoutManager
import com.example.defenseapplication.R import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.DeviceInfoActivityBinding import com.example.defenseapplication.adapter.WifiListAdapter
import com.example.defenseapplication.databinding.LinkedUserActivityBinding import com.example.defenseapplication.databinding.DialogWifiListBinding
import com.example.defenseapplication.databinding.WifiManagementActivityBinding import com.example.defenseapplication.databinding.WifiManagementActivityBinding
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
class WiFiManagementActivity : AppCompatActivity() { class WiFiManagementActivity : AppCompatActivity() {
private lateinit var binding: WifiManagementActivityBinding private lateinit var binding: WifiManagementActivityBinding
private lateinit var wifiManager: WifiManager
private lateinit var wifiScanReceiver: BroadcastReceiver
private var popupWindow: PopupWindow? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = WifiManagementActivityBinding.inflate(layoutInflater) binding = WifiManagementActivityBinding.inflate(layoutInflater)
@@ -24,5 +42,118 @@ class WiFiManagementActivity : AppCompatActivity() {
binding.ivBack.setOnClickListener { binding.ivBack.setOnClickListener {
finish() finish()
} }
binding.btnSelectWifi.setOnClickListener {
showWifiListDialog()
}
binding.etWifiName.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
updateBottomButtonVisibility()
}
})
wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiScanReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
if (success) {
updateWifiList()
}
}
}
//点击确定成功失败吐司
binding.btnConfirm.setOnClickListener {
// if(){
// ToastUtils.showSuccess(this, getString(R.string.wifi_connection_success))
// }else{
// ToastUtils.showError(this, getString(R.string.wifi_connection_failed))
// }
}
}
private fun showWifiListDialog() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.CHANGE_WIFI_STATE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
1001)
return
}
if (!wifiManager.isWifiEnabled) {
wifiManager.isWifiEnabled = true
}
wifiManager.startScan()
val dialogBinding = DialogWifiListBinding.inflate(LayoutInflater.from(this))
popupWindow = PopupWindow(
dialogBinding.root,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
isFocusable = true
setBackgroundDrawable(null)
setOnDismissListener {
binding.maskView.visibility = android.view.View.GONE
}
showAtLocation(window.decorView, Gravity.BOTTOM, 0, 0)
}
binding.maskView.visibility = android.view.View.VISIBLE
dialogBinding.rvWifiList.layoutManager = LinearLayoutManager(this@WiFiManagementActivity)
val wifiList = getWifiList()
dialogBinding.rvWifiList.adapter = WifiListAdapter(wifiList) { wifiName ->
binding.etWifiName.setText(wifiName)
popupWindow?.dismiss()
}
}
private fun updateBottomButtonVisibility() {
val wifiName = binding.etWifiName.text.toString().trim()
binding.bottomButtonLayout.visibility =
if (wifiName.isNotEmpty()) android.view.View.VISIBLE else android.view.View.GONE
}
private fun getWifiList(): List<String> {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return emptyList()
}
val results: List<ScanResult> = wifiManager.scanResults
return results.map { it.SSID }.distinct()
}
private fun updateWifiList() {
popupWindow?.contentView?.findViewById<androidx.recyclerview.widget.RecyclerView>(R.id.rvWifiList)?.let { recyclerView ->
val wifiList = getWifiList()
recyclerView.adapter = WifiListAdapter(wifiList) { wifiName ->
binding.etWifiName.setText(wifiName)
popupWindow?.dismiss()
}
}
}
override fun onStart() {
super.onStart()
val intentFilter = IntentFilter()
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
registerReceiver(wifiScanReceiver, intentFilter)
}
override fun onStop() {
super.onStop()
unregisterReceiver(wifiScanReceiver)
popupWindow?.dismiss()
} }
} }

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/check_ellipse"/>
<item android:drawable="@drawable/ellipse"/>
</selector>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".liveVideo.AddLinkedUserActivity">
<!-- 标题栏 -->
<LinearLayout
android:id="@+id/topBar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical"
android:paddingHorizontal="16dp"
android:background="@color/white">
<ImageView
android:id="@+id/ivBack"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/back" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/linked_user"
android:textColor="@color/black"
android:textSize="16dp"
android:textStyle="bold" />
</LinearLayout>
<!-- 搜索区域 -->
<LinearLayout
android:id="@+id/searchLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp"
android:layout_marginTop="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/bg_user_manage"
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<ImageView
android:layout_width="18dp"
android:layout_height="18dp"
android:src="@drawable/search"
android:layout_marginRight="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search_preset_text"
android:textColor="@color/gray"
android:textSize="14sp"/>
</LinearLayout>
</LinearLayout>
<!-- 列表区域 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvAddLinkedUser"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingHorizontal="16dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"/>
<!-- 底部按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingBottom="60dp">
<android.widget.Button
android:id="@+id/btnAddLinkedUser"
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="@string/confirm"
android:textColor="@color/white"
android:textSize="14dp"
android:background="@drawable/rounded_blue_bg" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/white"
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<TextView
android:id="@+id/tvUserName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="@color/black"
android:textSize="16sp" />
<CheckBox
android:id="@+id/cbSelect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@drawable/check_box_selector" />
</LinearLayout>

View File

@@ -1,36 +1,141 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main" android:id="@+id/main"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:background="@color/white"
tools:context=".liveVideo.WiFiManagementActivity"> tools:context=".liveVideo.WiFiManagementActivity">
<!-- 标题栏 -->
<LinearLayout <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topBar" android:id="@+id/topBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="56dp" android:layout_height="56dp">
android:gravity="center_vertical"
android:paddingHorizontal="16dp">
<ImageView <ImageView
android:id="@+id/ivBack" android:id="@+id/ivBack"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:src="@drawable/back" /> android:layout_marginStart="16dp"
android:src="@drawable/back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:layout_width="0dp" android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/wiFi_management" android:text="@string/wiFi_management"
android:textColor="@color/black" android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@drawable/textinput_white_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="16dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_wifi" />
<EditText
android:id="@+id/etWifiName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_weight="1"
android:background="@null"
android:hint="@string/enter_wifi_name"
android:textColor="@color/black"
android:textSize="16sp" />
<android.widget.Button
android:id="@+id/btnSelectWifi"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:layout_marginStart="12dp"
android:background="@drawable/rounded_blue_bg"
android:text="@string/select_wifi"
android:textColor="@color/white"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="12dp"
android:background="@drawable/textinput_white_bg"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="16dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_lock" />
<EditText
android:id="@+id/etWifiPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:background="@null"
android:hint="@string/enter_wifi_password"
android:inputType="textPassword"
android:textColor="@color/black"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/maskView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000"
android:visibility="gone" />
<LinearLayout
android:id="@+id/bottomButtonLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:layout_marginBottom="60dp"
android:padding="16dp">
<android.widget.Button
android:id="@+id/btnConfirm"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/rounded_blue_bg"
android:text="@string/confirm"
android:textColor="@color/white"
android:textSize="16dp" android:textSize="16dp"
android:textStyle="bold" /> android:textStyle="bold" />
</LinearLayout> </LinearLayout>
</LinearLayout> </RelativeLayout>

View File

@@ -206,7 +206,8 @@
<string name="device_model">设备型号</string> <string name="device_model">设备型号</string>
<string name="auto_arms_start_time">自动布防开始时间</string> <string name="auto_arms_start_time">自动布防开始时间</string>
<string name="auto_arms_end_time">自动布防结束时间</string> <string name="auto_arms_end_time">自动布防结束时间</string>
<string name="please_select_at_least_one_user">请至少选择一个用户</string>
<string name="selected_users_voice">已选择 %d 个用户,语音</string>
<!-- Personal Profile --> <!-- Personal Profile -->
<string name="personal_info">个人信息</string> <string name="personal_info">个人信息</string>
@@ -231,8 +232,8 @@
<string name="enter_wifi_password">请输入WiFi密码</string> <string name="enter_wifi_password">请输入WiFi密码</string>
<string name="connect">连接</string> <string name="connect">连接</string>
<string name="connecting">连接中...</string> <string name="connecting">连接中...</string>
<string name="connection_failed">连接失败</string> <string name="wifi_connection_failed">WiFi连接失败</string>
<string name="connection_success">连接成功</string> <string name="wifi_connection_success">WiFi连接成功</string>
<!-- Dialog --> <!-- Dialog -->
<string name="tip">提示</string> <string name="tip">提示</string>

View File

@@ -181,6 +181,8 @@
<string name="device_model">Device model</string> <string name="device_model">Device model</string>
<string name="auto_arms_start_time">Auto arm start time</string> <string name="auto_arms_start_time">Auto arm start time</string>
<string name="auto_arms_end_time">Auto arm End time</string> <string name="auto_arms_end_time">Auto arm End time</string>
<string name="please_select_at_least_one_user">Please select at least one user</string>
<string name="selected_users_voice">%d user(s) selected, voice</string>
<!-- Personal Profile --> <!-- Personal Profile -->
@@ -203,8 +205,8 @@
<string name="enter_wifi_password">Enter WiFi password</string> <string name="enter_wifi_password">Enter WiFi password</string>
<string name="connect">Connect</string> <string name="connect">Connect</string>
<string name="connecting">Connecting...</string> <string name="connecting">Connecting...</string>
<string name="connection_failed">Connection failed</string> <string name="wifi_connection_failed">WiFi Connection failed</string>
<string name="connection_success">Connected successfully</string> <string name="wifi_connection_success">WiFi Connected successfully</string>
<!-- Dialog --> <!-- Dialog -->
<string name="tip">Tip</string> <string name="tip">Tip</string>