diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/custom/SetNumberOrWordUtils.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/custom/SetNumberOrWordUtils.kt index 40736dd..78b9a7f 100644 --- a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/custom/SetNumberOrWordUtils.kt +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/custom/SetNumberOrWordUtils.kt @@ -1,5 +1,10 @@ package com.xyzshell.myphoneinfo.custom +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale +import java.util.TimeZone import kotlin.math.abs object SetNumberOrWordUtils { @@ -98,5 +103,36 @@ object SetNumberOrWordUtils { fun setYesOrNo(boolean: Boolean): String { return if (boolean) "Yes" else "No" } + // Long 扩展函数:获取格式化日期字符串 + fun Long.toFormattedDate( + pattern: String = "MMMM dd, yyyy h:mm a", + timeZone: TimeZone = TimeZone.getDefault() + ): String { + val sdf = SimpleDateFormat(pattern, Locale.getDefault()) + sdf.timeZone = timeZone + return sdf.format(Date(this)) + } + // 获取各个时间字段的扩展函数 + fun Long.toCalendar(): Calendar { + return Calendar.getInstance().apply { + time = Date(this@toCalendar) + } + } + + fun Long.getYear(): Int = this.toCalendar().get(Calendar.YEAR) + fun Long.getMonth(): Int = this.toCalendar().get(Calendar.MONTH) + 1 + fun Long.getDay(): Int = this.toCalendar().get(Calendar.DAY_OF_MONTH) + fun Long.getHour(): Int = this.toCalendar().get(Calendar.HOUR_OF_DAY) + fun Long.getMinute(): Int = this.toCalendar().get(Calendar.MINUTE) + fun Long.getSecond(): Int = this.toCalendar().get(Calendar.SECOND) + fun Long.getMillisecond(): Int = this.toCalendar().get(Calendar.MILLISECOND) + + // Long 扩展函数:获取格式化大小字符串 + fun Long.toSizeString(): String = when { + this < 1000 -> "$this B" + this < 1000*1000 -> "%.1f KB".format(this/1000.0) + this < 1000*1000*1000 -> "%.1f MB".format(this/(1000.0*1000)) + else -> "%.1f GB".format(this/(1000.0*1000*1000)) + } } \ No newline at end of file diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/AppsFragment.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/AppsFragment.kt index e8a5bd8..2e4df6e 100644 --- a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/AppsFragment.kt +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/AppsFragment.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.xyzshell.andinfo.AndInfo import com.xyzshell.andinfo.libs.AppDetails @@ -15,6 +16,10 @@ 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 kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener { private lateinit var binding: FragmentAppsBinding @@ -34,15 +39,25 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener { val adapter= AppListAdapter() val installedApps = AndInfo.instance.app.getInstalledApps() val userSize=installedApps.size - adapter.setList(installedApps) - adapter.setOnclickListener(this) + viewLifecycleOwner.lifecycleScope.launch { + delay(50) // 短暂延迟确保UI完成布局 + withContext(Dispatchers.Main) { + adapter.setList(installedApps) + 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 + 0 -> "User($userSize)" + 1 -> "System(23)" + 2 -> "All(23)" + else -> "None" + } binding.llTitle.setOnClickListener { bottomDialog= BottomDialogFragment(type = "apps", sel = sel, invoke = {item-> sel = item binding.tvTitle.text=when(item){ - 0 -> "User$userSize" + 0 -> "User($userSize)" 1 -> "System(23)" 2 -> "All(23)" else -> "None" @@ -66,7 +81,7 @@ class AppsFragment : Fragment(),AppListAdapter.OnShowDialogListener { } override fun onShowAppSelectDialog(item: AppDetails) { - dialogFragment = AppDialogFragment() + dialogFragment = AppDialogFragment(item) dialogFragment.show(requireActivity().supportFragmentManager, "AppDialogFragment") } diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/NetworkFragment.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/NetworkFragment.kt index f09bc1d..97fe63a 100644 --- a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/NetworkFragment.kt +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dashboard/NetworkFragment.kt @@ -9,6 +9,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.annotation.RequiresPermission +import androidx.lifecycle.lifecycleScope import com.xyzshell.andinfo.AndInfo import com.xyzshell.andinfo.libs.NetworkInfo import com.xyzshell.myphoneinfo.R @@ -17,6 +18,10 @@ 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 kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import kotlin.toString class NetworkFragment : Fragment() { @@ -42,69 +47,74 @@ private lateinit var binding:FragmentNetworkBinding override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) networkInfo= AndInfo.instance.network - 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() + viewLifecycleOwner.lifecycleScope.launch { + 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) + //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) + 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) + //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) + //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) + //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.conTexts.textTitle.text=getString(R.string.status) - binding.defText1.textTitle.text=getString(R.string.data) + 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.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.networkLayout.pubShow.setOnClickListener{ + val tag = "showLoadFragment" + if (requireActivity().supportFragmentManager.findFragmentByTag(tag) == null) { + val showLoadFragment = ShowLoadFragment() + showLoadFragment.show(requireActivity().supportFragmentManager, tag) + } + } + }} + } private fun refreshStatus() { diff --git a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dialog/AppDialogFragment.kt b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dialog/AppDialogFragment.kt index 821c41f..0528b62 100644 --- a/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dialog/AppDialogFragment.kt +++ b/myphoneinfo/src/main/java/com/xyzshell/myphoneinfo/dialog/AppDialogFragment.kt @@ -1,23 +1,39 @@ package com.xyzshell.myphoneinfo.dialog import android.graphics.Color +import android.graphics.drawable.Drawable import android.os.Bundle +import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.WindowManager +import android.widget.LinearLayout import androidx.core.graphics.drawable.toDrawable import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import com.xyzshell.andinfo.libs.AppDetails +import com.xyzshell.myphoneinfo.R +import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.toFormattedDate +import com.xyzshell.myphoneinfo.custom.SetNumberOrWordUtils.toSizeString +import com.xyzshell.myphoneinfo.databinding.CommonCheckStyle2Binding import com.xyzshell.myphoneinfo.databinding.DialogAppClickBinding +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext -class AppDialogFragment : DialogFragment() { +class AppDialogFragment(var appInfo:AppDetails) : DialogFragment() { private var _binding: DialogAppClickBinding? = null private val baseBinding get() = _binding!! + private lateinit var appDetails:AppDetails - open fun onPositiveClick() {} + open fun onPositiveClick() { + + } override fun onCreateView( inflater: LayoutInflater, @@ -25,18 +41,74 @@ class AppDialogFragment : DialogFragment() { savedInstanceState: Bundle? ): View { _binding = DialogAppClickBinding.inflate(inflater, container, false) + appDetails = appInfo return baseBinding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - + setBasicAppInfo() + loadPermissionsAsync() baseBinding.textCancel.setOnClickListener { onPositiveClick() dismiss() } + baseBinding.textManage.setOnClickListener { + dismiss() + } } + private fun loadPermissionsAsync() { + viewLifecycleOwner.lifecycleScope.launch { + delay(50) // 短暂延迟确保UI完成布局 + withContext(Dispatchers.Main) { + appDetails.permissions.forEach { + //允许 + val allowedView= LayoutInflater.from(context).inflate(R.layout.common_check_style2,baseBinding.allowedLL,false) + val allowedBinding = CommonCheckStyle2Binding.bind(allowedView) + //不允许 + val notAllowedView= LayoutInflater.from(context).inflate(R.layout.common_check_style1,baseBinding.notAllowedLL,false) + val notAllowedBinding = CommonCheckStyle2Binding.bind(notAllowedView) + //特殊 + val specialView= LayoutInflater.from(context).inflate(R.layout.common_check_style3,baseBinding.specialLL,false) + val specialBinding = CommonCheckStyle2Binding.bind(specialView) + when(it.status){ + "Allowed"->{ + baseBinding.allowedTv.visibility = View.VISIBLE + allowedBinding.content.text = it.name + baseBinding.allowedLL.addView(allowedView) + } + "Denied"->{ + baseBinding.notAllowedTv.visibility = View.VISIBLE + notAllowedBinding.content.text = it.name + baseBinding.notAllowedLL.addView(notAllowedView) + } + "Special Access"->{ + baseBinding.specialTv.visibility = View.VISIBLE + specialBinding.content.text = it.name + baseBinding.specialLL.addView(specialView) + } + } + Log.d("AppDialogFragment", it.status) + } + }} + + } + + private fun setBasicAppInfo() { + baseBinding.imageIcon.setImageDrawable(appDetails.icon as? Drawable) + baseBinding.dialogTitle.text = appDetails.appName + baseBinding.tv1.setValue(appDetails.packageName) + baseBinding.tv2.setValue(appDetails.versionName.toString()) + baseBinding.tv3.setValue(appDetails.targetSdkVersion.toString()) + baseBinding.tv4.setValue(appDetails.minSdkVersion.toString()) +// todo baseBinding.tv5.setValue(appDetails.packageName) + baseBinding.tv6.setValue(appDetails.installer.toString()) + baseBinding.tv7.setValue(appDetails.size.toSizeString()) + baseBinding.tv8.setValue(appDetails.uid.toString()) + baseBinding.tv9.setValue("${appDetails.lastUpdateTime.toFormattedDate(pattern = "MMM dd, yyyy h:mm a")}") + + } override fun onStart() { super.onStart() dialog?.window?.let { window -> @@ -56,4 +128,6 @@ class AppDialogFragment : DialogFragment() { super.onDestroyView() _binding = null } + + } \ No newline at end of file diff --git a/myphoneinfo/src/main/res/layout/common_dialog_item.xml b/myphoneinfo/src/main/res/layout/common_dialog_item.xml index 119fdeb..e392793 100644 --- a/myphoneinfo/src/main/res/layout/common_dialog_item.xml +++ b/myphoneinfo/src/main/res/layout/common_dialog_item.xml @@ -34,7 +34,6 @@ android:layout_alignTop="@id/tv_label" android:layout_marginStart="35dp" android:layout_toEndOf="@id/tv_label" - android:gravity="center" android:textSize="15sp" android:textColor="#C1C5C2" android:text="sppppppppppppppppppppp" /> diff --git a/myphoneinfo/src/main/res/layout/dialog_app_click.xml b/myphoneinfo/src/main/res/layout/dialog_app_click.xml index c0a8750..6b501f0 100644 --- a/myphoneinfo/src/main/res/layout/dialog_app_click.xml +++ b/myphoneinfo/src/main/res/layout/dialog_app_click.xml @@ -1,44 +1,53 @@ - - - - - - + + android:paddingBottom="35dp" + > + + + + + + + - - - + + @@ -219,4 +236,4 @@ /> - + diff --git a/myphoneinfo/src/main/res/layout/fragment_apps.xml b/myphoneinfo/src/main/res/layout/fragment_apps.xml index 1b14421..1fe888b 100644 --- a/myphoneinfo/src/main/res/layout/fragment_apps.xml +++ b/myphoneinfo/src/main/res/layout/fragment_apps.xml @@ -35,7 +35,7 @@ android:layout_width="wrap_content" android:id="@+id/tvTitle" android:layout_height="wrap_content" - android:text="User apps (23)" + android:text="" style="@style/TextHeavy20" android:textSize="16sp" /> diff --git a/myphoneinfo/src/main/res/layout/item_app_list.xml b/myphoneinfo/src/main/res/layout/item_app_list.xml index 4b75675..3fa9e00 100644 --- a/myphoneinfo/src/main/res/layout/item_app_list.xml +++ b/myphoneinfo/src/main/res/layout/item_app_list.xml @@ -1,6 +1,7 @@ - Minimum SDK Installer type Installed + Last updated time UID Permissions Allowed