Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3074e9697 | ||
|
|
513ebcfa23 | ||
|
|
50d9057f1a | ||
|
|
2a563e7884 | ||
|
|
c69cd18842 | ||
|
|
7f2ced85a8 | ||
|
|
6c5eef99b5 | ||
|
|
d7c3bae8cc | ||
|
|
57c98f7c50 | ||
|
|
49be23c56a | ||
|
|
9b658e9a22 | ||
|
|
aaa84d081f | ||
|
|
5628cbee3a | ||
|
|
3dd663d927 | ||
|
|
9e49a2dbd9 | ||
|
|
6c199c1687 | ||
|
|
39af5fdb86 | ||
|
|
7b2794f6be | ||
|
|
411d9e5c9a | ||
|
|
a57aee9424 | ||
|
|
4602afc67e | ||
|
|
ceb29840f2 | ||
|
|
1c1f130ca7 | ||
|
|
afa0eb9375 | ||
|
|
49b682f0f3 | ||
|
|
d5def3bf2f | ||
|
|
51b97b64f2 | ||
|
|
3af9ce1a1a | ||
|
|
a5d3dda941 | ||
|
|
71a3e300d8 | ||
|
|
030b9a3900 | ||
|
|
24d105a53c |
@@ -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
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ type Status struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CheckVersion() int {
|
func CheckVersion() int {
|
||||||
return 21
|
return 22
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Status) GetDataDir() string {
|
func (v *Status) GetDataDir() string {
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package Escort
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/2dust/AndroidLibV2rayLite/CoreI"
|
"github.com/2dust/AndroidLibV2rayLite/CoreI"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string, sendFd func() int) {
|
func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string) {
|
||||||
log.Println(proc, pt)
|
log.Println(proc, pt)
|
||||||
count := 0
|
count := 0
|
||||||
for count <= 42 {
|
for count <= 42 {
|
||||||
@@ -37,13 +36,6 @@ func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string, se
|
|||||||
*v.escortProcess = append(*v.escortProcess, cmd.Process)
|
*v.escortProcess = append(*v.escortProcess, cmd.Process)
|
||||||
log.Println("EscortRun Waiting....")
|
log.Println("EscortRun Waiting....")
|
||||||
|
|
||||||
if count > 0 {
|
|
||||||
go func() {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
sendFd()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
log.Println("EscortRun cmd.Wait err:", err)
|
log.Println("EscortRun cmd.Wait err:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type V2RayPoint struct {
|
|||||||
ConfigureFileContent string
|
ConfigureFileContent string
|
||||||
EnableLocalDNS bool
|
EnableLocalDNS bool
|
||||||
ForwardIpv6 bool
|
ForwardIpv6 bool
|
||||||
|
ProxyOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
/*V2RayVPNServiceSupportsSet To support Android VPN mode*/
|
/*V2RayVPNServiceSupportsSet To support Android VPN mode*/
|
||||||
@@ -57,7 +58,6 @@ type V2RayVPNServiceSupportsSet interface {
|
|||||||
Shutdown() int
|
Shutdown() int
|
||||||
Protect(int) int
|
Protect(int) int
|
||||||
OnEmitStatus(int, string) int
|
OnEmitStatus(int, string) int
|
||||||
SendFd() int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*RunLoop Run V2Ray main loop
|
/*RunLoop Run V2Ray main loop
|
||||||
@@ -81,7 +81,6 @@ func (v *V2RayPoint) RunLoop() (err error) {
|
|||||||
if !v.dialer.IsVServerReady() {
|
if !v.dialer.IsVServerReady() {
|
||||||
log.Println("vServer cannot resolved, shutdown")
|
log.Println("vServer cannot resolved, shutdown")
|
||||||
v.StopLoop()
|
v.StopLoop()
|
||||||
v.SupportSet.Shutdown()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop waiting if manually closed
|
// stop waiting if manually closed
|
||||||
@@ -100,9 +99,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
|
||||||
}
|
}
|
||||||
@@ -112,6 +109,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 {
|
||||||
@@ -125,24 +126,19 @@ 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.OnEmitStatus(0, "Closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *V2RayPoint) pointloop() error {
|
func (v *V2RayPoint) pointloop() error {
|
||||||
if err := v.runTun2socks(); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
|
|
||||||
v.EnableLocalDNS,
|
|
||||||
v.ForwardIpv6,
|
|
||||||
v.DomainName)
|
|
||||||
|
|
||||||
log.Println("loading v2ray config")
|
log.Println("loading v2ray config")
|
||||||
config, err := v2serial.LoadJSONConfig(strings.NewReader(v.ConfigureFileContent))
|
config, err := v2serial.LoadJSONConfig(strings.NewReader(v.ConfigureFileContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -170,6 +166,21 @@ func (v *V2RayPoint) pointloop() error {
|
|||||||
v.SupportSet.Prepare()
|
v.SupportSet.Prepare()
|
||||||
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 err := v.runTun2socks(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.status.IsTRunning = true
|
||||||
|
|
||||||
|
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
|
||||||
|
v.EnableLocalDNS,
|
||||||
|
v.ForwardIpv6,
|
||||||
|
v.DomainName)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +240,7 @@ func (v V2RayPoint) runTun2socks() error {
|
|||||||
v.escorter.EscortingUp()
|
v.escorter.EscortingUp()
|
||||||
go v.escorter.EscortRun(
|
go v.escorter.EscortRun(
|
||||||
v.status.GetApp("libtun2socks.so"),
|
v.status.GetApp("libtun2socks.so"),
|
||||||
v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "",
|
v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "")
|
||||||
v.SupportSet.SendFd)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -3,7 +3,7 @@
|
|||||||
A V2Ray client for Android
|
A V2Ray client for Android
|
||||||
|
|
||||||
[](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)
|
||||||
@@ -14,7 +14,16 @@ A V2Ray client for Android
|
|||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
See our [wiki](https://github.com/2dust/v2rayNG/wiki)
|
#### Geoip and Geosite
|
||||||
|
v2rayNG release already embedded domain file `geoip.dat` and `geosite.dat`. However it is (probably) not the latest and not the most complete list.
|
||||||
|
For power user, the embedded files can be easily replaced with the following steps:
|
||||||
|
1. Launch v2rayNG (v1.4.9+)
|
||||||
|
2. Find existing geoip.dat and geosite.dat in `Android/data/com.v2ray.ang/files/assets` (path may differ on some Android device)
|
||||||
|
3. Replace them with the latest [domain list](https://github.com/v2fly/domain-list-community) and [ip list](https://github.com/v2fly/geoip)
|
||||||
|
4. Enhanced version can be found in this [repo](https://github.com/Loyalsoldier/v2ray-rules-dat) (recommend to use `geosite:geolocation-!cn` for proxy dns and routing)
|
||||||
|
5. It is also possible to use third party dat file in the same folder, like [h2y](https://guide.v2fly.org/routing/sitedata.html#%E5%A4%96%E7%BD%AE%E7%9A%84%E5%9F%9F%E5%90%8D%E6%96%87%E4%BB%B6)
|
||||||
|
|
||||||
|
#### See more in our [wiki](https://github.com/2dust/v2rayNG/wiki)
|
||||||
|
|
||||||
### Development guide
|
### Development guide
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Binary file not shown.
3
V2rayNG/app/proguard-rules.pro
vendored
3
V2rayNG/app/proguard-rules.pro
vendored
@@ -44,9 +44,6 @@
|
|||||||
static void throwUninitializedPropertyAccessException(java.lang.String);
|
static void throwUninitializedPropertyAccessException(java.lang.String);
|
||||||
}
|
}
|
||||||
|
|
||||||
-dontwarn org.jetbrains.anko.internals.**
|
|
||||||
-keep class org.jetbrains.anko.internals.** { *;}
|
|
||||||
|
|
||||||
-dontwarn rx.internal.util.unsafe.**
|
-dontwarn rx.internal.util.unsafe.**
|
||||||
-keep class rx.internal.util.unsafe.** { *;}
|
-keep class rx.internal.util.unsafe.** { *;}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.v2ray.ang">
|
package="com.v2ray.ang">
|
||||||
|
|
||||||
<supports-screens
|
<supports-screens
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- https://developer.android.com/about/versions/11/privacy/package-visibility -->
|
||||||
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||||
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@@ -21,12 +27,14 @@
|
|||||||
<uses-permission android:name="com.android.vending.BILLING" />
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
|
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".AngApplication"
|
android:name=".AngApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
|
android:extractNativeLibs="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.MainActivity"
|
android:name=".ui.MainActivity"
|
||||||
@@ -34,20 +42,16 @@
|
|||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.app.shortcuts"
|
android:name="android.app.shortcuts"
|
||||||
android:resource="@xml/shortcuts" />
|
android:resource="@xml/shortcuts" />
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,4 @@ interface ServiceControl {
|
|||||||
|
|
||||||
fun vpnProtect(socket: Int): Boolean
|
fun vpnProtect(socket: Int): Boolean
|
||||||
|
|
||||||
fun vpnSendFd()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,6 @@ class V2RayProxyOnlyService : Service(), ServiceControl {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vpnSendFd() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ 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
|
||||||
@@ -111,16 +112,6 @@ object V2RayServiceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendFd(): Long {
|
|
||||||
val serviceControl = serviceControl?.get() ?: return -1
|
|
||||||
try {
|
|
||||||
serviceControl.vpnSendFd()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.d(serviceControl.getService().packageName, e.toString())
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startV2rayPoint() {
|
fun startV2rayPoint() {
|
||||||
@@ -141,6 +132,8 @@ object V2RayServiceManager {
|
|||||||
v2rayPoint.enableLocalDNS = service.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
v2rayPoint.enableLocalDNS = service.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
||||||
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"
|
||||||
|
currentConfigName = service.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "NG")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
v2rayPoint.runLoop()
|
v2rayPoint.runLoop()
|
||||||
@@ -244,7 +237,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)
|
||||||
@@ -355,13 +348,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
|
||||||
@@ -50,7 +49,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
setUnderlyingNetworks(arrayOf(network))
|
setUnderlyingNetworks(arrayOf(network))
|
||||||
}
|
}
|
||||||
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities?) {
|
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||||
// it's a good idea to refresh capabilities
|
// it's a good idea to refresh capabilities
|
||||||
setUnderlyingNetworks(arrayOf(network))
|
setUnderlyingNetworks(arrayOf(network))
|
||||||
}
|
}
|
||||||
@@ -79,7 +78,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
V2RayServiceManager.cancelNotification()
|
stopV2Ray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setup(parameters: String) {
|
private fun setup(parameters: String) {
|
||||||
@@ -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)) {
|
||||||
@@ -155,8 +154,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
try {
|
try {
|
||||||
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
|
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
|
||||||
} catch (ignored: Exception) {
|
} catch (e: Exception) {
|
||||||
// ignored
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +171,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
stopV2Ray()
|
stopV2Ray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendFd()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendFd() {
|
private fun sendFd() {
|
||||||
@@ -181,7 +182,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
var tries = 0
|
var tries = 0
|
||||||
while (true) try {
|
while (true) try {
|
||||||
Thread.sleep(50L shl tries)
|
Thread.sleep(1000L shl tries)
|
||||||
Log.d(packageName, "sendFd tries: $tries")
|
Log.d(packageName, "sendFd tries: $tries")
|
||||||
LocalSocket().use { localSocket ->
|
LocalSocket().use { localSocket ->
|
||||||
localSocket.connect(LocalSocketAddress(path, LocalSocketAddress.Namespace.FILESYSTEM))
|
localSocket.connect(LocalSocketAddress(path, LocalSocketAddress.Namespace.FILESYSTEM))
|
||||||
@@ -251,7 +252,4 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
|||||||
return protect(socket)
|
return protect(socket)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun vpnSendFd() {
|
|
||||||
sendFd()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -128,27 +133,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ object AngConfigManager {
|
|||||||
result = Utils.decode(result)
|
result = Utils.decode(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".toRegex()
|
val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)/?$".toRegex()
|
||||||
val match = legacyPattern.matchEntire(result)
|
val match = legacyPattern.matchEntire(result)
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
return R.string.toast_incorrect_protocol
|
return R.string.toast_incorrect_protocol
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ package com.v2ray.ang.util
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.*
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.dto.AngConfig.VmessBean
|
import com.v2ray.ang.dto.AngConfig.VmessBean
|
||||||
@@ -14,7 +12,6 @@ import com.v2ray.ang.ui.SettingsActivity
|
|||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.v2ray.ang.dto.EConfigType
|
import com.v2ray.ang.dto.EConfigType
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import com.v2ray.ang.extension.defaultDPreference
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
@@ -64,11 +61,16 @@ object V2rayConfigUtil {
|
|||||||
if (TextUtils.isEmpty(jsonConfig)) {
|
if (TextUtils.isEmpty(jsonConfig)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val v2rayConfig = Gson().fromJson(jsonConfig, V2rayConfig::class.java) ?: return null
|
val v2rayConfig: V2rayConfig? = try {
|
||||||
for (outbound in v2rayConfig.outbounds) {
|
Gson().fromJson(jsonConfig, V2rayConfig::class.java)
|
||||||
if (outbound.protocol.equals(EConfigType.VMESS.name.toLowerCase()) ||
|
} catch (e: JsonSyntaxException) {
|
||||||
outbound.protocol.equals(EConfigType.SHADOWSOCKS.name.toLowerCase()) ||
|
e.printStackTrace()
|
||||||
outbound.protocol.equals(EConfigType.SOCKS.name.toLowerCase())) {
|
null
|
||||||
|
}
|
||||||
|
v2rayConfig?.outbounds?.forEach { outbound ->
|
||||||
|
if (outbound.protocol.equals(EConfigType.VMESS.name, true) ||
|
||||||
|
outbound.protocol.equals(EConfigType.SHADOWSOCKS.name, true) ||
|
||||||
|
outbound.protocol.equals(EConfigType.SOCKS.name, true)) {
|
||||||
return outbound
|
return outbound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ buildscript {
|
|||||||
maven { url 'https://maven.google.com' }
|
maven { url 'https://maven.google.com' }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
|
|||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
#Fri Jun 02 14:08:42 CST 2017
|
#Fri Jun 02 14:08:42 CST 2017
|
||||||
kotlinVersion=1.4.0
|
kotlinVersion=1.4.10
|
||||||
supportLibVersion=28.0.0
|
supportLibVersion=28.0.0
|
||||||
buildToolsVer=29.0.3
|
buildToolsVer=30.0.2
|
||||||
compileSdkVer=29
|
compileSdkVer=30
|
||||||
kotlin.incremental=true
|
kotlin.incremental=true
|
||||||
targetSdkVer=29
|
targetSdkVer=30
|
||||||
|
|||||||
Reference in New Issue
Block a user