Using AI to improve function documentation

This commit is contained in:
2dust
2025-03-19 11:01:07 +08:00
parent 172d9fd093
commit faa4385087
9 changed files with 337 additions and 43 deletions

View File

@@ -8,6 +8,12 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
object AppManagerUtil {
/**
* Load the list of network applications.
*
* @param context The context to use.
* @return A list of AppInfo objects representing the network applications.
*/
suspend fun loadNetworkAppList(context: Context): ArrayList<AppInfo> =
withContext(Dispatchers.IO) {
val packageManager = context.packageManager

View File

@@ -10,11 +10,24 @@ import java.util.*
object HttpUtil {
/**
* Converts a URL string to its ASCII representation.
*
* @param str The URL string to convert.
* @return The ASCII representation of the URL.
*/
fun idnToASCII(str: String): String {
val url = URL(str)
return URL(url.protocol, IDN.toASCII(url.host, IDN.ALLOW_UNASSIGNED), url.port, url.file).toExternalForm()
}
/**
* Retrieves the content of a URL as a string.
*
* @param url The URL to fetch content from.
* @param timeout The timeout value in milliseconds.
* @return The content of the URL as a string.
*/
fun getUrlContent(url: String, timeout: Int): String {
var result: String = ""
val conn = createProxyConnection(url, 0, timeout, timeout) ?: return result
@@ -27,6 +40,15 @@ object HttpUtil {
return result
}
/**
* Retrieves the content of a URL as a string with a custom User-Agent header.
*
* @param url The URL to fetch content from.
* @param timeout The timeout value in milliseconds.
* @param httpPort The HTTP port to use.
* @return The content of the URL as a string.
* @throws IOException If an I/O error occurs.
*/
@Throws(IOException::class)
fun getUrlContentWithUserAgent(url: String?, timeout: Int = 30000, httpPort: Int = 0): String {
var currentUrl = url
@@ -65,11 +87,10 @@ object HttpUtil {
* Creates an HttpURLConnection object connected through a proxy.
*
* @param urlStr The target URL address.
* @param ip The IP address of the proxy server.
* @param port The port of the proxy server.
* @param connectTimeout The connection timeout in milliseconds (default is 30000 ms).
* @param readTimeout The read timeout in milliseconds (default is 30000 ms).
* @param needStream
* @param needStream Whether the connection needs to support streaming.
* @return Returns a configured HttpURLConnection object, or null if it fails.
*/
fun createProxyConnection(

View File

@@ -13,14 +13,33 @@ import java.lang.reflect.Type
object JsonUtil {
private var gson = Gson()
/**
* Converts an object to its JSON representation.
*
* @param src The object to convert.
* @return The JSON representation of the object.
*/
fun toJson(src: Any?): String {
return gson.toJson(src)
}
/**
* Parses a JSON string into an object of the specified class.
*
* @param src The JSON string to parse.
* @param cls The class of the object to parse into.
* @return The parsed object.
*/
fun <T> fromJson(src: String, cls: Class<T>): T {
return gson.fromJson(src, cls)
}
/**
* Converts an object to its pretty-printed JSON representation.
*
* @param src The object to convert.
* @return The pretty-printed JSON representation of the object, or null if the object is null.
*/
fun toJsonPretty(src: Any?): String? {
if (src == null)
return null
@@ -39,6 +58,12 @@ object JsonUtil {
return gsonPre.toJson(src)
}
/**
* Parses a JSON string into a JsonObject.
*
* @param src The JSON string to parse.
* @return The parsed JsonObject, or null if parsing fails.
*/
fun parseString(src: String?): JsonObject? {
if (src == null)
return null

View File

@@ -7,17 +7,37 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.service.V2RayTestService
import java.io.Serializable
object MessageUtil {
/**
* Sends a message to the service.
*
* @param ctx The context.
* @param what The message identifier.
* @param content The message content.
*/
fun sendMsg2Service(ctx: Context, what: Int, content: Serializable) {
sendMsg(ctx, AppConfig.BROADCAST_ACTION_SERVICE, what, content)
}
/**
* Sends a message to the UI.
*
* @param ctx The context.
* @param what The message identifier.
* @param content The message content.
*/
fun sendMsg2UI(ctx: Context, what: Int, content: Serializable) {
sendMsg(ctx, AppConfig.BROADCAST_ACTION_ACTIVITY, what, content)
}
/**
* Sends a message to the test service.
*
* @param ctx The context.
* @param what The message identifier.
* @param content The message content.
*/
fun sendMsg2TestService(ctx: Context, what: Int, content: Serializable) {
try {
val intent = Intent()
@@ -30,6 +50,14 @@ object MessageUtil {
}
}
/**
* Sends a message with the specified action.
*
* @param ctx The context.
* @param action The action string.
* @param what The message identifier.
* @param content The message content.
*/
private fun sendMsg(ctx: Context, action: String, what: Int, content: Serializable) {
try {
val intent = Intent()

View File

@@ -11,12 +11,18 @@ import java.util.Locale
open class MyContextWrapper(base: Context?) : ContextWrapper(base) {
companion object {
/**
* Wraps the context with a new locale.
*
* @param context The original context.
* @param newLocale The new locale to set.
* @return A ContextWrapper with the new locale.
*/
@RequiresApi(Build.VERSION_CODES.N)
fun wrap(context: Context, newLocale: Locale?): ContextWrapper {
var mContext = context
val res: Resources = mContext.resources
val configuration: Configuration = res.configuration
//注意 Android 7.0 前后的不同处理方法
mContext = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(newLocale)
val localeList = LocaleList(newLocale)

View File

@@ -12,17 +12,19 @@ import com.v2ray.ang.service.ProcessService
import java.io.File
object PluginUtil {
//private const val HYSTERIA2 = "hysteria2-plugin"
private const val HYSTERIA2 = "libhysteria2.so"
private const val TAG = ANG_PACKAGE
private val procService: ProcessService by lazy {
ProcessService()
}
// fun initPlugin(name: String): PluginManager.InitResult {
// return PluginManager.init(name)!!
// }
/**
* Run the plugin based on the provided configuration.
*
* @param context The context to use.
* @param config The profile configuration.
* @param domainPort The domain and port information.
*/
fun runPlugin(context: Context, config: ProfileItem?, domainPort: String?) {
Log.d(TAG, "runPlugin")
@@ -34,10 +36,20 @@ object PluginUtil {
}
}
/**
* Stop the running plugin.
*/
fun stopPlugin() {
stopHy2()
}
/**
* Perform a real ping using Hysteria2.
*
* @param context The context to use.
* @param config The profile configuration.
* @return The ping delay in milliseconds, or -1 if it fails.
*/
fun realPingHy2(context: Context, config: ProfileItem?): Long {
Log.d(TAG, "realPingHy2")
val retFailure = -1L
@@ -58,6 +70,14 @@ object PluginUtil {
return retFailure
}
/**
* Generate the configuration file for Hysteria2.
*
* @param context The context to use.
* @param config The profile configuration.
* @param domainPort The domain and port information.
* @return The generated configuration file.
*/
private fun genConfigHy2(context: Context, config: ProfileItem, domainPort: String?): File? {
Log.d(TAG, "runPlugin $HYSTERIA2")
@@ -75,10 +95,16 @@ object PluginUtil {
return configFile
}
/**
* Generate the command to run Hysteria2.
*
* @param context The context to use.
* @param configFile The configuration file.
* @return The command to run Hysteria2.
*/
private fun genCmdHy2(context: Context, configFile: File): MutableList<String> {
return mutableListOf(
File(context.applicationInfo.nativeLibraryDir, HYSTERIA2).absolutePath,
//initPlugin(HYSTERIA2).path,
"--disable-update-check",
"--config",
configFile.absolutePath,
@@ -88,6 +114,9 @@ object PluginUtil {
)
}
/**
* Stop the Hysteria2 process.
*/
private fun stopHy2() {
try {
Log.d(TAG, "$HYSTERIA2 destroy")

View File

@@ -14,13 +14,17 @@ import com.google.zxing.qrcode.QRCodeWriter
import java.util.EnumMap
/**
* 描述:解析二维码图片
* QR code decoder utility.
*/
object QRCodeDecoder {
val HINTS: MutableMap<DecodeHintType, Any?> = EnumMap(DecodeHintType::class.java)
/**
* create qrcode using zxing
* Creates a QR code bitmap from the given text.
*
* @param text The text to encode in the QR code.
* @param size The size of the QR code bitmap.
* @return The generated QR code bitmap, or null if an error occurs.
*/
fun createQRCode(text: String, size: Int = 800): Bitmap? {
return runCatching {
@@ -35,22 +39,21 @@ object QRCodeDecoder {
}.getOrNull()
}
/**
* 同步解析本地图片二维码。该方法是耗时操作,请在子线程中调用。
* Decodes a QR code from a local image file. This method is time-consuming and should be called in a background thread.
*
* @param picturePath 要解析的二维码图片本地路径
* @return 返回二维码图片里的内容 或 null
* @param picturePath The local path of the image file to decode.
* @return The content of the QR code, or null if decoding fails.
*/
fun syncDecodeQRCode(picturePath: String): String? {
return syncDecodeQRCode(getDecodeAbleBitmap(picturePath))
}
/**
* 同步解析bitmap二维码。该方法是耗时操作请在子线程中调用。
* Decodes a QR code from a bitmap. This method is time-consuming and should be called in a background thread.
*
* @param bitmap 要解析的二维码图片
* @return 返回二维码图片里的内容 或 null
* @param bitmap The bitmap to decode.
* @return The content of the QR code, or null if decoding fails.
*/
fun syncDecodeQRCode(bitmap: Bitmap?): String? {
return bitmap?.let {
@@ -70,12 +73,11 @@ object QRCodeDecoder {
}
}
/**
* 将本地图片文件转换成可解码二维码的 Bitmap。为了避免图片太大这里对图片进行了压缩。感谢 https://github.com/devilsen 提的 PR
* Converts a local image file to a bitmap that can be decoded as a QR code. The image is compressed to avoid being too large.
*
* @param picturePath 本地图片文件路径
* @return
* @param picturePath The local path of the image file.
* @return The decoded bitmap, or null if an error occurs.
*/
private fun getDecodeAbleBitmap(picturePath: String): Bitmap? {
return try {

View File

@@ -30,17 +30,21 @@ import java.util.UUID
object Utils {
/**
* convert string to editalbe for kotlin
* Convert string to editable for Kotlin.
*
* @param text
* @return
* @param text The string to convert.
* @return An Editable instance containing the text.
*/
fun getEditable(text: String?): Editable {
return Editable.Factory.getInstance().newEditable(text.orEmpty())
}
/**
* find value in array position
* Find the position of a value in an array.
*
* @param array The array to search.
* @param value The value to find.
* @return The index of the value in the array, or -1 if not found.
*/
fun arrayFind(array: Array<out String>, value: String): Int {
for (i in array.indices) {
@@ -52,19 +56,31 @@ object Utils {
}
/**
* parseInt
* Parse a string to an integer.
*
* @param str The string to parse.
* @return The parsed integer, or 0 if parsing fails.
*/
fun parseInt(str: String): Int {
return parseInt(str, 0)
}
/**
* Parse a string to an integer with a default value.
*
* @param str The string to parse.
* @param default The default value if parsing fails.
* @return The parsed integer, or the default value if parsing fails.
*/
fun parseInt(str: String?, default: Int): Int {
return str?.toIntOrNull() ?: default
}
/**
* get text from clipboard
* Get text from the clipboard.
*
* @param context The context to use.
* @return The text from the clipboard, or an empty string if an error occurs.
*/
fun getClipboard(context: Context): String {
return try {
@@ -77,7 +93,10 @@ object Utils {
}
/**
* set text to clipboard
* Set text to the clipboard.
*
* @param context The context to use.
* @param content The text to set to the clipboard.
*/
fun setClipboard(context: Context, content: String) {
try {
@@ -90,13 +109,21 @@ object Utils {
}
/**
* base64 decode
* Decode a base64 encoded string.
*
* @param text The base64 encoded string.
* @return The decoded string, or an empty string if decoding fails.
*/
fun decode(text: String?): String {
return tryDecodeBase64(text) ?: text?.trimEnd('=')?.let { tryDecodeBase64(it) }.orEmpty()
}
/**
* Try to decode a base64 encoded string.
*
* @param text The base64 encoded string.
* @return The decoded string, or null if decoding fails.
*/
fun tryDecodeBase64(text: String?): String? {
try {
return Base64.decode(text, Base64.NO_WRAP).toString(Charsets.UTF_8)
@@ -112,7 +139,10 @@ object Utils {
}
/**
* base64 encode
* Encode a string to base64.
*
* @param text The string to encode.
* @return The base64 encoded string, or an empty string if encoding fails.
*/
fun encode(text: String): String {
return try {
@@ -123,9 +153,11 @@ object Utils {
}
}
/**
* is ip address
* Check if a string is a valid IP address.
*
* @param value The string to check.
* @return True if the string is a valid IP address, false otherwise.
*/
fun isIpAddress(value: String?): Boolean {
try {
@@ -169,16 +201,34 @@ object Utils {
}
}
/**
* Check if a string is a pure IP address (IPv4 or IPv6).
*
* @param value The string to check.
* @return True if the string is a pure IP address, false otherwise.
*/
fun isPureIpAddress(value: String): Boolean {
return isIpv4Address(value) || isIpv6Address(value)
}
/**
* Check if a string is a valid IPv4 address.
*
* @param value The string to check.
* @return True if the string is a valid IPv4 address, false otherwise.
*/
private fun isIpv4Address(value: String): Boolean {
val regV4 =
Regex("^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$")
return regV4.matches(value)
}
/**
* Check if a string is a valid IPv6 address.
*
* @param value The string to check.
* @return True if the string is a valid IPv6 address, false otherwise.
*/
private fun isIpv6Address(value: String): Boolean {
var addr = value
if (addr.indexOf("[") == 0 && addr.lastIndexOf("]") > 0) {
@@ -190,6 +240,12 @@ object Utils {
return regV6.matches(addr)
}
/**
* Check if a string is a CoreDNS address.
*
* @param s The string to check.
* @return True if the string is a CoreDNS address, false otherwise.
*/
fun isCoreDNSAddress(s: String): Boolean {
return s.startsWith("https")
|| s.startsWith("tcp")
@@ -198,7 +254,10 @@ object Utils {
}
/**
* is valid url
* Check if a string is a valid URL.
*
* @param value The string to check.
* @return True if the string is a valid URL, false otherwise.
*/
fun isValidUrl(value: String?): Boolean {
try {
@@ -218,14 +277,21 @@ object Utils {
return false
}
/**
* Open a URI in a browser.
*
* @param context The context to use.
* @param uriString The URI string to open.
*/
fun openUri(context: Context, uriString: String) {
val uri = uriString.toUri()
context.startActivity(Intent(Intent.ACTION_VIEW, uri))
}
/**
* uuid
* Generate a UUID.
*
* @return A UUID string without dashes.
*/
fun getUuid(): String {
return try {
@@ -236,6 +302,12 @@ object Utils {
}
}
/**
* Decode a URL-encoded string.
*
* @param url The URL-encoded string.
* @return The decoded string, or the original string if decoding fails.
*/
fun urlDecode(url: String): String {
return try {
URLDecoder.decode(url, Charsets.UTF_8.toString())
@@ -245,6 +317,12 @@ object Utils {
}
}
/**
* Encode a string to URL-encoded format.
*
* @param url The string to encode.
* @return The URL-encoded string, or the original string if encoding fails.
*/
fun urlEncode(url: String): String {
return try {
URLEncoder.encode(url, Charsets.UTF_8.toString()).replace("+", "%20")
@@ -254,9 +332,12 @@ object Utils {
}
}
/**
* readTextFromAssets
* Read text from an asset file.
*
* @param context The context to use.
* @param fileName The name of the asset file.
* @return The content of the asset file as a string.
*/
fun readTextFromAssets(context: Context?, fileName: String): String {
if (context == null) {
@@ -268,6 +349,12 @@ object Utils {
return content
}
/**
* Get the path to the user asset directory.
*
* @param context The context to use.
* @return The path to the user asset directory.
*/
fun userAssetPath(context: Context?): String {
if (context == null)
return ""
@@ -276,6 +363,12 @@ object Utils {
return extDir.absolutePath
}
/**
* Get the path to the backup directory.
*
* @param context The context to use.
* @return The path to the backup directory.
*/
fun backupPath(context: Context?): String {
if (context == null)
return ""
@@ -284,15 +377,32 @@ object Utils {
return extDir.absolutePath
}
/**
* Get the device ID for XUDP base key.
*
* @return The device ID for XUDP base key.
*/
fun getDeviceIdForXUDPBaseKey(): String {
val androidId = Settings.Secure.ANDROID_ID.toByteArray(Charsets.UTF_8)
return Base64.encodeToString(androidId.copyOf(32), Base64.NO_PADDING.or(Base64.URL_SAFE))
}
/**
* Get the dark mode status.
*
* @param context The context to use.
* @return True if dark mode is enabled, false otherwise.
*/
fun getDarkModeStatus(context: Context): Boolean {
return context.resources.configuration.uiMode and UI_MODE_NIGHT_MASK != UI_MODE_NIGHT_NO
}
/**
* Get the IPv6 address in a formatted string.
*
* @param address The IPv6 address.
* @return The formatted IPv6 address, or the original address if not valid.
*/
fun getIpv6Address(address: String?): String {
if (address == null) {
return ""
@@ -304,25 +414,55 @@ object Utils {
}
}
/**
* Get the system locale.
*
* @return The system locale.
*/
fun getSysLocale(): Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleList.getDefault()[0]
} else {
Locale.getDefault()
}
/**
* Fix illegal characters in a URL.
*
* @param str The URL string.
* @return The URL string with illegal characters replaced.
*/
fun fixIllegalUrl(str: String): String {
return str
.replace(" ", "%20")
.replace("|", "%7C")
}
/**
* Remove white space from a string.
*
* @param str The string to process.
* @return The string without white space.
*/
fun removeWhiteSpace(str: String?): String? {
return str?.replace(" ", "")
}
/**
* Check if the device is a TV.
*
* @param context The context to use.
* @return True if the device is a TV, false otherwise.
*/
fun isTv(context: Context): Boolean =
context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
/**
* Find a free port from a list of ports.
*
* @param ports The list of ports to check.
* @return The first free port found.
* @throws IOException If no free port is found.
*/
fun findFreePort(ports: List<Int>): Int {
for (port in ports) {
try {
@@ -336,6 +476,12 @@ object Utils {
throw IOException("no free port found")
}
/**
* Check if a string is a valid subscription URL.
*
* @param value The string to check.
* @return True if the string is a valid subscription URL, false otherwise.
*/
fun isValidSubUrl(value: String?): Boolean {
try {
if (value.isNullOrEmpty()) return false
@@ -347,12 +493,22 @@ object Utils {
return false
}
/**
* Get the receiver flags based on the Android version.
*
* @return The receiver flags.
*/
fun receiverFlags(): Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.RECEIVER_EXPORTED
} else {
ContextCompat.RECEIVER_NOT_EXPORTED
}
/**
* Check if the package is Xray.
*
* @return True if the package is Xray, false otherwise.
*/
fun isXray(): Boolean = (ANG_PACKAGE.startsWith("com.v2ray.ang"))
}

View File

@@ -13,6 +13,14 @@ import java.util.zip.ZipOutputStream
object ZipUtil {
private const val BUFFER_SIZE = 4096
/**
* Zip the contents of a folder.
*
* @param folderPath The path to the folder to zip.
* @param outputZipFilePath The path to the output zip file.
* @return True if the operation is successful, false otherwise.
* @throws IOException If an I/O error occurs.
*/
@Throws(IOException::class)
fun zipFromFolder(folderPath: String, outputZipFilePath: String): Boolean {
val buffer = ByteArray(BUFFER_SIZE)
@@ -59,6 +67,14 @@ object ZipUtil {
return true
}
/**
* Unzip the contents of a zip file to a folder.
*
* @param zipFile The zip file to unzip.
* @param destDirectory The destination directory.
* @return True if the operation is successful, false otherwise.
* @throws IOException If an I/O error occurs.
*/
@Throws(IOException::class)
fun unzipToFolder(zipFile: File, destDirectory: String): Boolean {
File(destDirectory).run {
@@ -72,10 +88,8 @@ object ZipUtil {
zip.getInputStream(entry).use { input ->
val filePath = destDirectory + File.separator + entry.name
if (!entry.isDirectory) {
// if the entry is a file, extracts it
extractFile(input, filePath)
} else {
// if the entry is a directory, make the directory
val dir = File(filePath)
dir.mkdir()
}
@@ -89,6 +103,13 @@ object ZipUtil {
return true
}
/**
* Extract a file from an input stream.
*
* @param inputStream The input stream to read from.
* @param destFilePath The destination file path.
* @throws IOException If an I/O error occurs.
*/
@Throws(IOException::class)
private fun extractFile(inputStream: InputStream, destFilePath: String) {
val bos = BufferedOutputStream(FileOutputStream(destFilePath))