新增蓝牙

This commit is contained in:
yuqian 2025-12-29 18:27:17 +08:00
parent a59073b0af
commit 5743722fe2
8 changed files with 692 additions and 274 deletions

View File

@ -4,6 +4,14 @@
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" /> <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<application <application
android:name=".MyApplication" android:name=".MyApplication"

View File

@ -1,12 +1,20 @@
package com.xyzshell.myphoneinfo.dashboard package com.xyzshell.myphoneinfo.dashboard
import android.bluetooth.BluetoothAdapter
import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer
import android.provider.Settings
import android.text.format.Formatter import android.text.format.Formatter
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import com.xyzshell.andinfo.AndInfo import com.xyzshell.andinfo.AndInfo
import com.xyzshell.andinfo.libs.CpuInfo import com.xyzshell.andinfo.libs.CpuInfo
import com.xyzshell.myphoneinfo.R import com.xyzshell.myphoneinfo.R
@ -21,14 +29,35 @@ import kotlin.math.roundToInt
class HardWareFragment : Fragment() { class HardWareFragment : Fragment() {
private lateinit var binding: FragmentHardWareBinding private lateinit var binding: FragmentHardWareBinding
private var dialogBlueTooth: DialogBlueTooth? = null private var dialogBlueTooth: DialogBlueTooth? = null
private var dialogNearBlueTooth: DialogBlueTooth? = null
private var dialogInput: DialogInput? = null private var dialogInput: DialogInput? = null
private var dialogExtension: DialogExtension? = null private var dialogExtension: DialogExtension? = null
private var dialogDiskPart: DialogDiskPart? = null private var dialogDiskPart: DialogDiskPart? = null
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val allGranted = permissions.all { it.value }
if (allGranted) {
// 权限已授予,刷新蓝牙信息
refreshBluetoothInfo()
} else {
// 显示权限被拒绝的UI
// showPermissionDeniedUI()
Toast.makeText(requireContext(), "权限被拒绝", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
override fun onResume() {
super.onResume()
checkAndDisplayBluetoothInfo()
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@ -40,11 +69,6 @@ class HardWareFragment : Fragment() {
var intent = Intent(requireContext(), AnalysisActivity::class.java) var intent = Intent(requireContext(), AnalysisActivity::class.java)
startActivity(intent) startActivity(intent)
} }
binding.bluetoothLayout.pair1.setOnClickListener {
dialogBlueTooth= dialogBlueTooth?: DialogBlueTooth()
println("showBluetoothDialog"+AndInfo.instance.bluetooth.bondedDevices.size)
dialogBlueTooth?.show(childFragmentManager, "BlueTooth1")
}
// binding.pair2.setOnClickListener { // binding.pair2.setOnClickListener {
// dialogBlueTooth= dialogBlueTooth?: DialogBlueTooth() // dialogBlueTooth= dialogBlueTooth?: DialogBlueTooth()
// dialogBlueTooth?.show(childFragmentManager, "BlueTooth2") // dialogBlueTooth?.show(childFragmentManager, "BlueTooth2")
@ -65,46 +89,141 @@ class HardWareFragment : Fragment() {
} }
private fun initText() { private fun initText() {
val cpu = AndInfo.instance.cpu//cpu信息
val device = AndInfo.instance.device//设备信息 val device = AndInfo.instance.device//设备信息
setProcessorInfo()
setGpuInfo()
setDisplayInfo()
setMemoryInfo()
setBlueToothInfo()
setAudioInfo()
}
/**
* Audio信息
* */
private fun setAudioInfo() {
binding.check1.content.text = getString(R.string.low_audio)
binding.check2.content.text = getString(R.string.pro_audio)
binding.check3.content.text = getString(R.string.midl)
}
/**
* memory信息
* */
private fun setMemoryInfo() {
val storageInfo = AndInfo.instance.storage//存储信息
val used =
Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageUsedSpace)
val free = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.internalStorageAvailableSpace
)
val total = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.internalStorageTotalSpace
)
val outused = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.externalStorageUsedSpace ?: 0
)
val outfree = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.externalStorageAvailableSpace ?: 0
)
val outtotal = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.externalStorageTotalSpace ?: 0
)
binding.memoryLayout.memText1.textTitle.text = getString(R.string.ram_size)
binding.memoryLayout.memText1.textContent.text = total
binding.memoryLayout.ram1.text = used + " used"
binding.memoryLayout.ram2.text = free + " free"
binding.memoryLayout.seekbar.progress =
(used.substringBefore(" ").toDouble() / total.substringBefore(" ").toDouble() * 100).toInt()
//storage
binding.memoryLayout.memText3.textTitle.text = getString(R.string.zram)
binding.memoryLayout.memText3.textContent.text = Formatter.formatFileSize(
AndInfo.instance.context,
storageInfo.internalStorageTotalSpace
)
binding.memoryLayout.ram3.text = outused + " used"
binding.memoryLayout.ram4.text = outfree + " free"
binding.memoryLayout.seekbar2.progress =
(outused.substringBefore(" ").toDouble() / outtotal.substringBefore(" ").toDouble() * 100).toInt()
//fileSystem
binding.memoryLayout.storText1.textTitle.text = getString(R.string.filesystem)
binding.memoryLayout.storText1.textContent.text = total
binding.memoryLayout.stor1.text = used + " used"
binding.memoryLayout.stor2.text = free + " free"
binding.memoryLayout.radius1.text = used
binding.memoryLayout.radius2.text = used
binding.memoryLayout.radius3.text = free
binding.memoryLayout.seekbar3.progress =
(used.substringBefore(" ").toDouble() / total.substringBefore(" ").toDouble() * 100).toInt()
//internalStorage
binding.memoryLayout.interText1.textTitle.text = getString(R.string.filesystem)
binding.memoryLayout.interText1.textContent.text =
storageInfo.internalStorageEncryptionType.toString()
binding.memoryLayout.interText2.textTitle.text = getString(R.string.block_size)
binding.memoryLayout.interText2.textContent.text = total
binding.memoryLayout.interText3.textTitle.text = "/data"
binding.memoryLayout.interText3.textContent.text = total
binding.memoryLayout.stor3.text = used + " used"
binding.memoryLayout.stor4.text = free + " free"
binding.memoryLayout.seekbar2.progress =
(used.substringBefore(" ").toDouble() / total.substringBefore(" ").toDouble() * 100).toInt()
}
/**
* display信息
* */
private fun setDisplayInfo() {
val display = AndInfo.instance.display//显示信息
val defaultDisplayInfo = display.getDefaultDisplayInfo()
val width = defaultDisplayInfo?.widthPixels.toString()
val height = defaultDisplayInfo?.heightPixels.toString()
if (defaultDisplayInfo != null) {
binding.disText1.textContent.text = width + "x" + height
}
binding.disText1.textTitle.text = getString(R.string.resolution)
binding.disText2.textTitle.text = getString(R.string.screen_density)//这个是px
binding.disText2.textContent.text = defaultDisplayInfo?.ppi.toString()
binding.disText3.textTitle.text = getString(R.string.screen_density_d)
val dpiStr =
defaultDisplayInfo?.densityDpi.toString() + "(xxhdpi)\n" + defaultDisplayInfo?.xdpi?.roundToInt() + "dpx" + defaultDisplayInfo?.ydpi?.roundToInt() + "dp"
binding.disText3.textContent.text = dpiStr
binding.disText4.textTitle.text = getString(R.string.screen_size_e)
binding.disText5.textTitle.text = getString(R.string.aspect_ratio)
binding.disText5.textContent.text = convertToApproximateAspectRatio(
width = width.toInt(),
height = height.toInt()
).toString()
binding.disText6.textTitle.text = getString(R.string.refresh_rate)
binding.disText6.textContent.text = defaultDisplayInfo?.refreshRate.toString() + "HZ"
binding.disText7.textTitle.text = getString(R.string.wide_color_gamut)
binding.disText7.textContent.text = defaultDisplayInfo?.isWideColorGamut.toString()
binding.disText8.textTitle.text = getString(R.string.hdr_support)
if (defaultDisplayInfo?.isHdr == true) {
defaultDisplayInfo.hdrTypes.joinToString()
binding.disText8.textContent.text = defaultDisplayInfo.hdrTypes.joinToString()
} else {
binding.disText8.textContent.text = "No"
}
}
/**
* gpu信息*/
private fun setGpuInfo() {
val gpu = AndInfo.instance.gpu//gpu信息 val gpu = AndInfo.instance.gpu//gpu信息
//processor
//处理器
binding.text0.textTitle.text = getString(R.string.processor)
binding.text0.textContent.text= cpu.getProcessorName()
//制造商
binding.text1.textTitle.text = getString(R.string.vendor)
binding.text1.textContent.text=cpu.getVendor()
//硬件
binding.text2.textTitle.text = getString(R.string.hardware)
binding.text2.textContent.text=cpu.getProcessorName()
//核心数
binding.text3.textTitle.text = getString(R.string.cores)
binding.text3.textContent.text=cpu.cores.size.toString()
//cpu内核详情
binding.text4.textTitle.text = getString(R.string.CPU)
binding.text4.textContent.text=cpu.getAllArchitectures().joinToString()
//制程工艺
binding.text5.textTitle.text = getString(R.string.process)
binding.text5.textContent.text=cpu.getProcessInfo().process
//架构
binding.text6.textTitle.text = getString(R.string.architecture)
binding.text6.textContent.text=cpu.getArchitecture()
//ABI
binding.text7.textTitle.text = getString(R.string.ABI)
binding.text7.textContent.text=cpu.getAbi()
//supported_ABls
binding.text8.textTitle.text = getString(R.string.supported_ABls)
binding.text8.textContent.text=cpu.getSupportedAbis().joinToString()
//频率
binding.text9.textTitle.text = getString(R.string.frequencies)
binding.text9.textContent.text=cpu.getFrequencyText()
//gpu
binding.gpuText1.textTitle.text = getString(R.string.vendor) binding.gpuText1.textTitle.text = getString(R.string.vendor)
binding.gpuText1.textContent.text = gpu.getVendorName() binding.gpuText1.textContent.text = gpu.getVendorName()
binding.gpuText2.textTitle.text = getString(R.string.gpu) binding.gpuText2.textTitle.text = getString(R.string.gpu)
@ -137,101 +256,209 @@ class HardWareFragment : Fragment() {
binding.openItem1.text = gpu.getVendorName() binding.openItem1.text = gpu.getVendorName()
binding.openItem2.text = gpu.getRendererName() binding.openItem2.text = gpu.getRendererName()
binding.openItem3.text = gpu.getOpenGLVersion() binding.openItem3.text = gpu.getOpenGLVersion()
//display
val display=AndInfo.instance.display//显示信息
val defaultDisplayInfo = display.getDefaultDisplayInfo()
val width = defaultDisplayInfo?.widthPixels.toString()
val height = defaultDisplayInfo?.heightPixels.toString()
if(defaultDisplayInfo!=null){
binding.disText1.textContent.text=width+"x"+height
} }
binding.disText1.textTitle.text=getString(R.string.resolution)
binding.disText2.textTitle.text=getString(R.string.screen_density)//这个是px
binding.disText2.textContent.text=defaultDisplayInfo?.ppi.toString()
binding.disText3.textTitle.text=getString(R.string.screen_density_d)
val dpiStr=defaultDisplayInfo?.densityDpi.toString()+"(xxhdpi)\n"+defaultDisplayInfo?.xdpi?.roundToInt()+"dpx"+defaultDisplayInfo?.ydpi?.roundToInt()+"dp"
binding.disText3.textContent.text=dpiStr
binding.disText4.textTitle.text=getString(R.string.screen_size_e)
binding.disText5.textTitle.text=getString(R.string.aspect_ratio) /**
binding.disText5.textContent.text=convertToApproximateAspectRatio(width = width.toInt(), height = height.toInt()).toString() * processor信息*/
binding.disText6.textTitle.text=getString(R.string.refresh_rate) private fun setProcessorInfo() {
binding.disText6.textContent.text=defaultDisplayInfo?.refreshRate.toString()+"HZ" val cpu = AndInfo.instance.cpu//cpu信息
binding.disText7.textTitle.text=getString(R.string.wide_color_gamut) //处理器
binding.disText7.textContent.text=defaultDisplayInfo?.isWideColorGamut.toString() binding.text0.textTitle.text = getString(R.string.processor)
binding.disText8.textTitle.text=getString(R.string.hdr_support) binding.text0.textContent.text = cpu.getProcessorName()
if(defaultDisplayInfo?.isHdr == true){ //制造商
defaultDisplayInfo.hdrTypes.joinToString() binding.text1.textTitle.text = getString(R.string.vendor)
binding.disText8.textContent.text= defaultDisplayInfo.hdrTypes.joinToString() binding.text1.textContent.text = cpu.getVendor()
//硬件
binding.text2.textTitle.text = getString(R.string.hardware)
binding.text2.textContent.text = cpu.getProcessorName()
//核心数
binding.text3.textTitle.text = getString(R.string.cores)
binding.text3.textContent.text = cpu.cores.size.toString()
//cpu内核详情
binding.text4.textTitle.text = getString(R.string.CPU)
binding.text4.textContent.text = cpu.getAllArchitectures().joinToString()
//制程工艺
binding.text5.textTitle.text = getString(R.string.process)
binding.text5.textContent.text = cpu.getProcessInfo().process
//架构
binding.text6.textTitle.text = getString(R.string.architecture)
binding.text6.textContent.text = cpu.getArchitecture()
//ABI
binding.text7.textTitle.text = getString(R.string.ABI)
binding.text7.textContent.text = cpu.getAbi()
//supported_ABls
binding.text8.textTitle.text = getString(R.string.supported_ABls)
binding.text8.textContent.text = cpu.getSupportedAbis().joinToString()
//频率
binding.text9.textTitle.text = getString(R.string.frequencies)
binding.text9.textContent.text = cpu.getFrequencyText()
}
/**
* bluetooth相关信息*/
private fun setBlueToothInfo() {
val bluetoothInfo = AndInfo.instance.bluetooth//蓝牙信息
if (!bluetoothInfo.isEnabled) return
binding.bluetoothLayout.showLayout.setOnClickListener {
requestBluetoothPermissions()
}
binding.bluetoothLayout.pair1.setOnClickListener {
showPairedDevicesDialog()
}
// 打开弹窗开始扫描超过15s扫描超时结束显示扫描到的列表
binding.bluetoothLayout.pair2.setOnClickListener {
showNearByDevicesDialog()
}
}
// 请求蓝牙权限的方法
private fun requestBluetoothPermissions() {
val permissions = AndInfo.instance.bluetooth.requiredPermissions
requestPermissionLauncher.launch(permissions)
}
// 检查权限的方法
private fun checkBluetoothPermissions(): Boolean {
val bluetoothInfo = AndInfo.instance.bluetooth
return bluetoothInfo.requiredPermissions.all { permission ->
ActivityCompat.checkSelfPermission(requireContext(), permission) ==
PackageManager.PERMISSION_GRANTED
}
}
/**
* 检查并显示蓝牙信息
*/
private fun checkAndDisplayBluetoothInfo() {
val bluetoothInfo = AndInfo.instance.bluetooth
// 1. 检查权限
val hasPermissions = checkBluetoothPermissions()
if (!hasPermissions) {
// 没有权限显示权限请求UI
binding.bluetoothLayout.showLayout.visibility = View.VISIBLE
binding.bluetoothLayout.blueList.visibility = View.GONE
return
}
// 2. 检查蓝牙是否可用
if (!bluetoothInfo.isEnabled) {
// 蓝牙未启用,显示提示
showBluetoothDisabledUI()
return
}
// 3. 有权限且蓝牙已启用,显示蓝牙信息
binding.bluetoothLayout.showLayout.visibility = View.GONE
binding.bluetoothLayout.blueList.visibility = View.VISIBLE
// 刷新蓝牙信息
refreshBluetoothInfo()
}
/**
* 显示蓝牙未启用的UI
*/
private fun showBluetoothDisabledUI() {
binding.bluetoothLayout.showLayout.visibility = View.VISIBLE
binding.bluetoothLayout.blueList.visibility = View.GONE
// 更新UI文本
binding.bluetoothLayout.showText.text = "Bluetooth is not enabled."
// 设置打开蓝牙按钮
binding.bluetoothLayout.show1.setOnClickListener {
openBluetoothSettings()
}
}
/**
* 显示已配对设备弹窗
*/
private fun showPairedDevicesDialog() {
dialogBlueTooth = dialogBlueTooth ?: DialogBlueTooth()
println("showBluetoothDialog" + AndInfo.instance.bluetooth.bondedDevices.size)
dialogBlueTooth?.show(childFragmentManager, "BlueTooth1")
}
/**
* 显示扫描到附近设备弹窗
*/
private fun showNearByDevicesDialog() {
// 检查权限
if (!checkBluetoothPermissions()) {
Toast.makeText(requireContext(), "需要蓝牙权限", Toast.LENGTH_SHORT).show()
return
}
// 检查蓝牙是否启用
if (!AndInfo.instance.bluetooth.isEnabled) {
Toast.makeText(requireContext(), "请先开启蓝牙", Toast.LENGTH_SHORT).show()
return
}
dialogNearBlueTooth = dialogNearBlueTooth ?: DialogBlueTooth()
println("showBluetoothDialog" + AndInfo.instance.bluetooth.bondedDevices.size)
dialogNearBlueTooth?.show(childFragmentManager, "BlueTooth2")
}
/**
* 刷新蓝牙信息
*/
private fun refreshBluetoothInfo() {
val bluetoothInfo = AndInfo.instance.bluetooth
// 更新基本信息
// binding.blueList.tvBluetoothStatus.text = bluetoothInfo.stateText
// binding.blueList.tvBluetoothStatus.setTextColor(
// when (bluetoothInfo.state) {
// BluetoothAdapter.STATE_ON -> ContextCompat.getColor(requireContext(), R.color.success_green)
// else -> ContextCompat.getColor(requireContext(), R.color.error_red)
// }
// )
//
// binding.blueList.tvBluetoothAdapter.text = bluetoothInfo.adapterName ?: "未知"
// binding.blueList.tvBluetoothVersion.text = bluetoothInfo.getBluetoothVersionDetails()
// binding.blueList.tvBleSupport.text = if (bluetoothInfo.isBluetoothLeSupported) "支持" else "不支持"
// 更新已配对设备数量
// val pairedCount = bluetoothInfo.bondedDevices.size
// binding.blueList.tvPairedCount.text = "已配对: ${pairedCount}个设备"
}
/**
* 打开蓝牙设置
*/
private fun openBluetoothSettings() {
try {
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(intent, REQUEST_ENABLE_BT)
} catch (e: ActivityNotFoundException) {
// 尝试其他方式打开设置
val intent = Intent(Settings.ACTION_BLUETOOTH_SETTINGS)
if (intent.resolveActivity(requireActivity().packageManager) != null) {
startActivity(intent)
}
}
}
/**
* 权限检查结果回调
*/
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
// 权限已授予刷新UI
checkAndDisplayBluetoothInfo()
} else { } else {
binding.disText8.textContent.text= "No" Toast.makeText(requireContext(), "Bluetooth permission is required.", Toast.LENGTH_SHORT).show()
} }
//memory
val storageInfo = AndInfo.instance.storage//存储信息
val used=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageUsedSpace)
val free=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageAvailableSpace)
val total=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageTotalSpace)
val outused=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.externalStorageUsedSpace?: 0)
val outfree=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.externalStorageAvailableSpace?: 0)
val outtotal=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.externalStorageTotalSpace?: 0)
binding.memoryLayout.memText1.textTitle.text=getString(R.string.ram_size)
binding.memoryLayout.memText1.textContent.text=total
binding.memoryLayout.ram1.text=used+" used"
binding.memoryLayout.ram2.text=free+" free"
binding.memoryLayout.seekbar.progress=(used.substring(0,used.indexOf(" ")).toDouble() / total.substring(0,total.indexOf(" ")).toDouble() *100).toInt()
//storage
binding.memoryLayout.memText3.textTitle.text=getString(R.string.zram)
binding.memoryLayout.memText3.textContent.text=Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageTotalSpace)
binding.memoryLayout.ram3.text=outused+" used"
binding.memoryLayout.ram4.text=outfree+" free"
binding.memoryLayout.seekbar2.progress=(outused.substring(0,outused.indexOf(" ")).toDouble() / outtotal.substring(0,outtotal.indexOf(" ")).toDouble() *100).toInt()
//fileSystem
binding.memoryLayout.storText1.textTitle.text=getString(R.string.filesystem)
binding.memoryLayout.storText1.textContent.text=total
binding.memoryLayout.stor1.text=used+" used"
binding.memoryLayout.stor2.text=free+" free"
binding.memoryLayout.radius1.text=used
binding.memoryLayout.radius2.text=used
binding.memoryLayout.radius3.text=free
binding.memoryLayout.seekbar3.progress=(used.substring(0,used.indexOf(" ")).toDouble() / total.substring(0,total.indexOf(" ")).toDouble() *100).toInt()
//internalStorage
binding.memoryLayout.interText1.textTitle.text=getString(R.string.filesystem)
binding.memoryLayout.interText1.textContent.text=storageInfo.internalStorageEncryptionType.toString()
binding.memoryLayout.interText2.textTitle.text=getString(R.string.block_size)
binding.memoryLayout.interText2.textContent.text=total
binding.memoryLayout.interText3.textTitle.text="/data"
binding.memoryLayout.interText3.textContent.text=total
binding.memoryLayout.stor3.text=used+" used"
binding.memoryLayout.stor4.text=free+" free"
binding.memoryLayout.seekbar2.progress=(used.substring(0,used.indexOf(" ")).toDouble() / total.substring(0,total.indexOf(" ")).toDouble() *100).toInt()
//Audio
binding.check1.content.text=getString(R.string.low_audio)
binding.check2.content.text=getString(R.string.pro_audio)
binding.check3.content.text=getString(R.string.midl)
} }
companion object { companion object {
private const val REQUEST_ENABLE_BT = 1001
@JvmStatic @JvmStatic
fun newInstance() = fun newInstance() =
HardWareFragment().apply { HardWareFragment().apply {

View File

@ -1,18 +1,21 @@
package com.xyzshell.myphoneinfo.dialog package com.xyzshell.myphoneinfo.dialog
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.compose.material3.Text import androidx.compose.material3.Text
import com.xyzshell.andinfo.AndInfo import com.xyzshell.andinfo.AndInfo
import com.xyzshell.myphoneinfo.R import com.xyzshell.myphoneinfo.R
import com.xyzshell.myphoneinfo.base.BaseDialogFragment import com.xyzshell.myphoneinfo.base.BaseDialogFragment
import com.xyzshell.myphoneinfo.databinding.DialogBlueToothBinding import com.xyzshell.myphoneinfo.databinding.DialogBlueToothBinding
class DialogBlueTooth :BaseDialogFragment<DialogBlueToothBinding>(DialogBlueToothBinding::inflate){ class DialogBlueTooth(val type:Int) :BaseDialogFragment<DialogBlueToothBinding>(DialogBlueToothBinding::inflate){
private var isScanning = false
private var scanTimer: CountDownTimer? = null
override fun getTitle(): String = resources.getString(R.string.bluetooth) override fun getTitle(): String = resources.getString(R.string.bluetooth)
override fun getIconRes(): Int=5 override fun getIconRes(): Int=5
@ -20,16 +23,18 @@ class DialogBlueTooth :BaseDialogFragment<DialogBlueToothBinding>(DialogBlueToot
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val bluetoothInfo = AndInfo.instance.bluetooth val bluetoothInfo = AndInfo.instance.bluetooth
val list=ArrayList<Map<String, String>>() val list= bluetoothInfo.getBondedDevicesInfo()
bluetoothInfo.bondedDevices.forEach { (name, address) ->
val deviceMap = mapOf(
"name" to (name ?: "Unknown device"),
"address" to (address ?: "")
)
list.add(deviceMap)
}
val container = binding.view as? ViewGroup
// ArrayList<Map<String, String>>()
// bluetoothInfo.bondedDevices.forEach { (name, address) ->
// val deviceMap = mapOf(
// "name" to (name ?: "Unknown device"),
// "address" to (address ?: "")
// )
// list.add(deviceMap)
// }
if(type==0){// 显示已配对设备列表
val container = binding.view as? ViewGroup
container?.let { container?.let {
// 遍历 list为每个设备创建 item view // 遍历 list为每个设备创建 item view
if(list.isEmpty()){ if(list.isEmpty()){
@ -46,24 +51,124 @@ class DialogBlueTooth :BaseDialogFragment<DialogBlueToothBinding>(DialogBlueToot
val tvName = itemView.findViewById<TextView>(R.id.textTitle) val tvName = itemView.findViewById<TextView>(R.id.textTitle)
val tvAddress = itemView.findViewById<TextView>(R.id.textContent) val tvAddress = itemView.findViewById<TextView>(R.id.textContent)
tvName.text = deviceMap["name"] tvName.text = deviceMap.name
tvAddress.text = deviceMap["address"] tvAddress.text = deviceMap.address
// 添加到容器 // 添加到容器
it.addView(itemView) it.addView(itemView)
} }
} }
} }
}else{// 显示扫描设备列表
// startScanning()
}
} }
// /**
// * 开始扫描设备
// */
// private fun startScanning() {
// if (isScanning) return
//
// val bluetoothInfo = AndInfo.instance.bluetooth
//
// // 显示扫描UI
// isScanning = true
// binding.view.visibility=View.GONE
// binding.progressbar.visibility=View.VISIBLE
//
// // 启动15秒倒计时
// startScanTimer(scanDialog)
//
// // 开始扫描
// try {
// // 同时扫描经典蓝牙和BLE设备
// bluetoothInfo.scanNearbyDevices(
// onDeviceFound = { device ->
// requireActivity().runOnUiThread {
// scanDialog.addDevice(device)
// }
// },
// onScanFinished = {
// requireActivity().runOnUiThread {
// stopScanning()
// scanDialog.scanFinished()
// }
// }
// )
//
// // 扫描BLE设备
// if (bluetoothInfo.isBluetoothLeSupported) {
// bluetoothInfo.scanLeDevices(
// onDeviceFound = { device ->
// requireActivity().runOnUiThread {
// scanDialog.addDevice(device)
// }
// },
// durationMillis = SCAN_DURATION
// )
// }
//
// } catch (e: SecurityException) {
// Toast.makeText(requireContext(), "蓝牙权限被拒绝", Toast.LENGTH_SHORT).show()
// stopScanning()
// }
// }
//
// /**
// * 启动扫描计时器
// */
// private fun startScanTimer(scanDialog: DialogScanDevices) {
// scanTimer = object : CountDownTimer(SCAN_DURATION, 1000) {
// override fun onTick(millisUntilFinished: Long) {
// val secondsLeft = millisUntilFinished / 1000
// binding.blueList.tvScanStatus.text =
// "正在扫描附近设备... ${secondsLeft}秒后结束"
//
// // 更新弹窗中的倒计时
// scanDialog.updateTimer(secondsLeft.toInt())
// }
//
// override fun onFinish() {
// stopScanning()
// scanDialog.scanFinished()
// }
// }.start()
// }
//
// /**
// * 停止扫描
// */
// private fun stopScanning() {
// if (!isScanning) return
//
// isScanning = false
//
// // 停止计时器
// scanTimer?.cancel()
// scanTimer = null
//
// // 隐藏扫描UI
// binding.blueList.scanLayout.visibility = View.GONE
//
// // 停止蓝牙扫描
// AndInfo.instance.bluetooth.stopScan()
// }
override fun onNegativeClick() { override fun onNegativeClick() {
super.onNegativeClick() super.onNegativeClick()
// stopScanning()
} }
override fun onPositiveClick() { override fun onPositiveClick() {
super.onPositiveClick() super.onPositiveClick()
// stopScanning()
}
override fun onPause() {
super.onPause()
// 停止扫描
// stopScanning()
} }
} }

View File

@ -88,7 +88,7 @@
android:padding="10dp" android:padding="10dp"
android:textColor="@color/white" android:textColor="@color/white"
android:text="@string/settings" android:text="@string/settings"
android:background="@drawable/hard_bg" android:background="@drawable/dialog_ok_bg"
android:visibility="gone" /> android:visibility="gone" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/text_ok" android:id="@+id/text_ok"

View File

@ -6,12 +6,31 @@
android:paddingVertical="20dp" android:paddingVertical="20dp"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout <LinearLayout
android:id="@+id/view" android:id="@+id/view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"/>
<LinearLayout
android:id="@+id/progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/module_title_color" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/scanning"/>
</LinearLayout> </LinearLayout>
</RelativeLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -31,11 +32,79 @@
android:layout_weight="1" /> android:layout_weight="1" />
<ImageView <ImageView
android:layout_width="23dp" android:id="@+id/blueSetting"
android:layout_height="23dp" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:src="@mipmap/setting" /> android:src="@mipmap/setting" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/showLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/showText"
style="@style/LeftContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bluetooth_support" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/show1"
style="@style/LeftContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:background="@drawable/hard_bg"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp"
android:text="@string/show"
android:textAlignment="center"
android:textColor="@color/module_title_color"
android:textSize="14sp"
tools:ignore="RelativeOverlap" />
</LinearLayout>
<LinearLayout
android:id="@+id/blueList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/pairText"
style="@style/LeftContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/paired_devices" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/pair1"
style="@style/LeftContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:background="@drawable/hard_bg"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp"
android:text="@string/show"
android:textAlignment="center"
android:textColor="@color/module_title_color"
android:textSize="14sp"
tools:ignore="RelativeOverlap" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -44,98 +113,87 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
style="@style/LeftContent" style="@style/LeftContent"
android:layout_width="150dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="27dp"
android:text="@string/paired_devices" /> android:text="@string/nearby_devices" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/pair1" android:id="@+id/pair2"
style="@style/LeftContent" style="@style/LeftContent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingHorizontal="12dp"
android:paddingVertical="8dp"
android:layout_marginTop="21dp" android:layout_marginTop="21dp"
android:background="@drawable/hard_bg" android:background="@drawable/hard_bg"
android:textStyle="normal" android:paddingHorizontal="12dp"
android:paddingVertical="8dp"
android:text="@string/show" android:text="@string/show"
android:textColor="@color/module_title_color"
android:textAlignment="center" android:textAlignment="center"
tools:ignore="RelativeOverlap" /> android:textColor="@color/module_title_color"
android:textSize="14sp" />
</LinearLayout> </LinearLayout>
<!-- <LinearLayout-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="15dp"-->
<!-- android:orientation="horizontal">-->
<!-- <com.google.android.material.textview.MaterialTextView--> <LinearLayout
<!-- style="@style/LeftContent"--> android:layout_width="match_parent"
<!-- android:layout_width="150dp"--> android:layout_height="wrap_content"
<!-- android:layout_height="27dp"--> android:orientation="vertical">
<!-- android:text="@string/nearby_devices" />-->
<!-- <View-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="1dp"-->
<!-- android:layout_weight="1"/>-->
<!-- <com.google.android.material.textview.MaterialTextView-->
<!-- android:id="@+id/pair2"-->
<!-- style="@style/LeftContent"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:paddingHorizontal="10dp"-->
<!-- android:text="@string/show"-->
<!-- tools:ignore="RelativeOverlap" />-->
<!-- </LinearLayout>-->
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
style="@style/TextHeavy20" style="@style/TextHeavy20"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="30dp" android:layout_marginTop="30dp"
android:textSize="16sp"
android:text="@string/bluetooth_4_features" android:text="@string/bluetooth_4_features"
android:textSize="16sp"
tools:ignore="RelativeOverlap" /> tools:ignore="RelativeOverlap" />
<include <include
android:id="@+id/blueCheck1" android:id="@+id/blueCheck1"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck2" android:id="@+id/blueCheck2"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck3" android:id="@+id/blueCheck3"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck4" android:id="@+id/blueCheck4"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
style="@style/TextHeavy20" style="@style/TextHeavy20"
android:textSize="16sp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="30dp" android:layout_marginTop="30dp"
android:text="@string/bluetooth_5_features" android:text="@string/bluetooth_5_features"
android:textSize="16sp"
tools:ignore="RelativeOverlap" /> tools:ignore="RelativeOverlap" />
<include <include
android:id="@+id/blueCheck01" android:id="@+id/blueCheck01"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck02" android:id="@+id/blueCheck02"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck03" android:id="@+id/blueCheck03"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck04" android:id="@+id/blueCheck04"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
<include <include
android:id="@+id/blueCheck05" android:id="@+id/blueCheck05"
layout="@layout/common_check_style" /> layout="@layout/common_check_style" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -442,7 +442,7 @@
android:text="@string/disk_partitions" /> android:text="@string/disk_partitions" />
<TextView <TextView
android:id="@+id/cpuBtn" android:id="@+id/cpuBtn"
style="@style/TextDialogSubTitle" style="@style/LeftContent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="21dp" android:layout_marginTop="21dp"

View File

@ -300,4 +300,5 @@
<string name="exposure_modes">Exposure modes</string> <string name="exposure_modes">Exposure modes</string>
<string name="autofocus_modes">Autofocus modes</string> <string name="autofocus_modes">Autofocus modes</string>
<string name="scene_modes">Scene modes</string> <string name="scene_modes">Scene modes</string>
<string name="scanning">Scanning...</string>
</resources> </resources>