新增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.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.xyzshell.myphoneinfo.R
|
import com.xyzshell.myphoneinfo.R
|
||||||
|
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||||
|
|
||||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||||
|
|
||||||
protected lateinit var binding: VB
|
protected lateinit var binding: VB
|
||||||
|
protected val mainViewModel: MainViewModel by lazy {
|
||||||
|
ViewModelProvider(this)[MainViewModel::class.java]
|
||||||
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
@ -28,7 +34,9 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
|
|
||||||
protected abstract fun inflateBinding(inflater: LayoutInflater): VB
|
protected abstract fun inflateBinding(inflater: LayoutInflater): VB
|
||||||
|
|
||||||
protected open fun initView() {}
|
protected open fun initView() {
|
||||||
|
mainViewModel
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun initData() {}
|
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.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.xyzshell.andinfo.AndInfo
|
import com.xyzshell.andinfo.AndInfo
|
||||||
import com.xyzshell.andinfo.libs.AppDetails
|
import com.xyzshell.andinfo.libs.AppDetails
|
||||||
import com.xyzshell.myphoneinfo.R
|
import com.xyzshell.myphoneinfo.R
|
||||||
import com.xyzshell.myphoneinfo.adapter.AppListAdapter
|
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.databinding.FragmentAppsBinding
|
||||||
import com.xyzshell.myphoneinfo.dialog.AppDialogFragment
|
import com.xyzshell.myphoneinfo.dialog.AppDialogFragment
|
||||||
import com.xyzshell.myphoneinfo.dialog.BottomDialogFragment
|
import com.xyzshell.myphoneinfo.dialog.BottomDialogFragment
|
||||||
import com.xyzshell.myphoneinfo.main.MainScrollActivity
|
import com.xyzshell.myphoneinfo.main.MainScrollActivity
|
||||||
|
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -25,7 +29,9 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
|||||||
private lateinit var binding: FragmentAppsBinding
|
private lateinit var binding: FragmentAppsBinding
|
||||||
private lateinit var dialogFragment: AppDialogFragment
|
private lateinit var dialogFragment: AppDialogFragment
|
||||||
private lateinit var bottomDialog: BottomDialogFragment
|
private lateinit var bottomDialog: BottomDialogFragment
|
||||||
|
private val viewModel: MainViewModel by activityViewModels()
|
||||||
private var sel: Int? = 0
|
private var sel: Int? = 0
|
||||||
|
private var userSize=0
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
@ -34,17 +40,15 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
|||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
// Inflate the layout for this fragment
|
|
||||||
binding = FragmentAppsBinding.inflate(inflater, container, false)
|
|
||||||
val adapter= AppListAdapter()
|
val adapter= AppListAdapter()
|
||||||
val installedApps = AndInfo.instance.app.getInstalledApps()
|
binding = FragmentAppsBinding.inflate(inflater, container, false)
|
||||||
val userSize=installedApps.size
|
viewModel.installedApps.observe(viewLifecycleOwner){
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
appDetails ->
|
||||||
delay(50) // 短暂延迟确保UI完成布局
|
stop(binding.swipeRefresh)
|
||||||
withContext(Dispatchers.Main) {
|
adapter.setList(appDetails)
|
||||||
adapter.setList(installedApps)
|
userSize=appDetails.size
|
||||||
|
}
|
||||||
adapter.setOnclickListener(this@AppsFragment)
|
adapter.setOnclickListener(this@AppsFragment)
|
||||||
}}
|
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
binding.tvTitle.text=when(0){//todo replace with user/system/all/none
|
binding.tvTitle.text=when(0){//todo replace with user/system/all/none
|
||||||
@ -53,6 +57,10 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener {
|
|||||||
2 -> "All(23)"
|
2 -> "All(23)"
|
||||||
else -> "None"
|
else -> "None"
|
||||||
}
|
}
|
||||||
|
binding.swipeRefresh.setOnRefreshListener {
|
||||||
|
load(binding.swipeRefresh)
|
||||||
|
viewModel.loadApps()
|
||||||
|
}
|
||||||
binding.llTitle.setOnClickListener {
|
binding.llTitle.setOnClickListener {
|
||||||
bottomDialog= BottomDialogFragment(type = "apps", sel = sel, invoke = {item->
|
bottomDialog= BottomDialogFragment(type = "apps", sel = sel, invoke = {item->
|
||||||
sel = item
|
sel = item
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import android.os.Bundle
|
|||||||
import android.os.CountDownTimer
|
import android.os.CountDownTimer
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.text.format.Formatter
|
import android.text.format.Formatter
|
||||||
|
import android.util.Log
|
||||||
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
|
||||||
@ -16,8 +17,10 @@ import android.view.ViewGroup
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
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.andinfo.libs.MemInfo
|
||||||
import com.xyzshell.myphoneinfo.R
|
import com.xyzshell.myphoneinfo.R
|
||||||
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.convertToApproximateAspectRatio
|
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.convertToApproximateAspectRatio
|
||||||
import com.xyzshell.myphoneinfo.databinding.FragmentHardWareBinding
|
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.DialogDiskPart
|
||||||
import com.xyzshell.myphoneinfo.dialog.DialogExtension
|
import com.xyzshell.myphoneinfo.dialog.DialogExtension
|
||||||
import com.xyzshell.myphoneinfo.dialog.DialogInput
|
import com.xyzshell.myphoneinfo.dialog.DialogInput
|
||||||
|
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||||
|
import kotlin.getValue
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class HardWareFragment : Fragment() {
|
class HardWareFragment : Fragment() {
|
||||||
@ -34,6 +39,8 @@ class HardWareFragment : Fragment() {
|
|||||||
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 mainViewModel: MainViewModel by activityViewModels()
|
||||||
|
|
||||||
|
|
||||||
private val requestPermissionLauncher = registerForActivityResult(
|
private val requestPermissionLauncher = registerForActivityResult(
|
||||||
ActivityResultContracts.RequestMultiplePermissions()
|
ActivityResultContracts.RequestMultiplePermissions()
|
||||||
@ -59,6 +66,7 @@ class HardWareFragment : Fragment() {
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
checkAndDisplayBluetoothInfo()
|
checkAndDisplayBluetoothInfo()
|
||||||
|
mainViewModel.refreshHardwareInfo(requireContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,7 +76,7 @@ class HardWareFragment : Fragment() {
|
|||||||
): View? {
|
): View? {
|
||||||
binding = FragmentHardWareBinding.inflate(inflater, container, false)
|
binding = FragmentHardWareBinding.inflate(inflater, container, false)
|
||||||
dialogExtension = dialogExtension ?: DialogExtension()
|
dialogExtension = dialogExtension ?: DialogExtension()
|
||||||
initText()
|
initView()
|
||||||
binding.cpuBtn.setOnClickListener {
|
binding.cpuBtn.setOnClickListener {
|
||||||
var intent = Intent(requireContext(), AnalysisActivity::class.java)
|
var intent = Intent(requireContext(), AnalysisActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
@ -84,7 +92,7 @@ class HardWareFragment : Fragment() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initText() {
|
private fun initView() {
|
||||||
setProcessorInfo()
|
setProcessorInfo()
|
||||||
setGpuInfo()
|
setGpuInfo()
|
||||||
setDisplayInfo()
|
setDisplayInfo()
|
||||||
@ -107,27 +115,31 @@ class HardWareFragment : Fragment() {
|
|||||||
* Input信息
|
* Input信息
|
||||||
* */
|
* */
|
||||||
private fun setInputInfo() {
|
private fun setInputInfo() {
|
||||||
val inputInfo = AndInfo.instance.input
|
|
||||||
binding.otherCheck1.content.text = getString(R.string.usb_host_support)
|
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.content.text = getString(R.string.usb_accessory_support)
|
||||||
binding.otherCheck2.image.isSelected = inputInfo.hasUsbAccessorySupport()
|
|
||||||
binding.otherCheck3.content.text = getString(R.string.fingerprint)
|
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.content.text = getString(R.string.infrared_transmitter)
|
||||||
binding.otherCheck4.image.isSelected = inputInfo.hasInfraredSensor()
|
|
||||||
binding.otherCheck5.content.text = getString(R.string.uwb_support)
|
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.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.content.text = getString(R.string.secure_nfc_support)
|
||||||
binding.otherCheck7.image.isSelected = inputInfo.hasSecureNfcSupport()
|
|
||||||
binding.otherCheck8.content.text = getString(R.string.gps)
|
binding.otherCheck8.content.text = getString(R.string.gps)
|
||||||
binding.otherCheck8.image.isSelected = inputInfo.hasGpsSupport()
|
|
||||||
binding.othertext.setOnClickListener {
|
binding.othertext.setOnClickListener {
|
||||||
dialogInput = dialogInput ?: DialogInput()
|
dialogInput = dialogInput ?: DialogInput()
|
||||||
dialogInput?.show(childFragmentManager, "Input")
|
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信息
|
* memory信息
|
||||||
* */
|
* */
|
||||||
private fun setMemoryInfo() {
|
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)
|
||||||
|
|
||||||
//总存储信息
|
binding.memoryLayout.memText0.textTitle.text = getString(R.string.type)
|
||||||
val outused =Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageUsedSpace)
|
binding.memoryLayout.memText0.textContent.text = memInfo.getMemoryInfo().memType
|
||||||
val outfree = Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageAvailableSpace)
|
|
||||||
val outtotal = Formatter.formatFileSize(AndInfo.instance.context, storageInfo.internalStorageTotalSpace)
|
|
||||||
|
|
||||||
//内存:todo
|
|
||||||
binding.memoryLayout.memText1.textTitle.text = getString(R.string.ram_size)
|
binding.memoryLayout.memText1.textTitle.text = getString(R.string.ram_size)
|
||||||
// binding.memoryLayout.memText1.textContent.text = total
|
binding.memoryLayout.memText1.textContent.text = memTotal
|
||||||
// binding.memoryLayout.ram1.text = used + " used"
|
binding.memoryLayout.ram1.text = "$memUsed used"
|
||||||
// binding.memoryLayout.ram2.text = free + " free"
|
binding.memoryLayout.ram2.text = "$memFree free"
|
||||||
// binding.memoryLayout.seekbar.progress =
|
binding.memoryLayout.seekbar.progress =
|
||||||
// (used.substringBefore(" ").toDouble() / total.substringBefore(" ")
|
(memUsed.substringBefore(" ").toDouble() / memTotal
|
||||||
// .toDouble() * 100).toInt()
|
.substringBefore(" ")
|
||||||
|
.toDouble() * 100).toInt()
|
||||||
//appsAndData
|
|
||||||
val appsAndData = storageInfo.getFormattedAppsAndDataSize()
|
|
||||||
val system = storageInfo.getFormattedSystemSize()
|
|
||||||
val other= storageInfo.getFormattedFreeSpace()+storageInfo.getFormattedCacheSize()
|
|
||||||
//zarm
|
//zarm
|
||||||
|
|
||||||
binding.memoryLayout.memText3.textTitle.text = getString(R.string.zram)
|
binding.memoryLayout.memText3.textTitle.text = getString(R.string.zram)
|
||||||
binding.memoryLayout.memText3.textContent.text = Formatter.formatFileSize(
|
binding.memoryLayout.memText3.textContent.text = zramTotal
|
||||||
AndInfo.instance.context,
|
binding.memoryLayout.ram3.text = "$zramUsed used"
|
||||||
storageInfo.internalStorageTotalSpace
|
binding.memoryLayout.ram4.text = "$zramFree free"
|
||||||
)
|
|
||||||
binding.memoryLayout.ram3.text = outused + " used"
|
|
||||||
binding.memoryLayout.ram4.text = outfree + " free"
|
|
||||||
binding.memoryLayout.seekbar2.progress =
|
binding.memoryLayout.seekbar2.progress =
|
||||||
(outused.substringBefore(" ").toDouble() / outtotal.substringBefore(" ")
|
(zramTotal.substringBefore(" ").toDouble() / zramTotal.substringBefore(" ")
|
||||||
.toDouble() * 100).toInt()
|
.toDouble() * 100).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//storage
|
//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.textTitle.text = getString(R.string.size)
|
||||||
binding.memoryLayout.storText1.textContent.text = outtotal
|
binding.memoryLayout.storText1.textContent.text = stoTotal
|
||||||
binding.memoryLayout.stor1.text = outused + " used"
|
binding.memoryLayout.stor1.text = stoUsed + " used"
|
||||||
binding.memoryLayout.stor2.text = outtotal + " total"
|
binding.memoryLayout.stor2.text = stoTotal + " total"
|
||||||
binding.memoryLayout.radius1.text = appsAndData
|
binding.memoryLayout.radius1.text = appsAndData
|
||||||
binding.memoryLayout.radius2.text = system
|
binding.memoryLayout.radius2.text = system
|
||||||
binding.memoryLayout.radius3.text = other
|
binding.memoryLayout.radius3.text = other
|
||||||
binding.memoryLayout.seekbar3.progress =
|
binding.memoryLayout.seekbar3.progress =
|
||||||
(outused.substringBefore(" ").toDouble() / outtotal.substringBefore(" ")
|
(stoUsed.substringBefore(" ").toDouble() / stoTotal.substringBefore(" ")
|
||||||
.toDouble() * 100).toInt()
|
.toDouble() * 100).toInt()
|
||||||
|
|
||||||
|
|
||||||
//internalStorage
|
//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.textTitle.text = getString(R.string.filesystem)
|
||||||
binding.memoryLayout.interText1.textContent.text =
|
binding.memoryLayout.interText1.textContent.text =
|
||||||
storageInfo.internalStorageEncryptionType.toString()
|
storageInfo.internalStorageFileSystemType.toString()
|
||||||
binding.memoryLayout.interText2.textTitle.text = getString(R.string.block_size)
|
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.textTitle.text = "/data"
|
||||||
binding.memoryLayout.interText3.textContent.text = intertotal
|
binding.memoryLayout.interText3.textContent.text = storageInfo.formatBytes(storageInfo.dataDirectoryTotalSpace)
|
||||||
binding.memoryLayout.stor3.text = interused + " used"
|
binding.memoryLayout.stor3.text = "${storageInfo.formatBytes(interUsed)} used"
|
||||||
binding.memoryLayout.stor4.text = interfree + " free"
|
binding.memoryLayout.stor4.text = "${storageInfo.formatBytes(interFree)} free"
|
||||||
binding.memoryLayout.seekbar2.progress =
|
binding.memoryLayout.seekbar5.progress =
|
||||||
(interused.substringBefore(" ").toDouble() / intertotal.substringBefore(" ")
|
(interUsed.toDouble() / interTotal.toDouble() * 100).toInt()
|
||||||
.toDouble() * 100).toInt()
|
storageInfo.abOtaPartitions?.forEach { text ->
|
||||||
|
Log.d("TTTTTTTT","disk part:${text}")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* display信息
|
* display信息
|
||||||
* */
|
* */
|
||||||
private fun setDisplayInfo() {
|
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 defaultDisplayInfo = display.getDefaultDisplayInfo()
|
||||||
val width = defaultDisplayInfo?.widthPixels.toString()
|
val width = defaultDisplayInfo?.widthPixels.toString()
|
||||||
val height = defaultDisplayInfo?.heightPixels.toString()
|
val height = defaultDisplayInfo?.heightPixels.toString()
|
||||||
@ -216,26 +260,24 @@ class HardWareFragment : Fragment() {
|
|||||||
|
|
||||||
binding.disText1.textContent.text = width + "x" + height
|
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.disText2.textContent.text = defaultDisplayInfo?.ppi.toString()
|
||||||
binding.disText3.textTitle.text = getString(R.string.screen_density_d)
|
|
||||||
val dpiStr =
|
val dpiStr =
|
||||||
defaultDisplayInfo?.densityDpi.toString() + "(xxhdpi)\n" + defaultDisplayInfo?.xdpi?.roundToInt() + "dpx" + defaultDisplayInfo?.ydpi?.roundToInt() + "dp"
|
defaultDisplayInfo?.densityDpi.toString() + "(xxhdpi)\n" + defaultDisplayInfo?.xdpi?.roundToInt() + "dpx" + defaultDisplayInfo?.ydpi?.roundToInt() + "dp"
|
||||||
binding.disText3.textContent.text = dpiStr
|
binding.disText3.textContent.text = dpiStr
|
||||||
binding.disText4.textTitle.text = getString(R.string.screen_size_e)
|
val screenSize = "${
|
||||||
val screenSize = "${String.format("%.2f", display.getScreenSize()?.diagonalInches)}/ ${String.format("%.1f", display.getScreenSize()?.diagonalMm)} mm"
|
String.format(
|
||||||
|
"%.2f",
|
||||||
|
display.getScreenSize()?.diagonalInches
|
||||||
|
)
|
||||||
|
}/ ${String.format("%.1f", display.getScreenSize()?.diagonalMm)} mm"
|
||||||
binding.disText4.textContent.text = screenSize
|
binding.disText4.textContent.text = screenSize
|
||||||
binding.disText5.textTitle.text = getString(R.string.aspect_ratio)
|
|
||||||
binding.disText5.textContent.text = convertToApproximateAspectRatio(
|
binding.disText5.textContent.text = convertToApproximateAspectRatio(
|
||||||
width = width.toInt(),
|
width = width.toInt(),
|
||||||
height = height.toInt()
|
height = height.toInt()
|
||||||
)
|
)
|
||||||
binding.disText6.textTitle.text = getString(R.string.refresh_rate)
|
binding.disText6.textContent.text =
|
||||||
binding.disText6.textContent.text = defaultDisplayInfo?.refreshRate.toString() + "HZ"
|
defaultDisplayInfo?.refreshRate.toString() + "HZ"
|
||||||
binding.disText7.textTitle.text = getString(R.string.wide_color_gamut)
|
|
||||||
binding.disText7.textContent.text = defaultDisplayInfo?.isWideColorGamut.toString()
|
binding.disText7.textContent.text = defaultDisplayInfo?.isWideColorGamut.toString()
|
||||||
binding.disText8.textTitle.text = getString(R.string.hdr_support)
|
|
||||||
if (defaultDisplayInfo?.isHdr == true) {
|
if (defaultDisplayInfo?.isHdr == true) {
|
||||||
defaultDisplayInfo.hdrTypes.joinToString()
|
defaultDisplayInfo.hdrTypes.joinToString()
|
||||||
binding.disText8.textContent.text = defaultDisplayInfo.hdrTypes.joinToString()
|
binding.disText8.textContent.text = defaultDisplayInfo.hdrTypes.joinToString()
|
||||||
@ -243,125 +285,155 @@ class HardWareFragment : Fragment() {
|
|||||||
binding.disText8.textContent.text = "No"
|
binding.disText8.textContent.text = "No"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gpu信息*/
|
* gpu信息*/
|
||||||
private fun setGpuInfo() {
|
private fun setGpuInfo() {
|
||||||
val gpu = AndInfo.instance.gpu//gpu信息
|
|
||||||
binding.gpuText1.textTitle.text = getString(R.string.vendor)
|
binding.gpuText1.textTitle.text = getString(R.string.vendor)
|
||||||
binding.gpuText1.textContent.text = gpu.getVendorName()
|
|
||||||
binding.gpuText2.textTitle.text = getString(R.string.gpu)
|
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 ->
|
gpu.getGpuInformation().vkPhysicalDevices?.let { devices ->
|
||||||
if (devices.isNotEmpty()) {
|
if (devices.isNotEmpty()) {
|
||||||
devices.forEachIndexed { index, vkPhysicalDevice ->
|
devices.forEachIndexed { index, vkPhysicalDevice ->
|
||||||
binding.gpuText2.textContent.text = vkPhysicalDevice.deviceName
|
binding.gpuText2.textContent.text = vkPhysicalDevice.deviceName
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.gpuText3.textTitle.text = getString(R.string.max_frequency)
|
|
||||||
binding.gpuText3.textContent.text = "${gpu.getMaxFrequency()} MHz"
|
binding.gpuText3.textContent.text = "${gpu.getMaxFrequency()} MHz"
|
||||||
binding.gpuText4.textTitle.text = getString(R.string.architecture)
|
|
||||||
binding.gpuText4.textContent.text = gpu.getArchitecture()
|
binding.gpuText4.textContent.text = gpu.getArchitecture()
|
||||||
binding.gpuText5.textTitle.text = getString(R.string.cores)
|
|
||||||
binding.gpuText5.textContent.text = gpu.getOpenGLExtensionCount().toString()
|
binding.gpuText5.textContent.text = gpu.getOpenGLExtensionCount().toString()
|
||||||
binding.gpuText6.textTitle.text = getString(R.string.total_l2)
|
|
||||||
binding.gpuText6.textContent.text = "${gpu.getCacheSize()} KB"
|
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.gpuText7.textContent.text = "${gpu.getBandwidth()} GB/s"
|
||||||
binding.gpuText8.textTitle.text = getString(R.string.vulkan_support)
|
|
||||||
binding.gpuText8.textContent.text = gpu.isVulkanSupported().toString()
|
binding.gpuText8.textContent.text = gpu.isVulkanSupported().toString()
|
||||||
binding.gpuText9.textTitle.text = getString(R.string.vulkan_API)
|
|
||||||
binding.gpuText9.textContent.text = gpu.getVulkanApiVersion()
|
binding.gpuText9.textContent.text = gpu.getVulkanApiVersion()
|
||||||
binding.open1.text = getString(R.string.opengl)
|
|
||||||
gpu.getGpuInformation().eglInformation?.let { eglInfo ->
|
gpu.getGpuInformation().eglInformation?.let { eglInfo ->
|
||||||
eglInfo.eglExtensions?.let {
|
eglInfo.eglExtensions?.let {
|
||||||
dialogExtension?.setContent(it.joinToString())
|
dialogExtension?.setContent(it.joinToString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// binding.openItem1.text = gpu.getVendorName()
|
|
||||||
// binding.openItem2.text = gpu.getRendererName()
|
|
||||||
binding.openItem3.text = gpu.getOpenGLVersion()
|
binding.openItem3.text = gpu.getOpenGLVersion()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* processor信息*/
|
* processor信息*/
|
||||||
private fun setProcessorInfo() {
|
private fun setProcessorInfo() {
|
||||||
val cpu = AndInfo.instance.cpu//cpu信息
|
|
||||||
//处理器
|
//处理器
|
||||||
binding.text0.textTitle.text = getString(R.string.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.textTitle.text = getString(R.string.vendor)
|
||||||
binding.text1.textContent.text = cpu.getVendor()
|
|
||||||
//硬件
|
//硬件
|
||||||
binding.text2.textTitle.text = getString(R.string.hardware)
|
binding.text2.textTitle.text = getString(R.string.hardware)
|
||||||
binding.text2.textContent.text = cpu.getProcessorName()
|
|
||||||
//核心数
|
//核心数
|
||||||
binding.text3.textTitle.text = getString(R.string.cores)
|
binding.text3.textTitle.text = getString(R.string.cores)
|
||||||
binding.text3.textContent.text = cpu.cores.size.toString()
|
|
||||||
//cpu内核详情
|
//cpu内核详情
|
||||||
binding.text4.textTitle.text = getString(R.string.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.textTitle.text = getString(R.string.process)
|
||||||
binding.text5.textContent.text = cpu.getProcessInfo().process
|
|
||||||
//架构
|
//架构
|
||||||
binding.text6.textTitle.text = getString(R.string.architecture)
|
binding.text6.textTitle.text = getString(R.string.architecture)
|
||||||
binding.text6.textContent.text = cpu.getArchitecture()
|
|
||||||
//ABI
|
//ABI
|
||||||
binding.text7.textTitle.text = getString(R.string.ABI)
|
binding.text7.textTitle.text = getString(R.string.ABI)
|
||||||
binding.text7.textContent.text = cpu.getAbi()
|
|
||||||
//supported_ABls
|
//supported_ABls
|
||||||
binding.text8.textTitle.text = getString(R.string.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.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()
|
binding.text9.textContent.text = cpu.getFrequencyText()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bluetooth相关信息*/
|
* bluetooth相关信息*/
|
||||||
@SuppressLint("SuspiciousIndentation")
|
@SuppressLint("SuspiciousIndentation")
|
||||||
private fun setBlueToothInfo() {
|
private fun setBlueToothInfo() {
|
||||||
val bluetoothInfo = AndInfo.instance.bluetooth//蓝牙信息
|
binding.bluetoothLayout.blueCheck1.content.text = getString(R.string.bluetooth_le)
|
||||||
if (!bluetoothInfo.isEnabled) return
|
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 {
|
binding.bluetoothLayout.showLayout.setOnClickListener {
|
||||||
requestBluetoothPermissions()
|
requestBluetoothPermissions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainViewModel.bluetoothInfo.observe(viewLifecycleOwner) { features ->
|
||||||
|
features?.let {
|
||||||
|
if (!it.isEnabled) return@let
|
||||||
//蓝牙features支持
|
//蓝牙features支持
|
||||||
bluetoothInfo.getBluetoothFeatures().let { features ->
|
it.getBluetoothFeatures().let { features ->
|
||||||
binding.bluetoothLayout.blueCheck1.content.text = getString(R.string.bluetooth_le)
|
|
||||||
binding.bluetoothLayout.blueCheck1.image.isSelected = features.bluetoothLe
|
binding.bluetoothLayout.blueCheck1.image.isSelected = features.bluetoothLe
|
||||||
binding.bluetoothLayout.blueCheck2.content.text =
|
|
||||||
getString(R.string.multiple_advertisement)
|
binding.bluetoothLayout.blueCheck2.image.isSelected =
|
||||||
binding.bluetoothLayout.blueCheck2.image.isSelected = features.multipleAdvertisement
|
features.multipleAdvertisement
|
||||||
binding.bluetoothLayout.blueCheck3.content.text =
|
|
||||||
getString(R.string.offloaded_filtering)
|
binding.bluetoothLayout.blueCheck3.image.isSelected =
|
||||||
binding.bluetoothLayout.blueCheck3.image.isSelected = features.offloadedFiltering
|
features.offloadedFiltering
|
||||||
binding.bluetoothLayout.blueCheck4.content.text =
|
|
||||||
getString(R.string.offloaded_scan_batching)
|
binding.bluetoothLayout.blueCheck4.image.isSelected =
|
||||||
binding.bluetoothLayout.blueCheck4.image.isSelected = features.offloadedScanBatching
|
features.offloadedScanBatching
|
||||||
binding.bluetoothLayout.blueCheck01.content.text =
|
|
||||||
getString(R.string.le_periodic_advertising)
|
binding.bluetoothLayout.blueCheck01.image.isSelected =
|
||||||
binding.bluetoothLayout.blueCheck01.image.isSelected = features.lePeriodicAdvertising
|
features.lePeriodicAdvertising
|
||||||
binding.bluetoothLayout.blueCheck02.content.text =
|
|
||||||
getString(R.string.le_extended_advertising)
|
binding.bluetoothLayout.blueCheck02.image.isSelected =
|
||||||
binding.bluetoothLayout.blueCheck02.image.isSelected = features.leExtendedAdvertising
|
features.leExtendedAdvertising
|
||||||
binding.bluetoothLayout.blueCheck03.content.text =
|
|
||||||
getString(R.string.le_2m_phy_high_speed)
|
|
||||||
binding.bluetoothLayout.blueCheck03.image.isSelected = features.leCodedPhy
|
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.blueCheck04.image.isSelected = features.le2MbPhy
|
||||||
binding.bluetoothLayout.blueCheck05.content.text = getString(R.string.le_audio_support)
|
|
||||||
binding.bluetoothLayout.blueCheck05.image.isSelected = features.leAudioSupport
|
binding.bluetoothLayout.blueCheck05.image.isSelected = features.leAudioSupport
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求蓝牙权限的方法
|
// 请求蓝牙权限的方法
|
||||||
|
|||||||
@ -9,15 +9,20 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresPermission
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.xyzshell.andinfo.AndInfo
|
import com.xyzshell.andinfo.AndInfo
|
||||||
import com.xyzshell.andinfo.libs.NetworkInfo
|
import com.xyzshell.andinfo.libs.NetworkInfo
|
||||||
import com.xyzshell.myphoneinfo.R
|
import com.xyzshell.myphoneinfo.R
|
||||||
|
import com.xyzshell.myphoneinfo.base.BaseActivity
|
||||||
import com.xyzshell.myphoneinfo.custom.PermissionChecker
|
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.getHoursString
|
||||||
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.setYesOrNo
|
import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.setYesOrNo
|
||||||
import com.xyzshell.myphoneinfo.databinding.FragmentNetworkBinding
|
import com.xyzshell.myphoneinfo.databinding.FragmentNetworkBinding
|
||||||
import com.xyzshell.myphoneinfo.dialog.ShowLoadFragment
|
import com.xyzshell.myphoneinfo.dialog.ShowLoadFragment
|
||||||
|
import com.xyzshell.myphoneinfo.main.MainViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -26,13 +31,20 @@ import kotlin.toString
|
|||||||
|
|
||||||
class NetworkFragment : Fragment() {
|
class NetworkFragment : Fragment() {
|
||||||
|
|
||||||
private var status=0//0:未连接,1:wifi 2:数据流量
|
private var status = 0//0:未连接,1:wifi 2:数据流量
|
||||||
private lateinit var networkInfo: NetworkInfo
|
|
||||||
private lateinit var binding:FragmentNetworkBinding
|
private val mainViewModel: MainViewModel by activityViewModels()
|
||||||
|
private var refreshStatus =false//刷新状态
|
||||||
|
private lateinit var binding: FragmentNetworkBinding
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
override fun onResume(){
|
||||||
|
super.onResume()
|
||||||
|
checkPermissionsAndRefresh()
|
||||||
|
mainViewModel.refreshNetworkInfo(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
@ -40,209 +52,257 @@ private lateinit var binding:FragmentNetworkBinding
|
|||||||
): View {
|
): View {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
binding = FragmentNetworkBinding.inflate(inflater, container, false)
|
binding = FragmentNetworkBinding.inflate(inflater, container, false)
|
||||||
// binding.signalStrength.setStrength(4)
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
networkInfo= AndInfo.instance.network
|
initView()
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
setObservers()
|
||||||
delay(50) // 短暂延迟确保UI完成布局
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
refreshStatus()
|
|
||||||
if(PermissionChecker.getMissingPermissions(context = requireContext()).isNotEmpty()){
|
|
||||||
PermissionChecker.requestSimple(
|
|
||||||
requireActivity(),
|
|
||||||
onGranted = {
|
|
||||||
// 权限已授予,执行操作
|
|
||||||
refreshStatus()
|
|
||||||
},
|
|
||||||
onDenied = {
|
|
||||||
// 权限被拒绝
|
|
||||||
Toast.makeText(context, getString(R.string.permissions_required), Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
//wifi
|
|
||||||
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)
|
|
||||||
binding.networkLayout.wfText4.textTitle.text=getString(R.string.function)
|
|
||||||
binding.networkLayout.wfText5.textTitle.text=getString(R.string.connection_speed)
|
|
||||||
binding.networkLayout.wfText6.textTitle.text=getString(R.string.signal_strength)
|
|
||||||
binding.networkLayout.wfText7.textTitle.text=getString(R.string.frequency)
|
|
||||||
binding.networkLayout.wfText8.textTitle.text=getString(R.string.channel)
|
|
||||||
binding.networkLayout.wfText10.textTitle.text=getString(R.string.standard)
|
|
||||||
|
|
||||||
//dhcp
|
|
||||||
binding.networkLayout.dhText1.textTitle.text=getString(R.string.dhcp_server)
|
|
||||||
binding.networkLayout.dhText2.textTitle.text=getString(R.string.dhcp_lease_time)
|
|
||||||
binding.networkLayout.dhText3.textTitle.text=getString(R.string.gateway)
|
|
||||||
binding.networkLayout.dhText4.textTitle.text=getString(R.string.subnet_mask)
|
|
||||||
binding.networkLayout.dhText5.textTitle.text=getString(R.string.dns1)
|
|
||||||
binding.networkLayout.dhText6.textTitle.text=getString(R.string.dns2)
|
|
||||||
binding.networkLayout.dhText7.textTitle.text=getString(R.string.ip_address)
|
|
||||||
binding.networkLayout.dhText8.textTitle.text=getString(R.string.ipv6)
|
|
||||||
|
|
||||||
//Hardware
|
|
||||||
binding.networkLayout.hardCheck1.content.text=getString(R.string.standard_all)
|
|
||||||
binding.networkLayout.hardCheck2.content.text=getString(R.string.wifi_direct_support)
|
|
||||||
binding.networkLayout.hardCheck3.content.text=getString(R.string.wifi_aware_support)
|
|
||||||
binding.networkLayout.hardCheck4.content.text=getString(R.string.wifi_passpoint_support)
|
|
||||||
binding.networkLayout.hardCheck5.content.text=getString(R.string.ghz_band_support)
|
|
||||||
binding.networkLayout.hardCheck6.content.text=getString(R.string.ghz6_band_support)
|
|
||||||
|
|
||||||
//mobel
|
|
||||||
binding.mdText1.textTitle.text=getString(R.string.dual_sim_dual_standby)
|
|
||||||
binding.mdText2.textTitle.text=getString(R.string.phone_type)
|
|
||||||
binding.mdText3.textTitle.text=getString(R.string.esim)
|
|
||||||
|
|
||||||
binding.conTexts.textTitle.text=getString(R.string.status)
|
|
||||||
|
|
||||||
binding.defText1.textTitle.text=getString(R.string.data)
|
|
||||||
|
|
||||||
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) {
|
|
||||||
val showLoadFragment = ShowLoadFragment()
|
|
||||||
showLoadFragment.show(requireActivity().supportFragmentManager, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshStatus() {
|
private fun setObservers() {
|
||||||
val currentNetworkType = networkInfo.getCurrentNetworkType()
|
mainViewModel.networkStatus.observe(viewLifecycleOwner) { type ->
|
||||||
Log.d("NetworkFragment", "currentNetworkType: $currentNetworkType")
|
stop(binding.swipeRefresh)
|
||||||
when (currentNetworkType) {
|
when (type) {
|
||||||
NetworkInfo.NetworkType.WIFI -> {
|
NetworkInfo.NetworkType.WIFI -> {
|
||||||
status = 1
|
status = 1
|
||||||
setWifiDetail()
|
binding.conText1.text = getString(R.string.wifi)
|
||||||
setMobileInfo()
|
binding.connectData.visibility = View.VISIBLE
|
||||||
|
binding.noConnect.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkInfo.NetworkType.MOBILE -> {
|
NetworkInfo.NetworkType.MOBILE -> {
|
||||||
status = 2
|
status = 2
|
||||||
setWifiDetail()
|
binding.conText1.text = getString(R.string.mobile)
|
||||||
setMobileInfo()
|
binding.connectData.visibility = View.VISIBLE
|
||||||
|
binding.noConnect.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
status = 0
|
status = 0
|
||||||
setNoConnect()
|
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 = {
|
||||||
|
mainViewModel.refreshNetworkInfo(requireContext())
|
||||||
|
},
|
||||||
|
onDenied = {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
getString(R.string.permissions_required),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
setNoConnect()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
binding.networkLayout.wfText4.textTitle.text = getString(R.string.function)
|
||||||
|
binding.networkLayout.wfText5.textTitle.text = getString(R.string.connection_speed)
|
||||||
|
binding.networkLayout.wfText6.textTitle.text = getString(R.string.signal_strength)
|
||||||
|
binding.networkLayout.wfText7.textTitle.text = getString(R.string.frequency)
|
||||||
|
binding.networkLayout.wfText8.textTitle.text = getString(R.string.channel)
|
||||||
|
binding.networkLayout.wfText10.textTitle.text = getString(R.string.standard)
|
||||||
|
|
||||||
|
//dhcp
|
||||||
|
binding.networkLayout.dhText1.textTitle.text = getString(R.string.dhcp_server)
|
||||||
|
binding.networkLayout.dhText2.textTitle.text = getString(R.string.dhcp_lease_time)
|
||||||
|
binding.networkLayout.dhText3.textTitle.text = getString(R.string.gateway)
|
||||||
|
binding.networkLayout.dhText4.textTitle.text = getString(R.string.subnet_mask)
|
||||||
|
binding.networkLayout.dhText5.textTitle.text = getString(R.string.dns1)
|
||||||
|
binding.networkLayout.dhText6.textTitle.text = getString(R.string.dns2)
|
||||||
|
binding.networkLayout.dhText7.textTitle.text = getString(R.string.ip_address)
|
||||||
|
binding.networkLayout.dhText8.textTitle.text = getString(R.string.ipv6)
|
||||||
|
|
||||||
|
//Hardware
|
||||||
|
binding.networkLayout.hardCheck1.content.text = getString(R.string.standard_all)
|
||||||
|
binding.networkLayout.hardCheck2.content.text = getString(R.string.wifi_direct_support)
|
||||||
|
binding.networkLayout.hardCheck3.content.text = getString(R.string.wifi_aware_support)
|
||||||
|
binding.networkLayout.hardCheck4.content.text = getString(R.string.wifi_passpoint_support)
|
||||||
|
binding.networkLayout.hardCheck5.content.text = getString(R.string.ghz_band_support)
|
||||||
|
binding.networkLayout.hardCheck6.content.text = getString(R.string.ghz6_band_support)
|
||||||
|
|
||||||
|
//mobel
|
||||||
|
binding.mdText1.textTitle.text = getString(R.string.dual_sim_dual_standby)
|
||||||
|
binding.mdText2.textTitle.text = getString(R.string.phone_type)
|
||||||
|
binding.mdText3.textTitle.text = getString(R.string.esim)
|
||||||
|
|
||||||
|
binding.conTexts.textTitle.text = getString(R.string.status)
|
||||||
|
|
||||||
|
binding.defText1.textTitle.text = getString(R.string.data)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
val showLoadFragment = ShowLoadFragment()
|
||||||
|
showLoadFragment.show(requireActivity().supportFragmentManager, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.swipeRefresh.setOnRefreshListener {
|
||||||
|
load(binding.swipeRefresh){
|
||||||
|
Log.d("TTTTTTTT","刷新超时")
|
||||||
|
}
|
||||||
|
mainViewModel.refreshNetworkInfo(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun setNoConnect() {
|
private fun setNoConnect() {
|
||||||
binding.noConnect.visibility=View.VISIBLE
|
binding.noConnect.visibility = View.VISIBLE
|
||||||
binding.connectData.visibility=View.GONE
|
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.wifiList.visibility = View.GONE
|
||||||
binding.networkLayout.llPubShow.visibility=View.GONE
|
binding.networkLayout.llPubShow.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置流量信息
|
* 设置流量信息
|
||||||
* */
|
* */
|
||||||
private fun setMobileInfo() {
|
private fun setMobileInfo(mobileDetails: NetworkInfo.MobileDetails) {
|
||||||
binding.noConnect.visibility=View.GONE
|
binding.noConnect.visibility = View.GONE
|
||||||
binding.conText1.text=getString(R.string.mobile)
|
binding.conText1.text = getString(R.string.mobile)
|
||||||
binding.connectData.visibility=View.VISIBLE
|
binding.connectData.visibility = View.VISIBLE
|
||||||
Log.d("TTTTTTTT", "wifi not connected")
|
Log.d("TTTTTTTT", "wifi not connected")
|
||||||
binding.networkLayout.wifiList.visibility=View.GONE
|
binding.networkLayout.wifiList.visibility = View.GONE
|
||||||
binding.networkLayout.llPubShow.visibility=View.GONE
|
binding.networkLayout.llPubShow.visibility = View.GONE
|
||||||
networkInfo.getMobileDetails()?.let { mobileDetails ->
|
binding.mdText1.textContent.text = setYesOrNo(mobileDetails.dualSim)
|
||||||
binding.mdText1.textContent.text=setYesOrNo(mobileDetails.dualSim)
|
binding.mdText2.textContent.text = "SIM${mobileDetails.phoneType}"
|
||||||
binding.mdText2.textContent.text="SIM${mobileDetails.phoneType}"
|
binding.mdText3.textContent.text = setYesOrNo(mobileDetails.esimSupported)
|
||||||
binding.mdText3.textContent.text=setYesOrNo(mobileDetails.esimSupported)
|
binding.conTexts.textContent.text =
|
||||||
binding.conTexts.textContent.text=if(mobileDetails.dataEnabled) getString(R.string.connected) else getString(R.string.not_connected)
|
if (mobileDetails.dataEnabled) getString(R.string.connected) else getString(R.string.not_connected)
|
||||||
binding.defText1.textContent.text=mobileDetails.dataSim.toString()
|
binding.defText1.textContent.text = mobileDetails.dataSim.toString()
|
||||||
binding.defText2.textContent.text=mobileDetails.voiceSim.toString()
|
binding.defText2.textContent.text = mobileDetails.voiceSim.toString()
|
||||||
binding.defText3.textContent.text=mobileDetails.smsSim.toString()
|
binding.defText3.textContent.text = mobileDetails.smsSim.toString()
|
||||||
if(mobileDetails.simInfos.isNotEmpty()){
|
if (mobileDetails.simInfos.isNotEmpty()) {
|
||||||
binding.simInfo1.root.visibility=View.VISIBLE
|
binding.simInfo1.root.visibility = View.VISIBLE
|
||||||
binding.simInfo1.simText1.textTitle.text=getString(R.string.status)
|
binding.simInfo1.simText1.textTitle.text = getString(R.string.status)
|
||||||
binding.simInfo1.simText2.textTitle.text=getString(R.string.nation)
|
binding.simInfo1.simText2.textTitle.text = getString(R.string.nation)
|
||||||
binding.simInfo1.simText3.textTitle.text=getString(R.string.roaming)
|
binding.simInfo1.simText3.textTitle.text = getString(R.string.roaming)
|
||||||
binding.simInfo1.simText4.textTitle.text=getString(R.string.network_type)
|
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.simText1.textContent.text =
|
||||||
binding.simInfo1.simText2.textContent.text=mobileDetails.simInfos[0].countryIso.toString()
|
if (mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
||||||
binding.simInfo1.simText3.textContent.text=if(mobileDetails.simInfos[0].roaming) getString(R.string.enable) else getString(R.string.disable)
|
binding.simInfo1.simText2.textContent.text =
|
||||||
binding.simInfo1.simText4.textContent.text=mobileDetails.simInfos[0].networkTypeText
|
mobileDetails.simInfos[0].countryIso.toString()
|
||||||
if(mobileDetails.simInfos.size>1){
|
binding.simInfo1.simText3.textContent.text =
|
||||||
binding.simInfo2.root.visibility=View.VISIBLE
|
if (mobileDetails.simInfos[0].roaming) getString(R.string.enable) else getString(R.string.disable)
|
||||||
binding.simInfo2.simTitle.text=getString(R.string.sim_card_2)
|
binding.simInfo1.simText4.textContent.text = mobileDetails.simInfos[0].networkTypeText
|
||||||
binding.simInfo2.simText1.textTitle.text=getString(R.string.status)
|
if (mobileDetails.simInfos.size > 1) {
|
||||||
binding.simInfo2.simText2.textTitle.text=getString(R.string.nation)
|
binding.simInfo2.root.visibility = View.VISIBLE
|
||||||
binding.simInfo2.simText3.textTitle.text=getString(R.string.roaming)
|
binding.simInfo2.simTitle.text = getString(R.string.sim_card_2)
|
||||||
binding.simInfo2.simText4.textTitle.text=getString(R.string.network_type)
|
binding.simInfo2.simText1.textTitle.text = getString(R.string.status)
|
||||||
binding.simInfo2.simText1.textContent.text=if(mobileDetails.dataEnabled) getString(R.string.ready) else getString(R.string.not_ready)
|
binding.simInfo2.simText2.textTitle.text = getString(R.string.nation)
|
||||||
binding.simInfo2.simText2.textContent.text=mobileDetails.simInfos[1].countryIso.toString()
|
binding.simInfo2.simText3.textTitle.text = getString(R.string.roaming)
|
||||||
binding.simInfo2.simText3.textContent.text=if(mobileDetails.simInfos[1].roaming) getString(R.string.enable) else getString(R.string.disable)
|
binding.simInfo2.simText4.textTitle.text = getString(R.string.network_type)
|
||||||
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{
|
} else {
|
||||||
binding.simInfo1.root.visibility=View.GONE
|
binding.simInfo1.root.visibility = View.GONE
|
||||||
binding.simInfo2.root.visibility=View.GONE
|
binding.simInfo2.root.visibility = View.GONE
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置wifi信息
|
* 设置wifi信息
|
||||||
* */
|
* */
|
||||||
private fun setWifiDetail() {
|
private fun setWifiDetail(wifiDetails: NetworkInfo.WifiDetails) {
|
||||||
binding.noConnect.visibility=View.GONE
|
binding.noConnect.visibility = View.GONE
|
||||||
binding.conText1.text=getString(R.string.wifi)
|
binding.conText1.text = getString(R.string.wifi)
|
||||||
binding.connectData.visibility=View.VISIBLE
|
binding.connectData.visibility = View.VISIBLE
|
||||||
binding.networkLayout.wifiList.visibility=View.VISIBLE
|
binding.networkLayout.wifiList.visibility = View.VISIBLE
|
||||||
binding.networkLayout.llPubShow.visibility=View.VISIBLE
|
binding.networkLayout.llPubShow.visibility = View.VISIBLE
|
||||||
networkInfo.getWifiDetails()?.let { wifiDetails ->
|
|
||||||
Log.d("TTTTTTTT", wifiDetails.connected.toString())
|
Log.d("TTTTTTTT", wifiDetails.connected.toString())
|
||||||
binding.networkLayout.wifiList.visibility=View.VISIBLE
|
binding.networkLayout.wifiList.visibility = View.VISIBLE
|
||||||
binding.networkLayout.wfText1.textContent.text=getString(R.string.connected)
|
binding.networkLayout.wfText1.textContent.text = getString(R.string.connected)
|
||||||
wifiDetails.signalLevelPercent?.let { percent->
|
wifiDetails.signalLevelPercent?.let { percent ->
|
||||||
binding.strengthView.setStrength(calculateSignalLevel(percent = percent))
|
binding.strengthView.setStrength(calculateSignalLevel(percent = percent))
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.conText2.text="${wifiDetails.ssid}·${wifiDetails.linkSpeedMbps} Mbps"
|
binding.conText2.text = "${wifiDetails.ssid}·${wifiDetails.linkSpeedMbps} Mbps"
|
||||||
binding.conTExt3.text="${wifiDetails.signalLevelPercent}% ${wifiDetails.rssi} dBm"
|
binding.conTExt3.text = "${wifiDetails.signalLevelPercent}% ${wifiDetails.rssi} dBm"
|
||||||
|
|
||||||
binding.networkLayout.wfText3.textContent.text=wifiDetails.bssid
|
binding.networkLayout.wfText3.textContent.text = wifiDetails.bssid
|
||||||
binding.networkLayout.wfText4.textContent.text=wifiDetails.capabilities
|
binding.networkLayout.wfText4.textContent.text = wifiDetails.capabilities
|
||||||
binding.networkLayout.wfText5.textContent.text="${wifiDetails.linkSpeedMbps} Mbps"
|
binding.networkLayout.wfText5.textContent.text = "${wifiDetails.linkSpeedMbps} Mbps"
|
||||||
binding.networkLayout.wfText6.textContent.text="${wifiDetails.rssi} dBm"
|
binding.networkLayout.wfText6.textContent.text = "${wifiDetails.rssi} dBm"
|
||||||
binding.networkLayout.wfText7.textContent.text="${wifiDetails.frequency} MHz"
|
binding.networkLayout.wfText7.textContent.text = "${wifiDetails.frequency} MHz"
|
||||||
binding.networkLayout.wfText8.textContent.text=wifiDetails.channel.toString()
|
binding.networkLayout.wfText8.textContent.text = wifiDetails.channel.toString()
|
||||||
binding.networkLayout.wfText10.textContent.text=wifiDetails.standard.toString()
|
binding.networkLayout.wfText10.textContent.text = wifiDetails.standard.toString()
|
||||||
|
|
||||||
binding.networkLayout.dhText1.textContent.text=wifiDetails.dhcpServer
|
binding.networkLayout.dhText1.textContent.text = wifiDetails.dhcpServer
|
||||||
binding.networkLayout.dhText2.textContent.text=getHoursString(wifiDetails.leaseDuration?: 0)
|
binding.networkLayout.dhText2.textContent.text =
|
||||||
binding.networkLayout.dhText3.textContent.text=wifiDetails.gateway
|
getHoursString(wifiDetails.leaseDuration ?: 0)
|
||||||
binding.networkLayout.dhText4.textContent.text=wifiDetails.subnetMask
|
binding.networkLayout.dhText3.textContent.text = wifiDetails.gateway
|
||||||
binding.networkLayout.dhText5.textContent.text=wifiDetails.dns1
|
binding.networkLayout.dhText4.textContent.text = wifiDetails.subnetMask
|
||||||
binding.networkLayout.dhText6.textContent.text=wifiDetails.dns2
|
binding.networkLayout.dhText5.textContent.text = wifiDetails.dns1
|
||||||
binding.networkLayout.dhText7.textContent.text=wifiDetails.ip
|
binding.networkLayout.dhText6.textContent.text = wifiDetails.dns2
|
||||||
|
binding.networkLayout.dhText7.textContent.text = wifiDetails.ip
|
||||||
val toString = wifiDetails.ipv6.toString()
|
val toString = wifiDetails.ipv6.toString()
|
||||||
val ipv6 = toString.replace("[", "").replace("]", "")
|
val ipv6 = toString.replace("[", "").replace("]", "")
|
||||||
binding.networkLayout.dhText8.textContent.text=ipv6
|
binding.networkLayout.dhText8.textContent.text = ipv6
|
||||||
|
|
||||||
binding.networkLayout.hardCheck1.image.isSelected= wifiDetails.supportedStandards?.size==5
|
binding.networkLayout.hardCheck1.image.isSelected =
|
||||||
binding.networkLayout.hardCheck2.image.isSelected= wifiDetails.wifiDirect == true
|
wifiDetails.supportedStandards?.size == 5
|
||||||
binding.networkLayout.hardCheck3.image.isSelected= wifiDetails.wifiAware == true
|
binding.networkLayout.hardCheck2.image.isSelected = wifiDetails.wifiDirect == true
|
||||||
binding.networkLayout.hardCheck4.image.isSelected= wifiDetails.wifiPasspoint == true
|
binding.networkLayout.hardCheck3.image.isSelected = wifiDetails.wifiAware == true
|
||||||
binding.networkLayout.hardCheck5.image.isSelected= wifiDetails.support5G == true
|
binding.networkLayout.hardCheck4.image.isSelected = wifiDetails.wifiPasspoint == true
|
||||||
binding.networkLayout.hardCheck6.image.isSelected= wifiDetails.support6G == true
|
binding.networkLayout.hardCheck5.image.isSelected = wifiDetails.support5G == true
|
||||||
|
binding.networkLayout.hardCheck6.image.isSelected = wifiDetails.support6G == true
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateSignalLevel( percent: Int) : Int {
|
private fun calculateSignalLevel(percent: Int): Int {
|
||||||
return when {
|
return when {
|
||||||
percent >= 80 -> 5 // 优秀
|
percent >= 80 -> 5 // 优秀
|
||||||
percent >= 60 -> 4 // 良好
|
percent >= 60 -> 4 // 良好
|
||||||
@ -251,6 +311,7 @@ private lateinit var binding:FragmentNetworkBinding
|
|||||||
else -> 1 // 非常差/无信号
|
else -> 1 // 非常差/无信号
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.xyzshell.myphoneinfo.main
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.xyzshell.andinfo.AndInfo
|
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.dashboard.SystemShowFragment
|
||||||
import com.xyzshell.myphoneinfo.databinding.ActivityMainBinding
|
import com.xyzshell.myphoneinfo.databinding.ActivityMainBinding
|
||||||
import com.xyzshell.myphoneinfo.dialog.SlideInPopView
|
import com.xyzshell.myphoneinfo.dialog.SlideInPopView
|
||||||
|
import kotlin.getValue
|
||||||
|
|
||||||
class MainScrollActivity : BaseActivity<ActivityMainBinding>() {
|
class MainScrollActivity : BaseActivity<ActivityMainBinding>() {
|
||||||
override fun inflateBinding(inflater: LayoutInflater): ActivityMainBinding =
|
override fun inflateBinding(inflater: LayoutInflater): ActivityMainBinding =
|
||||||
@ -48,12 +50,6 @@ class MainScrollActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
})
|
})
|
||||||
}) { tab, position ->
|
}) { tab, position ->
|
||||||
tab.text = stringArray[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()
|
}.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"
|
android:id="@+id/dialog_title"
|
||||||
style="@style/TextHeavy20"
|
style="@style/TextHeavy20"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="80dp"
|
android:layout_marginStart="80dp"
|
||||||
android:text="@string/screenreader"
|
android:text="@string/screenreader"
|
||||||
app:layout_constraintLeft_toRightOf="@id/image_icon"
|
app:layout_constraintLeft_toRightOf="@id/image_icon"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/image_icon"
|
app:layout_constraintTop_toTopOf="@id/image_icon"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/image_icon"/>
|
app:layout_constraintBottom_toBottomOf="@id/image_icon"/>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/swipeRefresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
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"
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:id="@+id/swipeRefresh"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/background_color"
|
android:background="@color/background_color"
|
||||||
tools:context=".dashboard.NetworkFragment">
|
tools:context=".dashboard.NetworkFragment">
|
||||||
|
|||||||
@ -51,7 +51,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
layout="@layout/mem_text_style" />
|
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
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user