Compare commits

...

26 Commits

Author SHA1 Message Date
2dust
884b444a41 up 1.9.12 2024-11-05 19:01:03 +08:00
2dust
e1ff2df36e Bug fix 2024-11-05 18:59:05 +08:00
2dust
61c0111778 Revert "Refactor listenForPackageChanges to remove redundant registerReceiver calls (#3872)"
This reverts commit 5f167512f5.
2024-11-05 18:07:55 +08:00
Tamim Hossain
bfc9a64e07 Correct isEmpty syntax for collection check (#3881)
Fixed the syntax for checking if `filesToCompress` is empty by using `isEmpty()` instead of `isEmpty`. This ensures correct functionality when verifying if the collection has elements.
2024-11-05 18:01:32 +08:00
Tamim Hossain
2ba92045cc Remove unnecessary Boolean comparisons in conditional checks (#3880)
Simplified conditional checks by removing unnecessary `== true` comparisons. The `decodeSettingsBool` function returns a non-nullable Boolean with a default value, so direct usage improves readability and keeps the code concise.
2024-11-05 18:00:52 +08:00
Tamim Hossain
aeca9f51c8 Remove redundant Boolean comparison in runLoop call (#3879)
Simplified the call to `runLoop` by removing the redundant `== true` comparison. Since `decodeSettingsBool` returns a non-nullable Boolean, direct usage improves readability.
2024-11-05 18:00:23 +08:00
Tamim Hossain
b107c0ac1d Remove redundant TAG field in ProcessService (#3878)
Refactored `ProcessService` by removing the redundant `TAG` variable and using `ANG_PACKAGE` directly in logging calls, simplifying the code and reducing unnecessary field assignments.
2024-11-05 17:59:37 +08:00
Tamim Hossain
65a04b4784 Refactor getString call to use orEmpty for null safety (#3877)
Updated `getString` call to use `orEmpty()` instead of specifying a default empty string, making the code cleaner and handling nullability more effectively.
2024-11-05 17:58:23 +08:00
Tamim Hossain
eab9f50cfd Refactor BootReceiver for improved null handling and readability (#3876)
Refactored `BootReceiver` to simplify null checks and conditional structure. Combined context and intent checks into a single early return and refactored logic for `decodeStartOnBoot` and `getSelectServer` to improve readability.
2024-11-05 17:57:51 +08:00
Tamim Hossain
b8bb83b524 Used safecall ? (#3874)
Used safecall `?`
2024-11-05 17:56:32 +08:00
Tamim Hossain
93eb9fe3b9 Introduce NetworkType enum to improve network type handling (#3873)
* Introduce NetworkType enum to improve network type handling

Created a `NetworkType` enum to represent various network types, improving readability and reducing potential errors caused by hardcoded string comparisons. Updated the `getQueryDic` function to utilize this enum.

* Refactor to use NetworkType enum in VmessFmt

Replaced hardcoded network type strings with the `NetworkType` enum in `VmessFmt` functions. Updated `parse`, `toUri`, and `parseVmessStd` methods to use `NetworkType.fromString`, improving readability and reducing errors caused by typos in network type strings.
2024-11-05 17:56:04 +08:00
Tamim Hossain
5f167512f5 Refactor listenForPackageChanges to remove redundant registerReceiver calls (#3872)
Refactored the `listenForPackageChanges` function to remove redundant calls to `registerReceiver` by creating a single `IntentFilter` instance. This simplifies the code and improves readability.
2024-11-05 17:55:08 +08:00
Tamim Hossain
a727b81263 Update registerReceiver usage to comply with Android Tiramisu+ guidelines (#3871)
### Summary
- Updated `registerReceiver` usage to align with Android Tiramisu+ documentation.

### Details
- Replaced direct `registerReceiver` calls with `ContextCompat.registerReceiver` for improved compatibility.
- Used `RECEIVER_EXPORTED` and `RECEIVER_NOT_EXPORTED` flags based on API level to ensure correct receiver permissions.
- Added reference to the official Android documentation for `registerReceiver`.

### References
- [Documentation on registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int))

This commit ensures that the `registerReceiver` call is consistent with the latest Android standards, improving compatibility and security across Android versions.
2024-11-05 16:42:17 +08:00
solokot
f27c9192d1 Update Russian translation (#3870) 2024-11-05 16:39:19 +08:00
DecorativeFamily
90153fa17f Update persian translate (#3869)
* Update persian translate

* Update strings.xml
2024-11-05 16:38:54 +08:00
DecorativeFamily
cdfaa01852 Revert "Update persian translate (#3867)" (#3868)
This reverts commit 33d2c3b00d.
2024-11-05 15:05:42 +08:00
DecorativeFamily
33d2c3b00d Update persian translate (#3867) 2024-11-05 15:03:35 +08:00
DecorativeFamily
b7f992cdc0 Update gradle-wrapper.properties (#3844)
Gradle 8.10.2
2024-11-05 15:03:21 +08:00
DecorativeFamily
0a6a24e309 Gradle (#3839)
* Create dependabot.yml

* Update dependabot.yml

* Update libs.versions.toml

* Delete .github/dependabot.yml
2024-11-05 15:03:07 +08:00
2dust
153b4cffef Unable to obtain the notification permission 2024-11-05 14:29:44 +08:00
2dust
f09a413232 Bug fix
https://github.com/2dust/v2rayNG/issues/3858
2024-11-05 10:24:06 +08:00
886963226
cba58f6ae2 Update V2rayConfigManager.kt (#3860) 2024-11-05 09:31:01 +08:00
2dust
2bf4b91488 Bug fix
https://github.com/2dust/v2rayNG/issues/3852
2024-11-04 20:22:40 +08:00
2dust
b60b7f4307 up 1.9.11 2024-11-04 19:56:28 +08:00
2dust
e4ca04a096 Bug fix
https://github.com/2dust/v2rayNG/issues/3851
2024-11-04 19:55:01 +08:00
2dust
d0f7ecec44 Bug fix
https://github.com/2dust/v2rayNG/issues/3693
2024-11-04 17:51:26 +08:00
30 changed files with 139 additions and 80 deletions

View File

@@ -11,8 +11,8 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 604
versionName = "1.9.10"
versionCode = 607
versionName = "1.9.12"
multiDexEnabled = true
splits {
abi {

View File

@@ -0,0 +1,17 @@
package com.v2ray.ang.dto
enum class NetworkType(val type: String) {
TCP("tcp"),
KCP("kcp"),
WS("ws"),
HTTP_UPGRADE("httpupgrade"),
SPLIT_HTTP("splithttp"),
HTTP("http"),
H2("h2"),
QUIC("quic"),
GRPC("grpc");
companion object {
fun fromString(type: String?) = entries.find { it.type == type } ?: TCP
}
}

View File

@@ -1,6 +1,7 @@
package com.v2ray.ang.fmt
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.NetworkType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.isNotNullEmpty
import com.v2ray.ang.util.Utils
@@ -31,7 +32,6 @@ open class FmtBase {
fun getQueryDic(config: ProfileItem): HashMap<String, String> {
val dicQuery = HashMap<String, String>()
dicQuery["security"] = config.security?.ifEmpty { "none" }.orEmpty()
config.sni.let { if (it.isNotNullEmpty()) dicQuery["sni"] = it.orEmpty() }
config.alpn.let { if (it.isNotNullEmpty()) dicQuery["alpn"] = it.orEmpty() }
@@ -41,37 +41,38 @@ open class FmtBase {
config.spiderX.let { if (it.isNotNullEmpty()) dicQuery["spx"] = it.orEmpty() }
config.flow.let { if (it.isNotNullEmpty()) dicQuery["flow"] = it.orEmpty() }
dicQuery["type"] = config.network?.ifEmpty { AppConfig.DEFAULT_NETWORK }.orEmpty()
val networkType = NetworkType.fromString(config.network)
dicQuery["type"] = networkType.type
when (config.network) {
"tcp" -> {
when (networkType) {
NetworkType.TCP -> {
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
}
"kcp" -> {
NetworkType.KCP -> {
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
config.seed.let { if (it.isNotNullEmpty()) dicQuery["seed"] = it.orEmpty() }
}
"ws", "httpupgrade", "splithttp" -> {
NetworkType.WS, NetworkType.HTTP_UPGRADE, NetworkType.SPLIT_HTTP -> {
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
config.path.let { if (it.isNotNullEmpty()) dicQuery["path"] = it.orEmpty() }
}
"http", "h2" -> {
NetworkType.HTTP, NetworkType.H2 -> {
dicQuery["type"] = "http"
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
config.path.let { if (it.isNotNullEmpty()) dicQuery["path"] = it.orEmpty() }
}
"quic" -> {
NetworkType.QUIC -> {
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
config.quicSecurity.let { if (it.isNotNullEmpty()) dicQuery["quicSecurity"] = it.orEmpty() }
config.quicKey.let { if (it.isNotNullEmpty()) dicQuery["key"] = it.orEmpty() }
}
"grpc" -> {
NetworkType.GRPC -> {
config.mode.let { if (it.isNotNullEmpty()) dicQuery["mode"] = it.orEmpty() }
config.authority.let { if (it.isNotNullEmpty()) dicQuery["authority"] = it.orEmpty() }
config.serviceName.let { if (it.isNotNullEmpty()) dicQuery["serviceName"] = it.orEmpty() }

View File

@@ -19,9 +19,9 @@ object ShadowsocksFmt : FmtBase() {
config.serverPort = uri.port.toString()
val result = if (uri.userInfo.contains(":")) {
uri.userInfo.split(":")
uri.userInfo.split(":", limit = 2)
} else {
Utils.decode(uri.userInfo).split(":")
Utils.decode(uri.userInfo).split(":", limit = 2)
}
if (result.count() == 2) {
config.method = result.first()

View File

@@ -21,7 +21,7 @@ object SocksFmt : FmtBase() {
config.serverPort = uri.port.toString()
if (uri.userInfo?.isEmpty() == false) {
val result = Utils.decode(uri.userInfo).split(":")
val result = Utils.decode(uri.userInfo).split(":", limit = 2)
if (result.count() == 2) {
config.username = result.first()
config.password = result.last()

View File

@@ -4,6 +4,7 @@ import android.text.TextUtils
import android.util.Log
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.NetworkType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.V2rayConfig.OutboundBean
import com.v2ray.ang.dto.VmessQRCode
@@ -52,22 +53,24 @@ object VmessFmt : FmtBase() {
config.host = vmessQRCode.host
config.path = vmessQRCode.path
when (config.network) {
"kcp" -> {
when (NetworkType.fromString(config.network)) {
NetworkType.KCP -> {
config.seed = vmessQRCode.path
}
"quic" -> {
NetworkType.QUIC -> {
config.quicSecurity = vmessQRCode.host
config.quicKey = vmessQRCode.path
}
"grpc" -> {
NetworkType.GRPC -> {
config.mode = vmessQRCode.type
config.serviceName = vmessQRCode.path
config.authority = vmessQRCode.host
}
else -> {}
}
config.security = vmessQRCode.tls
config.insecure = allowInsecure
config.sni = vmessQRCode.sni
@@ -90,22 +93,24 @@ object VmessFmt : FmtBase() {
vmessQRCode.net = config.network.orEmpty()
vmessQRCode.type = config.headerType.orEmpty()
when (config.network) {
"kcp" -> {
when (NetworkType.fromString(config.network)) {
NetworkType.KCP -> {
vmessQRCode.path = config.seed.orEmpty()
}
"quic" -> {
NetworkType.QUIC -> {
vmessQRCode.host = config.quicSecurity.orEmpty()
vmessQRCode.path = config.quicKey.orEmpty()
}
"grpc" -> {
NetworkType.GRPC -> {
vmessQRCode.type = config.mode.orEmpty()
vmessQRCode.path = config.serviceName.orEmpty()
vmessQRCode.host = config.authority.orEmpty()
}
else -> {}
}
config.host.let { if (it.isNotNullEmpty()) vmessQRCode.host = it.orEmpty() }
config.path.let { if (it.isNotNullEmpty()) vmessQRCode.path = it.orEmpty() }
@@ -119,7 +124,7 @@ object VmessFmt : FmtBase() {
}
fun parseVmessStd(str: String): ProfileItem? {
var allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
val allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
val config = ProfileItem.create(EConfigType.VMESS)
val uri = URI(Utils.fixIllegalUrl(str))
@@ -132,7 +137,7 @@ object VmessFmt : FmtBase() {
config.password = uri.userInfo
config.method = AppConfig.DEFAULT_SECURITY
config.network = queryParam["type"] ?: "tcp"
config.network = NetworkType.fromString(queryParam["type"]).name
config.headerType = queryParam["headerType"]
config.host = queryParam["host"]
config.path = queryParam["path"]

View File

@@ -277,7 +277,7 @@ object AngConfigManager {
if (serverList.isNotEmpty()) {
var count = 0
for (srv in serverList.reversed()) {
val config = CustomFmt.parse(server) ?: continue
val config = CustomFmt.parse(JsonUtil.toJson(srv)) ?: continue
config.subscriptionId = subid
val key = MmkvManager.encodeServerConfig("", config)
MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(srv))

View File

@@ -19,7 +19,7 @@ object MigrateManager {
if (serverStorage.count().toInt() == 0) {
return false
}
var serverList = serverStorage.allKeys() ?: return false
val serverList = serverStorage.allKeys() ?: return false
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-" + serverList.count())
for (guid in serverList) {
@@ -36,7 +36,7 @@ object MigrateManager {
//check and remove old
decodeServerConfig(guid) ?: continue
serverStorage.remove(guid)
//serverStorage.remove(guid)
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-" + config.remarks)
}
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-end")
@@ -70,10 +70,10 @@ object MigrateManager {
config.serverPort = outbound.getServerPort().toString()
config.method = outbound.getSecurityEncryption()
config.password = outbound.getPassword()
config.flow = outbound?.settings?.vnext?.get(0)?.users[0]?.flow ?: outbound?.settings?.servers?.get(0)?.flow
config.flow = outbound?.settings?.vnext?.get(0)?.users?.get(0)?.flow ?: outbound?.settings?.servers?.get(0)?.flow
config.network = outbound?.streamSettings?.network ?: "tcp"
outbound.getTransportSettingDetails()?.let { transportDetails ->
config.network = "tcp"
config.headerType = transportDetails[0].orEmpty()
config.host = transportDetails[1].orEmpty()
config.path = transportDetails[2].orEmpty()

View File

@@ -336,7 +336,7 @@ object MmkvManager {
}
fun decodeSettingsBool(key: String): Boolean {
return settingsStorage.decodeBool(key)
return settingsStorage.decodeBool(key,false)
}
fun decodeSettingsBool(key: String, defaultValue: Boolean): Boolean {

View File

@@ -334,9 +334,7 @@ object V2rayConfigManager {
servers.add(
V2rayConfig.DnsBean.ServersBean(
address = remoteDns.first(),
port = 53,
domains = proxyDomain,
expectIPs = null
)
)
}
@@ -350,7 +348,6 @@ object V2rayConfigManager {
servers.add(
V2rayConfig.DnsBean.ServersBean(
address = domesticDns.first(),
port = 53,
domains = directDomain,
expectIPs = if (isCnRoutingMode) geoipCn else null,
skipFallback = true
@@ -458,7 +455,7 @@ object V2rayConfigManager {
val host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host
val requestString: String by lazy {
"""{"version":"1.1","method":"GET","headers":{"User-Agent":"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.122 Mobile Safari/537.36"Safari/537.36,"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
"""{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.122 Mobile Safari/537.36"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
}
outbound.streamSettings?.tcpSettings?.header?.request = JsonUtil.fromJson(
requestString,

View File

@@ -8,11 +8,11 @@ import com.v2ray.ang.service.V2RayServiceManager
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Intent.ACTION_BOOT_COMPLETED == intent?.action && MmkvManager.decodeStartOnBoot()) {
if (MmkvManager.getSelectServer().isNullOrEmpty()) {
return
}
V2RayServiceManager.startV2Ray(context!!)
}
//Check if context is not null and action is the one we want
if (context == null || intent?.action != Intent.ACTION_BOOT_COMPLETED) return
//Check if flag is true and a server is selected
if (!MmkvManager.decodeStartOnBoot() || MmkvManager.getSelectServer().isNullOrEmpty()) return
//Start v2ray
V2RayServiceManager.startV2Ray(context)
}
}
}

View File

@@ -16,9 +16,9 @@ class TaskerReceiver : BroadcastReceiver() {
try {
val bundle = intent?.getBundleExtra(AppConfig.TASKER_EXTRA_BUNDLE)
val switch = bundle?.getBoolean(AppConfig.TASKER_EXTRA_BUNDLE_SWITCH, false)
val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID, "")
val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID).orEmpty()
if (switch == null || guid == null || TextUtils.isEmpty(guid)) {
if (switch == null || TextUtils.isEmpty(guid)) {
return
} else if (switch) {
if (guid == AppConfig.TASKER_DEFAULT_GUID) {

View File

@@ -8,11 +8,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class ProcessService {
private val TAG = ANG_PACKAGE
private var process: Process? = null
fun runProcess(context: Context, cmd: MutableList<String>) {
Log.d(TAG, cmd.toString())
Log.d(ANG_PACKAGE, cmd.toString())
try {
val proBuilder = ProcessBuilder(cmd)
@@ -23,23 +22,23 @@ class ProcessService {
CoroutineScope(Dispatchers.IO).launch {
Thread.sleep(50L)
Log.d(TAG, "runProcess check")
Log.d(ANG_PACKAGE, "runProcess check")
process?.waitFor()
Log.d(TAG, "runProcess exited")
Log.d(ANG_PACKAGE, "runProcess exited")
}
Log.d(TAG, process.toString())
Log.d(ANG_PACKAGE, process.toString())
} catch (e: Exception) {
Log.d(TAG, e.toString())
Log.d(ANG_PACKAGE, e.toString())
}
}
fun stopProcess() {
try {
Log.d(TAG, "runProcess destroy")
Log.d(ANG_PACKAGE, "runProcess destroy")
process?.destroy()
} catch (e: Exception) {
Log.d(TAG, e.toString())
Log.d(ANG_PACKAGE, e.toString())
}
}
}

View File

@@ -9,8 +9,10 @@ import android.graphics.drawable.Icon
import android.os.Build
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import androidx.core.content.ContextCompat
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.Utils
import java.lang.ref.SoftReference
@@ -32,14 +34,20 @@ class QSTileService : TileService() {
qsTile?.updateTile()
}
/**
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
*/
override fun onStartListening() {
super.onStartListening()
setState(Tile.STATE_INACTIVE)
mMsgReceive = ReceiveMessageHandler(this)
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY), RECEIVER_EXPORTED)
ContextCompat.registerReceiver(applicationContext,mMsgReceive,mFilter,ContextCompat.RECEIVER_EXPORTED)
} else {
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
ContextCompat.registerReceiver(applicationContext,mMsgReceive,mFilter,ContextCompat.RECEIVER_NOT_EXPORTED)
}
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")

View File

@@ -13,6 +13,7 @@ import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.TAG_DIRECT
@@ -65,7 +66,7 @@ object V2RayServiceManager {
if (v2rayPoint.isRunning) return
val guid = MmkvManager.getSelectServer() ?: return
val config = MmkvManager.decodeServerConfig(guid) ?: return
if (!Utils.isValidUrl(config.server) && !Utils.isValidUrl(config.server)) return
if (!Utils.isValidUrl(config.server) && !Utils.isIpAddress(config.server)) return
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
// if (!result.status) return
@@ -126,6 +127,11 @@ object V2RayServiceManager {
}
}
/**
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
*/
fun startV2rayPoint() {
val service = serviceControl?.get()?.getService() ?: return
val guid = MmkvManager.getSelectServer() ?: return
@@ -143,9 +149,15 @@ object V2RayServiceManager {
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
mFilter.addAction(Intent.ACTION_USER_PRESENT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
service.registerReceiver(mMsgReceive, mFilter, Context.RECEIVER_EXPORTED)
ContextCompat.registerReceiver(
service, mMsgReceive, mFilter,
ContextCompat.RECEIVER_EXPORTED
)
} else {
service.registerReceiver(mMsgReceive, mFilter)
ContextCompat.registerReceiver(
service, mMsgReceive, mFilter,
ContextCompat.RECEIVER_NOT_EXPORTED
)
}
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
@@ -156,7 +168,7 @@ object V2RayServiceManager {
currentConfig = config
try {
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true)
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6))
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}

View File

@@ -17,6 +17,7 @@ import android.os.StrictMode
import android.util.Log
import androidx.annotation.RequiresApi
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.LOOPBACK
import com.v2ray.ang.BuildConfig
import com.v2ray.ang.R
@@ -153,9 +154,9 @@ class V2RayVpnService : VpnService(), ServiceControl {
builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty())
val selfPackageName = BuildConfig.APPLICATION_ID
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY) == true) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY)) {
val apps = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS) == true
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS)
//process self package
if (bypassApps) apps?.add(selfPackageName) else apps?.remove(selfPackageName)
apps?.forEach {
@@ -165,6 +166,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
else
builder.addAllowedApplication(it)
} catch (e: PackageManager.NameNotFoundException) {
Log.d(ANG_PACKAGE, "setup error : --${e.localizedMessage}")
}
}
} else {
@@ -215,11 +217,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
"--loglevel", "notice"
)
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) {
cmd.add("--netif-ip6addr")
cmd.add(PRIVATE_VLAN6_ROUTER)
}
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED)) {
val localDnsPort = Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
cmd.add("--dnsgw")
cmd.add("$LOOPBACK:${localDnsPort}")
@@ -232,7 +234,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
process = proBuilder
.directory(applicationContext.filesDir)
.start()
Thread(Runnable {
Thread {
Log.d(packageName, "$TUN2SOCKS check")
process.waitFor()
Log.d(packageName, "$TUN2SOCKS exited")
@@ -240,7 +242,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
Log.d(packageName, "$TUN2SOCKS restart")
runTun2socks()
}
}).start()
}.start()
Log.d(packageName, process.toString())
sendFd()

View File

@@ -133,7 +133,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
.request(Manifest.permission.POST_NOTIFICATIONS)
.subscribe {
if (!it)
toast(R.string.toast_permission_denied)
toast(R.string.toast_permission_denied_notification)
}
}

View File

@@ -159,8 +159,11 @@ object Utils {
/**
* is ip address
*/
fun isIpAddress(value: String): Boolean {
fun isIpAddress(value: String?): Boolean {
try {
if (value.isNullOrEmpty()) {
return false
}
var addr = value
if (addr.isEmpty() || addr.isBlank()) {
return false

View File

@@ -31,7 +31,7 @@ object ZipUtil {
}
}
}
if (filesToCompress.isEmpty) {
if (filesToCompress.isEmpty()) {
return false
}

View File

@@ -8,6 +8,7 @@ import android.content.IntentFilter
import android.content.res.AssetManager
import android.os.Build
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
@@ -44,18 +45,24 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
val updateTestResultAction by lazy { MutableLiveData<String>() }
private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
/**
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
*/
fun startListenBroadcast() {
isRunning.value = false
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getApplication<AngApplication>().registerReceiver(
mMsgReceiver,
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY),
Context.RECEIVER_EXPORTED
ContextCompat.registerReceiver(
getApplication(), mMsgReceiver, mFilter,
ContextCompat.RECEIVER_EXPORTED
)
} else {
getApplication<AngApplication>().registerReceiver(
mMsgReceiver,
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
ContextCompat.registerReceiver(
getApplication(), mMsgReceiver, mFilter,
ContextCompat.RECEIVER_NOT_EXPORTED
)
}
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_REGISTER_CLIENT, "")

View File

@@ -12,6 +12,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">إيقاف</string>
<string name="toast_permission_denied">تعذر الحصول على الإذن</string>
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
<string name="notification_action_more">انقر للمزيد</string>
<string name="toast_services_start">بدء الخدمات</string>
<string name="toast_services_stop">إيقاف الخدمات</string>

View File

@@ -12,6 +12,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">বন্ধ করুন</string>
<string name="toast_permission_denied">অনুমতি পাওয়া যাচ্ছে না</string>
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
<string name="notification_action_more">আরও দেখতে ক্লিক করুন</string>
<string name="toast_services_start">সার্ভিস শুরু করুন</string>
<string name="toast_services_stop">সার্ভিস বন্ধ করুন</string>

View File

@@ -10,8 +10,9 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">توقف</string>
<string name="toast_permission_denied">قادر به دریافت مجوز نیست</string>
<string name="notification_action_more">برای اطلاعات بیشتر کلیک کنید</string>
<string name="toast_permission_denied">دریافت مجوز امکان پذیر نیست</string>
<string name="toast_permission_denied_notification">دریافت مجوز اعلان امکان پذیر نیست</string>
<string name="notification_action_more">برای کسب اطلاعات بیشتر کلیک کنید</string>
<string name="toast_services_start">شروع خدمات</string>
<string name="toast_services_stop">توقف خدمات</string>
<string name="toast_services_success">شروع خدمات با موفقیت انجام شد</string>
@@ -159,7 +160,7 @@
<string name="summary_pref_local_dns_enabled">درخواست های DNS به هسته وارد شده و توسط ماژول DNS پردازش می شوند (توصیه می شود در صورت نیاز به مسیریابی برای دور زدن آدرس های LAN و سرزمین اصلی فعال شود)</string>
<string name="title_pref_fake_dns_enabled">فعال کردن DNS جعلی</string>
<string name="summary_pref_fake_dns_enabled">DNS محلی آدرس های آیپی فیک را بر می گرداند (سریع تر می باشد اما ممکن است برای برخی از برنامه ها کار نکند)</string>
<string name="summary_pref_fake_dns_enabled">دی ان اس محلی آدرس های آیپی جعلی را بر می گرداند (سریع تر می باشد و تاخیر را کاهش می دهد اما ممکن است برای برخی از برنامه ها کار نکند)</string>
<string name="title_pref_prefer_ipv6">ترجیح دادن IPv6</string>
<string name="summary_pref_prefer_ipv6">ترجیح دادن نشانی و مسیر های IPv6</string>

View File

@@ -11,6 +11,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Остановить</string>
<string name="toast_permission_denied">Разрешение не получено</string>
<string name="toast_permission_denied_notification">Разрешение на отображение уведомлений не получено</string>
<string name="notification_action_more">Ещё…</string>
<string name="toast_services_start">Запуск служб</string>
<string name="toast_services_stop">Остановка служб</string>

View File

@@ -11,6 +11,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Ngắt kết nối v2rayNG</string>
<string name="toast_permission_denied">Vui lòng cấp quyền cần thiết cho v2rayNG! Bạn đã từ chối các quyền cần thiết như Camera hay Bộ nhớ?</string>
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
<string name="notification_action_more">Nhấn để biết thêm...</string>
<string name="toast_services_start">Đang khởi động v2rayNG...</string>
<string name="toast_services_stop">Đã dừng v2rayNG!</string>

View File

@@ -11,6 +11,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">停止</string>
<string name="toast_permission_denied">无法取得权限</string>
<string name="toast_permission_denied_notification">无法取得通知权限</string>
<string name="notification_action_more">点击了解更多</string>
<string name="toast_services_start">启动服务中</string>
<string name="toast_services_stop">关闭中</string>

View File

@@ -11,6 +11,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">停止</string>
<string name="toast_permission_denied">無法取得此權限</string>
<string name="toast_permission_denied_notification">無法取得此通知權限</string>
<string name="notification_action_more">瞭解更多</string>
<string name="toast_services_start">啟動服務</string>
<string name="toast_services_stop">停止服務</string>

View File

@@ -12,6 +12,7 @@
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Stop</string>
<string name="toast_permission_denied">Unable to obtain the permission</string>
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
<string name="notification_action_more">click for more</string>
<string name="toast_services_start">Start Services</string>
<string name="toast_services_stop">Stop Services</string>

View File

@@ -2,7 +2,7 @@
activityKtx = "1.9.3"
appcompat = "1.7.0"
cardview = "1.0.0"
constraintlayout = "2.1.4"
constraintlayout = "2.2.0"
core = "3.5.3"
editorkit = "2.9.0"
flexbox = "3.0.0"
@@ -12,7 +12,7 @@ junit = "4.13.2"
kotlinReflect = "2.0.21"
kotlinxCoroutinesCore = "1.9.0"
legacySupportV4 = "1.0.0"
lifecycleViewmodelKtx = "2.8.6"
lifecycleViewmodelKtx = "2.8.7"
material = "1.12.0"
mmkvStatic = "1.3.9"
multidex = "2.0.1"
@@ -25,7 +25,7 @@ rxpermissions = "0.12"
toastcompat = "1.1.0"
viewpager2 = "1.1.0"
workRuntimeKtx = "2.9.1"
androidGradlePlugin = "8.7.1"
androidGradlePlugin = "8.7.2"
androidKotlinPlugin = "2.0.21"
mockitoMockitoInline = "4.0.0"

View File

@@ -1,6 +1,6 @@
#Sun Jul 28 13:40:50 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https://services.gradle.org/distributions/gradle-8.10.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists