新增viewmodel,修改完善hardware
This commit is contained in:
parent
d3de7d8907
commit
596daf5fcc
@ -6,12 +6,18 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.xyzshell.myphoneinfo.R
|
||||
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||
|
||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
protected lateinit var binding: VB
|
||||
protected val mainViewModel: MainViewModel by lazy {
|
||||
ViewModelProvider(this)[MainViewModel::class.java]
|
||||
}
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
@ -28,7 +34,9 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
protected abstract fun inflateBinding(inflater: LayoutInflater): VB
|
||||
|
||||
protected open fun initView() {}
|
||||
protected open fun initView() {
|
||||
mainViewModel
|
||||
}
|
||||
|
||||
protected open fun initData() {}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.xyzshell.myphoneinfo.custom
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
||||
object RefreshManager {
|
||||
private var isLoading = false
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var timeoutRunnable: Runnable? = null
|
||||
|
||||
/**
|
||||
* 开始刷新
|
||||
* @param swipeRefreshLayout 可选的 SwipeRefreshLayout,会自动显示刷新动画
|
||||
* @param timeoutMs 超时时间(毫秒),默认10秒
|
||||
* @param onTimeout 超时回调
|
||||
*/
|
||||
fun load(
|
||||
swipeRefreshLayout: SwipeRefreshLayout? = null,
|
||||
timeoutMs: Long = 10000L,
|
||||
onTimeout: (() -> Unit)? = null
|
||||
) {
|
||||
if (isLoading) return
|
||||
|
||||
isLoading = true
|
||||
swipeRefreshLayout?.isRefreshing = true
|
||||
|
||||
// 设置超时
|
||||
timeoutRunnable = Runnable {
|
||||
if (isLoading) {
|
||||
isLoading = false
|
||||
swipeRefreshLayout?.isRefreshing = false
|
||||
onTimeout?.invoke()
|
||||
}
|
||||
}
|
||||
handler.postDelayed(timeoutRunnable!!, timeoutMs)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止刷新
|
||||
* @param swipeRefreshLayout 可选的 SwipeRefreshLayout,会自动停止刷新动画
|
||||
*/
|
||||
fun stop(swipeRefreshLayout: SwipeRefreshLayout? = null) {
|
||||
if (!isLoading) return
|
||||
|
||||
isLoading = false
|
||||
timeoutRunnable?.let { handler.removeCallbacks(it) }
|
||||
timeoutRunnable = null
|
||||
swipeRefreshLayout?.isRefreshing = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否正在刷新
|
||||
*/
|
||||
fun isLoading(): Boolean = isLoading
|
||||
|
||||
/**
|
||||
* 安全的执行刷新操作(最简用法)
|
||||
* @param refreshAction 刷新逻辑
|
||||
* @param swipeRefreshLayout SwipeRefreshLayout
|
||||
* @param timeoutMs 超时时间
|
||||
*/
|
||||
fun safeRefresh(
|
||||
refreshAction: () -> Unit,
|
||||
swipeRefreshLayout: SwipeRefreshLayout,
|
||||
timeoutMs: Long = 10000L
|
||||
) {
|
||||
if (isLoading) return
|
||||
|
||||
load(swipeRefreshLayout, timeoutMs) {
|
||||
// 超时回调
|
||||
}
|
||||
|
||||
refreshAction()
|
||||
}
|
||||
}
|
||||
@ -6,16 +6,20 @@ import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.xyzshell.andinfo.AndInfo
|
||||
import com.xyzshell.andinfo.libs.AppDetails
|
||||
import com.xyzshell.myphoneinfo.R
|
||||
import com.xyzshell.myphoneinfo.adapter.AppListAdapter
|
||||
import com.xyzshell.myphoneinfo.custom.RefreshManager.load
|
||||
import com.xyzshell.myphoneinfo.custom.RefreshManager.stop
|
||||
import com.xyzshell.myphoneinfo.databinding.FragmentAppsBinding
|
||||
import com.xyzshell.myphoneinfo.dialog.AppDialogFragment
|
||||
import com.xyzshell.myphoneinfo.dialog.BottomDialogFragment
|
||||
import com.xyzshell.myphoneinfo.main.MainScrollActivity
|
||||
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@ -25,7 +29,9 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
||||
private lateinit var binding: FragmentAppsBinding
|
||||
private lateinit var dialogFragment: AppDialogFragment
|
||||
private lateinit var bottomDialog: BottomDialogFragment
|
||||
private val viewModel: MainViewModel by activityViewModels()
|
||||
private var sel: Int? = 0
|
||||
private var userSize=0
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
@ -34,17 +40,15 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
// Inflate the layout for this fragment
|
||||
binding = FragmentAppsBinding.inflate(inflater, container, false)
|
||||
val adapter= AppListAdapter()
|
||||
val installedApps = AndInfo.instance.app.getInstalledApps()
|
||||
val userSize=installedApps.size
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
delay(50) // 短暂延迟确保UI完成布局
|
||||
withContext(Dispatchers.Main) {
|
||||
adapter.setList(installedApps)
|
||||
binding = FragmentAppsBinding.inflate(inflater, container, false)
|
||||
viewModel.installedApps.observe(viewLifecycleOwner){
|
||||
appDetails ->
|
||||
stop(binding.swipeRefresh)
|
||||
adapter.setList(appDetails)
|
||||
userSize=appDetails.size
|
||||
}
|
||||
adapter.setOnclickListener(this@AppsFragment)
|
||||
}}
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.tvTitle.text=when(0){//todo replace with user/system/all/none
|
||||
@ -53,6 +57,10 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
||||
2 -> "All(23)"
|
||||
else -> "None"
|
||||
}
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
load(binding.swipeRefresh)
|
||||
viewModel.loadApps()
|
||||
}
|
||||
binding.llTitle.setOnClickListener {
|
||||
bottomDialog= BottomDialogFragment(type = "apps", sel = sel, invoke = {item->
|
||||
sel = item
|
||||
|
||||
@ -9,6 +9,7 @@ import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.provider.Settings
|
||||
import android.text.format.Formatter
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -16,8 +17,10 @@ import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import com.xyzshell.andinfo.AndInfo
|
||||
import com.xyzshell.andinfo.libs.CpuInfo
|
||||
import com.xyzshell.andinfo.libs.MemInfo
|
||||
import com.xyzshell.myphoneinfo.R
|
||||
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.convertToApproximateAspectRatio
|
||||
import com.xyzshell.myphoneinfo.databinding.FragmentHardWareBinding
|
||||
@ -25,6 +28,8 @@ import com.xyzshell.myphoneinfo.dialog.DialogBlueTooth
|
||||
import com.xyzshell.myphoneinfo.dialog.DialogDiskPart
|
||||
import com.xyzshell.myphoneinfo.dialog.DialogExtension
|
||||
import com.xyzshell.myphoneinfo.dialog.DialogInput
|
||||
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||
import kotlin.getValue
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class HardWareFragment : Fragment() {
|
||||
@ -34,6 +39,8 @@ class HardWareFragment : Fragment() {
|
||||
private var dialogInput: DialogInput? = null
|
||||
private var dialogExtension: DialogExtension? = null
|
||||
private var dialogDiskPart: DialogDiskPart? = null
|
||||
private val mainViewModel: MainViewModel by activityViewModels()
|
||||
|
||||
|
||||
private val requestPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
@ -59,6 +66,7 @@ class HardWareFragment : Fragment() {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
checkAndDisplayBluetoothInfo()
|
||||
mainViewModel.refreshHardwareInfo(requireContext())
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +76,7 @@ class HardWareFragment : Fragment() {
|
||||
): View? {
|
||||
binding = FragmentHardWareBinding.inflate(inflater, container, false)
|
||||
dialogExtension = dialogExtension ?: DialogExtension()
|
||||
initText()
|
||||
initView()
|
||||
binding.cpuBtn.setOnClickListener {
|
||||
var intent = Intent(requireContext(), AnalysisActivity::class.java)
|
||||
startActivity(intent)
|
||||
@ -84,7 +92,7 @@ class HardWareFragment : Fragment() {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun initText() {
|
||||
private fun initView() {
|
||||
setProcessorInfo()
|
||||
setGpuInfo()
|
||||
setDisplayInfo()
|
||||
@ -107,27 +115,31 @@ class HardWareFragment : Fragment() {
|
||||
* Input信息
|
||||
* */
|
||||
private fun setInputInfo() {
|
||||
val inputInfo = AndInfo.instance.input
|
||||
binding.otherCheck1.content.text = getString(R.string.usb_host_support)
|
||||
binding.otherCheck1.image.isSelected = inputInfo.hasUsbHostSupport()
|
||||
binding.otherCheck2.content.text = getString(R.string.usb_accessory_support)
|
||||
binding.otherCheck2.image.isSelected = inputInfo.hasUsbAccessorySupport()
|
||||
binding.otherCheck3.content.text = getString(R.string.fingerprint)
|
||||
binding.otherCheck3.image.isSelected = inputInfo.hasFingerprintSensor()
|
||||
binding.otherCheck4.content.text = getString(R.string.infrared_transmitter)
|
||||
binding.otherCheck4.image.isSelected = inputInfo.hasInfraredSensor()
|
||||
binding.otherCheck5.content.text = getString(R.string.uwb_support)
|
||||
binding.otherCheck5.image.isSelected = inputInfo.hasUwbSupport()
|
||||
binding.otherCheck6.content.text = getString(R.string.nfc_support)
|
||||
binding.otherCheck6.image.isSelected = inputInfo.hasNfcSupport()
|
||||
binding.otherCheck7.content.text = getString(R.string.secure_nfc_support)
|
||||
binding.otherCheck7.image.isSelected = inputInfo.hasSecureNfcSupport()
|
||||
binding.otherCheck8.content.text = getString(R.string.gps)
|
||||
binding.otherCheck8.image.isSelected = inputInfo.hasGpsSupport()
|
||||
binding.othertext.setOnClickListener {
|
||||
dialogInput = dialogInput ?: DialogInput()
|
||||
dialogInput?.show(childFragmentManager, "Input")
|
||||
}
|
||||
mainViewModel.input.observe(viewLifecycleOwner) { inputInfo ->
|
||||
inputInfo?.let {
|
||||
binding.otherCheck1.image.isSelected = inputInfo.hasUsbHostSupport()
|
||||
binding.otherCheck2.image.isSelected = inputInfo.hasUsbAccessorySupport()
|
||||
binding.otherCheck3.image.isSelected = inputInfo.hasFingerprintSensor()
|
||||
binding.otherCheck4.image.isSelected = inputInfo.hasInfraredSensor()
|
||||
binding.otherCheck5.image.isSelected = inputInfo.hasUwbSupport()
|
||||
binding.otherCheck6.image.isSelected = inputInfo.hasNfcSupport()
|
||||
binding.otherCheck7.image.isSelected = inputInfo.hasSecureNfcSupport()
|
||||
binding.otherCheck8.image.isSelected = inputInfo.hasGpsSupport()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -135,79 +147,111 @@ class HardWareFragment : Fragment() {
|
||||
* memory信息
|
||||
* */
|
||||
private fun setMemoryInfo() {
|
||||
val storageInfo = AndInfo.instance.storage//存储信息
|
||||
// 获取详细的存储分解
|
||||
val breakdown = storageInfo.getInternalStorageBreakdown()
|
||||
//内部存储器
|
||||
val interused = storageInfo.formatBytes(breakdown.usedSpace)
|
||||
val interfree = storageInfo.formatBytes(breakdown.freeSpace)
|
||||
val intertotal = storageInfo.formatBytes(breakdown.totalSpace)
|
||||
|
||||
mainViewModel.memInfo.observe(viewLifecycleOwner){memInfo ->
|
||||
memInfo?.let {
|
||||
//内存memory
|
||||
val memUsed = memInfo.formatBytes(memInfo.getMemoryInfo().usedRam)
|
||||
val memFree = memInfo.formatBytes(memInfo.getMemoryInfo().availableRam)
|
||||
val memTotal = memInfo.formatBytes(memInfo.getMemoryInfo().totalRam)
|
||||
val zramTotal = memInfo.formatBytes(memInfo.getMemoryInfo().zramTotal)
|
||||
val zramUsed = memInfo.formatBytes(memInfo.getMemoryInfo().zramUsed)
|
||||
val zramFree =
|
||||
memInfo.formatBytes(memInfo.getMemoryInfo().zramTotal - memInfo.getMemoryInfo().zramUsed)
|
||||
|
||||
//总存储信息
|
||||
val outused =Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageUsedSpace)
|
||||
val outfree = Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageAvailableSpace)
|
||||
val outtotal = Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageTotalSpace)
|
||||
|
||||
//内存:todo
|
||||
binding.memoryLayout.memText0.textTitle.text = getString(R.string.type)
|
||||
binding.memoryLayout.memText0.textContent.text = memInfo.getMemoryInfo().memType
|
||||
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()
|
||||
|
||||
//appsAndData
|
||||
val appsAndData = storageInfo.getFormattedAppsAndDataSize()
|
||||
val system = storageInfo.getFormattedSystemSize()
|
||||
val other= storageInfo.getFormattedFreeSpace()+storageInfo.getFormattedCacheSize()
|
||||
binding.memoryLayout.memText1.textContent.text = memTotal
|
||||
binding.memoryLayout.ram1.text = "$memUsed used"
|
||||
binding.memoryLayout.ram2.text = "$memFree free"
|
||||
binding.memoryLayout.seekbar.progress =
|
||||
(memUsed.substringBefore(" ").toDouble() / memTotal
|
||||
.substringBefore(" ")
|
||||
.toDouble() * 100).toInt()
|
||||
//zarm
|
||||
|
||||
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.memText3.textContent.text = zramTotal
|
||||
binding.memoryLayout.ram3.text = "$zramUsed used"
|
||||
binding.memoryLayout.ram4.text = "$zramFree free"
|
||||
binding.memoryLayout.seekbar2.progress =
|
||||
(outused.substringBefore(" ").toDouble() / outtotal.substringBefore(" ")
|
||||
(zramTotal.substringBefore(" ").toDouble() / zramTotal.substringBefore(" ")
|
||||
.toDouble() * 100).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//storage
|
||||
// 获取总存储详细的存储分解
|
||||
mainViewModel.storageInfo.observe(viewLifecycleOwner){storageInfo ->
|
||||
storageInfo?.let {
|
||||
val breakdown = storageInfo.getInternalStorageBreakdown()
|
||||
val stoUsed = storageInfo.formatBytes(breakdown.usedSpace)
|
||||
val stoFree = storageInfo.formatBytes(breakdown.freeSpace)
|
||||
val stoTotal = storageInfo.formatBytes(breakdown.totalSpace)
|
||||
//appsAndData
|
||||
val appsAndData = storageInfo.getFormattedAppsAndDataSize()
|
||||
val system = storageInfo.getFormattedSystemSize()
|
||||
val other = storageInfo.getFormattedFreeSpace()
|
||||
|
||||
binding.memoryLayout.storText1.textTitle.text = getString(R.string.size)
|
||||
binding.memoryLayout.storText1.textContent.text = outtotal
|
||||
binding.memoryLayout.stor1.text = outused + " used"
|
||||
binding.memoryLayout.stor2.text = outtotal + " total"
|
||||
binding.memoryLayout.storText1.textContent.text = stoTotal
|
||||
binding.memoryLayout.stor1.text = stoUsed + " used"
|
||||
binding.memoryLayout.stor2.text = stoTotal + " total"
|
||||
binding.memoryLayout.radius1.text = appsAndData
|
||||
binding.memoryLayout.radius2.text = system
|
||||
binding.memoryLayout.radius3.text = other
|
||||
binding.memoryLayout.seekbar3.progress =
|
||||
(outused.substringBefore(" ").toDouble() / outtotal.substringBefore(" ")
|
||||
(stoUsed.substringBefore(" ").toDouble() / stoTotal.substringBefore(" ")
|
||||
.toDouble() * 100).toInt()
|
||||
|
||||
|
||||
//internalStorage
|
||||
val interUsed = storageInfo.getInternalStorageBreakdown().usedSpace
|
||||
val interFree = storageInfo.getInternalStorageBreakdown().freeSpace
|
||||
|
||||
val interTotal = storageInfo.getInternalStorageBreakdown().totalSpace
|
||||
|
||||
binding.memoryLayout.interText1.textTitle.text = getString(R.string.filesystem)
|
||||
binding.memoryLayout.interText1.textContent.text =
|
||||
storageInfo.internalStorageEncryptionType.toString()
|
||||
storageInfo.internalStorageFileSystemType.toString()
|
||||
binding.memoryLayout.interText2.textTitle.text = getString(R.string.block_size)
|
||||
binding.memoryLayout.interText2.textContent.text = intertotal
|
||||
binding.memoryLayout.interText2.textContent.text = storageInfo.formatBytes(interTotal)
|
||||
binding.memoryLayout.interText3.textTitle.text = "/data"
|
||||
binding.memoryLayout.interText3.textContent.text = intertotal
|
||||
binding.memoryLayout.stor3.text = interused + " used"
|
||||
binding.memoryLayout.stor4.text = interfree + " free"
|
||||
binding.memoryLayout.seekbar2.progress =
|
||||
(interused.substringBefore(" ").toDouble() / intertotal.substringBefore(" ")
|
||||
.toDouble() * 100).toInt()
|
||||
binding.memoryLayout.interText3.textContent.text = storageInfo.formatBytes(storageInfo.dataDirectoryTotalSpace)
|
||||
binding.memoryLayout.stor3.text = "${storageInfo.formatBytes(interUsed)} used"
|
||||
binding.memoryLayout.stor4.text = "${storageInfo.formatBytes(interFree)} free"
|
||||
binding.memoryLayout.seekbar5.progress =
|
||||
(interUsed.toDouble() / interTotal.toDouble() * 100).toInt()
|
||||
storageInfo.abOtaPartitions?.forEach { text ->
|
||||
Log.d("TTTTTTTT","disk part:${text}")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* display信息
|
||||
* */
|
||||
private fun setDisplayInfo() {
|
||||
val display = AndInfo.instance.display//显示信息
|
||||
|
||||
binding.disText1.textTitle.text = getString(R.string.resolution)
|
||||
binding.disText2.textTitle.text = getString(R.string.screen_density)//这个是px
|
||||
|
||||
binding.disText3.textTitle.text = getString(R.string.screen_density_d)
|
||||
binding.disText4.textTitle.text = getString(R.string.screen_size_e)
|
||||
|
||||
|
||||
binding.disText5.textTitle.text = getString(R.string.aspect_ratio)
|
||||
|
||||
binding.disText6.textTitle.text = getString(R.string.refresh_rate)
|
||||
binding.disText7.textTitle.text = getString(R.string.wide_color_gamut)
|
||||
binding.disText8.textTitle.text = getString(R.string.hdr_support)
|
||||
mainViewModel.displayInfo.observe(viewLifecycleOwner) { display ->
|
||||
display?.let {
|
||||
val defaultDisplayInfo = display.getDefaultDisplayInfo()
|
||||
val width = defaultDisplayInfo?.widthPixels.toString()
|
||||
val height = defaultDisplayInfo?.heightPixels.toString()
|
||||
@ -216,26 +260,24 @@ class HardWareFragment : Fragment() {
|
||||
|
||||
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)
|
||||
val screenSize = "${String.format("%.2f", display.getScreenSize()?.diagonalInches)}/ ${String.format("%.1f", display.getScreenSize()?.diagonalMm)} mm"
|
||||
val screenSize = "${
|
||||
String.format(
|
||||
"%.2f",
|
||||
display.getScreenSize()?.diagonalInches
|
||||
)
|
||||
}/ ${String.format("%.1f", display.getScreenSize()?.diagonalMm)} mm"
|
||||
binding.disText4.textContent.text = screenSize
|
||||
binding.disText5.textTitle.text = getString(R.string.aspect_ratio)
|
||||
binding.disText5.textContent.text = convertToApproximateAspectRatio(
|
||||
width = width.toInt(),
|
||||
height = height.toInt()
|
||||
)
|
||||
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.disText6.textContent.text =
|
||||
defaultDisplayInfo?.refreshRate.toString() + "HZ"
|
||||
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()
|
||||
@ -243,125 +285,155 @@ class HardWareFragment : Fragment() {
|
||||
binding.disText8.textContent.text = "No"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gpu信息*/
|
||||
private fun setGpuInfo() {
|
||||
val gpu = AndInfo.instance.gpu//gpu信息
|
||||
binding.gpuText1.textTitle.text = getString(R.string.vendor)
|
||||
binding.gpuText1.textContent.text = gpu.getVendorName()
|
||||
binding.gpuText2.textTitle.text = getString(R.string.gpu)
|
||||
|
||||
|
||||
binding.gpuText3.textTitle.text = getString(R.string.max_frequency)
|
||||
binding.gpuText4.textTitle.text = getString(R.string.architecture)
|
||||
binding.gpuText5.textTitle.text = getString(R.string.cores)
|
||||
binding.gpuText6.textTitle.text = getString(R.string.total_l2)
|
||||
binding.gpuText7.textTitle.text = getString(R.string.bus_width)
|
||||
binding.gpuText8.textTitle.text = getString(R.string.vulkan_support)
|
||||
binding.gpuText9.textTitle.text = getString(R.string.vulkan_API)
|
||||
binding.open1.text = getString(R.string.opengl)
|
||||
mainViewModel.gpuInfo.observe(viewLifecycleOwner) { gpu ->
|
||||
gpu?.let {
|
||||
binding.gpuText1.textContent.text = gpu.getVendorName()
|
||||
gpu.getGpuInformation().vkPhysicalDevices?.let { devices ->
|
||||
if (devices.isNotEmpty()) {
|
||||
devices.forEachIndexed { index, vkPhysicalDevice ->
|
||||
binding.gpuText2.textContent.text = vkPhysicalDevice.deviceName
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.gpuText3.textTitle.text = getString(R.string.max_frequency)
|
||||
binding.gpuText3.textContent.text = "${gpu.getMaxFrequency()} MHz"
|
||||
binding.gpuText4.textTitle.text = getString(R.string.architecture)
|
||||
binding.gpuText4.textContent.text = gpu.getArchitecture()
|
||||
binding.gpuText5.textTitle.text = getString(R.string.cores)
|
||||
binding.gpuText5.textContent.text = gpu.getOpenGLExtensionCount().toString()
|
||||
binding.gpuText6.textTitle.text = getString(R.string.total_l2)
|
||||
binding.gpuText6.textContent.text = "${gpu.getCacheSize()} KB"
|
||||
binding.gpuText7.textTitle.text = getString(R.string.bus_width)
|
||||
binding.gpuText7.textContent.text = "${gpu.getBandwidth()} GB/s"
|
||||
binding.gpuText8.textTitle.text = getString(R.string.vulkan_support)
|
||||
binding.gpuText8.textContent.text = gpu.isVulkanSupported().toString()
|
||||
binding.gpuText9.textTitle.text = getString(R.string.vulkan_API)
|
||||
binding.gpuText9.textContent.text = gpu.getVulkanApiVersion()
|
||||
binding.open1.text = getString(R.string.opengl)
|
||||
gpu.getGpuInformation().eglInformation?.let { eglInfo ->
|
||||
eglInfo.eglExtensions?.let {
|
||||
dialogExtension?.setContent(it.joinToString())
|
||||
}
|
||||
}
|
||||
// binding.openItem1.text = gpu.getVendorName()
|
||||
// binding.openItem2.text = gpu.getRendererName()
|
||||
binding.openItem3.text = gpu.getOpenGLVersion()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* processor信息*/
|
||||
private fun setProcessorInfo() {
|
||||
val cpu = AndInfo.instance.cpu//cpu信息
|
||||
//处理器
|
||||
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)
|
||||
mainViewModel.cpuInfo.observe(viewLifecycleOwner) { cpu ->
|
||||
cpu?.let {
|
||||
binding.text0.textContent.text = cpu.getProcessorName()
|
||||
binding.text1.textContent.text = cpu.getVendor()
|
||||
binding.text2.textContent.text = cpu.getProcessorName()
|
||||
binding.text3.textContent.text = cpu.cores.size.toString()
|
||||
binding.text4.textContent.text = cpu.getAllArchitectures().joinToString()
|
||||
binding.text5.textContent.text = cpu.getProcessInfo().process
|
||||
binding.text6.textContent.text = cpu.getArchitecture()
|
||||
binding.text7.textContent.text = cpu.getAbi()
|
||||
binding.text8.textContent.text = cpu.getSupportedAbis().joinToString()
|
||||
binding.text9.textContent.text = cpu.getFrequencyText()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bluetooth相关信息*/
|
||||
@SuppressLint("SuspiciousIndentation")
|
||||
private fun setBlueToothInfo() {
|
||||
val bluetoothInfo = AndInfo.instance.bluetooth//蓝牙信息
|
||||
if (!bluetoothInfo.isEnabled) return
|
||||
binding.bluetoothLayout.blueCheck1.content.text = getString(R.string.bluetooth_le)
|
||||
binding.bluetoothLayout.blueCheck2.content.text =
|
||||
getString(R.string.multiple_advertisement)
|
||||
binding.bluetoothLayout.blueCheck3.content.text =
|
||||
getString(R.string.offloaded_filtering)
|
||||
binding.bluetoothLayout.blueCheck4.content.text =
|
||||
getString(R.string.offloaded_scan_batching)
|
||||
binding.bluetoothLayout.blueCheck01.content.text =
|
||||
getString(R.string.le_periodic_advertising)
|
||||
binding.bluetoothLayout.blueCheck02.content.text =
|
||||
getString(R.string.le_extended_advertising)
|
||||
binding.bluetoothLayout.blueCheck03.content.text =
|
||||
getString(R.string.le_2m_phy_high_speed)
|
||||
binding.bluetoothLayout.blueCheck04.content.text =
|
||||
getString(R.string.le_2m_phy_low_power)
|
||||
binding.bluetoothLayout.blueCheck05.content.text = getString(R.string.le_audio_support)
|
||||
binding.bluetoothLayout.showLayout.setOnClickListener {
|
||||
requestBluetoothPermissions()
|
||||
}
|
||||
|
||||
mainViewModel.bluetoothInfo.observe(viewLifecycleOwner) { features ->
|
||||
features?.let {
|
||||
if (!it.isEnabled) return@let
|
||||
//蓝牙features支持
|
||||
bluetoothInfo.getBluetoothFeatures().let { features ->
|
||||
binding.bluetoothLayout.blueCheck1.content.text = getString(R.string.bluetooth_le)
|
||||
it.getBluetoothFeatures().let { features ->
|
||||
binding.bluetoothLayout.blueCheck1.image.isSelected = features.bluetoothLe
|
||||
binding.bluetoothLayout.blueCheck2.content.text =
|
||||
getString(R.string.multiple_advertisement)
|
||||
binding.bluetoothLayout.blueCheck2.image.isSelected = features.multipleAdvertisement
|
||||
binding.bluetoothLayout.blueCheck3.content.text =
|
||||
getString(R.string.offloaded_filtering)
|
||||
binding.bluetoothLayout.blueCheck3.image.isSelected = features.offloadedFiltering
|
||||
binding.bluetoothLayout.blueCheck4.content.text =
|
||||
getString(R.string.offloaded_scan_batching)
|
||||
binding.bluetoothLayout.blueCheck4.image.isSelected = features.offloadedScanBatching
|
||||
binding.bluetoothLayout.blueCheck01.content.text =
|
||||
getString(R.string.le_periodic_advertising)
|
||||
binding.bluetoothLayout.blueCheck01.image.isSelected = features.lePeriodicAdvertising
|
||||
binding.bluetoothLayout.blueCheck02.content.text =
|
||||
getString(R.string.le_extended_advertising)
|
||||
binding.bluetoothLayout.blueCheck02.image.isSelected = features.leExtendedAdvertising
|
||||
binding.bluetoothLayout.blueCheck03.content.text =
|
||||
getString(R.string.le_2m_phy_high_speed)
|
||||
|
||||
binding.bluetoothLayout.blueCheck2.image.isSelected =
|
||||
features.multipleAdvertisement
|
||||
|
||||
binding.bluetoothLayout.blueCheck3.image.isSelected =
|
||||
features.offloadedFiltering
|
||||
|
||||
binding.bluetoothLayout.blueCheck4.image.isSelected =
|
||||
features.offloadedScanBatching
|
||||
|
||||
binding.bluetoothLayout.blueCheck01.image.isSelected =
|
||||
features.lePeriodicAdvertising
|
||||
|
||||
binding.bluetoothLayout.blueCheck02.image.isSelected =
|
||||
features.leExtendedAdvertising
|
||||
|
||||
binding.bluetoothLayout.blueCheck03.image.isSelected = features.leCodedPhy
|
||||
binding.bluetoothLayout.blueCheck04.content.text =
|
||||
getString(R.string.le_2m_phy_low_power)
|
||||
|
||||
binding.bluetoothLayout.blueCheck04.image.isSelected = features.le2MbPhy
|
||||
binding.bluetoothLayout.blueCheck05.content.text = getString(R.string.le_audio_support)
|
||||
|
||||
binding.bluetoothLayout.blueCheck05.image.isSelected = features.leAudioSupport
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求蓝牙权限的方法
|
||||
|
||||
@ -9,15 +9,20 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.xyzshell.andinfo.AndInfo
|
||||
import com.xyzshell.andinfo.libs.NetworkInfo
|
||||
import com.xyzshell.myphoneinfo.R
|
||||
import com.xyzshell.myphoneinfo.base.BaseActivity
|
||||
import com.xyzshell.myphoneinfo.custom.PermissionChecker
|
||||
import com.xyzshell.myphoneinfo.custom.RefreshManager.load
|
||||
import com.xyzshell.myphoneinfo.custom.RefreshManager.stop
|
||||
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.getHoursString
|
||||
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.setYesOrNo
|
||||
import com.xyzshell.myphoneinfo.databinding.FragmentNetworkBinding
|
||||
import com.xyzshell.myphoneinfo.dialog.ShowLoadFragment
|
||||
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@ -27,12 +32,19 @@ import kotlin.toString
|
||||
class NetworkFragment : Fragment() {
|
||||
|
||||
private var status = 0//0:未连接,1:wifi 2:数据流量
|
||||
private lateinit var networkInfo: NetworkInfo
|
||||
|
||||
private val mainViewModel: MainViewModel by activityViewModels()
|
||||
private var refreshStatus =false//刷新状态
|
||||
private lateinit var binding: FragmentNetworkBinding
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
}
|
||||
override fun onResume(){
|
||||
super.onResume()
|
||||
checkPermissionsAndRefresh()
|
||||
mainViewModel.refreshNetworkInfo(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
@ -40,31 +52,87 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
): View {
|
||||
// Inflate the layout for this fragment
|
||||
binding = FragmentNetworkBinding.inflate(inflater, container, false)
|
||||
// binding.signalStrength.setStrength(4)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
networkInfo= AndInfo.instance.network
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
delay(50) // 短暂延迟确保UI完成布局
|
||||
withContext(Dispatchers.Main) {
|
||||
refreshStatus()
|
||||
if(PermissionChecker.getMissingPermissions(context = requireContext()).isNotEmpty()){
|
||||
initView()
|
||||
setObservers()
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun setObservers() {
|
||||
mainViewModel.networkStatus.observe(viewLifecycleOwner) { type ->
|
||||
stop(binding.swipeRefresh)
|
||||
when (type) {
|
||||
NetworkInfo.NetworkType.WIFI -> {
|
||||
status = 1
|
||||
binding.conText1.text = getString(R.string.wifi)
|
||||
binding.connectData.visibility = View.VISIBLE
|
||||
binding.noConnect.visibility = View.GONE
|
||||
}
|
||||
|
||||
NetworkInfo.NetworkType.MOBILE -> {
|
||||
status = 2
|
||||
binding.conText1.text = getString(R.string.mobile)
|
||||
binding.connectData.visibility = View.VISIBLE
|
||||
binding.noConnect.visibility = View.GONE
|
||||
}
|
||||
|
||||
else -> {
|
||||
status = 0
|
||||
setNoConnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
// 观察 WiFi 详情
|
||||
mainViewModel.wifiDetails.observe(viewLifecycleOwner) { wifiDetails ->
|
||||
wifiDetails?.let {
|
||||
setWifiDetail(it)
|
||||
} ?: run {
|
||||
binding.networkLayout.wifiList.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
// 观察移动网络详情
|
||||
mainViewModel.mobileDetails.observe(viewLifecycleOwner) { mobileDetails ->
|
||||
mobileDetails?.let {
|
||||
setMobileInfo(it)
|
||||
}
|
||||
}
|
||||
|
||||
// 观察权限状态
|
||||
mainViewModel.networkPermissionGranted.observe(viewLifecycleOwner) { granted ->
|
||||
if (!granted) {
|
||||
requestPermissions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPermissionsAndRefresh() {
|
||||
mainViewModel.checkNetworkPermissions(requireContext())
|
||||
}
|
||||
|
||||
private fun requestPermissions() {
|
||||
PermissionChecker.requestSimple(
|
||||
requireActivity(),
|
||||
onGranted = {
|
||||
// 权限已授予,执行操作
|
||||
refreshStatus()
|
||||
mainViewModel.refreshNetworkInfo(requireContext())
|
||||
},
|
||||
onDenied = {
|
||||
// 权限被拒绝
|
||||
Toast.makeText(context, getString(R.string.permissions_required), Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(
|
||||
context,
|
||||
getString(R.string.permissions_required),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
setNoConnect()
|
||||
}
|
||||
)
|
||||
}
|
||||
//wifi
|
||||
|
||||
private fun initView() {
|
||||
binding.networkLayout.wfText1.textTitle.text = getString(R.string.status)
|
||||
// binding.networkLayout.wfText2.textTitle.text=getString(R.string.network)
|
||||
binding.networkLayout.wfText3.textTitle.text = getString(R.string.bssid)
|
||||
@ -104,8 +172,6 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
|
||||
binding.defText2.textTitle.text = getString(R.string.voice)
|
||||
binding.defText3.textTitle.text = getString(R.string.short_message)
|
||||
|
||||
|
||||
binding.networkLayout.pubShow.setOnClickListener {
|
||||
val tag = "showLoadFragment"
|
||||
if (requireActivity().supportFragmentManager.findFragmentByTag(tag) == null) {
|
||||
@ -113,34 +179,20 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
showLoadFragment.show(requireActivity().supportFragmentManager, tag)
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
load(binding.swipeRefresh){
|
||||
Log.d("TTTTTTTT","刷新超时")
|
||||
}
|
||||
mainViewModel.refreshNetworkInfo(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshStatus() {
|
||||
val currentNetworkType = networkInfo.getCurrentNetworkType()
|
||||
Log.d("NetworkFragment", "currentNetworkType: $currentNetworkType")
|
||||
when (currentNetworkType) {
|
||||
NetworkInfo.NetworkType.WIFI -> {
|
||||
status = 1
|
||||
setWifiDetail()
|
||||
setMobileInfo()
|
||||
}
|
||||
NetworkInfo.NetworkType.MOBILE -> {
|
||||
status = 2
|
||||
setWifiDetail()
|
||||
setMobileInfo()
|
||||
}
|
||||
else -> {
|
||||
status = 0
|
||||
setNoConnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setNoConnect() {
|
||||
binding.noConnect.visibility = View.VISIBLE
|
||||
binding.connectData.visibility = View.GONE
|
||||
binding.networkLayout.wfText1.textContent.text="Disconnected"
|
||||
binding.networkLayout.wfText1.textContent.text = getString(R.string.not_connected)
|
||||
binding.networkLayout.wifiList.visibility = View.GONE
|
||||
binding.networkLayout.llPubShow.visibility = View.GONE
|
||||
}
|
||||
@ -148,18 +200,18 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
/**
|
||||
* 设置流量信息
|
||||
* */
|
||||
private fun setMobileInfo() {
|
||||
private fun setMobileInfo(mobileDetails: NetworkInfo.MobileDetails) {
|
||||
binding.noConnect.visibility = View.GONE
|
||||
binding.conText1.text = getString(R.string.mobile)
|
||||
binding.connectData.visibility = View.VISIBLE
|
||||
Log.d("TTTTTTTT", "wifi not connected")
|
||||
binding.networkLayout.wifiList.visibility = View.GONE
|
||||
binding.networkLayout.llPubShow.visibility = View.GONE
|
||||
networkInfo.getMobileDetails()?.let { mobileDetails ->
|
||||
binding.mdText1.textContent.text = setYesOrNo(mobileDetails.dualSim)
|
||||
binding.mdText2.textContent.text = "SIM${mobileDetails.phoneType}"
|
||||
binding.mdText3.textContent.text = setYesOrNo(mobileDetails.esimSupported)
|
||||
binding.conTexts.textContent.text=if(mobileDetails.dataEnabled) getString(R.string.connected) else getString(R.string.not_connected)
|
||||
binding.conTexts.textContent.text =
|
||||
if (mobileDetails.dataEnabled) getString(R.string.connected) else getString(R.string.not_connected)
|
||||
binding.defText1.textContent.text = mobileDetails.dataSim.toString()
|
||||
binding.defText2.textContent.text = mobileDetails.voiceSim.toString()
|
||||
binding.defText3.textContent.text = mobileDetails.smsSim.toString()
|
||||
@ -169,9 +221,12 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
binding.simInfo1.simText2.textTitle.text = getString(R.string.nation)
|
||||
binding.simInfo1.simText3.textTitle.text = getString(R.string.roaming)
|
||||
binding.simInfo1.simText4.textTitle.text = getString(R.string.network_type)
|
||||
binding.simInfo1.simText1.textContent.text=if(mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
||||
binding.simInfo1.simText2.textContent.text=mobileDetails.simInfos[0].countryIso.toString()
|
||||
binding.simInfo1.simText3.textContent.text=if(mobileDetails.simInfos[0].roaming) getString(R.string.enable) else getString(R.string.disable)
|
||||
binding.simInfo1.simText1.textContent.text =
|
||||
if (mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
||||
binding.simInfo1.simText2.textContent.text =
|
||||
mobileDetails.simInfos[0].countryIso.toString()
|
||||
binding.simInfo1.simText3.textContent.text =
|
||||
if (mobileDetails.simInfos[0].roaming) getString(R.string.enable) else getString(R.string.disable)
|
||||
binding.simInfo1.simText4.textContent.text = mobileDetails.simInfos[0].networkTypeText
|
||||
if (mobileDetails.simInfos.size > 1) {
|
||||
binding.simInfo2.root.visibility = View.VISIBLE
|
||||
@ -180,10 +235,16 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
binding.simInfo2.simText2.textTitle.text = getString(R.string.nation)
|
||||
binding.simInfo2.simText3.textTitle.text = getString(R.string.roaming)
|
||||
binding.simInfo2.simText4.textTitle.text = getString(R.string.network_type)
|
||||
binding.simInfo2.simText1.textContent.text=if(mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
||||
binding.simInfo2.simText2.textContent.text=mobileDetails.simInfos[1].countryIso.toString()
|
||||
binding.simInfo2.simText3.textContent.text=if(mobileDetails.simInfos[1].roaming) getString(R.string.enable) else getString(R.string.disable)
|
||||
binding.simInfo2.simText4.textContent.text=mobileDetails.simInfos[1].networkTypeText
|
||||
binding.simInfo2.simText1.textContent.text =
|
||||
if (mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
||||
binding.simInfo2.simText2.textContent.text =
|
||||
mobileDetails.simInfos[1].countryIso.toString()
|
||||
binding.simInfo2.simText3.textContent.text =
|
||||
if (mobileDetails.simInfos[1].roaming) getString(R.string.enable) else getString(
|
||||
R.string.disable
|
||||
)
|
||||
binding.simInfo2.simText4.textContent.text =
|
||||
mobileDetails.simInfos[1].networkTypeText
|
||||
}
|
||||
} else {
|
||||
binding.simInfo1.root.visibility = View.GONE
|
||||
@ -191,18 +252,16 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置wifi信息
|
||||
* */
|
||||
private fun setWifiDetail() {
|
||||
private fun setWifiDetail(wifiDetails: NetworkInfo.WifiDetails) {
|
||||
binding.noConnect.visibility = View.GONE
|
||||
binding.conText1.text = getString(R.string.wifi)
|
||||
binding.connectData.visibility = View.VISIBLE
|
||||
binding.networkLayout.wifiList.visibility = View.VISIBLE
|
||||
binding.networkLayout.llPubShow.visibility = View.VISIBLE
|
||||
networkInfo.getWifiDetails()?.let { wifiDetails ->
|
||||
Log.d("TTTTTTTT", wifiDetails.connected.toString())
|
||||
binding.networkLayout.wifiList.visibility = View.VISIBLE
|
||||
binding.networkLayout.wfText1.textContent.text = getString(R.string.connected)
|
||||
@ -222,7 +281,8 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
binding.networkLayout.wfText10.textContent.text = wifiDetails.standard.toString()
|
||||
|
||||
binding.networkLayout.dhText1.textContent.text = wifiDetails.dhcpServer
|
||||
binding.networkLayout.dhText2.textContent.text=getHoursString(wifiDetails.leaseDuration?: 0)
|
||||
binding.networkLayout.dhText2.textContent.text =
|
||||
getHoursString(wifiDetails.leaseDuration ?: 0)
|
||||
binding.networkLayout.dhText3.textContent.text = wifiDetails.gateway
|
||||
binding.networkLayout.dhText4.textContent.text = wifiDetails.subnetMask
|
||||
binding.networkLayout.dhText5.textContent.text = wifiDetails.dns1
|
||||
@ -232,7 +292,8 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
val ipv6 = toString.replace("[", "").replace("]", "")
|
||||
binding.networkLayout.dhText8.textContent.text = ipv6
|
||||
|
||||
binding.networkLayout.hardCheck1.image.isSelected= wifiDetails.supportedStandards?.size==5
|
||||
binding.networkLayout.hardCheck1.image.isSelected =
|
||||
wifiDetails.supportedStandards?.size == 5
|
||||
binding.networkLayout.hardCheck2.image.isSelected = wifiDetails.wifiDirect == true
|
||||
binding.networkLayout.hardCheck3.image.isSelected = wifiDetails.wifiAware == true
|
||||
binding.networkLayout.hardCheck4.image.isSelected = wifiDetails.wifiPasspoint == true
|
||||
@ -240,7 +301,6 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
binding.networkLayout.hardCheck6.image.isSelected = wifiDetails.support6G == true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateSignalLevel(percent: Int): Int {
|
||||
return when {
|
||||
@ -251,6 +311,7 @@ private lateinit var binding:FragmentNetworkBinding
|
||||
else -> 1 // 非常差/无信号
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@ -2,6 +2,7 @@ package com.xyzshell.myphoneinfo.main
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.xyzshell.andinfo.AndInfo
|
||||
@ -18,6 +19,7 @@ import com.xyzshell.myphoneinfo.dashboard.SensorsFragment
|
||||
import com.xyzshell.myphoneinfo.dashboard.SystemShowFragment
|
||||
import com.xyzshell.myphoneinfo.databinding.ActivityMainBinding
|
||||
import com.xyzshell.myphoneinfo.dialog.SlideInPopView
|
||||
import kotlin.getValue
|
||||
|
||||
class MainScrollActivity : BaseActivity<ActivityMainBinding>() {
|
||||
override fun inflateBinding(inflater: LayoutInflater): ActivityMainBinding =
|
||||
@ -48,12 +50,6 @@ class MainScrollActivity : BaseActivity<ActivityMainBinding>() {
|
||||
})
|
||||
}) { tab, position ->
|
||||
tab.text = stringArray[position]
|
||||
// tab.setCustomView(R.layout.custom_ta
|
||||
//
|
||||
// tab.customView?.run {
|
||||
// val indicator: ImageView = findViewById(R.id.image_indicator)
|
||||
// indicator.isVisible = position == 0
|
||||
// }
|
||||
}.attach()
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,182 @@
|
||||
package com.xyzshell.myphoneinfo.main
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.xyzshell.andinfo.AndInfo
|
||||
import com.xyzshell.andinfo.libs.AppDetails
|
||||
import com.xyzshell.andinfo.libs.BluetoothInfo
|
||||
import com.xyzshell.andinfo.libs.CpuInfo
|
||||
import com.xyzshell.andinfo.libs.DisplayInfo
|
||||
import com.xyzshell.andinfo.libs.GpuInfo
|
||||
import com.xyzshell.andinfo.libs.InputInfo
|
||||
import com.xyzshell.andinfo.libs.MemInfo
|
||||
import com.xyzshell.andinfo.libs.MemoryInfo
|
||||
import com.xyzshell.andinfo.libs.NetworkInfo
|
||||
import com.xyzshell.andinfo.libs.StorageInfo
|
||||
import com.xyzshell.myphoneinfo.custom.PermissionChecker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainViewModel: ViewModel() {
|
||||
// 硬件相关数据
|
||||
private val _cpuInfo = MutableLiveData<CpuInfo?>()
|
||||
val cpuInfo: LiveData<CpuInfo?> = _cpuInfo
|
||||
|
||||
private val _gpuInfo = MutableLiveData<GpuInfo?>()
|
||||
val gpuInfo: LiveData<GpuInfo?> = _gpuInfo
|
||||
|
||||
private val _displayInfo = MutableLiveData<DisplayInfo?>()
|
||||
val displayInfo: LiveData<DisplayInfo?> = _displayInfo
|
||||
|
||||
private val _storageInfo = MutableLiveData<StorageInfo?>()
|
||||
val storageInfo: LiveData<StorageInfo?> = _storageInfo
|
||||
private val _memInfo = MutableLiveData<MemInfo?>()
|
||||
val memInfo: LiveData<MemInfo?> = _memInfo
|
||||
|
||||
private val _bluetoothInfo = MutableLiveData<BluetoothInfo?>()
|
||||
val bluetoothInfo: LiveData<BluetoothInfo?> = _bluetoothInfo
|
||||
|
||||
private val _inputInfo= MutableLiveData<InputInfo?>()
|
||||
val input: LiveData<InputInfo?> = _inputInfo
|
||||
|
||||
//网络相关
|
||||
private val networkInfo= AndInfo.instance.network
|
||||
private val _networkStatus= MutableLiveData<NetworkInfo.NetworkType?>()
|
||||
val networkStatus: LiveData<NetworkInfo.NetworkType?> = _networkStatus
|
||||
private val _wifiDetails = MutableLiveData<NetworkInfo.WifiDetails?>()
|
||||
val wifiDetails: LiveData<NetworkInfo.WifiDetails?> = _wifiDetails
|
||||
|
||||
private val _mobileDetails = MutableLiveData<NetworkInfo.MobileDetails?>()
|
||||
val mobileDetails: LiveData<NetworkInfo.MobileDetails?> = _mobileDetails
|
||||
|
||||
private val _networkPermissionGranted = MutableLiveData<Boolean>()
|
||||
val networkPermissionGranted: LiveData<Boolean> = _networkPermissionGranted
|
||||
|
||||
|
||||
//应用列表
|
||||
private val _installedApps= MutableLiveData<List<AppDetails>>()
|
||||
|
||||
|
||||
val installedApps: LiveData<List<AppDetails>> = _installedApps
|
||||
|
||||
init{
|
||||
loadApps()
|
||||
}
|
||||
|
||||
fun refreshApps() {
|
||||
loadApps()
|
||||
}
|
||||
/**
|
||||
* 刷新网络信息(带权限检查)
|
||||
*/
|
||||
fun refreshNetworkInfo(context: Context){
|
||||
viewModelScope.launch(Dispatchers.IO){
|
||||
// 检查权限
|
||||
val hasPermissions = PermissionChecker.getMissingPermissions(context).isEmpty()
|
||||
_networkPermissionGranted.postValue(hasPermissions)
|
||||
|
||||
if (!hasPermissions) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取网络类型
|
||||
val type = networkInfo.getCurrentNetworkType()
|
||||
_networkStatus.postValue(type)
|
||||
|
||||
// 根据网络类型获取详细信息
|
||||
when (type) {
|
||||
NetworkInfo.NetworkType.WIFI -> {
|
||||
_wifiDetails.postValue(networkInfo.getWifiDetails())
|
||||
_mobileDetails.postValue(networkInfo.getMobileDetails())
|
||||
}
|
||||
NetworkInfo.NetworkType.MOBILE -> {
|
||||
_mobileDetails.postValue(networkInfo.getMobileDetails())
|
||||
_wifiDetails.postValue(networkInfo.getWifiDetails())
|
||||
}
|
||||
else -> {
|
||||
_wifiDetails.postValue(null)
|
||||
_mobileDetails.postValue(null)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
// 处理异常
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 仅检查网络权限
|
||||
*/
|
||||
fun checkNetworkPermissions(context: Context) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val hasPermissions = PermissionChecker.getMissingPermissions(context).isEmpty()
|
||||
_networkPermissionGranted.postValue(hasPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前网络状态(快速检查)
|
||||
*/
|
||||
fun getCurrentNetworkType(context: Context): NetworkInfo.NetworkType? {
|
||||
return try {
|
||||
if (PermissionChecker.getMissingPermissions(context).isEmpty()) {
|
||||
networkInfo.getCurrentNetworkType()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
fun loadApps() {
|
||||
viewModelScope.launch(Dispatchers.IO){
|
||||
val apps= AndInfo.instance.app.getInstalledApps()
|
||||
_installedApps.postValue(apps)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 硬件刷新方法
|
||||
* */
|
||||
|
||||
fun refreshHardwareInfo(context: Context){
|
||||
viewModelScope.launch(Dispatchers.IO){
|
||||
try {
|
||||
val cpu= AndInfo.instance.cpu
|
||||
_cpuInfo.postValue(cpu)
|
||||
val gpu= AndInfo.instance.gpu
|
||||
_gpuInfo.postValue(gpu)
|
||||
val display = AndInfo.instance.display
|
||||
_displayInfo.postValue(display)
|
||||
val storage = AndInfo.instance.storage
|
||||
_storageInfo.postValue(storage)
|
||||
val mem = AndInfo.instance.memory
|
||||
_memInfo.postValue(mem)
|
||||
// 检查权限
|
||||
val bluetoothInfo = AndInfo.instance.bluetooth
|
||||
val inputInfo= AndInfo.instance.input
|
||||
_inputInfo.postValue(inputInfo)
|
||||
|
||||
val hasPermissions= bluetoothInfo.requiredPermissions.all { permission ->
|
||||
ActivityCompat.checkSelfPermission(context, permission) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
if (!hasPermissions) {
|
||||
return@launch
|
||||
}
|
||||
_bluetoothInfo.postValue(bluetoothInfo)
|
||||
//蓝牙信息
|
||||
}catch (e: Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,11 +40,12 @@
|
||||
android:id="@+id/dialog_title"
|
||||
style="@style/TextHeavy20"
|
||||
android:textSize="18sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="80dp"
|
||||
android:text="@string/screenreader"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_icon"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/image_icon"
|
||||
app:layout_constraintBottom_toBottomOf="@id/image_icon"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/swipeRefresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/swipeRefresh"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/background_color"
|
||||
tools:context=".dashboard.NetworkFragment">
|
||||
|
||||
@ -51,7 +51,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
layout="@layout/mem_text_style" />
|
||||
|
||||
<include
|
||||
android:id="@+id/memText0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
layout="@layout/mem_text_style" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user