Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b47bbe99a | ||
|
|
0fb2165015 | ||
|
|
03eeeb9b62 | ||
|
|
038daf5fda | ||
|
|
bfd1387d9b | ||
|
|
5afec5cf25 | ||
|
|
ec29bdf5bf | ||
|
|
57efab093f | ||
|
|
9c92a64811 | ||
|
|
7ddc82d5cd | ||
|
|
c286ba18a8 | ||
|
|
867b5fc880 | ||
|
|
e8a7fa5320 | ||
|
|
f2f9e55286 | ||
|
|
4a1c62a67c | ||
|
|
c9a6a459d4 | ||
|
|
21fdcf4ccf | ||
|
|
7c7a623ae5 | ||
|
|
b3074e9697 | ||
|
|
513ebcfa23 | ||
|
|
50d9057f1a | ||
|
|
2a563e7884 | ||
|
|
c69cd18842 | ||
|
|
7f2ced85a8 | ||
|
|
6c5eef99b5 | ||
|
|
d7c3bae8cc | ||
|
|
57c98f7c50 | ||
|
|
49be23c56a | ||
|
|
9b658e9a22 | ||
|
|
aaa84d081f |
@@ -1,3 +1,8 @@
|
|||||||
|
---
|
||||||
|
name: v2rayNG程序问题
|
||||||
|
about: 创建一个报告来帮助我们改进
|
||||||
|
---
|
||||||
|
|
||||||
在提出问题前请先自行排除服务器端问题,同时也请通过搜索确认是否有人提出过相同问题。
|
在提出问题前请先自行排除服务器端问题,同时也请通过搜索确认是否有人提出过相同问题。
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +19,8 @@
|
|||||||
|
|
||||||
### 日志信息
|
### 日志信息
|
||||||
<details>
|
<details>
|
||||||
通过 `adb logcat -s com.v2ray.ang GoLog V2rayConfigUtilGoLog Main` 获取日志。请自行删减日志中可能出现的敏感信息。
|
|
||||||
|
通过`adb logcat -s com.v2ray.ang GoLog V2rayConfigUtilGoLog Main`获取日志。请自行删减日志中可能出现的敏感信息。
|
||||||
|
|
||||||
如果问题可重现,建议先执行`adb logcat -c`清空系统日志再执行上述命令,再操作重现问题。
|
如果问题可重现,建议先执行`adb logcat -c`清空系统日志再执行上述命令,再操作重现问题。
|
||||||
```
|
```
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: V2Ray程序问题
|
||||||
|
url: https://github.com/v2fly/v2ray-core/
|
||||||
|
about: 如果您有V2Ray而非v2rayNG的问题,请至这个链接讨论。
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
IsRunning bool
|
IsRunning bool
|
||||||
|
IsTRunning bool
|
||||||
PackageName string
|
PackageName string
|
||||||
PackageCodePath string
|
PackageCodePath string
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
v2filesystem "v2ray.com/core/common/platform/filesystem"
|
v2filesystem "v2ray.com/core/common/platform/filesystem"
|
||||||
v2stats "v2ray.com/core/features/stats"
|
v2stats "v2ray.com/core/features/stats"
|
||||||
v2serial "v2ray.com/core/infra/conf/serial"
|
v2serial "v2ray.com/core/infra/conf/serial"
|
||||||
_ "v2ray.com/core/main/distro/all"
|
|
||||||
v2internet "v2ray.com/core/transport/internet"
|
v2internet "v2ray.com/core/transport/internet"
|
||||||
|
|
||||||
v2applog "v2ray.com/core/app/log"
|
v2applog "v2ray.com/core/app/log"
|
||||||
@@ -99,9 +98,7 @@ func (v *V2RayPoint) StopLoop() (err error) {
|
|||||||
v.v2rayOP.Lock()
|
v.v2rayOP.Lock()
|
||||||
defer v.v2rayOP.Unlock()
|
defer v.v2rayOP.Unlock()
|
||||||
if v.status.IsRunning {
|
if v.status.IsRunning {
|
||||||
close(v.closeChan)
|
|
||||||
v.shutdownInit()
|
v.shutdownInit()
|
||||||
v.SupportSet.OnEmitStatus(0, "Closed")
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -111,6 +108,10 @@ func (v *V2RayPoint) GetIsRunning() bool {
|
|||||||
return v.status.IsRunning
|
return v.status.IsRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *V2RayPoint) GetIsTRunning() bool {
|
||||||
|
return v.status.IsTRunning
|
||||||
|
}
|
||||||
|
|
||||||
//Delegate Funcation
|
//Delegate Funcation
|
||||||
func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
|
func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
|
||||||
if v.statsManager == nil {
|
if v.statsManager == nil {
|
||||||
@@ -124,12 +125,16 @@ func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *V2RayPoint) shutdownInit() {
|
func (v *V2RayPoint) shutdownInit() {
|
||||||
v.status.IsRunning = false
|
close(v.closeChan)
|
||||||
|
v.statsManager = nil
|
||||||
v.status.Vpoint.Close()
|
v.status.Vpoint.Close()
|
||||||
v.status.Vpoint = nil
|
v.status.Vpoint = nil
|
||||||
v.statsManager = nil
|
v.status.IsRunning = false
|
||||||
|
|
||||||
v.escorter.EscortingDown()
|
v.escorter.EscortingDown()
|
||||||
|
|
||||||
v.SupportSet.Shutdown()
|
v.SupportSet.Shutdown()
|
||||||
|
v.SupportSet.OnEmitStatus(0, "Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *V2RayPoint) pointloop() error {
|
func (v *V2RayPoint) pointloop() error {
|
||||||
@@ -161,11 +166,13 @@ func (v *V2RayPoint) pointloop() error {
|
|||||||
v.SupportSet.Setup(v.status.GetVPNSetupArg(v.EnableLocalDNS, v.ForwardIpv6))
|
v.SupportSet.Setup(v.status.GetVPNSetupArg(v.EnableLocalDNS, v.ForwardIpv6))
|
||||||
v.SupportSet.OnEmitStatus(0, "Running")
|
v.SupportSet.OnEmitStatus(0, "Running")
|
||||||
|
|
||||||
|
v.status.IsTRunning = false
|
||||||
if !v.ProxyOnly {
|
if !v.ProxyOnly {
|
||||||
if err := v.runTun2socks(); err != nil {
|
if err := v.runTun2socks(); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
v.status.IsTRunning = true
|
||||||
|
|
||||||
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
|
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
|
||||||
v.EnableLocalDNS,
|
v.EnableLocalDNS,
|
||||||
|
|||||||
58
AndroidLibV2rayLite/libv2init.go
Normal file
58
AndroidLibV2rayLite/libv2init.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package libv2ray
|
||||||
|
|
||||||
|
import (
|
||||||
|
// The following are necessary as they register handlers in their init functions.
|
||||||
|
|
||||||
|
// Required features. Can't remove unless there is replacements.
|
||||||
|
_ "v2ray.com/core/app/dispatcher"
|
||||||
|
_ "v2ray.com/core/app/proxyman/inbound"
|
||||||
|
_ "v2ray.com/core/app/proxyman/outbound"
|
||||||
|
|
||||||
|
// Other optional features.
|
||||||
|
_ "v2ray.com/core/app/dns"
|
||||||
|
_ "v2ray.com/core/app/log"
|
||||||
|
_ "v2ray.com/core/app/policy"
|
||||||
|
_ "v2ray.com/core/app/router"
|
||||||
|
_ "v2ray.com/core/app/stats"
|
||||||
|
|
||||||
|
// Inbound and outbound proxies.
|
||||||
|
_ "v2ray.com/core/proxy/blackhole"
|
||||||
|
_ "v2ray.com/core/proxy/dns"
|
||||||
|
_ "v2ray.com/core/proxy/dokodemo"
|
||||||
|
_ "v2ray.com/core/proxy/freedom"
|
||||||
|
_ "v2ray.com/core/proxy/http"
|
||||||
|
_ "v2ray.com/core/proxy/mtproto"
|
||||||
|
_ "v2ray.com/core/proxy/shadowsocks"
|
||||||
|
_ "v2ray.com/core/proxy/socks"
|
||||||
|
_ "v2ray.com/core/proxy/trojan"
|
||||||
|
_ "v2ray.com/core/proxy/vless/inbound"
|
||||||
|
_ "v2ray.com/core/proxy/vless/outbound"
|
||||||
|
_ "v2ray.com/core/proxy/vmess/inbound"
|
||||||
|
_ "v2ray.com/core/proxy/vmess/outbound"
|
||||||
|
|
||||||
|
// Transport
|
||||||
|
_ "v2ray.com/core/transport/internet/http"
|
||||||
|
_ "v2ray.com/core/transport/internet/kcp"
|
||||||
|
_ "v2ray.com/core/transport/internet/quic"
|
||||||
|
_ "v2ray.com/core/transport/internet/tcp"
|
||||||
|
_ "v2ray.com/core/transport/internet/tls"
|
||||||
|
_ "v2ray.com/core/transport/internet/udp"
|
||||||
|
_ "v2ray.com/core/transport/internet/websocket"
|
||||||
|
|
||||||
|
// Transport headers
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/http"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/noop"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/srtp"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/tls"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/utp"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/wechat"
|
||||||
|
_ "v2ray.com/core/transport/internet/headers/wireguard"
|
||||||
|
|
||||||
|
// JSON config support. Choose only one from the two below.
|
||||||
|
// The following line loads JSON from v2ctl
|
||||||
|
// _ "v2ray.com/core/main/json"
|
||||||
|
// The following line loads JSON internally
|
||||||
|
_ "v2ray.com/core/main/jsonem"
|
||||||
|
// Load config from file or http(s)
|
||||||
|
// _ "v2ray.com/core/main/confloader/external"
|
||||||
|
)
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
# v2rayNG
|
# v2rayNG
|
||||||
|
|
||||||
A V2Ray client for Android
|
A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core)
|
||||||
|
|
||||||
[](https://developer.android.com/about/versions/jelly-bean#android-4.2)
|
[](https://developer.android.com/about/versions/jelly-bean#android-4.2)
|
||||||
[](https://kotlinlang.org)
|
[](https://kotlinlang.org)
|
||||||
[](https://github.com/2dust/v2rayNG/commits/master)
|
[](https://github.com/2dust/v2rayNG/commits/master)
|
||||||
[](https://www.codefactor.io/repository/github/2dust/v2rayng)
|
[](https://www.codefactor.io/repository/github/2dust/v2rayng)
|
||||||
[](https://github.com/2dust/v2rayNG/releases)
|
[](https://github.com/2dust/v2rayNG/releases)
|
||||||
|
[](https://t.me/v2rayn)
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.v2ray.ang">
|
<a href="https://play.google.com/store/apps/details?id=com.v2ray.ang">
|
||||||
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
|
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ android {
|
|||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
enable true
|
enable true
|
||||||
@@ -70,6 +74,10 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
|
||||||
|
|
||||||
|
// Androidx ktx
|
||||||
|
implementation 'android.arch.lifecycle:extensions:1.1.1'
|
||||||
|
implementation 'android.arch.lifecycle:livedata:1.1.1'
|
||||||
|
|
||||||
// Android support library
|
// Android support library
|
||||||
implementation "com.android.support:support-v4:$supportLibVersion"
|
implementation "com.android.support:support-v4:$supportLibVersion"
|
||||||
implementation "com.android.support:appcompat-v7:$supportLibVersion"
|
implementation "com.android.support:appcompat-v7:$supportLibVersion"
|
||||||
@@ -88,6 +96,7 @@ dependencies {
|
|||||||
implementation 'me.dm7.barcodescanner:core:1.9.8'
|
implementation 'me.dm7.barcodescanner:core:1.9.8'
|
||||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||||
implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar'
|
implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar'
|
||||||
|
implementation 'me.drakeet.support:toastcompat:1.1.0'
|
||||||
|
|
||||||
implementation(name: 'libv2ray', ext: 'aar')
|
implementation(name: 'libv2ray', ext: 'aar')
|
||||||
//implementation(name: 'tun2socks', ext: 'aar')
|
//implementation(name: 'tun2socks', ext: 'aar')
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.os.Build
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import me.dozen.dpreference.DPreference
|
import me.dozen.dpreference.DPreference
|
||||||
|
import me.drakeet.support.toast.ToastCompat
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.net.URLConnection
|
import java.net.URLConnection
|
||||||
|
|
||||||
@@ -15,16 +16,20 @@ import java.net.URLConnection
|
|||||||
val Context.v2RayApplication: AngApplication
|
val Context.v2RayApplication: AngApplication
|
||||||
get() = applicationContext as AngApplication
|
get() = applicationContext as AngApplication
|
||||||
|
|
||||||
|
// Usage note: DPreference use Android ContentProvider to redirect multi process access to main process.
|
||||||
|
// Currently, RunSoLibV2RayDaemon process will run proxy core, keep minimum configuration and long running
|
||||||
|
// in the background, support toggle on/off. That means it should NOT use DPreference after the initial
|
||||||
|
// creation and setup of the service
|
||||||
val Context.defaultDPreference: DPreference
|
val Context.defaultDPreference: DPreference
|
||||||
get() = v2RayApplication.defaultDPreference
|
get() = v2RayApplication.defaultDPreference
|
||||||
|
|
||||||
inline fun Context.toast(message: Int): Toast = Toast
|
inline fun Context.toast(message: Int): Toast = ToastCompat
|
||||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||||
.apply {
|
.apply {
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun Context.toast(message: CharSequence): Toast = Toast
|
inline fun Context.toast(message: CharSequence): Toast = ToastCompat
|
||||||
.makeText(this, message, Toast.LENGTH_SHORT)
|
.makeText(this, message, Toast.LENGTH_SHORT)
|
||||||
.apply {
|
.apply {
|
||||||
show()
|
show()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class TaskerReceiver : BroadcastReceiver() {
|
|||||||
return
|
return
|
||||||
} else if (switch) {
|
} else if (switch) {
|
||||||
if (guid == AppConfig.TASKER_DEFAULT_GUID) {
|
if (guid == AppConfig.TASKER_DEFAULT_GUID) {
|
||||||
Utils.startVService(context)
|
Utils.startVServiceFromToggle(context)
|
||||||
} else {
|
} else {
|
||||||
Utils.startVService(context, guid)
|
Utils.startVService(context, guid)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,15 +50,16 @@ class WidgetProvider : AppWidgetProvider() {
|
|||||||
Utils.startVServiceFromToggle(context)
|
Utils.startVServiceFromToggle(context)
|
||||||
}
|
}
|
||||||
} else if (AppConfig.BROADCAST_ACTION_ACTIVITY == intent.action) {
|
} else if (AppConfig.BROADCAST_ACTION_ACTIVITY == intent.action) {
|
||||||
val manager = AppWidgetManager.getInstance(context)
|
AppWidgetManager.getInstance(context)?.let { manager ->
|
||||||
when (intent.getIntExtra("key", 0)) {
|
when (intent.getIntExtra("key", 0)) {
|
||||||
AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> {
|
AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> {
|
||||||
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
|
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
|
||||||
true)
|
true)
|
||||||
}
|
}
|
||||||
AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> {
|
AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> {
|
||||||
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
|
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
|
||||||
false)
|
false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,10 @@ import android.service.quicksettings.Tile
|
|||||||
import android.service.quicksettings.TileService
|
import android.service.quicksettings.TileService
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
|
||||||
import com.v2ray.ang.util.MessageUtil
|
import com.v2ray.ang.util.MessageUtil
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
import java.lang.ref.SoftReference
|
import java.lang.ref.SoftReference
|
||||||
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
class QSTileService : TileService() {
|
class QSTileService : TileService() {
|
||||||
|
|
||||||
@@ -27,7 +25,7 @@ class QSTileService : TileService() {
|
|||||||
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v_idle)
|
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v_idle)
|
||||||
} else if (state == Tile.STATE_ACTIVE) {
|
} else if (state == Tile.STATE_ACTIVE) {
|
||||||
qsTile?.state = Tile.STATE_ACTIVE
|
qsTile?.state = Tile.STATE_ACTIVE
|
||||||
qsTile?.label = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "NG")
|
qsTile?.label = V2RayServiceManager.currentConfigName
|
||||||
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v)
|
qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import com.v2ray.ang.AppConfig.TAG_DIRECT
|
|||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
import com.v2ray.ang.extension.toSpeedString
|
import com.v2ray.ang.extension.toSpeedString
|
||||||
|
import com.v2ray.ang.extension.toast
|
||||||
|
import com.v2ray.ang.extension.v2RayApplication
|
||||||
import com.v2ray.ang.ui.MainActivity
|
import com.v2ray.ang.ui.MainActivity
|
||||||
import com.v2ray.ang.ui.SettingsActivity
|
import com.v2ray.ang.ui.SettingsActivity
|
||||||
import com.v2ray.ang.util.MessageUtil
|
import com.v2ray.ang.util.MessageUtil
|
||||||
@@ -50,14 +52,20 @@ object V2RayServiceManager {
|
|||||||
Seq.setContext(context)
|
Seq.setContext(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var currentConfigName = "NG"
|
||||||
|
|
||||||
private var lastQueryTime = 0L
|
private var lastQueryTime = 0L
|
||||||
private var mBuilder: NotificationCompat.Builder? = null
|
private var mBuilder: NotificationCompat.Builder? = null
|
||||||
private var mSubscription: Subscription? = null
|
private var mSubscription: Subscription? = null
|
||||||
private var mNotificationManager: NotificationManager? = null
|
private var mNotificationManager: NotificationManager? = null
|
||||||
|
|
||||||
fun startV2Ray(context: Context, mode: String) {
|
fun startV2Ray(context: Context) {
|
||||||
val intent = if (mode == "VPN") {
|
if (context.v2RayApplication.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
|
||||||
|
context.toast(R.string.toast_warning_pref_proxysharing_short)
|
||||||
|
}else{
|
||||||
|
context.toast(R.string.toast_services_start)
|
||||||
|
}
|
||||||
|
val intent = if (context.v2RayApplication.defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN") == "VPN") {
|
||||||
Intent(context.applicationContext, V2RayVpnService::class.java)
|
Intent(context.applicationContext, V2RayVpnService::class.java)
|
||||||
} else {
|
} else {
|
||||||
Intent(context.applicationContext, V2RayProxyOnlyService::class.java)
|
Intent(context.applicationContext, V2RayProxyOnlyService::class.java)
|
||||||
@@ -132,6 +140,7 @@ object V2RayServiceManager {
|
|||||||
v2rayPoint.forwardIpv6 = service.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_FORWARD_IPV6, false)
|
v2rayPoint.forwardIpv6 = service.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_FORWARD_IPV6, false)
|
||||||
v2rayPoint.domainName = service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_DOMAIN, "")
|
v2rayPoint.domainName = service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_DOMAIN, "")
|
||||||
v2rayPoint.proxyOnly = service.defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN") != "VPN"
|
v2rayPoint.proxyOnly = service.defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN") != "VPN"
|
||||||
|
currentConfigName = service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "NG")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
v2rayPoint.runLoop()
|
v2rayPoint.runLoop()
|
||||||
@@ -235,7 +244,7 @@ object V2RayServiceManager {
|
|||||||
|
|
||||||
mBuilder = NotificationCompat.Builder(service, channelId)
|
mBuilder = NotificationCompat.Builder(service, channelId)
|
||||||
.setSmallIcon(R.drawable.ic_v)
|
.setSmallIcon(R.drawable.ic_v)
|
||||||
.setContentTitle(service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, ""))
|
.setContentTitle(currentConfigName)
|
||||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setShowWhen(false)
|
.setShowWhen(false)
|
||||||
@@ -346,13 +355,10 @@ object V2RayServiceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun stopSpeedNotification() {
|
fun stopSpeedNotification() {
|
||||||
val service = serviceControl?.get()?.getService() ?: return
|
|
||||||
if (mSubscription != null) {
|
if (mSubscription != null) {
|
||||||
mSubscription?.unsubscribe() //stop queryStats
|
mSubscription?.unsubscribe() //stop queryStats
|
||||||
mSubscription = null
|
mSubscription = null
|
||||||
|
updateNotification(currentConfigName, 0, 0)
|
||||||
val cfName = service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
|
|
||||||
updateNotification(cfName, 0, 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import android.os.ParcelFileDescriptor
|
|||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import android.support.annotation.RequiresApi
|
import android.support.annotation.RequiresApi
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.v2ray.ang.AppConfig
|
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
import com.v2ray.ang.ui.PerAppProxyActivity
|
import com.v2ray.ang.ui.PerAppProxyActivity
|
||||||
@@ -127,7 +126,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setSession(defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, ""))
|
builder.setSession(V2RayServiceManager.currentConfigName)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
|
||||||
defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PER_APP_PROXY, false)) {
|
defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PER_APP_PROXY, false)) {
|
||||||
|
|||||||
@@ -1,42 +1,41 @@
|
|||||||
package com.v2ray.ang.ui
|
package com.v2ray.ang.ui
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.*
|
import android.arch.lifecycle.ViewModelProviders
|
||||||
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.VpnService
|
import android.net.VpnService
|
||||||
import android.support.v7.widget.LinearLayoutManager
|
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuItem
|
|
||||||
import com.tbruyelle.rxpermissions.RxPermissions
|
|
||||||
import com.v2ray.ang.R
|
|
||||||
import com.v2ray.ang.util.AngConfigManager
|
|
||||||
import com.v2ray.ang.util.Utils
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import com.v2ray.ang.AppConfig
|
|
||||||
import com.v2ray.ang.util.MessageUtil
|
|
||||||
import com.v2ray.ang.util.V2rayConfigUtil
|
|
||||||
import java.lang.ref.SoftReference
|
|
||||||
import java.net.URL
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.support.design.widget.NavigationView
|
import android.support.design.widget.NavigationView
|
||||||
import android.support.v4.view.GravityCompat
|
import android.support.v4.view.GravityCompat
|
||||||
import android.support.v7.app.ActionBarDrawerToggle
|
import android.support.v7.app.ActionBarDrawerToggle
|
||||||
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper
|
import android.support.v7.widget.helper.ItemTouchHelper
|
||||||
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import com.tbruyelle.rxpermissions.RxPermissions
|
||||||
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.BuildConfig
|
import com.v2ray.ang.BuildConfig
|
||||||
import com.v2ray.ang.dto.EConfigType
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
import com.v2ray.ang.extension.toast
|
import com.v2ray.ang.extension.toast
|
||||||
|
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
|
||||||
|
import com.v2ray.ang.util.AngConfigManager
|
||||||
|
import com.v2ray.ang.util.Utils
|
||||||
|
import com.v2ray.ang.util.V2rayConfigUtil
|
||||||
|
import com.v2ray.ang.viewmodel.MainViewModel
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import libv2ray.Libv2ray
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import java.net.URL
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
|
|
||||||
import com.v2ray.ang.util.AngConfigManager.configs
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import libv2ray.Libv2ray
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
|
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -46,23 +45,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
private const val REQUEST_SCAN_URL = 3
|
private const val REQUEST_SCAN_URL = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
var isRunning = false
|
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
adapter.changeable = !value
|
|
||||||
if (value) {
|
|
||||||
fab.setImageResource(R.drawable.ic_v)
|
|
||||||
tv_test_state.text = getString(R.string.connection_connected)
|
|
||||||
} else {
|
|
||||||
fab.setImageResource(R.drawable.ic_v_idle)
|
|
||||||
tv_test_state.text = getString(R.string.connection_not_connected)
|
|
||||||
}
|
|
||||||
hideCircle()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val adapter by lazy { MainRecyclerAdapter(this) }
|
private val adapter by lazy { MainRecyclerAdapter(this) }
|
||||||
private var mItemTouchHelper: ItemTouchHelper? = null
|
private var mItemTouchHelper: ItemTouchHelper? = null
|
||||||
private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
|
private val mainViewModel: MainViewModel by lazy { ViewModelProviders.of(this).get(MainViewModel::class.java) }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -71,7 +56,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
fab.setOnClickListener {
|
fab.setOnClickListener {
|
||||||
if (isRunning) {
|
if (mainViewModel.isRunning.value == true) {
|
||||||
Utils.stopVService(this)
|
Utils.stopVService(this)
|
||||||
} else if (defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN") == "VPN") {
|
} else if (defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN") == "VPN") {
|
||||||
val intent = VpnService.prepare(this)
|
val intent = VpnService.prepare(this)
|
||||||
@@ -85,16 +70,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
layout_test.setOnClickListener {
|
layout_test.setOnClickListener {
|
||||||
if (isRunning) {
|
if (mainViewModel.isRunning.value == true) {
|
||||||
val socksPort = 10808//Utils.parseInt(defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
|
|
||||||
|
|
||||||
tv_test_state.text = getString(R.string.connection_test_testing)
|
tv_test_state.text = getString(R.string.connection_test_testing)
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
mainViewModel.testCurrentServerRealPing()
|
||||||
val result = Utils.testConnection(this@MainActivity, socksPort)
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
tv_test_state.text = Utils.getEditable(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// tv_test_state.text = getString(R.string.connection_test_fail)
|
// tv_test_state.text = getString(R.string.connection_test_fail)
|
||||||
}
|
}
|
||||||
@@ -115,6 +93,33 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
toggle.syncState()
|
toggle.syncState()
|
||||||
nav_view.setNavigationItemSelectedListener(this)
|
nav_view.setNavigationItemSelectedListener(this)
|
||||||
version.text = "v${BuildConfig.VERSION_NAME} (${Libv2ray.checkVersionX()})"
|
version.text = "v${BuildConfig.VERSION_NAME} (${Libv2ray.checkVersionX()})"
|
||||||
|
|
||||||
|
setupViewModelObserver()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupViewModelObserver() {
|
||||||
|
mainViewModel.updateListAction.observe(this, {
|
||||||
|
val index = it ?: return@observe
|
||||||
|
if (index >= 0) {
|
||||||
|
adapter.updateSelectedItem(index)
|
||||||
|
} else {
|
||||||
|
adapter.updateConfigList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
mainViewModel.updateTestResultAction.observe(this, { tv_test_state.text = it })
|
||||||
|
mainViewModel.isRunning.observe(this, {
|
||||||
|
val isRunning = it ?: return@observe
|
||||||
|
adapter.changeable = !isRunning
|
||||||
|
if (isRunning) {
|
||||||
|
fab.setImageResource(R.drawable.ic_v)
|
||||||
|
tv_test_state.text = getString(R.string.connection_connected)
|
||||||
|
} else {
|
||||||
|
fab.setImageResource(R.drawable.ic_v_idle)
|
||||||
|
tv_test_state.text = getString(R.string.connection_not_connected)
|
||||||
|
}
|
||||||
|
hideCircle()
|
||||||
|
})
|
||||||
|
mainViewModel.startListenBroadcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startV2Ray() {
|
fun startV2Ray() {
|
||||||
@@ -123,32 +128,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
showCircle()
|
showCircle()
|
||||||
// toast(R.string.toast_services_start)
|
// toast(R.string.toast_services_start)
|
||||||
if (!Utils.startVService(this)) {
|
if (!Utils.startVService(this, AngConfigManager.configs.index)) {
|
||||||
hideCircle()
|
hideCircle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
isRunning = false
|
|
||||||
|
|
||||||
// val intent = Intent(this.applicationContext, V2RayVpnService::class.java)
|
|
||||||
// intent.`package` = AppConfig.ANG_PACKAGE
|
|
||||||
// bindService(intent, mConnection, BIND_AUTO_CREATE)
|
|
||||||
|
|
||||||
mMsgReceive = ReceiveMessageHandler(this@MainActivity)
|
|
||||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
|
||||||
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
if (mMsgReceive != null) {
|
|
||||||
unregisterReceiver(mMsgReceive)
|
|
||||||
mMsgReceive = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun onResume() {
|
public override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
adapter.updateConfigList()
|
adapter.updateConfigList()
|
||||||
@@ -188,7 +172,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getOptionIntent() = Intent().putExtra("position", -1)
|
private fun getOptionIntent() = Intent().putExtra("position", -1)
|
||||||
.putExtra("isRunning", isRunning)
|
.putExtra("isRunning", mainViewModel.isRunning.value == true)
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||||
R.id.import_qrcode -> {
|
R.id.import_qrcode -> {
|
||||||
@@ -251,30 +235,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
R.id.ping_all -> {
|
R.id.ping_all -> {
|
||||||
tcpingTestScope.coroutineContext[Job]?.cancelChildren()
|
mainViewModel.testAllTcping()
|
||||||
Utils.closeAllTcpSockets()
|
|
||||||
for (k in 0 until configs.vmess.count()) {
|
|
||||||
configs.vmess[k].testResult = ""
|
|
||||||
adapter.updateConfigList()
|
|
||||||
}
|
|
||||||
for (k in 0 until configs.vmess.count()) {
|
|
||||||
var serverAddress = configs.vmess[k].address
|
|
||||||
var serverPort = configs.vmess[k].port
|
|
||||||
if (configs.vmess[k].configType == EConfigType.CUSTOM.value) {
|
|
||||||
val serverOutbound = V2rayConfigUtil.getCustomConfigServerOutbound(applicationContext, configs.vmess[k].guid)
|
|
||||||
?: continue
|
|
||||||
serverAddress = serverOutbound.getServerAddress() ?: continue
|
|
||||||
serverPort = serverOutbound.getServerPort() ?: continue
|
|
||||||
}
|
|
||||||
tcpingTestScope.launch {
|
|
||||||
configs.vmess.getOrNull(k)?.let { // check null in case array is modified during testing
|
|
||||||
it.testResult = Utils.tcping(serverAddress, serverPort)
|
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
adapter.updateSelectedItem(k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,35 +475,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private
|
|
||||||
var mMsgReceive: BroadcastReceiver? = null
|
|
||||||
|
|
||||||
private class ReceiveMessageHandler(activity: MainActivity) : BroadcastReceiver() {
|
|
||||||
internal var mReference: SoftReference<MainActivity> = SoftReference(activity)
|
|
||||||
override fun onReceive(ctx: Context?, intent: Intent?) {
|
|
||||||
val activity = mReference.get()
|
|
||||||
when (intent?.getIntExtra("key", 0)) {
|
|
||||||
AppConfig.MSG_STATE_RUNNING -> {
|
|
||||||
activity?.isRunning = true
|
|
||||||
}
|
|
||||||
AppConfig.MSG_STATE_NOT_RUNNING -> {
|
|
||||||
activity?.isRunning = false
|
|
||||||
}
|
|
||||||
AppConfig.MSG_STATE_START_SUCCESS -> {
|
|
||||||
activity?.toast(R.string.toast_services_success)
|
|
||||||
activity?.isRunning = true
|
|
||||||
}
|
|
||||||
AppConfig.MSG_STATE_START_FAILURE -> {
|
|
||||||
activity?.toast(R.string.toast_services_failure)
|
|
||||||
activity?.isRunning = false
|
|
||||||
}
|
|
||||||
AppConfig.MSG_STATE_STOP_SUCCESS -> {
|
|
||||||
activity?.isRunning = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
moveTaskToBack(false)
|
moveTaskToBack(false)
|
||||||
@@ -585,7 +517,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
R.id.settings -> {
|
R.id.settings -> {
|
||||||
startActivity(Intent(this, SettingsActivity::class.java)
|
startActivity(Intent(this, SettingsActivity::class.java)
|
||||||
.putExtra("isRunning", isRunning))
|
.putExtra("isRunning", mainViewModel.isRunning.value == true))
|
||||||
}
|
}
|
||||||
R.id.feedback -> {
|
R.id.feedback -> {
|
||||||
Utils.openUri(this, AppConfig.v2rayNGIssues)
|
Utils.openUri(this, AppConfig.v2rayNGIssues)
|
||||||
|
|||||||
@@ -64,11 +64,13 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
|||||||
holder.radio.isChecked = (position == configs.index)
|
holder.radio.isChecked = (position == configs.index)
|
||||||
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
|
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
|
||||||
holder.test_result.text = test_result
|
holder.test_result.text = test_result
|
||||||
|
holder.subscription.text = ""
|
||||||
if (TextUtils.isEmpty(subid)) {
|
if (!TextUtils.isEmpty(subid)) {
|
||||||
holder.subid.text = ""
|
for (sub in configs.subItem) {
|
||||||
} else {
|
if (sub.id == subid) {
|
||||||
holder.subid.text = "S"
|
holder.subscription.text = sub.remarks
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var shareOptions = share_method.asList()
|
var shareOptions = share_method.asList()
|
||||||
@@ -143,16 +145,14 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
|||||||
} else {
|
} else {
|
||||||
mActivity.showCircle()
|
mActivity.showCircle()
|
||||||
Utils.stopVService(mActivity)
|
Utils.stopVService(mActivity)
|
||||||
AngConfigManager.setActiveServer(position)
|
|
||||||
Observable.timer(500, TimeUnit.MILLISECONDS)
|
Observable.timer(500, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
mActivity.showCircle()
|
mActivity.showCircle()
|
||||||
if (!Utils.startVService(mActivity)) {
|
if (!Utils.startVService(mActivity, position)) {
|
||||||
mActivity.hideCircle()
|
mActivity.hideCircle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
|||||||
open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||||
|
|
||||||
class MainViewHolder(itemView: View) : BaseViewHolder(itemView), ItemTouchHelperViewHolder {
|
class MainViewHolder(itemView: View) : BaseViewHolder(itemView), ItemTouchHelperViewHolder {
|
||||||
val subid = itemView.tv_subid
|
val subscription = itemView.tv_subscription
|
||||||
val radio = itemView.btn_radio!!
|
val radio = itemView.btn_radio!!
|
||||||
val name = itemView.tv_name!!
|
val name = itemView.tv_name!!
|
||||||
val test_result = itemView.tv_test_result!!
|
val test_result = itemView.tv_test_result!!
|
||||||
|
|||||||
@@ -69,40 +69,32 @@ class Server2Activity : BaseActivity() {
|
|||||||
* save server config
|
* save server config
|
||||||
*/
|
*/
|
||||||
fun saveServer(): Boolean {
|
fun saveServer(): Boolean {
|
||||||
var saveSuccess: Boolean
|
|
||||||
val vmess = configs.vmess[edit_index]
|
val vmess = configs.vmess[edit_index]
|
||||||
|
|
||||||
vmess.remarks = et_remarks.text.toString()
|
vmess.remarks = et_remarks.text.toString()
|
||||||
|
|
||||||
if (TextUtils.isEmpty(vmess.remarks)) {
|
if (TextUtils.isEmpty(vmess.remarks)) {
|
||||||
toast(R.string.server_lab_remarks)
|
toast(R.string.server_lab_remarks)
|
||||||
saveSuccess = false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
|
||||||
toast(R.string.toast_success)
|
|
||||||
saveSuccess = true
|
|
||||||
} else {
|
|
||||||
toast(R.string.toast_failure)
|
|
||||||
saveSuccess = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Gson().fromJson<Object>(tv_content.text.toString(), Object::class.java)
|
Gson().fromJson<Object>(tv_content.text.toString(), Object::class.java)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
toast(R.string.toast_malformed_josn)
|
toast(R.string.toast_malformed_josn)
|
||||||
saveSuccess = false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveSuccess) {
|
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
||||||
//update config
|
//update config
|
||||||
defaultDPreference.setPrefString(AppConfig.ANG_CONFIG + edit_guid, tv_content.text.toString())
|
defaultDPreference.setPrefString(AppConfig.ANG_CONFIG + edit_guid, tv_content.text.toString())
|
||||||
|
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||||
|
toast(R.string.toast_success)
|
||||||
finish()
|
finish()
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
|
toast(R.string.toast_failure)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class Server3Activity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (AngConfigManager.addShadowsocksServer(vmess, edit_index) == 0) {
|
if (AngConfigManager.addShadowsocksServer(vmess, edit_index) == 0) {
|
||||||
|
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||||
toast(R.string.toast_success)
|
toast(R.string.toast_success)
|
||||||
finish()
|
finish()
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class Server4Activity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (AngConfigManager.addSocksServer(vmess, edit_index) == 0) {
|
if (AngConfigManager.addSocksServer(vmess, edit_index) == 0) {
|
||||||
|
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||||
toast(R.string.toast_success)
|
toast(R.string.toast_success)
|
||||||
finish()
|
finish()
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ class ServerActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (AngConfigManager.addServer(vmess, edit_index) == 0) {
|
if (AngConfigManager.addServer(vmess, edit_index) == 0) {
|
||||||
|
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||||
toast(R.string.toast_success)
|
toast(R.string.toast_success)
|
||||||
finish()
|
finish()
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.v2ray.ang.ui
|
package com.v2ray.ang.ui
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModelProviders
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v7.preference.*
|
import android.support.v7.preference.*
|
||||||
@@ -7,7 +8,9 @@ import android.view.View
|
|||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.extension.toast
|
import com.v2ray.ang.extension.toast
|
||||||
|
import com.v2ray.ang.util.AngConfigManager
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
|
import com.v2ray.ang.viewmodel.SettingsViewModel
|
||||||
|
|
||||||
class SettingsActivity : BaseActivity() {
|
class SettingsActivity : BaseActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -36,6 +39,8 @@ class SettingsActivity : BaseActivity() {
|
|||||||
const val PREF_FORWARD_IPV6 = "pref_forward_ipv6"
|
const val PREF_FORWARD_IPV6 = "pref_forward_ipv6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val settingsViewModel by lazy { ViewModelProviders.of(this).get(SettingsViewModel::class.java) }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_settings)
|
setContentView(R.layout.activity_settings)
|
||||||
@@ -43,6 +48,8 @@ class SettingsActivity : BaseActivity() {
|
|||||||
title = getString(R.string.title_settings)
|
title = getString(R.string.title_settings)
|
||||||
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
settingsViewModel.startListenPreferenceChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsFragment : PreferenceFragmentCompat() {
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
@@ -74,7 +81,7 @@ class SettingsActivity : BaseActivity() {
|
|||||||
|
|
||||||
private fun restartProxy() {
|
private fun restartProxy() {
|
||||||
Utils.stopVService(requireContext())
|
Utils.stopVService(requireContext())
|
||||||
Utils.startVService(requireContext())
|
Utils.startVService(requireContext(), AngConfigManager.configs.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isRunning(): Boolean {
|
private fun isRunning(): Boolean {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.v2ray.ang.util
|
|||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
@@ -154,6 +155,10 @@ object AngConfigManager {
|
|||||||
angConfig.index = index
|
angConfig.index = index
|
||||||
app.curIndex = index
|
app.curIndex = index
|
||||||
storeConfigFile()
|
storeConfigFile()
|
||||||
|
if (!genStoreV2rayConfig()) {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "set active index $index but generate full configuration failed!")
|
||||||
|
return -1
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
app.curIndex = -1
|
app.curIndex = -1
|
||||||
@@ -174,35 +179,32 @@ object AngConfigManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun genStoreV2rayConfigIfActive(index: Int) {
|
||||||
|
if (index == configs.index) {
|
||||||
|
if (!genStoreV2rayConfig()) {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "update config $index but generate full configuration failed!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gen and store v2ray config file
|
* gen and store v2ray config file
|
||||||
*/
|
*/
|
||||||
fun genStoreV2rayConfig(index: Int): Boolean {
|
fun genStoreV2rayConfig(): Boolean {
|
||||||
try {
|
try {
|
||||||
if (angConfig.index < 0
|
angConfig.vmess.getOrNull(angConfig.index)?.let {
|
||||||
|| angConfig.vmess.count() <= 0
|
val result = V2rayConfigUtil.getV2rayConfig(app, it)
|
||||||
|| angConfig.index > angConfig.vmess.count() - 1
|
if (result.status) {
|
||||||
) {
|
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG, result.content)
|
||||||
return false
|
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_GUID, currConfigGuid())
|
||||||
}
|
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_NAME, currConfigName())
|
||||||
var index2 = angConfig.index
|
return true
|
||||||
if (index >= 0) {
|
}
|
||||||
index2 = index
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = V2rayConfigUtil.getV2rayConfig(app, angConfig.vmess[index2])
|
|
||||||
if (result.status) {
|
|
||||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG, result.content)
|
|
||||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_GUID, currConfigGuid())
|
|
||||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_NAME, currConfigName())
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun currGeneratedV2rayConfig(): String {
|
fun currGeneratedV2rayConfig(): String {
|
||||||
@@ -586,9 +588,9 @@ object AngConfigManager {
|
|||||||
*/
|
*/
|
||||||
fun shareFullContent2Clipboard(index: Int): Int {
|
fun shareFullContent2Clipboard(index: Int): Int {
|
||||||
try {
|
try {
|
||||||
if (AngConfigManager.genStoreV2rayConfig(index)) {
|
val result = V2rayConfigUtil.getV2rayConfig(app, angConfig.vmess[index])
|
||||||
val configContent = app.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
|
if (result.status) {
|
||||||
Utils.setClipboard(app.applicationContext, configContent)
|
Utils.setClipboard(app.applicationContext, result.content)
|
||||||
} else {
|
} else {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import android.webkit.URLUtil
|
|||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.dto.EConfigType
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
import com.v2ray.ang.extension.responseLength
|
import com.v2ray.ang.extension.responseLength
|
||||||
import com.v2ray.ang.extension.toast
|
import com.v2ray.ang.extension.toast
|
||||||
import com.v2ray.ang.extension.v2RayApplication
|
import com.v2ray.ang.extension.v2RayApplication
|
||||||
@@ -32,7 +32,6 @@ import kotlinx.coroutines.isActive
|
|||||||
import me.dozen.dpreference.DPreference
|
import me.dozen.dpreference.DPreference
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.*
|
import java.net.*
|
||||||
import libv2ray.Libv2ray
|
|
||||||
import kotlin.coroutines.coroutineContext
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
object Utils {
|
object Utils {
|
||||||
@@ -272,38 +271,13 @@ object Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startVServiceFromToggle(context: Context): Boolean {
|
fun startVServiceFromToggle(context: Context): Boolean {
|
||||||
val result = startVService(context)
|
val result = context.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
|
||||||
if (!result) {
|
if (result.isBlank()) {
|
||||||
context.toast(R.string.app_tile_first_use)
|
context.toast(R.string.app_tile_first_use)
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* startVService
|
|
||||||
*/
|
|
||||||
fun startVService(context: Context): Boolean {
|
|
||||||
if (context.v2RayApplication.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
|
|
||||||
context.toast(R.string.toast_warning_pref_proxysharing_short)
|
|
||||||
}else{
|
|
||||||
context.toast(R.string.toast_services_start)
|
|
||||||
}
|
|
||||||
if (AngConfigManager.genStoreV2rayConfig(-1)) {
|
|
||||||
val configContent = AngConfigManager.currGeneratedV2rayConfig()
|
|
||||||
val configType = AngConfigManager.currConfigType()
|
|
||||||
if (configType == EConfigType.CUSTOM) {
|
|
||||||
try {
|
|
||||||
Libv2ray.testConfig(configContent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
context.toast(e.toString())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
V2RayServiceManager.startV2Ray(context, context.v2RayApplication.defaultDPreference.getPrefString(AppConfig.PREF_MODE, "VPN"))
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
V2RayServiceManager.startV2Ray(context)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -319,8 +293,11 @@ object Utils {
|
|||||||
* startVService
|
* startVService
|
||||||
*/
|
*/
|
||||||
fun startVService(context: Context, index: Int): Boolean {
|
fun startVService(context: Context, index: Int): Boolean {
|
||||||
AngConfigManager.setActiveServer(index)
|
if (AngConfigManager.setActiveServer(index) < 0) {
|
||||||
return startVService(context)
|
return false
|
||||||
|
}
|
||||||
|
V2RayServiceManager.startV2Ray(context)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.v2ray.ang.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.arch.lifecycle.AndroidViewModel
|
||||||
|
import android.arch.lifecycle.MutableLiveData
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.util.Log
|
||||||
|
import com.v2ray.ang.AngApplication
|
||||||
|
import com.v2ray.ang.AppConfig
|
||||||
|
import com.v2ray.ang.R
|
||||||
|
import com.v2ray.ang.dto.EConfigType
|
||||||
|
import com.v2ray.ang.extension.toast
|
||||||
|
import com.v2ray.ang.util.AngConfigManager
|
||||||
|
import com.v2ray.ang.util.MessageUtil
|
||||||
|
import com.v2ray.ang.util.Utils
|
||||||
|
import com.v2ray.ang.util.V2rayConfigUtil
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
val isRunning by lazy { MutableLiveData<Boolean>() }
|
||||||
|
val updateListAction by lazy { MutableLiveData<Int>() }
|
||||||
|
val updateTestResultAction by lazy { MutableLiveData<String>() }
|
||||||
|
|
||||||
|
private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
|
||||||
|
|
||||||
|
fun startListenBroadcast() {
|
||||||
|
isRunning.value = false
|
||||||
|
getApplication<AngApplication>().registerReceiver(mMsgReceiver, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
||||||
|
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_REGISTER_CLIENT, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
getApplication<AngApplication>().unregisterReceiver(mMsgReceiver)
|
||||||
|
Log.i(AppConfig.ANG_PACKAGE, "Main ViewModel is cleared")
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testAllTcping() {
|
||||||
|
tcpingTestScope.coroutineContext[Job]?.cancelChildren()
|
||||||
|
Utils.closeAllTcpSockets()
|
||||||
|
for (k in 0 until AngConfigManager.configs.vmess.count()) {
|
||||||
|
AngConfigManager.configs.vmess[k].testResult = ""
|
||||||
|
updateListAction.value = -1 // update all
|
||||||
|
}
|
||||||
|
for (k in 0 until AngConfigManager.configs.vmess.count()) {
|
||||||
|
var serverAddress = AngConfigManager.configs.vmess[k].address
|
||||||
|
var serverPort = AngConfigManager.configs.vmess[k].port
|
||||||
|
if (AngConfigManager.configs.vmess[k].configType == EConfigType.CUSTOM.value) {
|
||||||
|
val serverOutbound = V2rayConfigUtil.getCustomConfigServerOutbound(getApplication(),
|
||||||
|
AngConfigManager.configs.vmess[k].guid) ?: continue
|
||||||
|
serverAddress = serverOutbound.getServerAddress() ?: continue
|
||||||
|
serverPort = serverOutbound.getServerPort() ?: continue
|
||||||
|
}
|
||||||
|
tcpingTestScope.launch {
|
||||||
|
AngConfigManager.configs.vmess.getOrNull(k)?.let { // check null in case array is modified during testing
|
||||||
|
it.testResult = Utils.tcping(serverAddress, serverPort)
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
updateListAction.value = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testCurrentServerRealPing() {
|
||||||
|
val socksPort = 10808//Utils.parseInt(defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
val result = Utils.testConnection(getApplication(), socksPort)
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
updateTestResultAction.value = result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mMsgReceiver = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(ctx: Context?, intent: Intent?) {
|
||||||
|
when (intent?.getIntExtra("key", 0)) {
|
||||||
|
AppConfig.MSG_STATE_RUNNING -> {
|
||||||
|
isRunning.value = true
|
||||||
|
}
|
||||||
|
AppConfig.MSG_STATE_NOT_RUNNING -> {
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
AppConfig.MSG_STATE_START_SUCCESS -> {
|
||||||
|
getApplication<AngApplication>().toast(R.string.toast_services_success)
|
||||||
|
isRunning.value = true
|
||||||
|
}
|
||||||
|
AppConfig.MSG_STATE_START_FAILURE -> {
|
||||||
|
getApplication<AngApplication>().toast(R.string.toast_services_failure)
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
AppConfig.MSG_STATE_STOP_SUCCESS -> {
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.v2ray.ang.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.arch.lifecycle.AndroidViewModel
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.support.v7.preference.PreferenceManager
|
||||||
|
import android.util.Log
|
||||||
|
import com.v2ray.ang.AppConfig
|
||||||
|
import com.v2ray.ang.ui.SettingsActivity.Companion
|
||||||
|
import com.v2ray.ang.util.AngConfigManager
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class SettingsViewModel(application: Application) : AndroidViewModel(application), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
fun startListenPreferenceChange() {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(getApplication()).registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(getApplication()).unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
Log.i(AppConfig.ANG_PACKAGE, "Settings ViewModel is cleared")
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "Observe settings changed: $key")
|
||||||
|
when(key) {
|
||||||
|
Companion.PREF_SNIFFING_ENABLED,
|
||||||
|
Companion.PREF_PROXY_SHARING,
|
||||||
|
Companion.PREF_LOCAL_DNS_ENABLED,
|
||||||
|
Companion.PREF_REMOTE_DNS,
|
||||||
|
Companion.PREF_DOMESTIC_DNS,
|
||||||
|
Companion.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||||
|
Companion.PREF_ROUTING_MODE,
|
||||||
|
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||||
|
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||||
|
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
|
||||||
|
GlobalScope.launch {
|
||||||
|
if (!AngConfigManager.genStoreV2rayConfig()) {
|
||||||
|
Log.d(AppConfig.ANG_PACKAGE, "$key changed but generate full configuration failed!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/item_bg"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/item_bg"
|
||||||
android:gravity="center_vertical">
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
<android.support.v7.widget.CardView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="3dp"
|
android:layout_margin="3dp"
|
||||||
card_view:cardCornerRadius="5dp">
|
app:cardCornerRadius="5dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/info_container"
|
android:id="@+id/info_container"
|
||||||
@@ -18,34 +20,19 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:nextFocusRight="@+id/layout_share">
|
android:nextFocusRight="@+id/layout_share">
|
||||||
|
|
||||||
<LinearLayout
|
<android.support.v7.widget.AppCompatRadioButton
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_subid"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="8dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
|
||||||
|
|
||||||
<android.support.v7.widget.AppCompatRadioButton
|
|
||||||
android:id="@+id/btn_radio"
|
android:id="@+id/btn_radio"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false" />
|
android:focusableInTouchMode="false" />
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -85,20 +72,31 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="right"
|
android:orientation="horizontal"
|
||||||
android:orientation="vertical"
|
android:paddingEnd="5dp">
|
||||||
android:paddingEnd="5dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_test_result"
|
android:id="@+id/tv_subscription"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:lines="1"
|
android:layout_weight="1"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
android:lines="1"
|
||||||
android:textColor="@color/colorPing"
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
android:textSize="10sp" />
|
android:textColor="@color/colorSubscription"
|
||||||
|
android:textSize="10sp"
|
||||||
|
tools:text="Sub" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_test_result"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
android:textColor="@color/colorPing"
|
||||||
|
android:textSize="10sp"
|
||||||
|
tools:text="214ms" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -185,4 +183,4 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -9,4 +9,5 @@
|
|||||||
<color name="icons">#FFFFFF</color>
|
<color name="icons">#FFFFFF</color>
|
||||||
<color name="divider">#BDBDBD</color>
|
<color name="divider">#BDBDBD</color>
|
||||||
<color name="colorPing">#185534</color>
|
<color name="colorPing">#185534</color>
|
||||||
|
<color name="colorSubscription">#247BA0</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user