diff --git a/.gitignore b/.gitignore
index 8400f229..0963c509 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,3 @@
-V2rayNG/app/src/main/res/layout/activity_inapp_buy.xml
-V2rayNG/app/src/main/assets/geoip.dat
-V2rayNG/app/src/main/assets/geosite.dat
-V2rayNG/app/src/main/java/com/v2ray/ang/InappBuyActivity.java
-*.aar
*.dat
*.jks
V2rayNG/app/release/output.json
diff --git a/AndroidLibV2rayLite/.gitignore b/AndroidLibV2rayLite/.gitignore
deleted file mode 100644
index db2c52e0..00000000
--- a/AndroidLibV2rayLite/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.jar
-*.aar
diff --git a/AndroidLibV2rayLite/CoreI/Status.go b/AndroidLibV2rayLite/CoreI/Status.go
deleted file mode 100644
index 8d025a1c..00000000
--- a/AndroidLibV2rayLite/CoreI/Status.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package CoreI
-
-import (
- v2core "github.com/xtls/xray-core/core"
-)
-
-type Status struct {
- IsRunning bool
- IsTRunning bool
- PackageName string
- PackageCodePath string
-
- Vpoint v2core.Server
-}
-
-func CheckVersion() int {
- return 23
-}
-
-func (v *Status) GetDataDir() string {
- return v.PackageName
-}
-
-func (v *Status) GetApp(name string) string {
- return v.PackageCodePath + name
-}
-
-func (v *Status) GetTun2socksArgs(localDNS bool, enableIPv6 bool) (ret []string) {
- ret = []string{"--netif-ipaddr",
- "26.26.26.2",
- "--netif-netmask",
- "255.255.255.252",
- "--socks-server-addr",
- "127.0.0.1:10808",
- "--tunmtu",
- "1500",
- "--loglevel",
- "notice",
- "--enable-udprelay",
- "--sock-path",
- v.GetDataDir() + "sock_path",
- }
-
- if enableIPv6 {
- ret = append(ret, "--netif-ip6addr", "da26:2626::2")
- }
-
- if localDNS {
- ret = append(ret, "--dnsgw", "127.0.0.1:10807")
- }
-
- return
-}
-
-func (v *Status) GetVPNSetupArg(localDNS bool, enableIPv6 bool) (ret string) {
- ret = "m,1500 a,26.26.26.1,30 r,0.0.0.0,0"
-
- if enableIPv6 {
- ret += " a,da26:2626::1,126 r,::,0"
- }
- if localDNS {
- ret += " d,26.26.26.2"
- }
- return
-}
diff --git a/AndroidLibV2rayLite/Makefile b/AndroidLibV2rayLite/Makefile
deleted file mode 100644
index 620df98b..00000000
--- a/AndroidLibV2rayLite/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-pb:
- go get -u github.com/golang/protobuf/protoc-gen-go
- @echo "pb Start"
-asset:
- bash gen_assets.sh download
- mkdir assets
- cp -v data/*.dat assets/
- # cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geosite.dat > geosite.dat
- # cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geoip.dat > geoip.dat
-
-ANDROID_HOME=$(HOME)/android-sdk-linux
-export ANDROID_HOME
-PATH:=$(PATH):$(GOPATH)/bin
-export PATH
-downloadGoMobile:
- sudo apt-get install -qq libstdc++6:i386 lib32z1 expect
- cd ~ ;curl -L https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/ubuntu-cli-install-android-sdk.sh | sudo bash - > /dev/null
- ls ~
- ls ~/android-sdk-linux/
-
-BuildMobile:
- gomobile init
- gomobile bind -v -ldflags='-s -w' github.com/2dust/AndroidLibV2rayLite
-
-all: asset pb
- @echo DONE
diff --git a/AndroidLibV2rayLite/Process/Escort/escort.go b/AndroidLibV2rayLite/Process/Escort/escort.go
deleted file mode 100644
index b8676cdd..00000000
--- a/AndroidLibV2rayLite/Process/Escort/escort.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package Escort
-
-import (
- "os"
- "os/exec"
-
- "log"
-
- "github.com/2dust/AndroidLibV2rayLite/CoreI"
-)
-
-func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string) {
- log.Println(proc, pt)
- count := 0
- for count <= 42 {
- cmd := exec.Command(proc, pt...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
-
- if len(additionalEnv) > 0 {
- //additionalEnv := "FOO=bar"
- newEnv := append(os.Environ(), additionalEnv)
- cmd.Env = newEnv
- }
-
- if err := cmd.Start(); err != nil {
- log.Println("EscortRun cmd.Start err", err)
- goto CMDERROR
- }
-
- if v.escortProcess == nil {
- log.Println("EscortRun v.escortProcess nil")
- break
- }
-
- *v.escortProcess = append(*v.escortProcess, cmd.Process)
- log.Println("EscortRun Waiting....")
-
- if err := cmd.Wait(); err != nil {
- log.Println("EscortRun cmd.Wait err:", err)
- }
-
- CMDERROR:
- if v.Status.IsRunning {
- log.Println("EscortRun Unexpected Exit, Restart now.")
- count++
- } else {
- log.Println("EscortRun Exit")
- break
- }
- }
-}
-
-func (v *Escorting) EscortingUp() {
- if v.escortProcess != nil {
- return
- }
- v.escortProcess = new([](*os.Process))
-}
-
-func (v *Escorting) EscortingDown() {
- if v.escortProcess == nil {
- return
- }
-
- log.Println("EscortingDown() Killing all escorted process ")
- for _, pr := range *v.escortProcess {
- pr.Kill()
- if _, err := pr.Wait(); err != nil {
- log.Println("EscortingDown pr.Wait err:", err)
- }
- }
- v.escortProcess = nil
-}
-
-type Escorting struct {
- escortProcess *[](*os.Process)
- Status *CoreI.Status
-}
diff --git a/AndroidLibV2rayLite/VPN/vpnservice_support.go b/AndroidLibV2rayLite/VPN/vpnservice_support.go
deleted file mode 100644
index 5647815b..00000000
--- a/AndroidLibV2rayLite/VPN/vpnservice_support.go
+++ /dev/null
@@ -1,286 +0,0 @@
-package VPN
-
-import (
- "context"
- "errors"
- "fmt"
- "log"
- "net"
- "os"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/sys/unix"
- v2net "github.com/xtls/xray-core/common/net"
- "github.com/xtls/xray-core/features/dns"
- "github.com/xtls/xray-core/features/outbound"
- v2internet "github.com/xtls/xray-core/transport/internet"
-)
-
-type protectSet interface {
- Protect(int) int
-}
-
-type resolved struct {
- domain string
- IPs []net.IP
- Port int
- ipIdx uint8
- ipLock sync.Mutex
- lastSwitched time.Time
-}
-
-// NextIP switch to another resolved result.
-// there still be race-condition here if multiple err concurently occured
-// may cause idx keep switching,
-// but that's an outside error can hardly handled here
-func (r *resolved) NextIP() {
- r.ipLock.Lock()
- defer r.ipLock.Unlock()
-
- if len(r.IPs) > 1 {
-
- // throttle, don't switch too quickly
- now := time.Now()
- if now.Sub(r.lastSwitched) < time.Second*5 {
- log.Println("switch too quickly")
- return
- }
- r.lastSwitched = now
- r.ipIdx++
-
- } else {
- return
- }
-
- if r.ipIdx >= uint8(len(r.IPs)) {
- r.ipIdx = 0
- }
-
- cur := r.currentIP()
- log.Printf("switched to next IP: %s", cur)
-}
-
-func (r *resolved) currentIP() net.IP {
- if len(r.IPs) > 0 {
- return r.IPs[r.ipIdx]
- }
-
- return nil
-}
-
-// NewPreotectedDialer ...
-func NewPreotectedDialer(p protectSet) *ProtectedDialer {
- d := &ProtectedDialer{
- // prefer native lookup on Android
- resolver: &net.Resolver{PreferGo: false},
- protectSet: p,
- }
- return d
-}
-
-// ProtectedDialer ...
-type ProtectedDialer struct {
- currentServer string
- resolveChan chan struct{}
-
- vServer *resolved
- resolver *net.Resolver
-
- protectSet
-}
-
-func (d *ProtectedDialer) IsVServerReady() bool {
- return (d.vServer != nil)
-}
-
-func (d *ProtectedDialer) PrepareResolveChan() {
- d.resolveChan = make(chan struct{})
-}
-
-func (d *ProtectedDialer) ResolveChan() <-chan struct{} {
- return d.resolveChan
-}
-
-// simplicated version of golang: internetAddrList in src/net/ipsock.go
-func (d *ProtectedDialer) lookupAddr(addr string) (*resolved, error) {
-
- var (
- err error
- host, port string
- portnum int
- )
-
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
-
- if host, port, err = net.SplitHostPort(addr); err != nil {
- log.Printf("PrepareDomain SplitHostPort Err: %v", err)
- return nil, err
- }
-
- if portnum, err = d.resolver.LookupPort(ctx, "tcp", port); err != nil {
- log.Printf("PrepareDomain LookupPort Err: %v", err)
- return nil, err
- }
-
- addrs, err := d.resolver.LookupIPAddr(ctx, host)
- if err != nil {
- return nil, err
- }
- if len(addrs) == 0 {
- return nil, fmt.Errorf("domain %s Failed to resolve", addr)
- }
-
- IPs := make([]net.IP, len(addrs))
- for i, ia := range addrs {
- IPs[i] = ia.IP
- }
-
- rs := &resolved{
- domain: host,
- IPs: IPs,
- Port: portnum,
- }
-
- return rs, nil
-}
-
-// PrepareDomain caches direct v2ray server host
-func (d *ProtectedDialer) PrepareDomain(domainName string, closeCh <-chan struct{}) {
- log.Printf("Preparing Domain: %s", domainName)
- d.currentServer = domainName
-
- defer close(d.resolveChan)
- maxRetry := 10
- for {
- if maxRetry == 0 {
- log.Println("PrepareDomain maxRetry reached. exiting.")
- return
- }
-
- resolved, err := d.lookupAddr(domainName)
- if err != nil {
- maxRetry--
- log.Printf("PrepareDomain err: %v\n", err)
- select {
- case <-closeCh:
- log.Printf("PrepareDomain exit due to v2ray closed")
- return
- case <-time.After(time.Second * 2):
- }
- continue
- }
-
- d.vServer = resolved
- log.Printf("Prepare Result:\n Domain: %s\n Port: %d\n IPs: %v\n",
- resolved.domain, resolved.Port, resolved.IPs)
- return
- }
-}
-
-func (d *ProtectedDialer) getFd(network v2net.Network) (fd int, err error) {
- switch network {
- case v2net.Network_TCP:
- fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, unix.IPPROTO_TCP)
- case v2net.Network_UDP:
- fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
- default:
- err = fmt.Errorf("unknow network")
- }
- return
-}
-
-// Init implement internet.SystemDialer
-func (d *ProtectedDialer) Init(_ dns.Client, _ outbound.Manager) {
- // do nothing
-}
-
-// Dial exported as the protected dial method
-func (d *ProtectedDialer) Dial(ctx context.Context,
- src v2net.Address, dest v2net.Destination, sockopt *v2internet.SocketConfig) (net.Conn, error) {
-
- network := dest.Network.SystemString()
- Address := dest.NetAddr()
-
- // v2ray server address,
- // try to connect fixed IP if multiple IP parsed from domain,
- // and switch to next IP if error occurred
- if strings.Compare(Address, d.currentServer) == 0 {
- if d.vServer == nil {
- log.Println("Dial pending prepare ...", Address)
- <-d.resolveChan
-
- // user may close connection during PrepareDomain,
- // fast return release resources.
- if d.vServer == nil {
- return nil, fmt.Errorf("fail to prepare domain %s", d.currentServer)
- }
- }
-
- fd, err := d.getFd(dest.Network)
- if err != nil {
- return nil, err
- }
-
- curIP := d.vServer.currentIP()
- conn, err := d.fdConn(ctx, curIP, d.vServer.Port, fd)
- if err != nil {
- d.vServer.NextIP()
- return nil, err
- }
- log.Printf("Using Prepared: %s", curIP)
- return conn, nil
- }
-
- // v2ray connecting to "domestic" servers, no caching results
- log.Printf("Not Using Prepared: %s,%s", network, Address)
- resolved, err := d.lookupAddr(Address)
- if err != nil {
- return nil, err
- }
-
- fd, err := d.getFd(dest.Network)
- if err != nil {
- return nil, err
- }
-
- // use the first resolved address.
- // the result IP may vary, eg: IPv6 addrs comes first if client has ipv6 address
- return d.fdConn(ctx, resolved.IPs[0], resolved.Port, fd)
-}
-
-func (d *ProtectedDialer) fdConn(ctx context.Context, ip net.IP, port int, fd int) (net.Conn, error) {
-
- defer unix.Close(fd)
-
- // call android VPN service to "protect" the fd connecting straight out
- d.Protect(fd)
-
- sa := &unix.SockaddrInet6{
- Port: port,
- }
- copy(sa.Addr[:], ip)
-
- if err := unix.Connect(fd, sa); err != nil {
- log.Printf("fdConn unix.Connect err, Close Fd: %d Err: %v", fd, err)
- return nil, err
- }
-
- file := os.NewFile(uintptr(fd), "Socket")
- if file == nil {
- // returned value will be nil if fd is not a valid file descriptor
- return nil, errors.New("fdConn fd invalid")
- }
-
- defer file.Close()
- //Closing conn does not affect file, and closing file does not affect conn.
- conn, err := net.FileConn(file)
- if err != nil {
- log.Printf("fdConn FileConn Close Fd: %d Err: %v", fd, err)
- return nil, err
- }
-
- return conn, nil
-}
diff --git a/AndroidLibV2rayLite/VPN/vpnservice_support_test.go b/AndroidLibV2rayLite/VPN/vpnservice_support_test.go
deleted file mode 100644
index 9cacbde2..00000000
--- a/AndroidLibV2rayLite/VPN/vpnservice_support_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package VPN
-
-import (
- "bufio"
- "context"
- "fmt"
- "net"
- "sync"
- "testing"
- "time"
-
- v2net "github.com/xtls/xray-core/common/net"
-)
-
-type fakeSupportSet struct{}
-
-func (f fakeSupportSet) Protect(int) int {
- return 0
-}
-
-func TestProtectedDialer_PrepareDomain(t *testing.T) {
- type args struct {
- domainName string
- }
- tests := []struct {
- name string
- args args
- }{
- // TODO: Add test cases.
- {"", args{"baidu.com:80"}},
- // {"", args{"cloudflare.com:443"}},
- // {"", args{"apple.com:443"}},
- // {"", args{"110.110.110.110:443"}},
- // {"", args{"[2002:1234::1]:443"}},
- }
- d := NewPreotectedDialer(fakeSupportSet{})
- for _, tt := range tests {
- ch := make(chan struct{})
- t.Run(tt.name, func(t *testing.T) {
- go d.PrepareDomain(tt.args.domainName, ch)
-
- time.Sleep(time.Second)
- go d.vServer.NextIP()
- t.Log(d.vServer.currentIP())
- })
- }
-
- time.Sleep(time.Second)
-}
-
-func TestProtectedDialer_Dial(t *testing.T) {
-
- tests := []struct {
- name string
- wantErr bool
- }{
- // TODO: Add test cases.
- {"baidu.com:80", false},
- {"cloudflare.com:80", false},
- {"172.16.192.11:80", true},
- // {"172.16.192.10:80", true},
- // {"[2fff:4322::1]:443", true},
- // {"[fc00::1]:443", true},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- ch := make(chan struct{})
-
- d := NewPreotectedDialer(fakeSupportSet{})
- d.currentServer = tt.name
-
- go d.PrepareDomain(tt.name, ch)
-
- var wg sync.WaitGroup
-
- dial := func() {
- defer wg.Done()
- dest, _ := v2net.ParseDestination("tcp:" + tt.name)
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
-
- conn, err := d.Dial(ctx, nil, dest, nil)
- if err != nil {
- t.Log(err)
- return
- }
- _host, _, _ := net.SplitHostPort(tt.name)
- fmt.Fprintf(conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", _host))
- status, err := bufio.NewReader(conn).ReadString('\n')
- t.Logf("%#v, %#v\n", status, err)
- conn.Close()
- }
-
- for n := 0; n < 3; n++ {
- wg.Add(1)
- go dial()
- // time.Sleep(time.Millisecond * 10)
- // d.pendingMap[tt.name] = make(chan struct{})
- }
-
- wg.Wait()
- })
- }
-}
-
-func Test_resolved_NextIP(t *testing.T) {
- type fields struct {
- domain string
- IPs []net.IP
- Port int
- }
- tests := []struct {
- name string
- fields fields
- }{
- // TODO: Add test cases.
- {"test1",
- fields{
- domain: "www.baidu.com",
- IPs: []net.IP{
- net.ParseIP("1.2.3.4"),
- net.ParseIP("4.3.2.1"),
- net.ParseIP("1234::1"),
- net.ParseIP("4321::1"),
- },
- }},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r := &resolved{
- domain: tt.fields.domain,
- IPs: tt.fields.IPs,
- Port: tt.fields.Port,
- }
- t.Logf("%v", r.IPs)
- t.Logf("%v", r.currentIP())
- r.NextIP()
- t.Logf("%v", r.currentIP())
- r.NextIP()
- t.Logf("%v", r.currentIP())
- r.NextIP()
- t.Logf("%v", r.currentIP())
- time.Sleep(3 * time.Second)
- r.NextIP()
- t.Logf("%v", r.currentIP())
- time.Sleep(5 * time.Second)
- r.NextIP()
- t.Logf("%v", r.currentIP())
- })
- }
-}
diff --git a/AndroidLibV2rayLite/compile-tun2socks.sh b/AndroidLibV2rayLite/compile-tun2socks.sh
deleted file mode 100755
index 497f77a4..00000000
--- a/AndroidLibV2rayLite/compile-tun2socks.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-# Set magic variables for current file & dir
-__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
-__base="$(basename ${__file} .sh)"
-
-if [[ ! -d $NDK_HOME ]]; then
- echo "Android NDK: NDK_HOME not found. please set env \$NDK_HOME"
- exit 1
-fi
-
-TMPDIR=$(mktemp -d)
-clear_tmp () {
- rm -rf $TMPDIR
-}
-
-trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; clear_tmp; exit 1' ERR INT
-install -m644 $__dir/tun2socks.mk $TMPDIR/
-
-pushd $TMPDIR
-git clone --depth=1 https://github.com/XTLS/badvpn.git
-git clone --depth=1 https://github.com/XTLS/libancillary.git
-$NDK_HOME/ndk-build \
- NDK_PROJECT_PATH=. \
- APP_BUILD_SCRIPT=./tun2socks.mk \
- APP_ABI=all \
- APP_PLATFORM=android-19 \
- NDK_LIBS_OUT=$TMPDIR/libs \
- NDK_OUT=$TMPDIR/tmp \
- APP_SHORT_COMMANDS=false LOCAL_SHORT_COMMANDS=false -B -j4
-
-install -v -m755 libs/armeabi-v7a/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so
-install -v -m755 libs/arm64-v8a/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so
-install -v -m755 libs/x86/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so
-install -v -m755 libs/x86_64/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so
-popd
-
-rm -rf $TMPDIR
diff --git a/AndroidLibV2rayLite/gen_assets.sh b/AndroidLibV2rayLite/gen_assets.sh
deleted file mode 100644
index 3a102fa2..00000000
--- a/AndroidLibV2rayLite/gen_assets.sh
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/bin/bash
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-# Set magic variables for current file & dir
-__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
-__base="$(basename ${__file} .sh)"
-
-
-DATADIR=${__dir}/data
-
-compile_dat () {
- local TMPDIR=$(mktemp -d)
-
- trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; rm -rf $TMPDIR; trap ERR; exit 1' ERR
-
- local GEOSITE=${GOPATH}/src/github.com/v2ray/domain-list-community
- if [[ -d ${GEOSITE} ]]; then
- cd ${GEOSITE} && git pull
- else
- mkdir -p ${GEOSITE}
- cd ${GEOSITE} && git clone https://github.com/v2ray/domain-list-community.git .
- fi
- go run main.go
-
- if [[ -e dlc.dat ]]; then
- rm -f $DATADIR/geosite.dat
- mv dlc.dat $DATADIR/geosite.dat
- echo "----------> geosite.dat updated."
- else
- echo "----------> geosite.dat failed to update."
- fi
-
-
- if [[ ! -x $GOPATH/bin/geoip ]]; then
- go get -v -u github.com/v2ray/geoip
- fi
-
- cd $TMPDIR
- curl -L -O http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip
- unzip -q GeoLite2-Country-CSV.zip
- mkdir geoip && find . -name '*.csv' -exec mv -t ./geoip {} +
- $GOPATH/bin/geoip \
- --country=./geoip/GeoLite2-Country-Locations-en.csv \
- --ipv4=./geoip/GeoLite2-Country-Blocks-IPv4.csv \
- --ipv6=./geoip/GeoLite2-Country-Blocks-IPv6.csv
-
- if [[ -e geoip.dat ]]; then
- rm -f $DATADIR/geoip.dat
- mv ./geoip.dat $DATADIR/geoip.dat
- echo "----------> geoip.dat updated."
- else
- echo "----------> geoip.dat failed to update."
- fi
- trap ERR
- return 0
-}
-
-
-download_dat () {
- wget -qO - https://api.github.com/repos/v2ray/geoip/releases/latest \
- | grep browser_download_url | cut -d '"' -f 4 \
- | wget -i - -O $DATADIR/geoip.dat
-
- wget -qO - https://api.github.com/repos/v2ray/domain-list-community/releases/latest \
- | grep browser_download_url | cut -d '"' -f 4 \
- | wget -i - -O $DATADIR/geosite.dat
-}
-
-ACTION="${1:-}"
-if [[ -z $ACTION ]]; then
- ACTION=download
-fi
-
-case $ACTION in
- "download") download_dat;;
- "compile") compile_dat;;
-esac
diff --git a/AndroidLibV2rayLite/go.mod b/AndroidLibV2rayLite/go.mod
deleted file mode 100644
index 83648e61..00000000
--- a/AndroidLibV2rayLite/go.mod
+++ /dev/null
@@ -1,49 +0,0 @@
-module github.com/2dust/AndroidLibV2rayLite
-
-go 1.18
-
-require (
- github.com/xtls/xray-core v1.5.7
- golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd
- golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68
-)
-
-require (
- github.com/cheekybits/genny v1.0.0 // indirect
- github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
- github.com/francoispqt/gojay v1.2.13 // indirect
- github.com/fsnotify/fsnotify v1.5.4 // indirect
- github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect
- github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
- github.com/gorilla/websocket v1.5.0 // indirect
- github.com/klauspost/cpuid/v2 v2.0.12 // indirect
- github.com/lucas-clemente/quic-go v0.27.1 // indirect
- github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
- github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
- github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
- github.com/nxadm/tail v1.4.8 // indirect
- github.com/onsi/ginkgo v1.16.5 // indirect
- github.com/pelletier/go-toml v1.9.5 // indirect
- github.com/pires/go-proxyproto v0.6.2 // indirect
- github.com/refraction-networking/utls v1.1.0 // indirect
- github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
- github.com/sagernet/sing v0.0.0-20220605012533-e0f722558141 // indirect
- github.com/sagernet/sing-shadowsocks v0.0.0-20220605012719-1e22882ea853 // indirect
- github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
- github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
- github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 // indirect
- go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect
- golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
- golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
- golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect
- golang.org/x/text v0.3.7 // indirect
- golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237 // indirect
- golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
- google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
- google.golang.org/grpc v1.47.0 // indirect
- google.golang.org/protobuf v1.28.0 // indirect
- gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- lukechampine.com/blake3 v1.1.7 // indirect
-)
diff --git a/AndroidLibV2rayLite/go.sum b/AndroidLibV2rayLite/go.sum
deleted file mode 100644
index 7699875f..00000000
--- a/AndroidLibV2rayLite/go.sum
+++ /dev/null
@@ -1,408 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
-github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
-github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
-github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
-github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
-github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
-github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
-github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
-github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
-github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
-github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
-github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lucas-clemente/quic-go v0.27.1 h1:sOw+4kFSVrdWOYmUjufQ9GBVPqZ+tu+jMtXxXNmRJyk=
-github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
-github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
-github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
-github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc=
-github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
-github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
-github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
-github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
-github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
-github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
-github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
-github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
-github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
-github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
-github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
-github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/refraction-networking/utls v1.1.0 h1:dKXJwSqni/t5csYJ+aQcEgqB7AMWYi6EUc9u3bEmjX0=
-github.com/refraction-networking/utls v1.1.0/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0=
-github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
-github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/sagernet/sing v0.0.0-20220605012533-e0f722558141 h1:YN9EeHRIFYKei1woz2OucLTSpiNrULAHH+jl6upDemQ=
-github.com/sagernet/sing v0.0.0-20220605012533-e0f722558141/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
-github.com/sagernet/sing-shadowsocks v0.0.0-20220605012719-1e22882ea853 h1:t1pn8v3kPvlaST/fY7GsPV8yIUFJDXzNcmSYQ+nrbEM=
-github.com/sagernet/sing-shadowsocks v0.0.0-20220605012719-1e22882ea853/go.mod h1:Afu8UIFlEwxTnlidTMSWqWHIduAWOrwY0tFr2LxBACQ=
-github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
-github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
-github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI=
-github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
-github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
-github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
-github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 h1:4mkzGhKqt3JO1BWYjtD3iRFyAx4ow67hmSqOcGjuxqQ=
-github.com/xtls/go v0.0.0-20210920065950-d4af136d3672/go.mod h1:YGGVbz9cOxyKFUmhW7LGaLZaMA0cPlHJinvAmVxEMSU=
-github.com/xtls/xray-core v1.5.7 h1:xQqUpRtzVHL/to2sDmvgn9GelD0jIwC0I8B36hbDgDo=
-github.com/xtls/xray-core v1.5.7/go.mod h1:H4q5qoCwtsYeF06Zsb0tk8oV8UuaQ9NdnOaPv49Cj7I=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM=
-go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
-golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
-golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
-golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd h1:x1GptNaTtxPAlTVIAJk61fuXg0y17h09DTxyb+VNC/k=
-golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
-golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
-golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
-golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237 h1:mAhaIX1KEgotq+ju3XYdXUHvll7bzJDTgiDzIAKDdPc=
-golang.org/x/tools v0.1.11-0.20220325154526-54af36eca237/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
-golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
-google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 h1:a221mAAEAzq4Lz6ZWRkcS8ptb2mxoxYSt4N68aRyQHM=
-google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
-google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
-lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/AndroidLibV2rayLite/interact.go b/AndroidLibV2rayLite/interact.go
deleted file mode 100644
index 0035bb4e..00000000
--- a/AndroidLibV2rayLite/interact.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package libv2ray
-
-import (
- "fmt"
- "io"
- "log"
- "os"
- "strings"
- "sync"
-
- "github.com/2dust/AndroidLibV2rayLite/CoreI"
- "github.com/2dust/AndroidLibV2rayLite/Process/Escort"
- "github.com/2dust/AndroidLibV2rayLite/VPN"
- mobasset "golang.org/x/mobile/asset"
-
- v2core "github.com/xtls/xray-core/core"
- v2filesystem "github.com/xtls/xray-core/common/platform/filesystem"
- v2stats "github.com/xtls/xray-core/features/stats"
- v2serial "github.com/xtls/xray-core/infra/conf/serial"
- _ "github.com/xtls/xray-core/main/distro/all"
- v2internet "github.com/xtls/xray-core/transport/internet"
-
- v2applog "github.com/xtls/xray-core/app/log"
- v2commlog "github.com/xtls/xray-core/common/log"
-)
-
-const (
- v2Assert = "xray.location.asset"
- assetperfix = "/dev/libv2rayfs0/asset"
-)
-
-/*V2RayPoint V2Ray Point Server
-This is territory of Go, so no getter and setters!
-*/
-type V2RayPoint struct {
- SupportSet V2RayVPNServiceSupportsSet
- statsManager v2stats.Manager
-
- dialer *VPN.ProtectedDialer
- status *CoreI.Status
- escorter *Escort.Escorting
- v2rayOP *sync.Mutex
- closeChan chan struct{}
-
- PackageName string
- PackageCodePath string
- DomainName string
- ConfigureFileContent string
- EnableLocalDNS bool
- ForwardIpv6 bool
- ProxyOnly bool
-}
-
-/*V2RayVPNServiceSupportsSet To support Android VPN mode*/
-type V2RayVPNServiceSupportsSet interface {
- Setup(Conf string) int
- Prepare() int
- Shutdown() int
- Protect(int) int
- OnEmitStatus(int, string) int
-}
-
-/*RunLoop Run V2Ray main loop
- */
-func (v *V2RayPoint) RunLoop() (err error) {
- v.v2rayOP.Lock()
- defer v.v2rayOP.Unlock()
- //Construct Context
- v.status.PackageName = v.PackageName
- v.status.PackageCodePath = v.PackageCodePath
-
- if !v.status.IsRunning {
- v.closeChan = make(chan struct{})
- v.dialer.PrepareResolveChan()
- go v.dialer.PrepareDomain(v.DomainName, v.closeChan)
- go func() {
- select {
- // wait until resolved
- case <-v.dialer.ResolveChan():
- // shutdown VPNService if server name can not reolved
- if !v.dialer.IsVServerReady() {
- log.Println("vServer cannot resolved, shutdown")
- v.StopLoop()
- }
-
- // stop waiting if manually closed
- case <-v.closeChan:
- }
- }()
-
- err = v.pointloop()
- }
- return
-}
-
-/*StopLoop Stop V2Ray main loop
- */
-func (v *V2RayPoint) StopLoop() (err error) {
- v.v2rayOP.Lock()
- defer v.v2rayOP.Unlock()
- if v.status.IsRunning {
- v.shutdownInit()
- }
- return
-}
-
-//Delegate Funcation
-func (v *V2RayPoint) GetIsRunning() bool {
- return v.status.IsRunning
-}
-
-func (v *V2RayPoint) GetIsTRunning() bool {
- return v.status.IsTRunning
-}
-
-//Delegate Funcation
-func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
- if v.statsManager == nil {
- return 0
- }
- counter := v.statsManager.GetCounter(fmt.Sprintf("outbound>>>%s>>>traffic>>>%s", tag, direct))
- if counter == nil {
- return 0
- }
- return counter.Set(0)
-}
-
-func (v *V2RayPoint) shutdownInit() {
- close(v.closeChan)
- v.statsManager = nil
- v.status.Vpoint.Close()
- v.status.Vpoint = nil
- v.status.IsRunning = false
-
- v.escorter.EscortingDown()
-
- v.SupportSet.Shutdown()
- v.SupportSet.OnEmitStatus(0, "Closed")
-}
-
-func (v *V2RayPoint) pointloop() error {
- log.Println("loading v2ray config")
- config, err := v2serial.LoadJSONConfig(strings.NewReader(v.ConfigureFileContent))
- if err != nil {
- log.Println(err)
- return err
- }
-
- log.Println("new v2ray core")
- inst, err := v2core.New(config)
- if err != nil {
- log.Println(err)
- return err
- }
- v.status.Vpoint = inst
- v.statsManager = inst.GetFeature(v2stats.ManagerType()).(v2stats.Manager)
-
- log.Println("start v2ray core")
- v.status.IsRunning = true
- if err := v.status.Vpoint.Start(); err != nil {
- v.status.IsRunning = false
- log.Println(err)
- return err
- }
-
- v.SupportSet.Prepare()
- v.SupportSet.Setup(v.status.GetVPNSetupArg(v.EnableLocalDNS, v.ForwardIpv6))
- 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
-}
-
-func initV2Env() {
- if os.Getenv(v2Assert) != "" {
- return
- }
- //Initialize asset API, Since Raymond Will not let notify the asset location inside Process,
- //We need to set location outside V2Ray
- os.Setenv(v2Assert, assetperfix)
- //Now we handle read
- v2filesystem.NewFileReader = func(path string) (io.ReadCloser, error) {
- if strings.HasPrefix(path, assetperfix) {
- p := path[len(assetperfix)+1:]
- //is it overridden?
- //by, ok := overridedAssets[p]
- //if ok {
- // return os.Open(by)
- //}
- return mobasset.Open(p)
- }
- return os.Open(path)
- }
-}
-
-//Delegate Funcation
-func TestConfig(ConfigureFileContent string) error {
- initV2Env()
- _, err := v2serial.LoadJSONConfig(strings.NewReader(ConfigureFileContent))
- return err
-}
-
-/*NewV2RayPoint new V2RayPoint*/
-func NewV2RayPoint(s V2RayVPNServiceSupportsSet) *V2RayPoint {
- initV2Env()
-
- // inject our own log writer
- v2applog.RegisterHandlerCreator(v2applog.LogType_Console,
- func(lt v2applog.LogType,
- options v2applog.HandlerCreatorOptions) (v2commlog.Handler, error) {
- return v2commlog.NewLogger(createStdoutLogWriter()), nil
- })
-
- dialer := VPN.NewPreotectedDialer(s)
- v2internet.UseAlternativeSystemDialer(dialer)
- status := &CoreI.Status{}
- return &V2RayPoint{
- SupportSet: s,
- v2rayOP: new(sync.Mutex),
- status: status,
- dialer: dialer,
- escorter: &Escort.Escorting{Status: status},
- }
-}
-
-func (v V2RayPoint) runTun2socks() error {
- v.escorter.EscortingUp()
- go v.escorter.EscortRun(
- v.status.GetApp("libtun2socks.so"),
- v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "")
-
- return nil
-}
-
-/*CheckVersion int
-This func will return libv2ray binding version.
-*/
-func CheckVersion() int {
- return CoreI.CheckVersion()
-}
-
-/*CheckVersionX string
-This func will return libv2ray binding version and V2Ray version used.
-*/
-func CheckVersionX() string {
- return fmt.Sprintf("Libv2rayLite V%d, Core V%s", CheckVersion(), v2core.Version())
-}
diff --git a/AndroidLibV2rayLite/libv2ray.go b/AndroidLibV2rayLite/libv2ray.go
deleted file mode 100644
index 8692373d..00000000
--- a/AndroidLibV2rayLite/libv2ray.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package libv2ray
-
-//go:generate make all
diff --git a/AndroidLibV2rayLite/readme.txt b/AndroidLibV2rayLite/readme.txt
deleted file mode 100644
index b2b2a781..00000000
--- a/AndroidLibV2rayLite/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-readme.txt
diff --git a/AndroidLibV2rayLite/tun2socks.mk b/AndroidLibV2rayLite/tun2socks.mk
deleted file mode 100644
index 99d84cb3..00000000
--- a/AndroidLibV2rayLite/tun2socks.mk
+++ /dev/null
@@ -1,128 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-#
-LOCAL_PATH := $(call my-dir)
-ROOT_PATH := $(LOCAL_PATH)
-
-########################################################
-## libancillary
-########################################################
-
-include $(CLEAR_VARS)
-
-ANCILLARY_SOURCE := fd_recv.c fd_send.c
-
-LOCAL_MODULE := libancillary
-#LOCAL_CFLAGS += -I$(LOCAL_PATH)/libancillary
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/libancillary
-LOCAL_SRC_FILES := $(addprefix libancillary/, $(ANCILLARY_SOURCE))
-
-include $(BUILD_STATIC_LIBRARY)
-
-########################################################
-## tun2socks
-########################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS := -std=gnu99
-LOCAL_CFLAGS += -DBADVPN_THREADWORK_USE_PTHREAD -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE
-LOCAL_CFLAGS += -DBADVPN_USE_SIGNALFD -DBADVPN_USE_EPOLL
-LOCAL_CFLAGS += -DBADVPN_LITTLE_ENDIAN -DBADVPN_THREAD_SAFE
-LOCAL_CFLAGS += -DNDEBUG -DANDROID
-LOCAL_CFLAGS += -I
-
-LOCAL_STATIC_LIBRARIES := libancillary
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/badvpn/libancillary \
- $(LOCAL_PATH)/badvpn/lwip/src/include/ipv4 \
- $(LOCAL_PATH)/badvpn/lwip/src/include/ipv6 \
- $(LOCAL_PATH)/badvpn/lwip/src/include \
- $(LOCAL_PATH)/badvpn/lwip/custom \
- $(LOCAL_PATH)/badvpn \
- $(LOCAL_PATH)/libancillary
-
-TUN2SOCKS_SOURCES := \
- base/BLog_syslog.c \
- system/BReactor_badvpn.c \
- system/BSignal.c \
- system/BConnection_common.c \
- system/BConnection_unix.c \
- system/BTime.c \
- system/BUnixSignal.c \
- system/BNetwork.c \
- flow/StreamRecvInterface.c \
- flow/PacketRecvInterface.c \
- flow/PacketPassInterface.c \
- flow/StreamPassInterface.c \
- flow/SinglePacketBuffer.c \
- flow/BufferWriter.c \
- flow/PacketBuffer.c \
- flow/PacketStreamSender.c \
- flow/PacketPassConnector.c \
- flow/PacketProtoFlow.c \
- flow/PacketPassFairQueue.c \
- flow/PacketProtoEncoder.c \
- flow/PacketProtoDecoder.c \
- socksclient/BSocksClient.c \
- tuntap/BTap.c \
- lwip/src/core/udp.c \
- lwip/src/core/memp.c \
- lwip/src/core/init.c \
- lwip/src/core/pbuf.c \
- lwip/src/core/tcp.c \
- lwip/src/core/tcp_out.c \
- lwip/src/core/netif.c \
- lwip/src/core/def.c \
- lwip/src/core/ip.c \
- lwip/src/core/mem.c \
- lwip/src/core/tcp_in.c \
- lwip/src/core/stats.c \
- lwip/src/core/inet_chksum.c \
- lwip/src/core/timeouts.c \
- lwip/src/core/ipv4/icmp.c \
- lwip/src/core/ipv4/igmp.c \
- lwip/src/core/ipv4/ip4_addr.c \
- lwip/src/core/ipv4/ip4_frag.c \
- lwip/src/core/ipv4/ip4.c \
- lwip/src/core/ipv4/autoip.c \
- lwip/src/core/ipv6/ethip6.c \
- lwip/src/core/ipv6/inet6.c \
- lwip/src/core/ipv6/ip6_addr.c \
- lwip/src/core/ipv6/mld6.c \
- lwip/src/core/ipv6/dhcp6.c \
- lwip/src/core/ipv6/icmp6.c \
- lwip/src/core/ipv6/ip6.c \
- lwip/src/core/ipv6/ip6_frag.c \
- lwip/src/core/ipv6/nd6.c \
- lwip/custom/sys.c \
- tun2socks/tun2socks.c \
- base/DebugObject.c \
- base/BLog.c \
- base/BPending.c \
- system/BDatagram_unix.c \
- flowextra/PacketPassInactivityMonitor.c \
- tun2socks/SocksUdpGwClient.c \
- udpgw_client/UdpGwClient.c
-
-LOCAL_MODULE := tun2socks
-
-LOCAL_LDLIBS := -ldl -llog
-
-LOCAL_SRC_FILES := $(addprefix badvpn/, $(TUN2SOCKS_SOURCES))
-
-include $(BUILD_SYSTEM)/build-executable.mk
-
diff --git a/AndroidLibV2rayLite/ubuntu-cli-install-android-sdk.sh b/AndroidLibV2rayLite/ubuntu-cli-install-android-sdk.sh
deleted file mode 100644
index 126d74ba..00000000
--- a/AndroidLibV2rayLite/ubuntu-cli-install-android-sdk.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/bash
-
-# Thanks to https://gist.github.com/wenzhixin/43cf3ce909c24948c6e7
-# Execute this script in your home directory. Lines 17 and 21 will prompt you for a y/n
-
-# Install Oracle JDK 8
-apt-get update
-apt-get install -y openjdk-8-jdk
-apt-get install -y unzip make expect # NDK stuff
-
-# Get SDK tools (link from https://developer.android.com/studio/index.html#downloads)
-wget -q https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
-mkdir android-sdk-linux
-unzip sdk*.zip -d android-sdk-linux
-
-# Get NDK (https://developer.android.com/ndk/downloads/index.html)
-# wget -q https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
-# unzip android-ndk*.zip >> /dev/null
-
-ACCEPT_LICENSES_URL=https://gist.githubusercontent.com/xiaokangwang/1489fd223d26581bfec92adb3cb0088e/raw/328eb6925099df5aae3e76790f8232f0fc378f8b/accept-licenses
-
-ACCEPT_LICENSES_ITEM="android-sdk-license-bcbbd656|intel-android-sysimage-license-1ea702d1|android-sdk-license-2742d1c5"
-
-# Let it update itself and install some stuff
-cd android-sdk-linux/tools
-
-curl -L -o accept-licenses $ACCEPT_LICENSES_URL
-
-chmod +x accept-licenses
-
-./accept-licenses "./android update sdk --use-sdk-wrapper --all --no-ui" $ACCEPT_LICENSES_ITEM >/dev/null
-
-# Download every build-tools version that has ever existed
-# This will save you time! Thank me later for this
-
-#./accept-licenses "./android update sdk --use-sdk-wrapper --all --no-ui --filter 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27" $ACCEPT_LICENSES_ITEM
-
-PACKAGE_PARSE_URL=https://gist.githubusercontent.com/xiaokangwang/06268fb23034ed94bc301880e862da09/raw/afd95cbbe2f8c1d9e7b0277b7c5ef39af756a6ee/parse.awk
-
-reduceout=https://gist.githubusercontent.com/xiaokangwang/4684bdb5c3415b943f52aa4803386480/raw/b46dab1cc60f02c0d87f88f01e27157034218faa/out.awk
-
-cd bin
-
-curl -L -o parse.awk $PACKAGE_PARSE_URL
-
-curl -L -o reduce.awk $reduceout
-
-sudo apt-get install gawk
-
-./sdkmanager --verbose --list |awk -f parse.awk > ~/package_to_install
-
-readarray -t filenames < $HOME/package_to_install
-
-cat $HOME/package_to_install
-
-yes|./sdkmanager --verbose "${filenames[@]}" |awk -f reduce.awk
-
-# If you need additional packages for your app, check available packages with:
-# ./android list sdk --all
-
-# install certain packages with:
-# ./android update sdk --no-ui --all --filter 1,2,3,<...>,N
-# where N is the number of the package in the list (see previous command)
-
-./sdkmanager "ndk-bundle"
-
-# Add the directory containing executables in PATH so that they can be found
-echo 'export ANDROID_HOME=$HOME/android-sdk-linux' >> ~/.bashrc
-echo 'export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools' >> ~/.bashrc
-# echo 'export NDK_HOME=$HOME/android-ndk-r15c' >> ~/.bashrc
-# echo 'export ANDROID_NDK_HOME=$NDK_HOME' >> ~/.bashrc
-
-
-source ~/.bashrc
-
-# Make sure you can execute 32 bit executables if this is 64 bit machine, otherwise skip this
-dpkg --add-architecture i386
-apt-get update
-apt-get install -y libc6:i386 libstdc++6:i386 zlib1g:i386
diff --git a/AndroidLibV2rayLite/v2logger.go b/AndroidLibV2rayLite/v2logger.go
deleted file mode 100644
index 8d63fdd5..00000000
--- a/AndroidLibV2rayLite/v2logger.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package libv2ray
-
-// This struct creates our own log writer without datatime stamp
-// As Android adds time stamps on each line
-
-import (
- "log"
- "os"
-
- v2commlog "github.com/xtls/xray-core/common/log"
-)
-
-type consoleLogWriter struct {
- logger *log.Logger
-}
-
-func (w *consoleLogWriter) Write(s string) error {
- w.logger.Print(s)
- return nil
-}
-
-func (w *consoleLogWriter) Close() error {
- return nil
-}
-
-// This logger won't print data/time stamps
-func createStdoutLogWriter() v2commlog.WriterCreator {
- return func() v2commlog.Writer {
- return &consoleLogWriter{
- logger: log.New(os.Stdout, "", 0)}
- }
-}
diff --git a/ExtRes/values-zh-rCN/strings.xml b/ExtRes/values-zh-rCN/strings.xml
deleted file mode 100644
index 7c12fd00..00000000
--- a/ExtRes/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-
-
- 开关
- 开关
- 初次使用此功能请先用APP添加配置
- Open navigation drawer
- Close navigation drawer
- 数据迁移成功!
- 数据迁移失败啦!
-
-
- 停止
- 无法取得权D:\vssHotel\SourceCode\Hotel.root\Hotel\Clubank.Hotel\FrontCounter\CheckoutListForm.cs限
- 点击了解更多
- 启动服务中
- 关闭中
- 启动服务成功
- 启动服务失败
-
-
- 配置文件
- 添加配置
- 保存配置
- 删除配置
- 扫描二维码
- 从剪贴板导入
- 手动输入[Vmess]
- 手动输入[VLESS]
- 手动输入[Shadowsocks]
- 手动输入[Socks]
- 手动输入[Trojan]
- 自定义配置
- 从剪贴板导入自定义配置
- 从本地导入自定义配置
- 剪贴板URL导入自定义配置
- 扫描URL导入自定义配置
- 确认删除?
- 别名(remarks)
- 地址(address)
- 端口(port)
- 用户ID(id)
- 额外ID(alterId)
- 加密方式(security)
- 传输协议(network)
- 底层传输方式(transport)
- 伪装类型(type)
- gRPC 传输模式 (mode)
- 伪装域名(host)(host/ws host/h2 host)/QUIC 加密方式
- path(ws path/h2 path)/QUIC 加密密钥/kcp seed/gRPC serviceName
- 传输层安全(tls)
- 跳过证书验证(allowInsecure)
- SNI
- 服务器地址
- 服务器端口
- 密码
- 加密方式
- 密码(可选)
- 用户名(可选)
- 加密(encryption)
- 流控(flow)
- 成功
- 失败
- 没有数据
- 不正确的协议
- 解码失败
- 选择一个配置文件
- 请安装一个文件管理器
- 自定义配置
- 无效的配置文件
- 内容
- 剪贴板中没有数据
- 无效的网址
- 确保inbounds port和设置中的一致
- 配置格式错误
- Host(SNI)(可选)
- 失败, 请使用文件管理器
- 添加文件
- 下载文件
-
-
-
- 正在加载
- 搜索
- 全选
- 输入关键字
- 绕行模式
- 自动选中需代理应用
- 正在下载内容
- 导出至剪贴板
- 从剪贴板导入
-
-
- 设置
- 进阶设置
- VPN 设置
- 分应用代理
- 常规:勾选的App被代理,未勾选的直连;\n绕行模式:勾选的App直连,未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用
-
- 启用Mux多路复用
- 开启可能会加速,关闭可能会减少断流
-
- 启用速度显示
- 在通知中显示当前速度\n小图标显示流量的路由情况
-
- 启用流量探测
- 从流量中探测域名 (默认启用)
-
- 启用本地DNS
- DNS 请求导入 core 由 DNS 模块处理(推荐启用 如果需要路由绕过局域网及大陆地址)
-
- 启用虚拟DNS
- 本地返回虚构解析结果 (减低延时 但个别应用可能无法使用)
-
- IPv6优先
- App优先使用IPv6地址连接服务器,同时开启VPN的IPv6路由
-
- 路由设置
- 域名策略
- 预定义规则
- 自定义规则
-
- 远程DNS (可选)
- DNS
-
- VPN DNS (仅支持 IPv4/v6)
-
- 境内DNS (可选)
- DNS
-
- 允许来自局域网的连接
- 其他设备可以使用socks/http协议通过您的IP地址连接到代理,仅在受信任的网络中启用以避免未经授权的连接
- 允许来自局域网的连接,请确保处于受信网络
-
- 跳过证书验证(allowInsecure)
- 传输层安全选tls时,默认跳过证书验证(allowInsecure)
-
- SOCKS5代理端口
- SOCKS5代理端口
-
- HTTP代理端口
- HTTP代理端口
-
- 本地DNS端口
- 本地DNS端口
-
- 删除配置文件确认
- 删除配置文件是否需要用户二次确认
-
- 反馈
- 反馈改进或漏洞至 GitHub
- 加入Telegram Group
- 未找到Telegram app
-
- 推广
- 一些推广,点击查看详情(捐赠可去除)
-
- 日志级别
- 模式
- 点此查看更多帮助
- 语言
-
- Logcat
- 复制
- 清除
- 服务重启
- 删除全部配置
- 删除无效配置(先测试)
- 导出全部(非自定义)配置至剪贴板
- 订阅分组设置
- 备注
- 可选地址(url)
- 启用更新
- 更新订阅
- 测试全部配置Tcping
- 测试全部配置真连接
- Geo 资源文件
- 按测试结果排序
- 过滤配置文件
- 所有订阅分组
-
- 启动服务
- 确定
-
- 路由设置
- 用逗号(,)隔开,可以一行多个,记得保存
- 保存
- 清空
- 扫描并替换
- 扫描并追加
- 设置默认路由规则
-
- "检查网络连接"
- "测试中…"
- "连接成功:延时 %d 毫秒"
- "失败:%s"
- "无互联网连接"
- "状态码无效(#%d)"
- "已连接,点击测试连接"
- "未连接"
-
-
- - 二维码
- - 导出至剪贴板
- - 导出完整配置至剪贴板
-
- share_method
-
- - 代理的网址或IP
- - 直连的网址或IP
- - 阻止的网址或IP
-
-
-
- - 全局代理
- - 绕过局域网地址而后代理
- - 绕过大陆地址而后代理
- - 绕过局域网及大陆地址而后代理
- - 全局直连
-
-
-
- - VPN
- - 仅代理
-
-
-
diff --git a/ExtRes/values-zh-rTW/strings.xml b/ExtRes/values-zh-rTW/strings.xml
deleted file mode 100644
index 927e1f05..00000000
--- a/ExtRes/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,226 +0,0 @@
-
-
- 開關
- 開關
- 首次使用此功能,請使用此應用程式新增伺服器
- 開啟導覽匣
- 關閉導覽匣
- 資料遷移成功!
- 資料遷移失敗!
-
-
- 停止
- 無法取得此權限
- 瞭解更多
- 啟動服務
- 停止服務
- 啟動服務成功
- 啟動服務失敗
-
-
- 組態檔案
- 新增組態
- 儲存組態
- 刪除組態
- 從 QR Code 匯入組態
- 從剪貼簿匯入組態
- 手動鍵入 [Vmess]
- 手動鍵入 [VLESS]
- 手動鍵入 [Shadowsocks]
- 手動鍵入 [Socks]
- 手動鍵入 [Trojan]
- 自訂組態
- 從剪貼簿匯入自訂組態
- 從 URL 匯入自訂組態
- 從 URL 匯入自訂組態
- 掃描 URL 匯入自訂組態
- 確定刪除?
- 備註
- 位址
- 埠
- 使用者 ID
- alterId
- 安全性
- 網路
- 底層傳輸方式 (transport)
- 標頭類型
- gRPC 傳輸模式 (mode)
- 要求主機 (host)(host/ws host/h2 host)/QUIC 加密方式
- path(ws path/h2 path)/QUIC 加密金鑰/kcp seed/gRPC serviceName
- 傳輸層安全 (tls)
- 跳過憑證驗證 (allowInsecure)
- SNI
- 伺服器位址
- 伺服器埠
- 密碼
- 加密方式
- 密碼 (可選)
- 使用者名稱 (可選)
- 加密 (encryption)
- 流程 (flow)
- 成功
- 失敗
- 無資料
- 通訊協定不正確
- 解碼失敗
- 選取一個組態檔
- 請安裝檔案總管。
- 自訂組態
- 無效組態
- 內容
- 剪貼簿內無資料
- URL 無效
- 確保 inbounds port 和設定中的一致
- 組態格式不正確
- Host(SNI)(可選)
- 失敗,請使用檔案總管
- 新增檔案
- 下載檔案
-
-
- 載入
- 搜尋
- 全選
- 輸入關鍵字
- 略過模式
- 自動選中需 Proxy 應用
- 正在下載內容
- 匯出至剪貼簿
- 從剪貼簿匯入
-
-
-
- 設定
- 進階
- VPN 設定
- Proxy 個別應用程式
- 常規:勾選的 App 啟用 Proxy,未勾選的直接連線;\n繞行模式:勾選的 App 直接連線,未勾選的啟用 Proxy。\n可在選單中選擇自動選中需 Proxy 應用
-
- 啟用 Mux
- 啟用或許會加快網路速度,切換或許會閃爍
-
- 啟用速度顯示
- 在通知中顯示當前速度\n小圖示顯示流量的轉送狀況
-
- 啟用流量監聽
- 從流量中監聽網域 (預設啟用)
-
- 啟用本機 DNS
- DNS 請求匯入 core 由 DNS 模塊處理 (建議啟用,如果需要轉送略過區域網路及中國大陸)
-
- 啟用假 DNS
- 本機退回假解析結果 (減低延時,但個別應用可能無法使用)
-
- IPv6 偏好
- App 優先使用 IPv6 位址連線伺服器,同时開啟 VPN 的 IPv6 路由
-
- 轉送設定
- 網域策略
- 轉送模式
- 自訂轉送
-
- 遠端 DNS (可選)
- DNS
-
- VPN DNS (僅支援 IPv4/v6)
-
- 國內 DNS (可選)
- DNS
-
- 允許來自區域網路的連線
- 其他裝置可以使用 socks/http 協定透過您的 IP 位址連線到 Proxy,僅在受信任的網路中啟用以避免未經授權的連線
- 允許來自區域網路的連線,請確保處於受信網路
-
- 跳過憑證驗證 (allowInsecure)
- 傳輸層安全選 tls 時,預設跳過憑證驗證 (allowInsecure)
-
- SOCKS5 Proxy 埠
- SOCKS5 Proxy 埠
-
- HTTP Proxy 埠
- HTTP Proxy 埠
-
- 本機 DNS 埠
- 本機 DNS 埠
-
- 刪除配置文件確認
- 刪除配置文件是否需要用戶二次確認
-
- 意見回饋
- 前往 GitHub 回報錯誤
- 加入 Telegram 群組
- 未找到 Telegram 應用程式
-
- 推廣
- 一些推廣,輕觸以檢視 (捐贈可去除)
-
- 記錄層級
- 模式
- 輕觸以檢視說明
- 語言
-
- Logcat
- 複製
- 清除
- 服務重啟
- 刪除全部組態
- 刪除無效組態 (先偵測)
- 匯出全部 (非自訂) 組態至剪貼簿
- 訂閱分組設定
- 備註
- Optional URL
- 啟用更新
- 更新訂閱
- 偵測所有組態 Tcping
- 偵測所有組態真延遲
- Geo 資源檔案
- 依偵測結果排序
- 過濾組態
- 所有訂閱分組
-
- 啟動服務
- 確定
-
- 轉送設定
- 以半形逗號「,」分隔,並手動儲存
- 儲存
- 清除
- 掃描並取代
- 掃描並附加
- 設定預設轉送規則
-
- "測試連線能力"
- "測試中……"
- "成功:%d ms延遲"
- "測試網際網路連線失敗:%s"
- "無法使用網際網路"
- "錯誤碼:(#%d)"
- "已連線,輕觸以檢查連線能力"
- "未連線"
-
-
- - QR Code
- - 匯出至剪貼簿
- - 匯出完整組態至剪貼簿
-
-
-
- - Proxy URL 或 IP
- - 直接連線 URL 或 IP
- - 已封鎖的 URL 或 IP
-
-
-
- - 全域 Proxy
- - 略過區域網路的 Proxy
- - 略過中國大陸的 Proxy
- - 略過區域網路及中國大陸的 Proxy
- - 直接連線
-
-
-
- - VPN
- - 僅 Proxy
-
-
-
diff --git a/ExtRes/values/strings.xml b/ExtRes/values/strings.xml
deleted file mode 100644
index 6e047f2b..00000000
--- a/ExtRes/values/strings.xml
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
- v2rayNG
- Switch
- Switch
- First use of this feature, please use the app to add server
- Open navigation drawer
- Close navigation drawer
- Data migration success!
- Data migration failed!
-
-
- Stop
- Unable to obtain the permission
- click for more
- Start Services
- Stop Services
- Start Services Success
- Start Services Failure
-
-
- Configuration file
- Add config
- Save config
- Delete config
- Import config from QRcode
- Import config from Clipboard
- Type manually[Vmess]
- Type manually[VLESS]
- Type manually[Shadowsocks]
- Type manually[Socks]
- Type manually[Trojan]
- custom config
- Import custom config from Clipboard
- Import custom config from locally
- Import custom config from URL
- Import custom config scan URL
- Confirm delete?
- remarks
- address
- port
- id
- alterId
- security
- Network
- Transport
- head type
- gRPC mode
- request host(host/ws host/h2 host)/QUIC security
- path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName
- tls
- allowInsecure
- SNI
- address
- port
- password
- security
- Password(Optional)
- User(Optional)
- encryption
- flow
- Success
- Failure
- There is nothing
- Incorrect protocol
- Decoding failed
- Select a Config File
- Please install a File Manager.
- Customize Config
- Invalid Config
- Content
- There is no data in the clipboard
- Invalid URL
- Ensure inbounds port is consistent with the settings
- Config malformed
- Host(SNI)(Optional)
- File copy failed, please use File Manager
- Add files
- Download files
-
-
- Loading
- Search
- Select all
- Enter keywords
- Bypass Mode
- Auto select proxy app
- Downloading content
- Export to Clipboard
- Import from Clipboard
-
-
-
- Settings
- Advanced Settings
- VPN Settings
- Per-app proxy
- General: Checked App is proxy, unchecked direct connection; \nbypass mode: checked app directly connected, unchecked proxy. \nThe option to automatically select the proxy application in the menu
-
- Enable Mux
- Enable maybe speed up network and switch network maybe flash
-
- Enable speed display
- Display current speed in the notification.\nNotification icon would change based on
- usage.
-
- Enable Sniffing
- Try sniff domain from the packet (default on)
-
- Enable local DNS
- DNS processed by core‘s DNS module (Recommended, if need routing Bypassing LAN and
- mainland address)
-
- Enable fake DNS
- local DNS returns fake IP address (faster, but it may not work for some apps)
-
- Prefer IPv6
- Prefer IPv6 address and routes
-
- Routing
- Domain strategy
- Predefined rules
- Custom rules
-
- Remote DNS (Optional)
- DNS
-
- VPN DNS (only IPv4/v6)
-
- Domestic DNS (Optional)
- DNS
-
- Allow connections from the LAN
- Other devices can connect to proxy by your ip address through socks/http, Only enable in trusted network to avoid unauthorized connection
- Allow connections from the LAN, Make sure you are in a trusted network
-
- allowInsecure
- When TLS, the default allowInsecure
-
- SOCKS5 proxy port
- SOCKS5 proxy port
-
- HTTP proxy port
- HTTP proxy port
-
- Local DNS port
- Local DNS port
-
- Delete configuration file confirmation
- Whether to delete the configuration file requires a second confirmation by the user
-
- Feedback
- Feedback enhancements or bugs to GitHub
- Join Telegram Group
- Telegram app not found
-
- Promotion
- Promotion,click for details(Donation can be removed)
-
- Log Level
- Mode
- Click me for more help
- Language
-
- Logcat
- Copy
- Clear
- Service restart
- Delete all config
- Delete invalid config(Test first)
- Export non-custom configs to clipboard
- Subscription group setting
- remarks
- Optional URL
- enable update
- Update subscription
- Tcping all configuration
- Real delay all configuration
- Geo asset files
- Sorting by test results
- Filter configuration file
- All subscription groups
-
- Start Service
- Confirm
-
- Routing Settings
- Separated by commas(,),remember to save
- Save
- Clear
- Scan and replace
- Scan and append
- set default routing rules
-
- Check Connectivity
- Testing…
- Success: HTTP connection took %dms
- Fail to detect internet connection: %s
- Internet Unavailable
- Error code: #%d
- Connected, tap to check connection
- Not connected
-
-
- - QRcode
- - Export to clipboard
- - Export full configuration to clipboard
-
-
-
- - proxy URL or IP
- - direct URL or IP
- - blocked URL or IP
-
-
-
- - Global proxy
- - Bypassing the LAN address then proxy
- - Bypass mainland address then proxy
- - Bypassing LAN and mainland address then proxy
- - Global direct
-
-
-
- - VPN
- - Proxy only
-
-
-
diff --git a/V2rayNG/app/build.gradle b/V2rayNG/app/build.gradle
index 38b358da..f0f2bf02 100644
--- a/V2rayNG/app/build.gradle
+++ b/V2rayNG/app/build.gradle
@@ -1,9 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
+Properties props = new Properties()
+props.load(new FileInputStream(new File('local.properties')))
+
android {
compileSdkVersion Integer.parseInt("$compileSdkVer")
- buildToolsVersion buildToolsVer
+ buildToolsVersion "$buildToolsVer"
compileOptions {
targetCompatibility = "8"
@@ -15,8 +18,25 @@ android {
minSdkVersion 21
targetSdkVersion Integer.parseInt("$targetSdkVer")
multiDexEnabled true
- versionCode 212
- versionName "1.0.2"
+ versionCode 466
+ versionName "1.7.15"
+ }
+
+ if (props["sign"]) {
+ signingConfigs {
+ release {
+ storeFile file("../key.jks")
+ keyAlias 'ang'
+ keyPassword '123456'
+ storePassword '123456'
+ }
+ debug {
+ storeFile file("../key.jks")
+ keyAlias 'ang'
+ keyPassword '123456'
+ storePassword '123456'
+ }
+ }
}
buildTypes {
@@ -24,6 +44,9 @@ android {
minifyEnabled false
zipAlignEnabled false
shrinkResources false
+ if (props["sign"]) {
+ signingConfig signingConfigs.release
+ }
ndk.abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
@@ -31,12 +54,18 @@ android {
minifyEnabled false
zipAlignEnabled false
shrinkResources false
+ if (props["sign"]) {
+ signingConfig signingConfigs.release
+ }
ndk.abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
}
sourceSets {
- main.java.srcDirs += 'src/main/kotlin'
+ main {
+ jniLibs.srcDirs = ['libs']
+ java.srcDirs += 'src/main/kotlin'
+ }
}
kotlinOptions {
@@ -76,20 +105,22 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
// Androidx
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- implementation "androidx.legacy:legacy-support-v4:1.0.0"
- implementation "androidx.appcompat:appcompat:1.4.1"
- implementation "com.google.android.material:material:1.5.0"
- implementation "androidx.cardview:cardview:1.0.0"
- implementation "androidx.preference:preference:1.0.0"
- implementation "androidx.recyclerview:recyclerview:1.2.1"
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.appcompat:appcompat:1.4.2'
+ implementation 'com.google.android.material:material:1.6.1'
+ implementation 'androidx.cardview:cardview:1.0.0'
+ implementation 'androidx.preference:preference-ktx:1.2.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.1'
+ implementation 'androidx.fragment:fragment-ktx:1.4.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
// Androidx ktx
implementation 'androidx.activity:activity-ktx:1.4.0'
- implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
//kotlin
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
@@ -97,7 +128,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
implementation 'com.tencent:mmkv-static:1.2.12'
- implementation 'com.google.code.gson:gson:2.8.6'
+ implementation 'com.google.code.gson:gson:2.8.9'
implementation 'io.reactivex:rxjava:1.3.4'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'
diff --git a/V2rayNG/app/libs/Readme.md b/V2rayNG/app/libs/Readme.md
deleted file mode 100644
index 0f2efdb3..00000000
--- a/V2rayNG/app/libs/Readme.md
+++ /dev/null
@@ -1 +0,0 @@
-https://github.com/2dust/v2rayNG/tree/master/AndroidLibV2rayLite
diff --git a/V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so b/V2rayNG/app/libs/arm64-v8a/libtun2socks.so
old mode 100755
new mode 100644
similarity index 99%
rename from V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so
rename to V2rayNG/app/libs/arm64-v8a/libtun2socks.so
index 0bbc6891..3dbdde7a
Binary files a/V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so and b/V2rayNG/app/libs/arm64-v8a/libtun2socks.so differ
diff --git a/V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so b/V2rayNG/app/libs/armeabi-v7a/libtun2socks.so
old mode 100755
new mode 100644
similarity index 99%
rename from V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so
rename to V2rayNG/app/libs/armeabi-v7a/libtun2socks.so
index 4f588c79..79e3a96a
Binary files a/V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so and b/V2rayNG/app/libs/armeabi-v7a/libtun2socks.so differ
diff --git a/V2rayNG/app/libs/libv2ray.aar b/V2rayNG/app/libs/libv2ray.aar
deleted file mode 100644
index df2a17b3..00000000
Binary files a/V2rayNG/app/libs/libv2ray.aar and /dev/null differ
diff --git a/V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so b/V2rayNG/app/libs/x86/libtun2socks.so
old mode 100755
new mode 100644
similarity index 99%
rename from V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so
rename to V2rayNG/app/libs/x86/libtun2socks.so
index 9ce3e627..30a48fc2
Binary files a/V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so and b/V2rayNG/app/libs/x86/libtun2socks.so differ
diff --git a/V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so b/V2rayNG/app/libs/x86_64/libtun2socks.so
old mode 100755
new mode 100644
similarity index 99%
rename from V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so
rename to V2rayNG/app/libs/x86_64/libtun2socks.so
index 58199692..ce965f06
Binary files a/V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so and b/V2rayNG/app/libs/x86_64/libtun2socks.so differ
diff --git a/V2rayNG/app/proguard-rules.pro b/V2rayNG/app/proguard-rules.pro
index c088e544..e69de29b 100644
--- a/V2rayNG/app/proguard-rules.pro
+++ b/V2rayNG/app/proguard-rules.pro
@@ -1,58 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in G:\android-sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Gson uses generic type information stored in a class file when working with fields. Proguard
-# removes such information by default, so configure it to keep all of it.
--keepattributes Signature
-
-# For using GSON @Expose annotation
--keepattributes *Annotation*
-
-# Gson specific classes
--keep class sun.misc.Unsafe { *; }
-
--dontwarn org.apache.commons.**
--keep class org.apache.commons.** { *;}
-
-# Disable debug info output
--assumenosideeffects class android.util.Log {
- public static boolean isLoggable(java.lang.String,int);
- public static int v(...);
- public static int i(...);
- public static int w(...);
- public static int d(...);
- public static int e(...);
-}
--assumenosideeffects class kotlin.jvm.internal.Intrinsics {
- static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
- static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
- static void throwUninitializedPropertyAccessException(java.lang.String);
-}
-
--dontwarn rx.internal.util.unsafe.**
--keep class rx.internal.util.unsafe.** { *;}
-
--dontwarn app.dinus.**
--keep class app.dinus.** { *;}
-
--keepclassmembers class ** {
- @com.hwangjr.rxbus.annotation.Subscribe public *;
- @com.hwangjr.rxbus.annotation.Produce public *;
-}
-
--keep class libv2ray.** { *;}
diff --git a/V2rayNG/app/src/main/AndroidManifest.xml b/V2rayNG/app/src/main/AndroidManifest.xml
index 6f38be00..f90f1274 100644
--- a/V2rayNG/app/src/main/AndroidManifest.xml
+++ b/V2rayNG/app/src/main/AndroidManifest.xml
@@ -4,27 +4,24 @@
package="com.v2ray.ang">
+ android:anyDensity="true"
+ android:smallScreens="true"
+ android:normalScreens="true"
+ android:largeScreens="true"
+ android:xlargeScreens="true"/>
-
-
-
-
+ tools:ignore="QueryAllPackagesPermission" />
+
+
-
+
-
@@ -34,23 +31,17 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@style/AppTheme"
+ android:theme="@style/AppThemeLight"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
-
-
-
-
@@ -85,6 +76,10 @@
+
+
@@ -98,6 +93,23 @@
android:process=":RunSoLibV2RayDaemon"
android:theme="@style/AppTheme.NoActionBar.Translucent" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl b/V2rayNG/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
deleted file mode 100644
index 2a492f78..00000000
--- a/V2rayNG/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.vending.billing;
-
-import android.os.Bundle;
-
-/**
- * InAppBillingService is the service that provides in-app billing version 3 and beyond.
- * This service provides the following features:
- * 1. Provides a new API to get details of in-app items published for the app including
- * price, type, title and description.
- * 2. The purchase flow is synchronous and purchase information is available immediately
- * after it completes.
- * 3. Purchase information of in-app purchases is maintained within the Google Play system
- * till the purchase is consumed.
- * 4. An API to consume a purchase of an inapp item. All purchases of one-time
- * in-app items are consumable and thereafter can be purchased again.
- * 5. An API to get current purchases of the user immediately. This will not contain any
- * consumed purchases.
- *
- * All calls will give a response code with the following possible values
- * RESULT_OK = 0 - success
- * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
- * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
- * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
- * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
- * RESULT_ERROR = 6 - Fatal error during the API action
- * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
- * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
- */
-interface IInAppBillingService {
- /**
- * Checks support for the requested billing API version, package and in-app type.
- * Minimum API version supported by this interface is 3.
- * @param apiVersion the billing version which the app is using
- * @param packageName the package name of the calling app
- * @param type type of the in-app item being purchased "inapp" for one-time purchases
- * and "subs" for subscription.
- * @return RESULT_OK(0) on success, corresponding result code on failures
- */
- int isBillingSupported(int apiVersion, String packageName, String type);
-
- /**
- * Provides details of a list of SKUs
- * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
- * with a list JSON strings containing the productId, price, title and description.
- * This API can be called with a maximum of 20 SKUs.
- * @param apiVersion billing API version that the Third-party is using
- * @param packageName the package name of the calling app
- * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
- * @return Bundle containing the following key-value pairs
- * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
- * failure as listed above.
- * "DETAILS_LIST" with a StringArrayList containing purchase information
- * in JSON format similar to:
- * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
- * "title : "Example Title", "description" : "This is an example description" }'
- */
- Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
-
- /**
- * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
- * the type, a unique purchase token and an optional developer payload.
- * @param apiVersion billing API version that the app is using
- * @param packageName package name of the calling app
- * @param sku the SKU of the in-app item as published in the developer console
- * @param type the type of the in-app item ("inapp" for one-time purchases
- * and "subs" for subscription).
- * @param developerPayload optional argument to be sent back with the purchase information
- * @return Bundle containing the following key-value pairs
- * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
- * failure as listed above.
- * "BUY_INTENT" - PendingIntent to start the purchase flow
- *
- * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
- * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
- * If the purchase is successful, the result data will contain the following key-value pairs
- * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
- * failure as listed above.
- * "INAPP_PURCHASE_DATA" - String in JSON format similar to
- * '{"orderId":"12999763169054705758.1371079406387615",
- * "packageName":"com.example.app",
- * "productId":"exampleSku",
- * "purchaseTime":1345678900000,
- * "purchaseToken" : "122333444455555",
- * "developerPayload":"example developer payload" }'
- * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
- * was signed with the private key of the developer
- * TODO: change this to app-specific keys.
- */
- Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
- String developerPayload);
-
- /**
- * Returns the current SKUs owned by the user of the type and package name specified along with
- * purchase information and a signature of the data to be validated.
- * This will return all SKUs that have been purchased in V3 and managed items purchased using
- * V1 and V2 that have not been consumed.
- * @param apiVersion billing API version that the app is using
- * @param packageName package name of the calling app
- * @param type the type of the in-app items being requested
- * ("inapp" for one-time purchases and "subs" for subscription).
- * @param continuationToken to be set as null for the first call, if the number of owned
- * skus are too many, a continuationToken is returned in the response bundle.
- * This method can be called again with the continuation token to get the next set of
- * owned skus.
- * @return Bundle containing the following key-value pairs
- * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
- * failure as listed above.
- * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
- * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
- * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
- * of the purchase information
- * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
- * next set of in-app purchases. Only set if the
- * user has more owned skus than the current list.
- */
- Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
-
- /**
- * Consume the last purchase of the given SKU. This will result in this item being removed
- * from all subsequent responses to getPurchases() and allow re-purchase of this item.
- * @param apiVersion billing API version that the app is using
- * @param packageName package name of the calling app
- * @param purchaseToken token in the purchase information JSON that identifies the purchase
- * to be consumed
- * @return 0 if consumption succeeded. Appropriate error values for failures.
- */
- int consumePurchase(int apiVersion, String packageName, String purchaseToken);
-}
diff --git a/V2rayNG/app/src/main/assets/custom_routing_block b/V2rayNG/app/src/main/assets/custom_routing_block
new file mode 100644
index 00000000..a6ebf394
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_block
@@ -0,0 +1 @@
+geosite:category-ads-all,
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/assets/custom_routing_direct b/V2rayNG/app/src/main/assets/custom_routing_direct
new file mode 100644
index 00000000..5408992c
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_direct
@@ -0,0 +1,132 @@
+domain:12306.com,
+domain:51ym.me,
+domain:52pojie.cn,
+domain:8686c.com,
+domain:abercrombie.com,
+domain:adobesc.com,
+domain:air-matters.com,
+domain:air-matters.io,
+domain:airtable.com,
+domain:akadns.net,
+domain:apache.org,
+domain:api.crisp.chat,
+domain:api.termius.com,
+domain:appshike.com,
+domain:appstore.com,
+domain:aweme.snssdk.com,
+domain:bababian.com,
+domain:battle.net,
+domain:beatsbydre.com,
+domain:bet365.com,
+domain:bilibili.cn,
+domain:ccgslb.com,
+domain:ccgslb.net,
+domain:chunbo.com,
+domain:chunboimg.com,
+domain:clashroyaleapp.com,
+domain:cloudsigma.com,
+domain:cloudxns.net,
+domain:cmfu.com,
+domain:culturedcode.com,
+domain:dct-cloud.com,
+domain:didialift.com,
+domain:douyutv.com,
+domain:duokan.com,
+domain:dytt8.net,
+domain:easou.com,
+domain:ecitic.net,
+domain:eclipse.org,
+domain:eudic.net,
+domain:ewqcxz.com,
+domain:fir.im,
+domain:frdic.com,
+domain:fresh-ideas.cc,
+domain:godic.net,
+domain:goodread.com,
+domain:haibian.com,
+domain:hdslb.net,
+domain:hollisterco.com,
+domain:hongxiu.com,
+domain:hxcdn.net,
+domain:images.unsplash.com,
+domain:img4me.com,
+domain:ipify.org,
+domain:ixdzs.com,
+domain:jd.hk,
+domain:jianshuapi.com,
+domain:jomodns.com,
+domain:jsboxbbs.com,
+domain:knewone.com,
+domain:kuaidi100.com,
+domain:lemicp.com,
+domain:letvcloud.com,
+domain:lizhi.io,
+domain:localizecdn.com,
+domain:lucifr.com,
+domain:luoo.net,
+domain:mai.tn,
+domain:maven.org,
+domain:miwifi.com,
+domain:moji.com,
+domain:moke.com,
+domain:mtalk.google.com,
+domain:mxhichina.com,
+domain:myqcloud.com,
+domain:myunlu.com,
+domain:netease.com,
+domain:nfoservers.com,
+domain:nssurge.com,
+domain:nuomi.com,
+domain:ourdvs.com,
+domain:overcast.fm,
+domain:paypal.com,
+domain:paypalobjects.com,
+domain:pgyer.com,
+domain:qdaily.com,
+domain:qdmm.com,
+domain:qin.io,
+domain:qingmang.me,
+domain:qingmang.mobi,
+domain:qqurl.com,
+domain:rarbg.to,
+domain:rrmj.tv,
+domain:ruguoapp.com,
+domain:sm.ms,
+domain:snwx.com,
+domain:soku.com,
+domain:startssl.com,
+domain:store.steampowered.com,
+domain:symcd.com,
+domain:teamviewer.com,
+domain:tmzvps.com,
+domain:trello.com,
+domain:trellocdn.com,
+domain:ttmeiju.com,
+domain:udache.com,
+domain:uxengine.net,
+domain:weather.bjango.com,
+domain:weather.com,
+domain:webqxs.com,
+domain:weico.cc,
+domain:wenku8.net,
+domain:werewolf.53site.com,
+domain:windowsupdate.com,
+domain:wkcdn.com,
+domain:workflowy.com,
+domain:xdrig.com,
+domain:xiaojukeji.com,
+domain:xiaomi.net,
+domain:xiaomicp.com,
+domain:ximalaya.com,
+domain:xitek.com,
+domain:xmcdn.com,
+domain:xslb.net,
+domain:xteko.com,
+domain:yach.me,
+domain:yixia.com,
+domain:yunjiasu-cdn.net,
+domain:zealer.com,
+domain:zgslb.net,
+domain:zimuzu.tv,
+domain:zmz002.com,
+domain:samsungdm.com,
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/assets/custom_routing_proxy b/V2rayNG/app/src/main/assets/custom_routing_proxy
new file mode 100644
index 00000000..d67a6237
--- /dev/null
+++ b/V2rayNG/app/src/main/assets/custom_routing_proxy
@@ -0,0 +1,33 @@
+geosite:google,
+geosite:github,
+geosite:netflix,
+geosite:steam,
+geosite:telegram,
+geosite:tumblr,
+geosite:speedtest,
+geosite:bbc,
+domain:gvt1.com,
+domain:textnow.com,
+domain:twitch.tv,
+domain:wikileaks.org,
+domain:naver.com,
+91.108.4.0/22,
+91.108.8.0/22,
+91.108.12.0/22,
+91.108.20.0/22,
+91.108.36.0/23,
+91.108.38.0/23,
+91.108.56.0/22,
+149.154.160.0/20,
+149.154.164.0/22,
+149.154.172.0/22,
+74.125.0.0/16,
+173.194.0.0/16,
+172.217.0.0/16,
+216.58.200.0/24,
+216.58.220.0/24,
+91.108.56.116,
+91.108.56.0/24,
+109.239.140.0/24,
+149.154.167.0/24,
+149.154.175.0/24,
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/assets/v2ray_config.json b/V2rayNG/app/src/main/assets/v2ray_config.json
index 5e009dc8..57b1bd8a 100644
--- a/V2rayNG/app/src/main/assets/v2ray_config.json
+++ b/V2rayNG/app/src/main/assets/v2ray_config.json
@@ -54,6 +54,7 @@
"users": [
{
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
+ "alterId": 0,
"security": "auto",
"level": 8
}
diff --git a/V2rayNG/app/src/main/ic_launcher-web.png b/V2rayNG/app/src/main/ic_launcher-web.png
index f6fc3b8c..03a4ce8a 100644
Binary files a/V2rayNG/app/src/main/ic_launcher-web.png and b/V2rayNG/app/src/main/ic_launcher-web.png differ
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/QRCodeDecoder.java b/V2rayNG/app/src/main/java/com/v2ray/ang/util/QRCodeDecoder.java
deleted file mode 100644
index 1a16ac3e..00000000
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/QRCodeDecoder.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.v2ray.ang.util;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.BinaryBitmap;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.RGBLuminanceSource;
-import com.google.zxing.Result;
-import com.google.zxing.common.GlobalHistogramBinarizer;
-import com.google.zxing.common.HybridBinarizer;
-
-import java.util.ArrayList;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 描述:解析二维码图片
- */
-public class QRCodeDecoder {
- public static final Map HINTS = new EnumMap<>(DecodeHintType.class);
-
- static {
- List allFormats = new ArrayList<>();
- allFormats.add(BarcodeFormat.AZTEC);
- allFormats.add(BarcodeFormat.CODABAR);
- allFormats.add(BarcodeFormat.CODE_39);
- allFormats.add(BarcodeFormat.CODE_93);
- allFormats.add(BarcodeFormat.CODE_128);
- allFormats.add(BarcodeFormat.DATA_MATRIX);
- allFormats.add(BarcodeFormat.EAN_8);
- allFormats.add(BarcodeFormat.EAN_13);
- allFormats.add(BarcodeFormat.ITF);
- allFormats.add(BarcodeFormat.MAXICODE);
- allFormats.add(BarcodeFormat.PDF_417);
- allFormats.add(BarcodeFormat.QR_CODE);
- allFormats.add(BarcodeFormat.RSS_14);
- allFormats.add(BarcodeFormat.RSS_EXPANDED);
- allFormats.add(BarcodeFormat.UPC_A);
- allFormats.add(BarcodeFormat.UPC_E);
- allFormats.add(BarcodeFormat.UPC_EAN_EXTENSION);
- HINTS.put(DecodeHintType.TRY_HARDER, BarcodeFormat.QR_CODE);
- HINTS.put(DecodeHintType.POSSIBLE_FORMATS, allFormats);
- HINTS.put(DecodeHintType.CHARACTER_SET, "utf-8");
- }
-
- private QRCodeDecoder() {
- }
-
- /**
- * 同步解析本地图片二维码。该方法是耗时操作,请在子线程中调用。
- *
- * @param picturePath 要解析的二维码图片本地路径
- * @return 返回二维码图片里的内容 或 null
- */
- public static String syncDecodeQRCode(String picturePath) {
- return syncDecodeQRCode(getDecodeAbleBitmap(picturePath));
- }
-
- /**
- * 同步解析bitmap二维码。该方法是耗时操作,请在子线程中调用。
- *
- * @param bitmap 要解析的二维码图片
- * @return 返回二维码图片里的内容 或 null
- */
- public static String syncDecodeQRCode(Bitmap bitmap) {
- Result result = null;
- RGBLuminanceSource source = null;
- try {
- int width = bitmap.getWidth();
- int height = bitmap.getHeight();
- int[] pixels = new int[width * height];
- bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
- source = new RGBLuminanceSource(width, height, pixels);
- result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), HINTS);
- return result.getText();
- } catch (Exception e) {
- e.printStackTrace();
- if (source != null) {
- try {
- result = new MultiFormatReader().decode(new BinaryBitmap(new GlobalHistogramBinarizer(source)), HINTS);
- return result.getText();
- } catch (Throwable e2) {
- e2.printStackTrace();
- }
- }
- return null;
- }
- }
-
- /**
- * 将本地图片文件转换成可解码二维码的 Bitmap。为了避免图片太大,这里对图片进行了压缩。感谢 https://github.com/devilsen 提的 PR
- *
- * @param picturePath 本地图片文件路径
- * @return
- */
- private static Bitmap getDecodeAbleBitmap(String picturePath) {
- try {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(picturePath, options);
- int sampleSize = options.outHeight / 400;
- if (sampleSize <= 0) {
- sampleSize = 1;
- }
- options.inSampleSize = sampleSize;
- options.inJustDecodeBounds = false;
- return BitmapFactory.decodeFile(picturePath, options);
- } catch (Exception e) {
- return null;
- }
- }
-}
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
index 6ca82ded..aa1ef7d4 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AngApplication.kt
@@ -9,7 +9,6 @@ class AngApplication : MultiDexApplication() {
const val PREF_LAST_VERSION = "pref_last_version"
}
- var curIndex = -1 //Current proxy that is opened. (Used to implement restart feature)
var firstRun = false
private set
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
index 5f37e276..3793e583 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt
@@ -6,6 +6,7 @@ package com.v2ray.ang
*/
object AppConfig {
const val ANG_PACKAGE = "com.v2ray.ang"
+ const val DIR_ASSETS = "assets"
// legacy
const val ANG_CONFIG = "ang_config"
@@ -23,7 +24,12 @@ object AppConfig {
const val PREF_REMOTE_DNS = "pref_remote_dns"
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
- const val PREF_FORWARD_IPV6 = "pref_forward_ipv6"
+ const val PREF_ALLOW_INSECURE = "pref_allow_insecure"
+ const val PREF_SOCKS_PORT = "pref_socks_port"
+ const val PREF_HTTP_PORT = "pref_http_port"
+ const val PREF_LOGLEVEL = "pref_core_loglevel"
+ const val PREF_LANGUAGE = "pref_language"
+ const val PREF_PREFER_IPV6 = "pref_prefer_ipv6"
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
const val PREF_ROUTING_MODE = "pref_routing_mode"
const val PREF_V2RAY_ROUTING_AGENT = "pref_v2ray_routing_agent"
@@ -32,16 +38,7 @@ object AppConfig {
const val PREF_PER_APP_PROXY = "pref_per_app_proxy"
const val PREF_PER_APP_PROXY_SET = "pref_per_app_proxy_set"
const val PREF_BYPASS_APPS = "pref_bypass_apps"
- // const val PREF_BYPASS_MAINLAND = "pref_bypass_mainland"
- // const val PREF_START_ON_BOOT = "pref_start_on_boot"
- // const val PREF_MUX_ENAimport libv2ray.Libv2rayBLED = "pref_mux_enabled"
- // const val PREF_SOCKS_PORT = "pref_socks_port"
-// const val PREF_HTTP_PORT = "pref_http_port"
- // const val PREF_DONATE = "pref_donate"
- // const val PREF_LICENSES = "pref_licenses"
-// const val PREF_FEEDBACK = "pref_feedback"
-// const val PREF_TG_GROUP = "pref_tg_group"
- // const val PREF_AUTO_RESTART = "pref_auto_restart"
+ const val PREF_CONFIRM_REMOVE = "pref_confirm_remove"
const val HTTP_PROTOCOL: String = "http://"
const val HTTPS_PROTOCOL: String = "https://"
@@ -64,11 +61,16 @@ object AppConfig {
const val v2rayCustomRoutingListUrl = "https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"
const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues"
const val v2rayNGWikiMode = "https://github.com/2dust/v2rayNG/wiki/Mode"
- const val promotionUrl = "https://1.2345345.xyz/ads.html"
+ const val promotionUrl = "aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="
+ const val geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/";
const val DNS_AGENT = "1.1.1.1"
const val DNS_DIRECT = "223.5.5.5"
+ const val PORT_LOCAL_DNS = "10853"
+ const val PORT_SOCKS = "10808"
+ const val PORT_HTTP = "10809"
+
const val MSG_REGISTER_CLIENT = 1
const val MSG_STATE_RUNNING = 11
const val MSG_STATE_NOT_RUNNING = 12
@@ -79,4 +81,9 @@ object AppConfig {
const val MSG_STATE_STOP = 4
const val MSG_STATE_STOP_SUCCESS = 41
const val MSG_STATE_RESTART = 5
+ const val MSG_MEASURE_DELAY = 6
+ const val MSG_MEASURE_DELAY_SUCCESS = 61
+ const val MSG_MEASURE_CONFIG = 7
+ const val MSG_MEASURE_CONFIG_SUCCESS = 71
+ const val MSG_MEASURE_CONFIG_CANCEL = 72
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/AngConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/AngConfig.kt
index c51d78b6..01f2bdd8 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/AngConfig.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/AngConfig.kt
@@ -17,12 +17,16 @@ data class AngConfig(
var requestHost: String = "",
var path: String = "",
var streamSecurity: String = "",
+ var allowInsecure: String = "",
var configType: Int = 1,
var configVersion: Int = 1,
var testResult: String = "",
- var subid: String = "")
+ var subid: String = "",
+ var flow: String = "",
+ var sni: String = "")
data class SubItemBean(var id: String = "",
var remarks: String = "",
- var url: String = "")
+ var url: String = "",
+ var enabled: Boolean = true)
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt
new file mode 100644
index 00000000..96d77397
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ERoutingMode.kt
@@ -0,0 +1,9 @@
+package com.v2ray.ang.dto
+
+enum class ERoutingMode(val value: String ) {
+ GLOBAL_PROXY("0"),
+ BYPASS_LAN("1"),
+ BYPASS_MAINLAND("2"),
+ BYPASS_LAN_MAINLAND("3"),
+ GLOBAL_DIRECT("4");
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ServersCache.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ServersCache.kt
new file mode 100644
index 00000000..e686b469
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/ServersCache.kt
@@ -0,0 +1,4 @@
+package com.v2ray.ang.dto
+
+data class ServersCache(val guid: String,
+ val config: ServerConfig)
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt
index e3bc1e22..fc9c7840 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt
@@ -89,6 +89,7 @@ data class V2rayConfig(
var users: List) {
data class UsersBean(var id: String = "",
+ var alterId: Int? = null,
var security: String = DEFAULT_SECURITY,
var level: Int = DEFAULT_LEVEL,
var encryption: String = "",
@@ -102,7 +103,7 @@ data class V2rayConfig(
var port: Int = DEFAULT_PORT,
var level: Int = DEFAULT_LEVEL,
val email: String? = null,
- val flow: String? = null,
+ var flow: String? = null,
val ivCheck: Boolean? = null,
var users: List? = null) {
@@ -261,12 +262,14 @@ data class V2rayConfig(
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String) {
security = streamSecurity
val tlsSetting = TlsSettingsBean(
- allowInsecure = allowInsecure,
- serverName = sni
+ allowInsecure = allowInsecure,
+ serverName = sni
)
if (security == TLS) {
tlsSettings = tlsSetting
+ xtlsSettings = null
} else if (security == XTLS) {
+ tlsSettings = null
xtlsSettings = tlsSetting
}
}
@@ -322,7 +325,8 @@ data class V2rayConfig(
fun getTransportSettingDetails(): List? {
if (protocol.equals(EConfigType.VMESS.name, true)
- || protocol.equals(EConfigType.VLESS.name, true)) {
+ || protocol.equals(EConfigType.VLESS.name, true)
+ || protocol.equals(EConfigType.TROJAN.name, true)) {
val transport = streamSettings?.network ?: return null
return when (transport) {
"tcp" -> {
@@ -383,7 +387,7 @@ data class V2rayConfig(
}
data class RoutingBean(var domainStrategy: String,
- val domainMatcher: String? = null,
+ var domainMatcher: String? = null,
var rules: ArrayList,
val balancers: List? = null) {
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/VmessQRCode.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/VmessQRCode.kt
index a114336c..90d58a5a 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/VmessQRCode.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/VmessQRCode.kt
@@ -6,9 +6,10 @@ data class VmessQRCode(var v: String = "",
var port: String = "",
var id: String = "",
var aid: String = "0",
+ var scy: String = "",
var net: String = "",
var type: String = "",
var host: String = "",
var path: String = "",
var tls: String = "",
- var sni: String = "")
+ var sni: String = "")
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/extension/_Ext.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/extension/_Ext.kt
index 9d8291c0..fb0bff63 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/extension/_Ext.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/extension/_Ext.kt
@@ -74,7 +74,7 @@ private fun Float.toShortString(): String {
}
val URLConnection.responseLength: Long
- get() = if (Build.VERSION.SDK_INT >= 24) contentLengthLong else contentLength.toLong()
+ get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) contentLengthLong else contentLength.toLong()
val URI.idnHost: String
get() = (host!!).replace("[", "").replace("]", "")
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/QSTileService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/QSTileService.kt
index b7e07e91..176b0fbe 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/QSTileService.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/QSTileService.kt
@@ -22,11 +22,11 @@ class QSTileService : TileService() {
if (state == Tile.STATE_INACTIVE) {
qsTile?.state = Tile.STATE_INACTIVE
qsTile?.label = getString(R.string.app_name)
- qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v_idle)
+ qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
} else if (state == Tile.STATE_ACTIVE) {
qsTile?.state = Tile.STATE_ACTIVE
qsTile?.label = V2RayServiceManager.currentConfig?.remarks
- qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v)
+ qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_stat_name)
}
qsTile?.updateTile()
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/ServiceControl.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/ServiceControl.kt
index 2998342a..36a26b88 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/ServiceControl.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/ServiceControl.kt
@@ -5,10 +5,9 @@ import android.app.Service
interface ServiceControl {
fun getService(): Service
- fun startService(parameters: String)
+ fun startService()
fun stopService()
fun vpnProtect(socket: Int): Boolean
-
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayProxyOnlyService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayProxyOnlyService.kt
index 4e4db1fb..3403af61 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayProxyOnlyService.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayProxyOnlyService.kt
@@ -1,8 +1,13 @@
package com.v2ray.ang.service
import android.app.Service
+import android.content.Context
import android.content.Intent
+import android.os.Build
import android.os.IBinder
+import androidx.annotation.RequiresApi
+import com.v2ray.ang.util.MyContextWrapper
+import com.v2ray.ang.util.Utils
import java.lang.ref.SoftReference
class V2RayProxyOnlyService : Service(), ServiceControl {
@@ -25,7 +30,7 @@ class V2RayProxyOnlyService : Service(), ServiceControl {
return this
}
- override fun startService(parameters: String) {
+ override fun startService() {
// do nothing
}
@@ -40,4 +45,12 @@ class V2RayProxyOnlyService : Service(), ServiceControl {
override fun onBind(intent: Intent?): IBinder? {
return null
}
+
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun attachBaseContext(newBase: Context?) {
+ val context = newBase?.let {
+ MyContextWrapper.wrap(newBase, Utils.getLocale(newBase))
+ }
+ super.attachBaseContext(context)
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayServiceManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayServiceManager.kt
index 8ee39792..15f4a1e8 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayServiceManager.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayServiceManager.kt
@@ -1,18 +1,15 @@
package com.v2ray.ang.service
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
+import android.app.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.Build
+import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
-import android.util.Log
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
@@ -44,7 +41,7 @@ object V2RayServiceManager {
private const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
private const val NOTIFICATION_ICON_THRESHOLD = 3000
- val v2rayPoint: V2RayPoint = Libv2ray.newV2RayPoint(V2RayCallback())
+ val v2rayPoint: V2RayPoint = Libv2ray.newV2RayPoint(V2RayCallback(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1)
private val mMsgReceive = ReceiveMessageHandler()
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
@@ -52,12 +49,8 @@ object V2RayServiceManager {
var serviceControl: SoftReference? = null
set(value) {
field = value
- val context = value?.get()?.getService()?.applicationContext
- context?.let {
- v2rayPoint.packageName = Utils.packagePath(context)
- v2rayPoint.packageCodePath = context.applicationInfo.nativeLibraryDir + "/"
- Seq.setContext(context)
- }
+ Seq.setContext(value?.get()?.getService()?.applicationContext)
+ Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()))
}
var currentConfig: ServerConfig? = null
@@ -69,7 +62,7 @@ object V2RayServiceManager {
fun startV2Ray(context: Context) {
if (settingsStorage?.decodeBool(AppConfig.PREF_PROXY_SHARING) == true) {
context.toast(R.string.toast_warning_pref_proxysharing_short)
- }else{
+ } else {
context.toast(R.string.toast_services_start)
}
val intent = if (settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN" == "VPN") {
@@ -88,7 +81,6 @@ object V2RayServiceManager {
override fun shutdown(): Long {
val serviceControl = serviceControl?.get() ?: return -1
// called by go
- // shutdown the whole vpn service
return try {
serviceControl.stopService()
0
@@ -102,9 +94,9 @@ object V2RayServiceManager {
return 0
}
- override fun protect(l: Long): Long {
- val serviceControl = serviceControl?.get() ?: return 0
- return if (serviceControl.vpnProtect(l.toInt())) 0 else 1
+ override fun protect(l: Long): Boolean {
+ val serviceControl = serviceControl?.get() ?: return true
+ return serviceControl.vpnProtect(l.toInt())
}
override fun onEmitStatus(l: Long, s: String?): Long {
@@ -116,7 +108,7 @@ object V2RayServiceManager {
val serviceControl = serviceControl?.get() ?: return -1
//Logger.d(s)
return try {
- serviceControl.startService(s)
+ serviceControl.startService()
lastQueryTime = System.currentTimeMillis()
startSpeedNotification()
0
@@ -125,7 +117,6 @@ object V2RayServiceManager {
-1
}
}
-
}
fun startV2rayPoint() {
@@ -150,12 +141,9 @@ object V2RayServiceManager {
v2rayPoint.configureFileContent = result.content
v2rayPoint.domainName = config.getV2rayPointDomainAndPort()
currentConfig = config
- v2rayPoint.enableLocalDNS = settingsStorage?.decodeBool(AppConfig.PREF_LOCAL_DNS_ENABLED) ?: false
- v2rayPoint.forwardIpv6 = settingsStorage?.decodeBool(AppConfig.PREF_FORWARD_IPV6) ?: false
- v2rayPoint.proxyOnly = settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN" != "VPN"
try {
- v2rayPoint.runLoop()
+ v2rayPoint.runLoop(settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) ?: false)
} catch (e: Exception) {
Log.d(ANG_PACKAGE, e.toString())
}
@@ -217,6 +205,9 @@ object V2RayServiceManager {
AppConfig.MSG_STATE_RESTART -> {
startV2rayPoint()
}
+ AppConfig.MSG_MEASURE_DELAY -> {
+ measureV2rayDelay()
+ }
}
when (intent?.action) {
@@ -232,6 +223,29 @@ object V2RayServiceManager {
}
}
+ private fun measureV2rayDelay() {
+ GlobalScope.launch(Dispatchers.IO) {
+ val service = serviceControl?.get()?.getService() ?: return@launch
+ var time = -1L
+ var errstr = ""
+ if (v2rayPoint.isRunning) {
+ try {
+ time = v2rayPoint.measureDelay()
+ } catch (e: Exception) {
+ Log.d(ANG_PACKAGE, "measureV2rayDelay: $e")
+ errstr = e.message?.substringAfter("\":") ?: "empty message"
+ }
+ }
+ val result = if (time == -1L) {
+ service.getString(R.string.connection_test_error, errstr)
+ } else {
+ service.getString(R.string.connection_test_available, time)
+ }
+
+ MessageUtil.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_SUCCESS, result)
+ }
+ }
+
private fun showNotification() {
val service = serviceControl?.get()?.getService() ?: return
val startMainIntent = Intent(service, MainActivity::class.java)
@@ -265,7 +279,7 @@ object V2RayServiceManager {
}
mBuilder = NotificationCompat.Builder(service, channelId)
- .setSmallIcon(R.drawable.ic_v)
+ .setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(currentConfig?.remarks)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true)
@@ -306,7 +320,7 @@ object V2RayServiceManager {
private fun updateNotification(contentText: String?, proxyTraffic: Long, directTraffic: Long) {
if (mBuilder != null) {
if (proxyTraffic < NOTIFICATION_ICON_THRESHOLD && directTraffic < NOTIFICATION_ICON_THRESHOLD) {
- mBuilder?.setSmallIcon(R.drawable.ic_v)
+ mBuilder?.setSmallIcon(R.drawable.ic_stat_name)
} else if (proxyTraffic > directTraffic) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_proxy)
} else {
@@ -326,7 +340,7 @@ object V2RayServiceManager {
return mNotificationManager
}
- fun startSpeedNotification() {
+ private fun startSpeedNotification() {
if (mSubscription == null &&
v2rayPoint.isRunning &&
settingsStorage?.decodeBool(AppConfig.PREF_SPEED_ENABLED) == true) {
@@ -375,7 +389,7 @@ object V2RayServiceManager {
text.append("• ${up.toLong().toSpeedString()}↑ ${down.toLong().toSpeedString()}↓\n")
}
- fun stopSpeedNotification() {
+ private fun stopSpeedNotification() {
if (mSubscription != null) {
mSubscription?.unsubscribe() //stop queryStats
mSubscription = null
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt
new file mode 100644
index 00000000..362b7196
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt
@@ -0,0 +1,45 @@
+package com.v2ray.ang.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG
+import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_CANCEL
+import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_SUCCESS
+import com.v2ray.ang.util.MessageUtil
+import com.v2ray.ang.util.SpeedtestUtil
+import com.v2ray.ang.util.Utils
+import go.Seq
+import kotlinx.coroutines.*
+import libv2ray.Libv2ray
+import java.util.concurrent.Executors
+
+class V2RayTestService : Service() {
+ private val realTestScope by lazy { CoroutineScope(Executors.newFixedThreadPool(10).asCoroutineDispatcher()) }
+
+ override fun onCreate() {
+ super.onCreate()
+ Seq.setContext(this)
+ Libv2ray.initV2Env(Utils.userAssetPath(this))
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ when (intent?.getIntExtra("key", 0)) {
+ MSG_MEASURE_CONFIG -> {
+ val contentPair = intent.getSerializableExtra("content") as Pair
+ realTestScope.launch {
+ val result = SpeedtestUtil.realPing(contentPair.second)
+ MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(contentPair.first, result))
+ }
+ }
+ MSG_MEASURE_CONFIG_CANCEL -> {
+ realTestScope.coroutineContext[Job]?.cancelChildren()
+ }
+ }
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
index 240e6db8..f328a9b9 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayVpnService.kt
@@ -1,6 +1,6 @@
package com.v2ray.ang.service
-import android.app.*
+import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -8,12 +8,14 @@ import android.net.*
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.StrictMode
-import androidx.annotation.RequiresApi
import android.util.Log
+import androidx.annotation.RequiresApi
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
+import com.v2ray.ang.dto.ERoutingMode
import com.v2ray.ang.util.MmkvManager
+import com.v2ray.ang.util.MyContextWrapper
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@@ -22,19 +24,31 @@ import java.io.File
import java.lang.ref.SoftReference
class V2RayVpnService : VpnService(), ServiceControl {
+ companion object {
+ private const val VPN_MTU = 1500
+ private const val PRIVATE_VLAN4_CLIENT = "26.26.26.1"
+ private const val PRIVATE_VLAN4_ROUTER = "26.26.26.2"
+ private const val PRIVATE_VLAN6_CLIENT = "da26:2626::1"
+ private const val PRIVATE_VLAN6_ROUTER = "da26:2626::2"
+ private const val TUN2SOCKS = "libtun2socks.so"
+ }
+
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
private lateinit var mInterface: ParcelFileDescriptor
- /**
- * Unfortunately registerDefaultNetworkCallback is going to return our VPN interface: https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
- *
- * This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
- * satisfies default network capabilities but only THE default network. Unfortunately we need to have
- * android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
- *
- * Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
- */
+ //val fd: Int get() = mInterface.fd
+ private lateinit var process: Process
+
+ /**destroy
+ * Unfortunately registerDefaultNetworkCallback is going to return our VPN interface: https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
+ *
+ * This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
+ * satisfies default network capabilities but only THE default network. Unfortunately we need to have
+ * android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
+ *
+ * Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
+ */
@delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkRequest by lazy {
NetworkRequest.Builder()
@@ -51,10 +65,12 @@ class V2RayVpnService : VpnService(), ServiceControl {
override fun onAvailable(network: Network) {
setUnderlyingNetworks(arrayOf(network))
}
+
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
// it's a good idea to refresh capabilities
setUnderlyingNetworks(arrayOf(network))
}
+
override fun onLost(network: Network) {
setUnderlyingNetworks(null)
}
@@ -73,18 +89,17 @@ class V2RayVpnService : VpnService(), ServiceControl {
stopV2Ray()
}
- override fun onLowMemory() {
- stopV2Ray()
- super.onLowMemory()
- }
+// override fun onLowMemory() {
+// stopV2Ray()
+// super.onLowMemory()
+// }
override fun onDestroy() {
super.onDestroy()
- stopV2Ray()
+ V2RayServiceManager.cancelNotification()
}
- private fun setup(parameters: String) {
-
+ private fun setup() {
val prepare = prepare(this)
if (prepare != null) {
return
@@ -93,35 +108,34 @@ class V2RayVpnService : VpnService(), ServiceControl {
// If the old interface has exactly the same parameters, use it!
// Configure a builder while parsing the parameters.
val builder = Builder()
- val enableLocalDns = settingsStorage?.decodeBool(AppConfig.PREF_LOCAL_DNS_ENABLED) ?: false
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: "0"
+ //val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
- parameters.split(" ")
- .map { it.split(",") }
- .forEach {
- when (it[0][0]) {
- 'm' -> builder.setMtu(java.lang.Short.parseShort(it[1]).toInt())
- 's' -> builder.addSearchDomain(it[1])
- 'a' -> builder.addAddress(it[1], Integer.parseInt(it[2]))
- 'r' -> {
- if (routingMode == "1" || routingMode == "3") {
- if (it[1] == "::") { //not very elegant, should move Vpn setting in Kotlin, simplify go code
- builder.addRoute("2000::", 3)
- } else {
- resources.getStringArray(R.array.bypass_private_ip_address).forEach { cidr ->
- val addr = cidr.split('/')
- builder.addRoute(addr[0], addr[1].toInt())
- }
- }
- } else {
- builder.addRoute(it[1], Integer.parseInt(it[2]))
- }
- }
- 'd' -> builder.addDnsServer(it[1])
- }
- }
+ val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: ERoutingMode.GLOBAL_PROXY.value
- if(!enableLocalDns) {
+ builder.setMtu(VPN_MTU)
+ builder.addAddress(PRIVATE_VLAN4_CLIENT, 30)
+ //builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
+ if (routingMode == ERoutingMode.BYPASS_LAN.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
+ resources.getStringArray(R.array.bypass_private_ip_address).forEach {
+ val addr = it.split('/')
+ builder.addRoute(addr[0], addr[1].toInt())
+ }
+ } else {
+ builder.addRoute("0.0.0.0", 0)
+ }
+
+ if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) {
+ builder.addAddress(PRIVATE_VLAN6_CLIENT, 126)
+ if (routingMode == ERoutingMode.BYPASS_LAN.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
+ builder.addRoute("2000::", 3) //currently only 1/8 of total ipV6 is in use
+ } else {
+ builder.addRoute("::", 0)
+ }
+ }
+
+ if (settingsStorage?.decodeBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) {
+ builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
+ } else {
Utils.getVpnDnsServers()
.forEach {
if (Utils.isPureIpAddress(it)) {
@@ -169,23 +183,59 @@ class V2RayVpnService : VpnService(), ServiceControl {
// Create a new interface using the builder and save the parameters.
try {
mInterface = builder.establish()!!
+ runTun2socks()
} catch (e: Exception) {
// non-nullable lateinit var
e.printStackTrace()
stopV2Ray()
}
+ }
- sendFd()
+ private fun runTun2socks() {
+ val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT), AppConfig.PORT_SOCKS.toInt())
+ val cmd = arrayListOf(File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
+ "--netif-ipaddr", PRIVATE_VLAN4_ROUTER,
+ "--netif-netmask", "255.255.255.252",
+ "--socks-server-addr", "127.0.0.1:${socksPort}",
+ "--tunmtu", VPN_MTU.toString(),
+ "--sock-path", "sock_path",//File(applicationContext.filesDir, "sock_path").absolutePath,
+ "--enable-udprelay",
+ "--loglevel", "notice")
+
+ if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) {
+ cmd.add("--netif-ip6addr")
+ cmd.add(PRIVATE_VLAN6_ROUTER)
+ }
+ if (settingsStorage?.decodeBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) {
+ val localDnsPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
+ cmd.add("--dnsgw")
+ cmd.add("127.0.0.1:${localDnsPort}")
+ }
+ Log.d(packageName, cmd.toString())
+
+ try {
+ val proBuilder = ProcessBuilder(cmd)
+ proBuilder.redirectErrorStream(true)
+ process = proBuilder
+ .directory(applicationContext.filesDir)
+ .start()
+ Log.d(packageName, process.toString())
+
+ sendFd()
+ } catch (e: Exception) {
+ Log.d(packageName, e.toString())
+ }
}
private fun sendFd() {
val fd = mInterface.fileDescriptor
- val path = File(Utils.packagePath(applicationContext), "sock_path").absolutePath
+ val path = File(applicationContext.filesDir, "sock_path").absolutePath
+ Log.d(packageName, path)
GlobalScope.launch(Dispatchers.IO) {
var tries = 0
while (true) try {
- Thread.sleep(1000L shl tries)
+ Thread.sleep(50L shl tries)
Log.d(packageName, "sendFd tries: $tries")
LocalSocket().use { localSocket ->
localSocket.connect(LocalSocketAddress(path, LocalSocketAddress.Namespace.FILESYSTEM))
@@ -220,6 +270,13 @@ class V2RayVpnService : VpnService(), ServiceControl {
}
}
+ try {
+ Log.d(packageName, "tun2socks destroy")
+ process.destroy()
+ } catch (e: Exception) {
+ Log.d(packageName, e.toString())
+ }
+
V2RayServiceManager.stopV2rayPoint()
if (isForced) {
@@ -235,7 +292,6 @@ class V2RayVpnService : VpnService(), ServiceControl {
} catch (ignored: Exception) {
// ignored
}
-
}
}
@@ -243,8 +299,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
return this
}
- override fun startService(parameters: String) {
- setup(parameters)
+ override fun startService() {
+ setup()
}
override fun stopService() {
@@ -255,4 +311,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
return protect(socket)
}
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun attachBaseContext(newBase: Context?) {
+ val context = newBase?.let {
+ MyContextWrapper.wrap(newBase, Utils.getLocale(newBase))
+ }
+ super.attachBaseContext(context)
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/BaseActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/BaseActivity.kt
index 3f11b649..66d8feb6 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/BaseActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/BaseActivity.kt
@@ -1,7 +1,14 @@
package com.v2ray.ang.ui
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem
+import androidx.annotation.RequiresApi
+import com.v2ray.ang.util.MyContextWrapper
+import com.v2ray.ang.R
+import com.v2ray.ang.util.Utils
abstract class BaseActivity : AppCompatActivity() {
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
@@ -11,4 +18,36 @@ abstract class BaseActivity : AppCompatActivity() {
}
else -> super.onOptionsItemSelected(item)
}
-}
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ checkDarkMode()
+ }
+
+ private fun checkDarkMode() {
+ if (Utils.getDarkModeStatus(this)) {
+ if (this.javaClass.simpleName == "MainActivity") {
+ setTheme(R.style.AppThemeDark_NoActionBar)
+ } else {
+ setTheme(R.style.AppThemeDark)
+ }
+ } else {
+ if (this.javaClass.simpleName == "MainActivity") {
+ setTheme(R.style.AppThemeLight_NoActionBar)
+ } else {
+ setTheme(R.style.AppThemeLight)
+ }
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.N)
+ override fun attachBaseContext(newBase: Context?) {
+ val context = newBase?.let {
+ MyContextWrapper.wrap(newBase, Utils.getLocale(newBase))
+ }
+ super.attachBaseContext(context)
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/LogcatActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/LogcatActivity.kt
index 7128010f..08d76490 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/LogcatActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/LogcatActivity.kt
@@ -1,12 +1,13 @@
package com.v2ray.ang.ui
-import android.os.Bundle
import android.os.Handler
import android.os.Looper
+import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.Menu
import android.view.MenuItem
import android.view.View
+import androidx.lifecycle.lifecycleScope
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityLogcatBinding
@@ -15,6 +16,7 @@ import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
+
import java.io.IOException
import java.util.LinkedHashSet
@@ -23,9 +25,9 @@ class LogcatActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- binding = ActivityLogcatBinding.inflate(layoutInflater)
- val view = binding.root
- setContentView(view)
+ binding = ActivityLogcatBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
title = getString(R.string.title_logcat)
@@ -38,7 +40,7 @@ class LogcatActivity : BaseActivity() {
try {
binding.pbWaiting.visibility = View.VISIBLE
- GlobalScope.launch(Dispatchers.Default) {
+ lifecycleScope.launch(Dispatchers.Default) {
if (shouldFlushLog) {
val lst = LinkedHashSet()
lst.add("logcat")
@@ -81,7 +83,7 @@ class LogcatActivity : BaseActivity() {
toast(R.string.toast_success)
true
}
- R.id.delete -> {
+ R.id.clear_all -> {
logcat(true)
true
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
index c876fe3e..3a3e1e1c 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt
@@ -1,46 +1,47 @@
package com.v2ray.ang.ui
import android.Manifest
-import android.content.Intent
+import android.content.*
import android.net.Uri
import android.net.VpnService
-import android.os.Bundle
-import com.google.android.material.navigation.NavigationView
-import androidx.core.view.GravityCompat
-import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.ItemTouchHelper
-import android.text.TextUtils
-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.R
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.KeyEvent
+import com.v2ray.ang.AppConfig
+import android.content.res.ColorStateList
+import com.google.android.material.navigation.NavigationView
+import androidx.core.content.ContextCompat
+import androidx.core.view.GravityCompat
+import androidx.appcompat.app.ActionBarDrawerToggle
+import androidx.recyclerview.widget.ItemTouchHelper
+import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
-import com.tbruyelle.rxpermissions.RxPermissions
+import androidx.appcompat.app.AlertDialog
+import androidx.lifecycle.lifecycleScope
import com.tencent.mmkv.MMKV
-import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.BuildConfig
-import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityMainBinding
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.toast
-import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
-import com.v2ray.ang.service.V2RayServiceManager
-import com.v2ray.ang.util.AngConfigManager
-import com.v2ray.ang.util.MmkvManager
-import com.v2ray.ang.util.Utils
-import com.v2ray.ang.viewmodel.MainViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import libv2ray.Libv2ray
-import me.drakeet.support.toast.ToastCompat
import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
+import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
+import com.v2ray.ang.service.V2RayServiceManager
+import com.v2ray.ang.util.*
+import com.v2ray.ang.viewmodel.MainViewModel
+import kotlinx.coroutines.*
+import me.drakeet.support.toast.ToastCompat
+import java.io.File
+import java.io.FileOutputStream
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var binding: ActivityMainBinding
@@ -80,7 +81,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
binding.layoutTest.setOnClickListener {
if (mainViewModel.isRunning.value == true) {
- binding.tvTestState.text = getString(R.string.connection_test_testing)
+ setTestState(getString(R.string.connection_test_testing))
mainViewModel.testCurrentServerRealPing()
} else {
// tv_test_state.text = getString(R.string.connection_test_fail)
@@ -101,32 +102,31 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
binding.drawerLayout.addDrawerListener(toggle)
toggle.syncState()
binding.navView.setNavigationItemSelectedListener(this)
- binding.version.text = "v${BuildConfig.VERSION_NAME} (${Libv2ray.checkVersionX()})"
+ binding.version.text = "v${BuildConfig.VERSION_NAME} (${SpeedtestUtil.getLibVersion()})"
- setupViewModelObserver()
+ setupViewModel()
+ copyAssets()
migrateLegacy()
}
- private fun setupViewModelObserver() {
- mainViewModel.updateListAction.observe(this) {
- val index = it ?: return@observe
+ private fun setupViewModel() {
+ mainViewModel.updateListAction.observe(this) { index ->
if (index >= 0) {
adapter.notifyItemChanged(index)
} else {
adapter.notifyDataSetChanged()
}
}
- mainViewModel.updateTestResultAction.observe(this) { binding.tvTestState.text = it }
- mainViewModel.isRunning.observe(this) {
- val isRunning = it ?: return@observe
+ mainViewModel.updateTestResultAction.observe(this) { setTestState(it) }
+ mainViewModel.isRunning.observe(this) { isRunning ->
adapter.isRunning = isRunning
if (isRunning) {
- binding.fab.setImageResource(R.drawable.ic_v)
- binding.tvTestState.text = getString(R.string.connection_connected)
+ binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorSelected))
+ setTestState(getString(R.string.connection_connected))
binding.layoutTest.isFocusable = true
} else {
- binding.fab.setImageResource(R.drawable.ic_v_idle)
- binding.tvTestState.text = getString(R.string.connection_not_connected)
+ binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.colorUnselected))
+ setTestState(getString(R.string.connection_not_connected))
binding.layoutTest.isFocusable = false
}
hideCircle()
@@ -134,8 +134,31 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
mainViewModel.startListenBroadcast()
}
+ private fun copyAssets() {
+ val extFolder = Utils.userAssetPath(this)
+ lifecycleScope.launch(Dispatchers.IO) {
+ try {
+ val geo = arrayOf("geosite.dat", "geoip.dat")
+ assets.list("")
+ ?.filter { geo.contains(it) }
+ ?.filter { !File(extFolder, it).exists() }
+ ?.forEach {
+ val target = File(extFolder, it)
+ assets.open(it).use { input ->
+ FileOutputStream(target).use { output ->
+ input.copyTo(output)
+ }
+ }
+ Log.i(ANG_PACKAGE, "Copied from apk assets folder to ${target.absolutePath}")
+ }
+ } catch (e: Exception) {
+ Log.e(ANG_PACKAGE, "asset copy failed", e)
+ }
+ }
+ }
+
private fun migrateLegacy() {
- GlobalScope.launch(Dispatchers.IO) {
+ lifecycleScope.launch(Dispatchers.IO) {
val result = AngConfigManager.migrateLegacyConfig(this@MainActivity)
if (result != null) {
launch(Dispatchers.Main) {
@@ -160,6 +183,17 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
hideCircle()
}
+ fun restartV2Ray() {
+ if (mainViewModel.isRunning.value == true) {
+ Utils.stopVService(this)
+ }
+ Observable.timer(500, TimeUnit.MILLISECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ startV2Ray()
+ }
+ }
+
public override fun onResume() {
super.onResume()
mainViewModel.reloadServerList()
@@ -184,18 +218,23 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
true
}
R.id.import_manually_vmess -> {
- startActivity(Intent().putExtra("createConfigType", EConfigType.VMESS.value).
- setClass(this, ServerActivity::class.java))
+ importManually(EConfigType.VMESS.value)
+ true
+ }
+ R.id.import_manually_vless -> {
+ importManually(EConfigType.VLESS.value)
true
}
R.id.import_manually_ss -> {
- startActivity(Intent().putExtra("createConfigType", EConfigType.SHADOWSOCKS.value).
- setClass(this, ServerActivity::class.java))
+ importManually(EConfigType.SHADOWSOCKS.value)
true
}
R.id.import_manually_socks -> {
- startActivity(Intent().putExtra("createConfigType", EConfigType.SOCKS.value).
- setClass(this, ServerActivity::class.java))
+ importManually(EConfigType.SOCKS.value)
+ true
+ }
+ R.id.import_manually_trojan -> {
+ importManually(EConfigType.TROJAN.value)
true
}
R.id.import_config_custom_clipboard -> {
@@ -239,17 +278,56 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
true
}
-// R.id.settings -> {
-// startActivity("isRunning" to isRunning)
-// true
-// }
-// R.id.logcat -> {
-// startActivity()
-// true
-// }
+ R.id.real_ping_all -> {
+ mainViewModel.testAllRealPing()
+ true
+ }
+
+ R.id.service_restart -> {
+ restartV2Ray()
+ true
+ }
+
+ R.id.del_all_config -> {
+ AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ MmkvManager.removeAllServer()
+ mainViewModel.reloadServerList()
+ }
+ .show()
+ true
+ }
+
+ R.id.del_invalid_config -> {
+ AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ MmkvManager.removeInvalidServer()
+ mainViewModel.reloadServerList()
+ }
+ .show()
+ true
+ }
+ R.id.sort_by_test_results -> {
+ MmkvManager.sortByTestResults()
+ mainViewModel.reloadServerList()
+ true
+ }
+ R.id.filter_config -> {
+ mainViewModel.filterConfig(this)
+ true
+ }
+
else -> super.onOptionsItemSelected(item)
}
+ private fun importManually(createConfigType : Int) {
+ startActivity(
+ Intent()
+ .putExtra("createConfigType", createConfigType)
+ .putExtra("subscriptionId", mainViewModel.subscriptionId)
+ .setClass(this, ServerActivity::class.java)
+ )
+ }
/**
* import config from qrcode
@@ -303,9 +381,16 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
fun importBatchConfig(server: String?, subid: String = "") {
- var count = AngConfigManager.importBatchConfig(server, subid)
+ val subid2 = if(subid.isNullOrEmpty()){
+ mainViewModel.subscriptionId
+ }else{
+ subid
+ }
+ val append = subid.isNullOrEmpty()
+
+ var count = AngConfigManager.importBatchConfig(server, subid2, append)
if (count <= 0) {
- count = AngConfigManager.importBatchConfig(Utils.decode(server!!), subid)
+ count = AngConfigManager.importBatchConfig(Utils.decode(server!!), subid2, append)
}
if (count > 0) {
toast(R.string.toast_success)
@@ -368,7 +453,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
toast(R.string.toast_invalid_url)
return false
}
- GlobalScope.launch(Dispatchers.IO) {
+ lifecycleScope.launch(Dispatchers.IO) {
val configText = try {
Utils.getUrlContentWithCustomUserAgent(url)
} catch (e: Exception) {
@@ -400,12 +485,15 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
) {
return@forEach
}
+ if (!it.second.enabled) {
+ return@forEach
+ }
val url = it.second.url
if (!Utils.isValidUrl(url)) {
return@forEach
}
Log.d(ANG_PACKAGE, url)
- GlobalScope.launch(Dispatchers.IO) {
+ lifecycleScope.launch(Dispatchers.IO) {
val configText = try {
Utils.getUrlContentWithCustomUserAgent(url)
} catch (e: Exception) {
@@ -416,7 +504,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
return@launch
}
launch(Dispatchers.Main) {
- importBatchConfig(Utils.decode(configText), it.first)
+ importBatchConfig(configText, it.first)
}
}
}
@@ -437,7 +525,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
try {
chooseFileForCustomConfig.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
- } catch (ex: android.content.ActivityNotFoundException) {
+ } catch (ex: ActivityNotFoundException) {
toast(R.string.toast_require_file_manager)
}
}
@@ -479,8 +567,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
return
}
mainViewModel.appendCustomConfigServer(server)
+ mainViewModel.reloadServerList()
toast(R.string.toast_success)
- adapter.notifyItemInserted(mainViewModel.serverList.lastIndex)
+ //adapter.notifyItemInserted(mainViewModel.serverList.lastIndex)
} catch (e: Exception) {
ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show()
e.printStackTrace()
@@ -488,6 +577,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
}
+ fun setTestState(content: String?) {
+ binding.tvTestState.text = content
+ }
+
// val mConnection = object : ServiceConnection {
// override fun onServiceDisconnected(name: ComponentName?) {
// }
@@ -514,11 +607,16 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
Observable.timer(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
- if (binding.fabProgressCircle.isShown) {
- binding.fabProgressCircle.hide()
+ try {
+ if (binding.fabProgressCircle.isShown) {
+ binding.fabProgressCircle.hide()
+ }
+ } catch (e: Exception) {
+ Log.w(ANG_PACKAGE, e)
}
}
} catch (e: Exception) {
+ Log.d(ANG_PACKAGE, e.toString())
}
}
@@ -541,14 +639,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
startActivity(Intent(this, SettingsActivity::class.java)
.putExtra("isRunning", mainViewModel.isRunning.value == true))
}
+ R.id.user_asset_setting -> {
+ startActivity(Intent(this, UserAssetActivity::class.java))
+ }
R.id.feedback -> {
Utils.openUri(this, AppConfig.v2rayNGIssues)
}
R.id.promotion -> {
- Utils.openUri(this, AppConfig.promotionUrl)
- }
- R.id.donate -> {
-// startActivity()
+ Utils.openUri(this, "${Utils.decode(AppConfig.promotionUrl)}?t=${System.currentTimeMillis()}")
}
R.id.logcat -> {
startActivity(Intent(this, LogcatActivity::class.java))
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt
index 92e5c681..b3f2f80d 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt
@@ -3,11 +3,11 @@ package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.Color
import androidx.core.content.ContextCompat
-import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.appcompat.app.AlertDialog
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
@@ -38,29 +38,43 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter by lazy {
mActivity.resources.getStringArray(R.array.share_method)
}
var isRunning = false
- override fun getItemCount() = mActivity.mainViewModel.serverList.size + 1
+ override fun getItemCount() = mActivity.mainViewModel.serversCache.size + 1
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
if (holder is MainViewHolder) {
- val guid = mActivity.mainViewModel.serverList.getOrNull(position) ?: return
- val config = mActivity.mainViewModel.serversCache.getOrElse(guid) { MmkvManager.decodeServerConfig(guid) } ?: return
+ val guid = mActivity.mainViewModel.serversCache[position].guid
+ val config = mActivity.mainViewModel.serversCache[position].config
+// //filter
+// if (mActivity.mainViewModel.subscriptionId.isNotEmpty()
+// && mActivity.mainViewModel.subscriptionId != config.subscriptionId
+// ) {
+// holder.itemMainBinding.cardView.visibility = View.GONE
+// } else {
+// holder.itemMainBinding.cardView.visibility = View.VISIBLE
+// }
+
val outbound = config.getProxyOutbound()
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
holder.itemMainBinding.tvName.text = config.remarks
- holder.itemMainBinding.btnRadio.isChecked = guid == mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
holder.itemMainBinding.tvTestResult.text = aff?.getTestDelayString() ?: ""
- if (aff?.testDelayMillis?:0L < 0L) {
- holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, android.R.color.holo_red_dark))
+ if ((aff?.testDelayMillis ?: 0L) < 0L) {
+ holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, R.color.colorPingRed))
} else {
holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, R.color.colorPing))
}
+ if (guid == mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)) {
+ holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorSelected)
+ } else {
+ holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorUnselected)
+ }
holder.itemMainBinding.tvSubscription.text = ""
val json = subStorage?.decodeString(config.subscriptionId)
if (!json.isNullOrBlank()) {
@@ -123,9 +137,15 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter
+ removeServer(guid, position)
+ }
+ .show()
+ } else {
+ removeServer(guid, position)
+ }
}
}
@@ -133,8 +153,8 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter
@@ -178,7 +204,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter threshold) {
+ header_view.hide()
+ dst = 0
+ } else if (dst < -20) {
+ header_view.show()
+ dst = 0
+ }
+ }
- binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
- var dst = 0
- val threshold = resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 3
- override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
- dst += dy
- if (dst > threshold) {
- binding.headerView.hide()
- dst = 0
- } else if (dst < -20) {
- binding.headerView.show()
- dst = 0
- }
- }
-
- var hiding = false
- fun View.hide() {
- val target = -height.toFloat()
- if (hiding || translationY == target) return
- animate()
- .translationY(target)
- .setInterpolator(AccelerateInterpolator(2F))
- .setListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- hiding = false
- }
- })
- hiding = true
- }
-
- var showing = false
- fun View.show() {
- val target = 0f
- if (showing || translationY == target) return
- animate()
- .translationY(target)
- .setInterpolator(DecelerateInterpolator(2F))
- .setListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- showing = false
- }
- })
- showing = true
- }
+ var hiding = false
+ fun View.hide() {
+ val target = -height.toFloat()
+ if (hiding || translationY == target) return
+ animate()
+ .translationY(target)
+ .setInterpolator(AccelerateInterpolator(2F))
+ .setListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ hiding = false
+ }
})
+ hiding = true
+ }
+
+ var showing = false
+ fun View.show() {
+ val target = 0f
+ if (showing || translationY == target) return
+ animate()
+ .translationY(target)
+ .setInterpolator(DecelerateInterpolator(2F))
+ .setListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ showing = false
+ }
+ })
+ showing = true
+ }
+ })
+ ***/
binding.switchPerAppProxy.setOnCheckedChangeListener { _, isChecked ->
defaultSharedPreferences.edit().putBoolean(AppConfig.PREF_PER_APP_PROXY, isChecked).apply()
@@ -152,33 +146,35 @@ class PerAppProxyActivity : BaseActivity() {
}
binding.switchBypassApps.isChecked = defaultSharedPreferences.getBoolean(AppConfig.PREF_BYPASS_APPS, false)
- binding.etSearch.setOnEditorActionListener { v, actionId, _ ->
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- //hide
- var imm: InputMethodManager = v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
- imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
+ /***
+ et_search.setOnEditorActionListener { v, actionId, event ->
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ //hide
+ var imm: InputMethodManager = v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS)
- val key = v.text.toString().uppercase()
- val apps = ArrayList()
- if (TextUtils.isEmpty(key)) {
- appsAll?.forEach {
- apps.add(it)
- }
- } else {
- appsAll?.forEach {
- if (it.appName.uppercase().indexOf(key) >= 0) {
- apps.add(it)
- }
- }
- }
- adapter = PerAppProxyAdapter(this, apps, adapter?.blacklist)
- binding.recyclerView.adapter = adapter
- adapter?.notifyDataSetChanged()
- true
- } else {
- false
- }
+ val key = v.text.toString().toUpperCase()
+ val apps = ArrayList()
+ if (TextUtils.isEmpty(key)) {
+ appsAll?.forEach {
+ apps.add(it)
}
+ } else {
+ appsAll?.forEach {
+ if (it.appName.toUpperCase().indexOf(key) >= 0) {
+ apps.add(it)
+ }
+ }
+ }
+ adapter = PerAppProxyAdapter(this, apps, adapter?.blacklist)
+ recycler_view.adapter = adapter
+ adapter?.notifyDataSetChanged()
+ true
+ } else {
+ false
+ }
+ }
+ ***/
}
override fun onPause() {
@@ -190,6 +186,23 @@ class PerAppProxyActivity : BaseActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_bypass_list, menu)
+
+ val searchItem = menu.findItem(R.id.search_view)
+ if (searchItem != null) {
+ val searchView = searchItem.actionView as SearchView
+ searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String?): Boolean {
+ return false
+ }
+
+ override fun onQueryTextChange(newText: String?): Boolean {
+ filterProxyApp(newText!!)
+ return false
+ }
+ })
+ }
+
+
return super.onCreateOptionsMenu(menu)
}
@@ -206,14 +219,20 @@ class PerAppProxyActivity : BaseActivity() {
val packageName = it.packageName
adapter?.blacklist!!.add(packageName)
}
-
}
it.notifyDataSetChanged()
true
} ?: false
R.id.select_proxy_app -> {
selectProxyApp()
-
+ true
+ }
+ R.id.import_proxy_app -> {
+ importProxyApp()
+ true
+ }
+ R.id.export_proxy_app -> {
+ exportProxyApp()
true
}
else -> super.onOptionsItemSelected(item)
@@ -222,27 +241,41 @@ class PerAppProxyActivity : BaseActivity() {
private fun selectProxyApp() {
toast(R.string.msg_downloading_content)
val url = AppConfig.androidpackagenamelistUrl
- GlobalScope.launch(Dispatchers.IO) {
- val content = try {
- URL(url).readText()
- } catch (e: Exception) {
- e.printStackTrace()
- ""
- }
+ lifecycleScope.launch(Dispatchers.IO) {
+ val content = Utils.getUrlContext(url, 5000)
launch(Dispatchers.Main) {
Log.d(ANG_PACKAGE, content)
- selectProxyApp(content)
+ selectProxyApp(content, true)
toast(R.string.toast_success)
}
}
}
- private fun selectProxyApp(content: String): Boolean {
+ private fun importProxyApp() {
+ val content = Utils.getClipboard(applicationContext)
+ if (TextUtils.isEmpty(content)) {
+ return
+ }
+ selectProxyApp(content, false)
+ toast(R.string.toast_success)
+ }
+
+ private fun exportProxyApp() {
+ var lst = binding.switchBypassApps.isChecked.toString()
+
+ adapter?.blacklist?.forEach block@{
+ lst = lst + System.getProperty("line.separator") + it
+ }
+ Utils.setClipboard(applicationContext, lst)
+ toast(R.string.toast_success)
+ }
+
+ private fun selectProxyApp(content: String, force: Boolean): Boolean {
try {
- var proxyApps = content
- if (TextUtils.isEmpty(content)) {
- val assets = Utils.readTextFromAssets(v2RayApplication, "proxy_packagename.txt")
- proxyApps = assets.lines().toString()
+ val proxyApps = if (TextUtils.isEmpty(content)) {
+ Utils.readTextFromAssets(v2RayApplication, "proxy_packagename.txt")
+ } else {
+ content
}
if (TextUtils.isEmpty(proxyApps)) {
return false
@@ -255,7 +288,7 @@ class PerAppProxyActivity : BaseActivity() {
it.apps.forEach block@{
val packageName = it.packageName
Log.d(ANG_PACKAGE, packageName)
- if (proxyApps.indexOf(packageName) < 0) {
+ if (!inProxyApps(proxyApps, packageName, force)) {
adapter?.blacklist!!.add(packageName)
println(packageName)
return@block
@@ -268,7 +301,7 @@ class PerAppProxyActivity : BaseActivity() {
it.apps.forEach block@{
val packageName = it.packageName
Log.d(ANG_PACKAGE, packageName)
- if (proxyApps.indexOf(packageName) >= 0) {
+ if (inProxyApps(proxyApps, packageName, force)) {
adapter?.blacklist!!.add(packageName)
println(packageName)
return@block
@@ -283,4 +316,40 @@ class PerAppProxyActivity : BaseActivity() {
}
return true
}
+
+ private fun inProxyApps(proxyApps: String, packageName: String, force: Boolean): Boolean {
+ if (force) {
+ if (packageName == "com.google.android.webview") {
+ return false
+ }
+ if (packageName.startsWith("com.google")) {
+ return true
+ }
+ }
+
+ return proxyApps.indexOf(packageName) >= 0
+ }
+
+ private fun filterProxyApp(content: String): Boolean {
+ val apps = ArrayList()
+
+ val key = content.uppercase()
+ if (key.isNotEmpty()) {
+ appsAll?.forEach {
+ if (it.appName.uppercase().indexOf(key) >= 0
+ || it.packageName.uppercase().indexOf(key) >= 0) {
+ apps.add(it)
+ }
+ }
+ } else {
+ appsAll?.forEach {
+ apps.add(it)
+ }
+ }
+
+ adapter = PerAppProxyAdapter(this, apps, adapter?.blacklist)
+ binding.recyclerView.adapter = adapter
+ adapter?.notifyDataSetChanged()
+ return true
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/PerAppProxyAdapter.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/PerAppProxyAdapter.kt
index ec7e1242..040e9b9c 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/PerAppProxyAdapter.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/PerAppProxyAdapter.kt
@@ -1,8 +1,7 @@
package com.v2ray.ang.ui
-import android.graphics.Color
-import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
+import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import com.v2ray.ang.R
@@ -36,7 +35,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List, bl
VIEW_TYPE_HEADER -> {
val view = View(ctx)
view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 3)
+ ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0)
BaseViewHolder(view)
}
// VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
@@ -66,10 +65,10 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List, bl
itemBypassBinding.packageName.text = appInfo.packageName
if (appInfo.isSystemApp) {
itemBypassBinding.name.text = String.format("** %1s", appInfo.appName)
- itemBypassBinding.name.setTextColor(Color.RED)
+ //name.textColor = Color.RED
} else {
itemBypassBinding.name.text = appInfo.appName
- itemBypassBinding.name.setTextColor(Color.DKGRAY)
+ //name.textColor = Color.DKGRAY
}
itemView.setOnClickListener(this)
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
index dc681fdc..030e80ff 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsActivity.kt
@@ -1,6 +1,5 @@
package com.v2ray.ang.ui
-import android.graphics.Color
import android.os.Bundle
import com.v2ray.ang.R
import androidx.fragment.app.Fragment
@@ -21,7 +20,7 @@ class RoutingSettingsActivity : BaseActivity() {
val view = binding.root
setContentView(view)
- title = getString(R.string.routing_settings_title)
+ title = getString(R.string.title_pref_routing_custom)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val fragments = ArrayList()
@@ -31,7 +30,7 @@ class RoutingSettingsActivity : BaseActivity() {
val adapter = FragmentAdapter(this, fragments)
binding.viewpager.adapter = adapter
- binding.tablayout.setTabTextColors(Color.BLACK, Color.RED)
+ //tablayout.setTabTextColors(Color.BLACK, Color.RED)
TabLayoutMediator(binding.tablayout, binding.viewpager) { tab, position ->
tab.text = titles[position]
}.attach()
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
index 7283537e..f5a8e395 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingsFragment.kt
@@ -5,11 +5,11 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
-import androidx.fragment.app.Fragment
-import androidx.preference.PreferenceManager
import android.view.*
-import android.view.MenuInflater
import androidx.activity.result.contract.ActivityResultContracts
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.preference.PreferenceManager
import com.tbruyelle.rxpermissions.RxPermissions
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
@@ -20,7 +20,6 @@ import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
-import java.net.URL
class RoutingSettingsFragment : Fragment() {
private lateinit var binding: FragmentRoutingSettingsBinding
@@ -61,9 +60,7 @@ class RoutingSettingsFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.save_routing -> {
- val content = binding.etRoutingContent.text.toString()
- defaultSharedPreferences.edit().putString(requireArguments().getString(routing_arg), content).apply()
- activity?.toast(R.string.toast_success)
+ saveRouting()
true
}
R.id.del_routing -> {
@@ -128,26 +125,23 @@ class RoutingSettingsFragment : Fragment() {
fun setDefaultRules(): Boolean {
var url = AppConfig.v2rayCustomRoutingListUrl
+ var tag = ""
when (requireArguments().getString(routing_arg)) {
AppConfig.PREF_V2RAY_ROUTING_AGENT -> {
- url += AppConfig.TAG_AGENT
+ tag = AppConfig.TAG_AGENT
}
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
- url += AppConfig.TAG_DIRECT
+ tag = AppConfig.TAG_DIRECT
}
AppConfig.PREF_V2RAY_ROUTING_BLOCKED -> {
- url += AppConfig.TAG_BLOCKED
+ tag = AppConfig.TAG_BLOCKED
}
}
+ url += tag
activity?.toast(R.string.msg_downloading_content)
- GlobalScope.launch(Dispatchers.IO) {
- val content = try {
- URL(url).readText()
- } catch (e: Exception) {
- e.printStackTrace()
- ""
- }
+ lifecycleScope.launch(Dispatchers.IO) {
+ val content = Utils.getUrlContext(url, 5000)
launch(Dispatchers.Main) {
val routingList = if (TextUtils.isEmpty(content)) {
Utils.readTextFromAssets(activity?.v2RayApplication!!, "custom_routing_$tag")
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScScannerActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScScannerActivity.kt
index c0e6563d..da1cb7cd 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScScannerActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScScannerActivity.kt
@@ -32,7 +32,7 @@ class ScScannerActivity : BaseActivity() {
private val scanQRCode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
- val count = AngConfigManager.importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"), "")
+ val count = AngConfigManager.importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"), "", false)
if (count > 0) {
toast(R.string.toast_success)
} else {
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScannerActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScannerActivity.kt
index e4982d83..bc3785ec 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScannerActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ScannerActivity.kt
@@ -106,7 +106,7 @@ class ScannerActivity : BaseActivity(), ZXingScannerView.ResultHandler {
try {
val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
val text = QRCodeDecoder.syncDecodeQRCode(bitmap)
- finished(text)
+ finished(text!!)
} catch (e: Exception) {
e.printStackTrace()
toast(e.message.toString())
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt
index 3abcee52..6f44a090 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt
@@ -1,17 +1,20 @@
package com.v2ray.ang.ui
import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.*
+import androidx.appcompat.app.AlertDialog
import com.tencent.mmkv.MMKV
+import com.v2ray.ang.AppConfig
+import com.v2ray.ang.AppConfig.PREF_ALLOW_INSECURE
import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
+import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_FLOW
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_PORT
import com.v2ray.ang.dto.V2rayConfig.Companion.XTLS
import com.v2ray.ang.extension.toast
@@ -33,6 +36,10 @@ class ServerActivity : BaseActivity() {
private val createConfigType by lazy {
EConfigType.fromInt(intent.getIntExtra("createConfigType", EConfigType.VMESS.value)) ?: EConfigType.VMESS
}
+ private val subscriptionId by lazy {
+ intent.getStringExtra("subscriptionId")
+ }
+
private val securitys: Array by lazy {
resources.getStringArray(R.array.securitys)
}
@@ -68,13 +75,13 @@ class ServerActivity : BaseActivity() {
private val et_address: EditText by lazy { findViewById(R.id.et_address) }
private val et_port: EditText by lazy { findViewById(R.id.et_port) }
private val et_id: EditText by lazy { findViewById(R.id.et_id) }
- //private val et_alterId: EditText? by lazy { findViewById(R.id.et_alterId) }
+ private val et_alterId: EditText? by lazy { findViewById(R.id.et_alterId) }
private val et_security: EditText? by lazy { findViewById(R.id.et_security) }
- //private val sp_flow: Spinner? by lazy { findViewById(R.id.sp_flow) }
+ private val sp_flow: Spinner? by lazy { findViewById(R.id.sp_flow) }
private val sp_security: Spinner? by lazy { findViewById(R.id.sp_security) }
private val sp_stream_security: Spinner? by lazy { findViewById(R.id.sp_stream_security) }
private val sp_allow_insecure: Spinner? by lazy { findViewById(R.id.sp_allow_insecure) }
- //private val et_sni: EditText? by lazy { findViewById(R.id.et_sni) }
+ private val et_sni: EditText? by lazy { findViewById(R.id.et_sni) }
private val sp_network: Spinner? by lazy { findViewById(R.id.sp_network) }
private val sp_header_type: Spinner? by lazy { findViewById(R.id.sp_header_type) }
private val sp_header_type_title: TextView? by lazy { findViewById(R.id.sp_header_type_title) }
@@ -91,8 +98,8 @@ class ServerActivity : BaseActivity() {
EConfigType.CUSTOM -> return
EConfigType.SHADOWSOCKS -> setContentView(R.layout.activity_server_shadowsocks)
EConfigType.SOCKS -> setContentView(R.layout.activity_server_socks)
-// EConfigType.VLESS -> setContentView(R.layout.activity_server_vless)
-// EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan)
+ EConfigType.VLESS -> setContentView(R.layout.activity_server_vless)
+ EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan)
}
sp_network?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
@@ -133,13 +140,19 @@ class ServerActivity : BaseActivity() {
et_address.text = Utils.getEditable(outbound.getServerAddress().orEmpty())
et_port.text = Utils.getEditable(outbound.getServerPort()?.toString() ?: DEFAULT_PORT.toString())
et_id.text = Utils.getEditable(outbound.getPassword().orEmpty())
+ et_alterId?.text = Utils.getEditable(outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString())
if (config.configType == EConfigType.SOCKS) {
et_security?.text = Utils.getEditable(outbound.settings?.servers?.get(0)?.users?.get(0)?.user.orEmpty())
} else if (config.configType == EConfigType.VLESS) {
et_security?.text = Utils.getEditable(outbound.getSecurityEncryption().orEmpty())
val flow = Utils.arrayFind(flows, outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow.orEmpty())
if (flow >= 0) {
- //sp_flow.setSelection(flow)
+ sp_flow?.setSelection(flow)
+ }
+ } else if (config.configType == EConfigType.TROJAN) {
+ val flow = Utils.arrayFind(flows, outbound.settings?.servers?.get(0)?.flow.orEmpty())
+ if (flow >= 0) {
+ sp_flow?.setSelection(flow)
}
}
val securityEncryptions = if (config.configType == EConfigType.SHADOWSOCKS) shadowsocksSecuritys else securitys
@@ -156,7 +169,7 @@ class ServerActivity : BaseActivity() {
if (allowinsecure >= 0) {
sp_allow_insecure?.setSelection(allowinsecure)
}
- et_request_host?.text = Utils.getEditable(tlsSetting.serverName)
+ et_sni?.text = Utils.getEditable(tlsSetting.serverName)
}
}
val network = Utils.arrayFind(networks, streamSetting.network)
@@ -174,6 +187,7 @@ class ServerActivity : BaseActivity() {
et_address.text = null
et_port.text = Utils.getEditable(DEFAULT_PORT.toString())
et_id.text = null
+ et_alterId?.text = Utils.getEditable("0")
sp_security?.setSelection(0)
sp_network?.setSelection(0)
@@ -182,9 +196,10 @@ class ServerActivity : BaseActivity() {
et_path?.text = null
sp_stream_security?.setSelection(0)
sp_allow_insecure?.setSelection(0)
+ et_sni?.text = null
//et_security.text = null
- //sp_flow?.setSelection(0)
+ sp_flow?.setSelection(0)
return true
}
@@ -210,6 +225,19 @@ class ServerActivity : BaseActivity() {
toast(R.string.server_lab_id)
return false
}
+ sp_stream_security?.let {
+ if (config.configType == EConfigType.TROJAN && TextUtils.isEmpty(streamSecuritys[it.selectedItemPosition])) {
+ toast(R.string.server_lab_stream_security)
+ return false
+ }
+ }
+ et_alterId?.let {
+ val alterId = Utils.parseInt(it.text.toString())
+ if (alterId < 0) {
+ toast(R.string.server_lab_alterid)
+ return false
+ }
+ }
config.remarks = et_remarks.text.toString().trim()
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
@@ -221,6 +249,9 @@ class ServerActivity : BaseActivity() {
config.outboundBean?.streamSettings?.let {
saveStreamSettings(it)
}
+ if(config.subscriptionId.isEmpty() && !subscriptionId.isNullOrEmpty()) {
+ config.subscriptionId = subscriptionId!!
+ }
MmkvManager.encodeServerConfig(editGuid, config)
toast(R.string.toast_success)
@@ -233,11 +264,12 @@ class ServerActivity : BaseActivity() {
vnext.port = port
vnext.users[0].id = et_id.text.toString().trim()
if (config.configType == EConfigType.VMESS) {
+ vnext.users[0].alterId = Utils.parseInt(et_alterId?.text.toString())
vnext.users[0].security = securitys[sp_security?.selectedItemPosition ?: 0]
} else if (config.configType == EConfigType.VLESS) {
vnext.users[0].encryption = et_security?.text.toString().trim()
if (streamSecuritys[sp_stream_security?.selectedItemPosition ?: 0] == XTLS) {
-// vnext.users[0].flow = flows[sp_flow.selectedItemPosition].ifBlank { V2rayConfig.DEFAULT_FLOW }
+ vnext.users[0].flow = flows[sp_flow?.selectedItemPosition ?: 0].ifBlank { DEFAULT_FLOW }
} else {
vnext.users[0].flow = ""
}
@@ -261,6 +293,12 @@ class ServerActivity : BaseActivity() {
}
} else if (config.configType == EConfigType.TROJAN) {
server.password = et_id.text.toString().trim()
+ server.flow =
+ if (streamSecuritys[sp_stream_security?.selectedItemPosition ?: 0] == XTLS) {
+ flows[sp_flow?.selectedItemPosition ?: 0].ifBlank { DEFAULT_FLOW }
+ } else {
+ ""
+ }
}
}
@@ -269,7 +307,7 @@ class ServerActivity : BaseActivity() {
val type = sp_header_type?.selectedItemPosition ?: return
val requestHost = et_request_host?.text?.toString()?.trim() ?: return
val path = et_path?.text?.toString()?.trim() ?: return
- //val sniField = et_sni?.text?.toString()?.trim() ?: return
+ val sniField = et_sni?.text?.toString()?.trim() ?: return
val allowInsecureField = sp_allow_insecure?.selectedItemPosition ?: return
val streamSecurity = sp_stream_security?.selectedItemPosition ?: return
@@ -284,16 +322,15 @@ class ServerActivity : BaseActivity() {
mode = transportTypes(networks[network])[type],
serviceName = path
)
- //if (sniField.isNotBlank()) {
- // sni = sniField
- //}
+ if (sniField.isNotBlank()) {
+ sni = sniField
+ }
val allowInsecure = if (allowinsecures[allowInsecureField].isBlank()) {
- false//settingsStorage?.decodeBool(PREF_ALLOW_INSECURE) ?: false
+ settingsStorage?.decodeBool(PREF_ALLOW_INSECURE) ?: false
} else {
allowinsecures[allowInsecureField].toBoolean()
}
streamSetting.populateTlsSettings(streamSecuritys[streamSecurity], allowInsecure, sni)
-
}
private fun transportTypes(network: String?): Array {
@@ -313,12 +350,19 @@ class ServerActivity : BaseActivity() {
*/
private fun deleteServer(): Boolean {
if (editGuid.isNotEmpty()) {
- AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
- .setPositiveButton(android.R.string.ok) { _, _ ->
- MmkvManager.removeServer(editGuid)
- finish()
- }
- .show()
+ if (editGuid != mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)) {
+ if (settingsStorage?.decodeBool(AppConfig.PREF_CONFIRM_REMOVE) == true) {
+ AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
+ .setPositiveButton(android.R.string.ok) { _, _ ->
+ MmkvManager.removeServer(editGuid)
+ finish()
+ }
+ .show()
+ } else {
+ MmkvManager.removeServer(editGuid)
+ finish()
+ }
+ }
}
return true
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt
index a38c1783..c8138915 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt
@@ -7,7 +7,7 @@ import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import com.blacksquircle.ui.language.json.JsonLanguage
-import com.google.gson.Gson
+import com.google.gson.*
import com.tencent.mmkv.MMKV
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityServerCustomConfigBinding
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
index c32d74cc..5284cc64 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt
@@ -2,14 +2,12 @@ package com.v2ray.ang.ui
import android.content.Intent
import android.os.Bundle
-import androidx.preference.*
import android.text.TextUtils
import android.view.View
import androidx.activity.viewModels
-import com.v2ray.ang.R
+import androidx.preference.*
import com.v2ray.ang.AppConfig
-import com.v2ray.ang.extension.toast
-import com.v2ray.ang.service.V2RayServiceManager
+import com.v2ray.ang.R
import com.v2ray.ang.util.Utils
import com.v2ray.ang.viewmodel.SettingsViewModel
@@ -28,146 +26,31 @@ class SettingsActivity : BaseActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
- private val perAppProxy by lazy { findPreference(AppConfig.PREF_PER_APP_PROXY) as CheckBoxPreference }
- private val localDns by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_ENABLED) }
- private val fakeDns by lazy { findPreference(AppConfig.PREF_FAKE_DNS_ENABLED) }
- private val localDnsPort by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_PORT) }
- private val vpnDns by lazy { findPreference(AppConfig.PREF_VPN_DNS) }
- private val sppedEnabled by lazy { findPreference(AppConfig.PREF_SPEED_ENABLED) as CheckBoxPreference }
- private val sniffingEnabled by lazy { findPreference(AppConfig.PREF_SNIFFING_ENABLED) as CheckBoxPreference }
- private val proxySharing by lazy { findPreference(AppConfig.PREF_PROXY_SHARING) as CheckBoxPreference }
- private val domainStrategy by lazy { findPreference(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY) as ListPreference }
- private val routingMode by lazy { findPreference(AppConfig.PREF_ROUTING_MODE) as ListPreference }
-
- private val forwardIpv6 by lazy { findPreference(AppConfig.PREF_FORWARD_IPV6) as CheckBoxPreference }
- private val enableLocalDns by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_ENABLED) as CheckBoxPreference }
- private val domesticDns by lazy { findPreference(AppConfig.PREF_DOMESTIC_DNS) as EditTextPreference }
- private val remoteDns by lazy { findPreference(AppConfig.PREF_REMOTE_DNS) as EditTextPreference }
-
+ private val perAppProxy by lazy { findPreference(AppConfig.PREF_PER_APP_PROXY) }
+ private val localDns by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_ENABLED) }
+ private val fakeDns by lazy { findPreference(AppConfig.PREF_FAKE_DNS_ENABLED) }
+ private val localDnsPort by lazy { findPreference(AppConfig.PREF_LOCAL_DNS_PORT) }
+ private val vpnDns by lazy { findPreference(AppConfig.PREF_VPN_DNS) }
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
-
-
-// val socksPort by lazy { findPreference(PREF_SOCKS_PORT) as EditTextPreference }
-// val httpPort by lazy { findPreference(PREF_HTTP_PORT) as EditTextPreference }
-
- private val routingCustom: Preference by lazy { findPreference(AppConfig.PREF_ROUTING_CUSTOM) }
-// val donate: Preference by lazy { findPreference(PREF_DONATE) }
+ private val remoteDns by lazy { findPreference(AppConfig.PREF_REMOTE_DNS) }
+ private val domesticDns by lazy { findPreference(AppConfig.PREF_DOMESTIC_DNS) }
+ private val socksPort by lazy { findPreference(AppConfig.PREF_SOCKS_PORT) }
+ private val httpPort by lazy { findPreference(AppConfig.PREF_HTTP_PORT) }
+ private val routingCustom by lazy { findPreference(AppConfig.PREF_ROUTING_CUSTOM) }
// val licenses: Preference by lazy { findPreference(PREF_LICENSES) }
// val feedback: Preference by lazy { findPreference(PREF_FEEDBACK) }
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
- private val mode by lazy { findPreference(AppConfig.PREF_MODE) as ListPreference }
-
- private fun restartProxy() {
- Utils.stopVService(requireContext())
- V2RayServiceManager.startV2Ray(requireContext())
- }
-
- private fun isRunning(): Boolean {
- return false //TODO no point of adding logic now since Settings will be changed soon
- }
+ private val mode by lazy { findPreference(AppConfig.PREF_MODE) }
override fun onCreatePreferences(bundle: Bundle?, s: String?) {
addPreferencesFromResource(R.xml.pref_settings)
- perAppProxy.setOnPreferenceClickListener {
- if (isRunning()) {
- Utils.stopVService(requireContext())
- }
- startActivity(Intent(activity, PerAppProxyActivity::class.java))
- perAppProxy.isChecked = true
- true
- }
- sppedEnabled.setOnPreferenceClickListener {
- if (isRunning())
- restartProxy()
- true
- }
- sniffingEnabled.setOnPreferenceClickListener {
- if (isRunning())
- restartProxy()
- true
- }
-
- proxySharing.setOnPreferenceClickListener {
- if (proxySharing.isChecked)
- activity?.toast(R.string.toast_warning_pref_proxysharing)
- if (isRunning())
- restartProxy()
- true
- }
-
- domainStrategy.setOnPreferenceChangeListener { _, _ ->
- if (isRunning())
- restartProxy()
- true
- }
- routingMode.setOnPreferenceChangeListener { _, _ ->
- if (isRunning())
- restartProxy()
- true
- }
-
- routingCustom.setOnPreferenceClickListener {
- if (isRunning())
- Utils.stopVService(requireContext())
+ routingCustom?.setOnPreferenceClickListener {
startActivity(Intent(activity, RoutingSettingsActivity::class.java))
false
}
- forwardIpv6.setOnPreferenceClickListener {
- if (isRunning())
- restartProxy()
- true
- }
-
- enableLocalDns.setOnPreferenceClickListener {
- if (isRunning())
- restartProxy()
- true
- }
-
-
- domesticDns.setOnPreferenceChangeListener { _, any ->
- // domesticDns.summary = any as String
- val nval = any as String
- domesticDns.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
- if (isRunning())
- restartProxy()
- true
- }
-
- remoteDns.setOnPreferenceChangeListener { _, any ->
- // remoteDns.summary = any as String
- val nval = any as String
- remoteDns.summary = if (nval == "") AppConfig.DNS_AGENT else nval
- if (isRunning())
- restartProxy()
- true
- }
- localDns?.setOnPreferenceChangeListener{ _, any ->
- updateLocalDns(any as Boolean)
- true
- }
- localDnsPort?.setOnPreferenceChangeListener { _, any ->
- val nval = any as String
- localDnsPort?.summary = if (TextUtils.isEmpty(nval)) "10807" else nval
- true
- }
- vpnDns?.setOnPreferenceChangeListener { _, any ->
- vpnDns?.summary = any as String
- true
- }
- mode.setOnPreferenceChangeListener { _, newValue ->
- updateMode(newValue.toString())
- true
- }
- mode.dialogLayoutResource = R.layout.preference_with_help_link
-
-// donate.onClick {
-// startActivity()
-// }
-
// licenses.onClick {
// val fragment = LicensesDialogFragment.Builder(act)
// .setNotices(R.raw.licenses)
@@ -190,15 +73,54 @@ class SettingsActivity : BaseActivity() {
// }
// }
+ perAppProxy?.setOnPreferenceClickListener {
+ startActivity(Intent(activity, PerAppProxyActivity::class.java))
+ perAppProxy?.isChecked = true
+ false
+ }
-// socksPort.setOnPreferenceChangeListener { preference, any ->
-// socksPort.summary = any as String
-// true
-// }
-// httpPort.setOnPreferenceChangeListener { preference, any ->
-// httpPort.summary = any as String
-// true
-// }
+ remoteDns?.setOnPreferenceChangeListener { _, any ->
+ // remoteDns.summary = any as String
+ val nval = any as String
+ remoteDns?.summary = if (nval == "") AppConfig.DNS_AGENT else nval
+ true
+ }
+ domesticDns?.setOnPreferenceChangeListener { _, any ->
+ // domesticDns.summary = any as String
+ val nval = any as String
+ domesticDns?.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
+ true
+ }
+
+ localDns?.setOnPreferenceChangeListener{ _, any ->
+ updateLocalDns(any as Boolean)
+ true
+ }
+ localDnsPort?.setOnPreferenceChangeListener { _, any ->
+ val nval = any as String
+ localDnsPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_LOCAL_DNS else nval
+ true
+ }
+ vpnDns?.setOnPreferenceChangeListener { _, any ->
+ vpnDns?.summary = any as String
+ true
+ }
+ socksPort?.setOnPreferenceChangeListener { _, any ->
+ val nval = any as String
+ socksPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_SOCKS else nval
+ true
+ }
+ httpPort?.setOnPreferenceChangeListener { _, any ->
+ val nval = any as String
+ httpPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_HTTP else nval
+ true
+ }
+ mode?.setOnPreferenceChangeListener { _, newValue ->
+ updateMode(newValue.toString())
+ true
+ }
+ mode?.dialogLayoutResource = R.layout.preference_with_help_link
+ //loglevel.summary = "LogLevel"
}
override fun onStart() {
@@ -206,26 +128,37 @@ class SettingsActivity : BaseActivity() {
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
updateMode(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN"))
var remoteDnsString = defaultSharedPreferences.getString(AppConfig.PREF_REMOTE_DNS, "")
- domesticDns.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "")
+ domesticDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "")
+
+ localDnsPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
+ socksPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
+ httpPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_HTTP_PORT, AppConfig.PORT_HTTP)
if (TextUtils.isEmpty(remoteDnsString)) {
remoteDnsString = AppConfig.DNS_AGENT
}
- if ( domesticDns.summary == "") {
- domesticDns.summary = AppConfig.DNS_DIRECT
+ if (TextUtils.isEmpty(domesticDns?.summary)) {
+ domesticDns?.summary = AppConfig.DNS_DIRECT
}
- remoteDns.summary = remoteDnsString
+ remoteDns?.summary = remoteDnsString
vpnDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_VPN_DNS, remoteDnsString)
-// socksPort.summary = defaultSharedPreferences.getString(PREF_SOCKS_PORT, "10808")
-// lanconnPort.summary = defaultSharedPreferences.getString(PREF_HTTP_PORT, "")
+ if (TextUtils.isEmpty(localDnsPort?.summary)) {
+ localDnsPort?.summary = AppConfig.PORT_LOCAL_DNS
+ }
+ if (TextUtils.isEmpty(socksPort?.summary)) {
+ socksPort?.summary = AppConfig.PORT_SOCKS
+ }
+ if (TextUtils.isEmpty(httpPort?.summary)) {
+ httpPort?.summary = AppConfig.PORT_HTTP
+ }
}
private fun updateMode(mode: String?) {
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
val vpn = mode == "VPN"
- perAppProxy.isEnabled = vpn
- perAppProxy.isChecked = PreferenceManager.getDefaultSharedPreferences(requireActivity())
+ perAppProxy?.isEnabled = vpn
+ perAppProxy?.isChecked = PreferenceManager.getDefaultSharedPreferences(requireActivity())
.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
localDns?.isEnabled = vpn
fakeDns?.isEnabled = vpn
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt
index f7b1c30a..5a5a8d44 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt
@@ -1,10 +1,10 @@
package com.v2ray.ang.ui
import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
+import androidx.appcompat.app.AlertDialog
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import com.v2ray.ang.R
@@ -45,7 +45,7 @@ class SubEditActivity : BaseActivity() {
private fun bindingServer(subItem: SubscriptionItem): Boolean {
binding.etRemarks.text = Utils.getEditable(subItem.remarks)
binding.etUrl.text = Utils.getEditable(subItem.url)
-
+ binding.chkEnable.isChecked = subItem.enabled
return true
}
@@ -55,7 +55,7 @@ class SubEditActivity : BaseActivity() {
private fun clearServer(): Boolean {
binding.etRemarks.text = null
binding.etUrl.text = null
-
+ binding.chkEnable.isChecked = true
return true
}
@@ -75,15 +75,16 @@ class SubEditActivity : BaseActivity() {
subItem.remarks = binding.etRemarks.text.toString()
subItem.url = binding.etUrl.text.toString()
+ subItem.enabled = binding.chkEnable.isChecked
if (TextUtils.isEmpty(subItem.remarks)) {
toast(R.string.sub_setting_remarks)
return false
}
- if (TextUtils.isEmpty(subItem.url)) {
- toast(R.string.sub_setting_url)
- return false
- }
+// if (TextUtils.isEmpty(subItem.url)) {
+// toast(R.string.sub_setting_url)
+// return false
+// }
subStorage?.encode(subId, Gson().toJson(subItem))
toast(R.string.toast_success)
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt
index a0030730..853a3878 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt
@@ -1,11 +1,11 @@
package com.v2ray.ang.ui
import android.content.Intent
+import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Menu
import android.view.MenuItem
import com.v2ray.ang.R
import android.os.Bundle
-import androidx.recyclerview.widget.LinearLayoutManager
import com.v2ray.ang.databinding.ActivitySubSettingBinding
import com.v2ray.ang.dto.SubscriptionItem
import com.v2ray.ang.util.MmkvManager
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingRecyclerAdapter.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingRecyclerAdapter.kt
index 80a20c10..f3732bf3 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingRecyclerAdapter.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingRecyclerAdapter.kt
@@ -2,14 +2,19 @@ package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.Color
-import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
+import androidx.recyclerview.widget.RecyclerView
import android.view.ViewGroup
+import com.google.gson.Gson
+import com.tencent.mmkv.MMKV
+import com.v2ray.ang.R
import com.v2ray.ang.databinding.ItemRecyclerSubSettingBinding
+import com.v2ray.ang.util.MmkvManager
class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView.Adapter() {
private var mActivity: SubSettingActivity = activity
+ private val subStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SUB, MMKV.MULTI_PROCESS_MODE) }
override fun getItemCount() = mActivity.subscriptions.size
@@ -18,6 +23,11 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
val subItem = mActivity.subscriptions[position].second
holder.itemSubSettingBinding.tvName.text = subItem.remarks
holder.itemSubSettingBinding.tvUrl.text = subItem.url
+ if (subItem.enabled) {
+ holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorSelected)
+ } else {
+ holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorUnselected)
+ }
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
holder.itemSubSettingBinding.layoutEdit.setOnClickListener {
@@ -25,6 +35,11 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
.putExtra("subId", subId)
)
}
+ holder.itemSubSettingBinding.infoContainer.setOnClickListener {
+ subItem.enabled = !subItem.enabled
+ subStorage?.encode(subId, Gson().toJson(subItem))
+ notifyItemChanged(position)
+ }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/TaskerActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/TaskerActivity.kt
index 1fff3fbc..da7ca188 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/TaskerActivity.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/TaskerActivity.kt
@@ -114,3 +114,4 @@ class TaskerActivity : BaseActivity() {
}
}
+
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt
new file mode 100644
index 00000000..90681100
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UrlSchemeActivity.kt
@@ -0,0 +1,51 @@
+package com.v2ray.ang.ui
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import com.google.zxing.WriterException
+import com.v2ray.ang.R
+import com.v2ray.ang.databinding.ActivityLogcatBinding
+import com.v2ray.ang.extension.toast
+import com.v2ray.ang.util.AngConfigManager
+
+class UrlSchemeActivity : BaseActivity() {
+ private lateinit var binding: ActivityLogcatBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityLogcatBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+
+ var shareUrl: String = ""
+ try {
+ intent?.apply {
+ when (action) {
+ Intent.ACTION_SEND -> {
+ if ("text/plain" == type) {
+ intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
+ shareUrl = it
+ }
+ }
+ }
+ Intent.ACTION_VIEW -> {
+ val uri: Uri? = intent.data
+ shareUrl = uri?.getQueryParameter("url")!!
+ }
+ }
+ }
+ toast(shareUrl)
+ val count = AngConfigManager.importBatchConfig(shareUrl, "", false)
+ if (count > 0) {
+ toast(R.string.toast_success)
+ } else {
+ toast(R.string.toast_failure)
+ }
+ startActivity(Intent(this, MainActivity::class.java))
+ finish()
+ } catch (e: WriterException) {
+ e.printStackTrace()
+ }
+ }
+}
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetActivity.kt
new file mode 100644
index 00000000..2203080a
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetActivity.kt
@@ -0,0 +1,216 @@
+package com.v2ray.ang.ui
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.provider.OpenableColumns
+import android.util.Log
+import android.view.*
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.tbruyelle.rxpermissions.RxPermissions
+import com.tencent.mmkv.MMKV
+import com.v2ray.ang.AppConfig
+import com.v2ray.ang.R
+import com.v2ray.ang.databinding.ActivitySubSettingBinding
+import com.v2ray.ang.databinding.ItemRecyclerUserAssetBinding
+import com.v2ray.ang.extension.toTrafficString
+import com.v2ray.ang.extension.toast
+import com.v2ray.ang.util.MmkvManager
+import com.v2ray.ang.util.Utils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.io.File
+import java.io.FileOutputStream
+import java.net.HttpURLConnection
+import java.net.InetSocketAddress
+import java.net.Proxy
+import java.net.URL
+import java.text.DateFormat
+import java.util.*
+
+class UserAssetActivity : BaseActivity() {
+ private lateinit var binding: ActivitySubSettingBinding
+ private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
+
+ val extDir by lazy { File(Utils.userAssetPath(this)) }
+ val geofiles = arrayOf("geosite.dat", "geoip.dat")
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivitySubSettingBinding.inflate(layoutInflater)
+ val view = binding.root
+ setContentView(view)
+ title = getString(R.string.title_user_asset_setting)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ binding.recyclerView.setHasFixedSize(true)
+ binding.recyclerView.layoutManager = LinearLayoutManager(this)
+ binding.recyclerView.adapter = UserAssetAdapter()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_asset, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
+ R.id.add_file -> {
+ showFileChooser()
+ true
+ }
+
+ R.id.download_file -> {
+ downloadGeoFiles()
+ true
+ }
+
+ else -> super.onOptionsItemSelected(item)
+ }
+
+ private fun showFileChooser() {
+ RxPermissions(this).request(Manifest.permission.READ_EXTERNAL_STORAGE).subscribe {
+ if (it) {
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = "*/*"
+ intent.addCategory(Intent.CATEGORY_OPENABLE)
+
+ try {
+ chooseFile.launch(
+ Intent.createChooser(
+ intent,
+ getString(R.string.title_file_chooser)
+ )
+ )
+ } catch (ex: android.content.ActivityNotFoundException) {
+ toast(R.string.toast_require_file_manager)
+ }
+ }
+ }
+ }
+
+ private val chooseFile =
+ registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
+ val uri = it.data?.data
+ if (it.resultCode == RESULT_OK && uri != null) {
+ try {
+ copyFile(uri)
+ } catch (e: Exception) {
+ toast(R.string.toast_asset_copy_failed)
+ }
+ }
+ }
+
+ private fun copyFile(uri: Uri): String {
+ val targetFile = File(extDir, getCursorName(uri) ?: uri.toString())
+ contentResolver.openInputStream(uri).use { inputStream ->
+ targetFile.outputStream().use { fileOut ->
+ inputStream?.copyTo(fileOut)
+ toast(R.string.toast_success)
+ binding.recyclerView.adapter?.notifyDataSetChanged()
+ }
+ }
+ return targetFile.path
+ }
+
+ private fun getCursorName(uri: Uri): String? = try {
+ contentResolver.query(uri, null, null, null, null)?.let { cursor ->
+ cursor.run {
+ if (moveToFirst()) getString(getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
+ else null
+ }.also { cursor.close() }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+
+ private fun downloadGeoFiles() {
+ val httpPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT), AppConfig.PORT_HTTP.toInt())
+
+ toast(R.string.msg_downloading_content)
+ geofiles.forEach {
+ //toast(getString(R.string.msg_downloading_content) + it)
+ lifecycleScope.launch(Dispatchers.IO) {
+ val result = downloadGeo(it, 60000, httpPort)
+ launch(Dispatchers.Main) {
+ if (result) {
+ toast(getString(R.string.toast_success) + it)
+ binding.recyclerView.adapter?.notifyDataSetChanged()
+ } else {
+ toast(getString(R.string.toast_failure) + it)
+ }
+ }
+ }
+ }
+ }
+
+ private fun downloadGeo(name: String, timeout: Int, httpPort: Int): Boolean {
+ val url = AppConfig.geoUrl + name
+ val targetTemp = File(extDir, name + "_temp")
+ val target = File(extDir, name)
+ var conn: HttpURLConnection? = null
+ //Log.d(AppConfig.ANG_PACKAGE, url)
+
+ try {
+ conn = URL(url).openConnection(
+ Proxy(
+ Proxy.Type.HTTP,
+ InetSocketAddress("127.0.0.1", httpPort)
+ )
+ ) as HttpURLConnection
+ conn.connectTimeout = timeout
+ conn.readTimeout = timeout
+ val inputStream = conn.inputStream
+ val responseCode = conn.responseCode
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ FileOutputStream(targetTemp).use { output ->
+ inputStream.copyTo(output)
+ }
+
+ targetTemp.renameTo(target)
+ }
+ return true
+ } catch (e: Exception) {
+ Log.e(AppConfig.ANG_PACKAGE, Log.getStackTraceString(e))
+ return false
+ } finally {
+ conn?.disconnect()
+ }
+ }
+
+ inner class UserAssetAdapter : RecyclerView.Adapter() {
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserAssetViewHolder {
+ return UserAssetViewHolder(ItemRecyclerUserAssetBinding.inflate(LayoutInflater.from(parent.context), parent, false))
+ }
+
+ @SuppressLint("SetTextI18n")
+ override fun onBindViewHolder(holder: UserAssetViewHolder, position: Int) {
+ val file = extDir.listFiles()?.getOrNull(position) ?: return
+ holder.itemUserAssetBinding.assetName.text = file.name
+ val dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM)
+ holder.itemUserAssetBinding.assetProperties.text = "${file.length().toTrafficString()} • ${dateFormat.format(Date(file.lastModified()))}"
+ if (file.name in geofiles) {
+ holder.itemUserAssetBinding.layoutRemove.visibility = GONE
+ } else {
+ holder.itemUserAssetBinding.layoutRemove.visibility = VISIBLE
+ }
+ holder.itemUserAssetBinding.layoutRemove.setOnClickListener {
+ file.delete()
+ binding.recyclerView.adapter?.notifyItemRemoved(position)
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return extDir.listFiles()?.size ?: 0
+ }
+ }
+
+ class UserAssetViewHolder(val itemUserAssetBinding: ItemRecyclerUserAssetBinding) : RecyclerView.ViewHolder(itemUserAssetBinding.root)
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
index c6cc1cfb..63f41427 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt
@@ -60,9 +60,9 @@ object AngConfigManager {
AppConfig.PREF_REMOTE_DNS,
AppConfig.PREF_DOMESTIC_DNS,
AppConfig.PREF_LOCAL_DNS_PORT,
-// AppConfig.PREF_SOCKS_PORT,
-// AppConfig.PREF_HTTP_PORT,
-// AppConfig.PREF_LOGLEVEL,
+ AppConfig.PREF_SOCKS_PORT,
+ AppConfig.PREF_HTTP_PORT,
+ AppConfig.PREF_LOGLEVEL,
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
AppConfig.PREF_ROUTING_MODE,
AppConfig.PREF_V2RAY_ROUTING_AGENT,
@@ -75,8 +75,8 @@ object AngConfigManager {
AppConfig.PREF_SPEED_ENABLED,
AppConfig.PREF_PROXY_SHARING,
AppConfig.PREF_LOCAL_DNS_ENABLED,
-// AppConfig.PREF_ALLOW_INSECURE,
-// AppConfig.PREF_PREFER_IPV6,
+ AppConfig.PREF_ALLOW_INSECURE,
+ AppConfig.PREF_PREFER_IPV6,
AppConfig.PREF_PER_APP_PROXY,
AppConfig.PREF_BYPASS_APPS,
).forEach { key ->
@@ -108,10 +108,11 @@ object AngConfigManager {
vnext.port = vmessBean.port
vnext.users[0].id = vmessBean.id
if (config.configType == EConfigType.VMESS) {
+ vnext.users[0].alterId = vmessBean.alterId
vnext.users[0].security = vmessBean.security
} else if (config.configType == EConfigType.VLESS) {
vnext.users[0].encryption = vmessBean.security
-// vnext.users[0].flow = vmessBean.flow
+ vnext.users[0].flow = vmessBean.flow
}
}
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
@@ -137,13 +138,13 @@ object AngConfigManager {
val sni = streamSetting.populateTransportSettings(vmessBean.network, vmessBean.headerType,
vmessBean.requestHost, vmessBean.path, vmessBean.path, vmessBean.requestHost, vmessBean.path,
vmessBean.headerType, vmessBean.path)
-// val allowInsecure = if (vmessBean.allowInsecure.isBlank()) {
-// settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
-// } else {
-// vmessBean.allowInsecure.toBoolean()
-// }
- streamSetting.populateTlsSettings(vmessBean.streamSecurity, false,
- sni)//vmessBean.sni.ifBlank { sni })
+ val allowInsecure = if (vmessBean.allowInsecure.isBlank()) {
+ settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
+ } else {
+ vmessBean.allowInsecure.toBoolean()
+ }
+ streamSetting.populateTlsSettings(vmessBean.streamSecurity, allowInsecure,
+ vmessBean.sni.ifBlank { sni })
}
}
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
@@ -158,7 +159,7 @@ object AngConfigManager {
val subItem = SubscriptionItem()
subItem.remarks = it.remarks
subItem.url = it.url
- //subItem.enabled = it.enabled
+ subItem.enabled = it.enabled
subStorage?.encode(it.id, Gson().toJson(subItem))
}
}
@@ -179,7 +180,7 @@ object AngConfigManager {
}
var config: ServerConfig? = null
- val allowInsecure = false//settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
+ val allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
if (str.startsWith(EConfigType.VMESS.protocolScheme)) {
config = ServerConfig.create(EConfigType.VMESS)
val streamSetting = config.outboundBean?.streamSettings ?: return -1
@@ -210,7 +211,8 @@ object AngConfigManager {
vnext.address = vmessQRCode.add
vnext.port = Utils.parseInt(vmessQRCode.port)
vnext.users[0].id = vmessQRCode.id
- vnext.users[0].encryption = DEFAULT_SECURITY
+ vnext.users[0].security = if (TextUtils.isEmpty(vmessQRCode.scy)) DEFAULT_SECURITY else vmessQRCode.scy
+ vnext.users[0].alterId = Utils.parseInt(vmessQRCode.aid)
}
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
@@ -268,7 +270,7 @@ object AngConfigManager {
//part decode
val indexS = result.indexOf("@")
if (indexS > 0) {
- //result = Utils.decode(result.substring(0, indexS)) + result.substring(indexS, result.length)
+ result = Utils.decode(result.substring(0, indexS)) + result.substring(indexS, result.length)
} else {
result = Utils.decode(result)
}
@@ -285,23 +287,32 @@ object AngConfigManager {
server.users = listOf(socksUsersBean)
}
} else if (str.startsWith(EConfigType.TROJAN.protocolScheme)) {
- val uri = URI(str)
+ val uri = URI(Utils.fixIllegalUrl(str))
config = ServerConfig.create(EConfigType.TROJAN)
config.remarks = Utils.urlDecode(uri.fragment ?: "")
+
+ var flow = ""
+ if (uri.rawQuery != null) {
+ val queryParam = uri.rawQuery.split("&")
+ .associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
+
+ val sni = config.outboundBean?.streamSettings?.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
+ queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
+ queryParam["mode"], queryParam["serviceName"])
+ config.outboundBean?.streamSettings?.populateTlsSettings(queryParam["security"] ?: TLS, allowInsecure, queryParam["sni"] ?: sni!!)
+ flow = queryParam["flow"] ?: ""
+ } else {
+ config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, "")
+ }
+
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
server.address = uri.idnHost
server.port = uri.port
server.password = uri.userInfo
+ server.flow = flow
}
- var sni = ""
- uri.rawQuery?.let { rawQuery ->
- val queryParam = rawQuery.split("&")
- .associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
- sni = queryParam["sni"] ?: ""
- }
- config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, sni)
} else if (str.startsWith(EConfigType.VLESS.protocolScheme)) {
- val uri = URI(str)
+ val uri = URI(Utils.fixIllegalUrl(str))
val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
config = ServerConfig.create(EConfigType.VLESS)
@@ -341,7 +352,7 @@ object AngConfigManager {
return runCatching {
val uri = URI(uriString)
check(uri.scheme == "vmess")
- val (_, protocol, tlsStr, uuid) =
+ val (_, protocol, tlsStr, uuid, alterId) =
Regex("(tcp|http|ws|kcp|quic|grpc)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})")
.matchEntire(uri.userInfo)?.groupValues
?: error("parse user info fail.")
@@ -355,7 +366,8 @@ object AngConfigManager {
vnext.address = uri.idnHost
vnext.port = uri.port
vnext.users[0].id = uuid
- vnext.users[0].encryption = DEFAULT_SECURITY
+ vnext.users[0].security = DEFAULT_SECURITY
+ vnext.users[0].alterId = alterId.toInt()
}
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
@@ -391,14 +403,15 @@ object AngConfigManager {
vnext.address = arr22[0]
vnext.port = Utils.parseInt(arr22[1])
vnext.users[0].id = arr21[1]
- vnext.users[0].encryption = arr21[0]
+ vnext.users[0].security = arr21[0]
+ vnext.users[0].alterId = 0
}
return true
}
private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean {
try {
- val uri = URI(str.replace(" ", "%20"))
+ val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment ?: "")
val method: String
@@ -449,6 +462,8 @@ object AngConfigManager {
vmessQRCode.add = outbound.getServerAddress().orEmpty()
vmessQRCode.port = outbound.getServerPort().toString()
vmessQRCode.id = outbound.getPassword().orEmpty()
+ vmessQRCode.aid = outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString()
+ vmessQRCode.scy = outbound.settings?.vnext?.get(0)?.users?.get(0)?.security.toString()
vmessQRCode.net = streamSetting.network
vmessQRCode.tls = streamSetting.security
vmessQRCode.sni = streamSetting.tlsSettings?.serverName.orEmpty()
@@ -463,33 +478,44 @@ object AngConfigManager {
EConfigType.CUSTOM -> ""
EConfigType.SHADOWSOCKS -> {
val remark = "#" + Utils.urlEncode(config.remarks)
- val url = String.format("%s:%s@%s:%s",
- outbound.getSecurityEncryption(),
- outbound.getPassword(),
- outbound.getServerAddress(),
+ val pw = Utils.encode("${outbound.getSecurityEncryption()}:${outbound.getPassword()}")
+ val url = String.format("%s@%s:%s",
+ pw,
+ Utils.getIpv6Address(outbound.getServerAddress()!!),
outbound.getServerPort())
- Utils.encode(url) + remark
+ url + remark
}
EConfigType.SOCKS -> {
val remark = "#" + Utils.urlEncode(config.remarks)
- val url = String.format("%s:%s@%s:%s",
- outbound.settings?.servers?.get(0)?.users?.get(0)?.user,
- outbound.getPassword(),
- outbound.getServerAddress(),
- outbound.getServerPort())
- Utils.encode(url) + remark
+ val pw = Utils.encode("${outbound.settings?.servers?.get(0)?.users?.get(0)?.user}:${outbound.getPassword()}")
+ val url = String.format("%s@%s:%s",
+ pw,
+ Utils.getIpv6Address(outbound.getServerAddress()!!),
+ outbound.getServerPort())
+ url + remark
}
- EConfigType.VLESS -> {
+ EConfigType.VLESS,
+ EConfigType.TROJAN -> {
val remark = "#" + Utils.urlEncode(config.remarks)
val dicQuery = HashMap()
- outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow?.let {
- if (!TextUtils.isEmpty(it)) {
- dicQuery["flow"] = it
+ if (config.configType == EConfigType.VLESS) {
+ outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow?.let {
+ if (!TextUtils.isEmpty(it)) {
+ dicQuery["flow"] = it
+ }
+ }
+ dicQuery["encryption"] =
+ if (outbound.getSecurityEncryption().isNullOrEmpty()) "none"
+ else outbound.getSecurityEncryption().orEmpty()
+ } else if (config.configType == EConfigType.TROJAN) {
+ config.outboundBean?.settings?.servers?.get(0)?.flow?.let {
+ if (!TextUtils.isEmpty(it)) {
+ dicQuery["flow"] = it
+ }
}
}
- dicQuery["encryption"] = if (outbound.getSecurityEncryption().isNullOrEmpty()) "none"
- else outbound.getSecurityEncryption().orEmpty()
+
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
(streamSetting.tlsSettings?: streamSetting.xtlsSettings)?.let { tlsSetting ->
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
@@ -550,20 +576,6 @@ object AngConfigManager {
outbound.getServerPort())
url + query + remark
}
- EConfigType.TROJAN -> {
- val remark = "#" + Utils.urlEncode(config.remarks)
- var query = ""
- (streamSetting.tlsSettings?: streamSetting.xtlsSettings)?.let { tlsSetting ->
- if (!TextUtils.isEmpty(tlsSetting.serverName)) {
- query = "?sni=${tlsSetting.serverName}"
- }
- }
- val url = String.format("%s@%s:%s",
- outbound.getPassword(),
- Utils.getIpv6Address(outbound.getServerAddress()!!),
- outbound.getServerPort())
- url + query + remark
- }
}
} catch (e: Exception) {
e.printStackTrace()
@@ -683,13 +695,13 @@ object AngConfigManager {
}
}
- fun importBatchConfig(servers: String?, subid: String): Int {
+ fun importBatchConfig(servers: String?, subid: String, append: Boolean): Int {
try {
if (servers == null) {
return 0
}
val removedSelectedServer =
- if (!TextUtils.isEmpty(subid)) {
+ if (!TextUtils.isEmpty(subid) && !append) {
MmkvManager.decodeServerConfig(mainStorage?.decodeString(KEY_SELECTED_SERVER) ?: "")?.let {
if (it.subscriptionId == subid) {
return@let it
@@ -699,8 +711,9 @@ object AngConfigManager {
} else {
null
}
- MmkvManager.removeServerViaSubid(subid)
-
+ if(!append) {
+ MmkvManager.removeServerViaSubid(subid)
+ }
// var servers = server
// if (server.indexOf("vmess") >= 0 && server.indexOf("vmess") == server.lastIndexOf("vmess")) {
// servers = server.replace("\n", "")
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MessageUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MessageUtil.kt
index 486023c8..0f521f57 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MessageUtil.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MessageUtil.kt
@@ -1,21 +1,36 @@
package com.v2ray.ang.util
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import com.v2ray.ang.AppConfig
+import com.v2ray.ang.service.V2RayTestService
+import java.io.Serializable
object MessageUtil {
- fun sendMsg2Service(ctx: Context, what: Int, content: String) {
+ fun sendMsg2Service(ctx: Context, what: Int, content: Serializable) {
sendMsg(ctx, AppConfig.BROADCAST_ACTION_SERVICE, what, content)
}
- fun sendMsg2UI(ctx: Context, what: Int, content: String) {
+ fun sendMsg2UI(ctx: Context, what: Int, content: Serializable) {
sendMsg(ctx, AppConfig.BROADCAST_ACTION_ACTIVITY, what, content)
}
- private fun sendMsg(ctx: Context, action: String, what: Int, content: String) {
+ fun sendMsg2TestService(ctx: Context, what: Int, content: Serializable) {
+ try {
+ val intent = Intent()
+ intent.component = ComponentName(ctx, V2RayTestService::class.java)
+ intent.putExtra("key", what)
+ intent.putExtra("content", content)
+ ctx.startService(intent)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun sendMsg(ctx: Context, action: String, what: Int, content: Serializable) {
try {
val intent = Intent()
intent.action = action
@@ -27,4 +42,4 @@ object MessageUtil {
e.printStackTrace()
}
}
-}
\ No newline at end of file
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
index ace87de0..533527e7 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt
@@ -44,7 +44,7 @@ object MmkvManager {
fun encodeServerConfig(guid: String, config: ServerConfig): String {
val key = guid.ifBlank { Utils.getUuid() }
serverStorage?.encode(key, Gson().toJson(config))
- val serverList= decodeServerList()
+ val serverList = decodeServerList()
if (!serverList.contains(key)) {
serverList.add(key)
mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
@@ -62,7 +62,7 @@ object MmkvManager {
if (mainStorage?.decodeString(KEY_SELECTED_SERVER) == guid) {
mainStorage?.remove(KEY_SELECTED_SERVER)
}
- val serverList= decodeServerList()
+ val serverList = decodeServerList()
serverList.remove(guid)
mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
serverStorage?.remove(guid)
@@ -141,4 +141,39 @@ object MmkvManager {
subStorage?.remove(subid)
removeServerViaSubid(subid)
}
+
+ fun removeAllServer() {
+ mainStorage?.clearAll()
+ serverStorage?.clearAll()
+ serverAffStorage?.clearAll()
+ }
+
+ fun removeInvalidServer() {
+ serverAffStorage?.allKeys()?.forEach { key ->
+ decodeServerAffiliationInfo(key)?.let { aff ->
+ if (aff.testDelayMillis <= 0L) {
+ removeServer(key)
+ }
+ }
+ }
+ }
+
+ fun sortByTestResults( ) {
+ data class ServerDelay(var guid: String, var testDelayMillis: Long)
+
+ val serverDelays = mutableListOf()
+ val serverList = decodeServerList()
+ serverList.forEach { key ->
+ val delay = decodeServerAffiliationInfo(key)?.testDelayMillis ?: 0L
+ serverDelays.add(ServerDelay(key, if (delay <= 0L) 999999 else delay))
+ }
+ serverDelays.sortBy { it.testDelayMillis }
+
+ serverDelays.forEach {
+ serverList.remove(it.guid)
+ serverList.add(it.guid)
+ }
+
+ mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MyContextWrapper.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MyContextWrapper.kt
new file mode 100644
index 00000000..cf9bd35e
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MyContextWrapper.kt
@@ -0,0 +1,33 @@
+package com.v2ray.ang.util
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.os.Build
+import android.os.LocaleList
+import androidx.annotation.RequiresApi
+import java.util.*
+
+open class MyContextWrapper(base: Context?) : ContextWrapper(base) {
+ companion object {
+ @RequiresApi(Build.VERSION_CODES.N)
+ fun wrap(context: Context, newLocale: Locale?): ContextWrapper {
+ var mContext = context
+ val res: Resources = mContext.resources
+ val configuration: Configuration = res.configuration
+ //注意 Android 7.0 前后的不同处理方法
+ mContext = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ configuration.setLocale(newLocale)
+ val localeList = LocaleList(newLocale)
+ LocaleList.setDefault(localeList)
+ configuration.setLocales(localeList)
+ mContext.createConfigurationContext(configuration)
+ } else {
+ configuration.setLocale(newLocale)
+ mContext.createConfigurationContext(configuration)
+ }
+ return ContextWrapper(mContext)
+ }
+ }
+}
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/QRCodeDecoder.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/QRCodeDecoder.kt
new file mode 100644
index 00000000..250f84df
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/QRCodeDecoder.kt
@@ -0,0 +1,100 @@
+package com.v2ray.ang.util
+
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import com.google.zxing.*
+import com.google.zxing.common.GlobalHistogramBinarizer
+import com.google.zxing.common.HybridBinarizer
+import java.util.*
+
+/**
+ * 描述:解析二维码图片
+ */
+object QRCodeDecoder {
+ val HINTS: MutableMap = EnumMap(DecodeHintType::class.java)
+
+ /**
+ * 同步解析本地图片二维码。该方法是耗时操作,请在子线程中调用。
+ *
+ * @param picturePath 要解析的二维码图片本地路径
+ * @return 返回二维码图片里的内容 或 null
+ */
+ fun syncDecodeQRCode(picturePath: String): String? {
+ return syncDecodeQRCode(getDecodeAbleBitmap(picturePath))
+ }
+
+ /**
+ * 同步解析bitmap二维码。该方法是耗时操作,请在子线程中调用。
+ *
+ * @param bitmap 要解析的二维码图片
+ * @return 返回二维码图片里的内容 或 null
+ */
+ fun syncDecodeQRCode(bitmap: Bitmap?): String? {
+ var source: RGBLuminanceSource? = null
+ try {
+ val width = bitmap!!.width
+ val height = bitmap.height
+ val pixels = IntArray(width * height)
+ bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
+ source = RGBLuminanceSource(width, height, pixels)
+ return MultiFormatReader().decode(BinaryBitmap(HybridBinarizer(source)), HINTS).text
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ if (source != null) {
+ try {
+ return MultiFormatReader().decode(BinaryBitmap(GlobalHistogramBinarizer(source)), HINTS).text
+ } catch (e2: Throwable) {
+ e2.printStackTrace()
+ }
+ }
+ return null
+ }
+
+ /**
+ * 将本地图片文件转换成可解码二维码的 Bitmap。为了避免图片太大,这里对图片进行了压缩。感谢 https://github.com/devilsen 提的 PR
+ *
+ * @param picturePath 本地图片文件路径
+ * @return
+ */
+ private fun getDecodeAbleBitmap(picturePath: String): Bitmap? {
+ return try {
+ val options = BitmapFactory.Options()
+ options.inJustDecodeBounds = true
+ BitmapFactory.decodeFile(picturePath, options)
+ var sampleSize = options.outHeight / 400
+ if (sampleSize <= 0) {
+ sampleSize = 1
+ }
+ options.inSampleSize = sampleSize
+ options.inJustDecodeBounds = false
+ BitmapFactory.decodeFile(picturePath, options)
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ init {
+ val allFormats: List = arrayListOf(
+ BarcodeFormat.AZTEC
+ ,BarcodeFormat.CODABAR
+ ,BarcodeFormat.CODE_39
+ ,BarcodeFormat.CODE_93
+ ,BarcodeFormat.CODE_128
+ ,BarcodeFormat.DATA_MATRIX
+ ,BarcodeFormat.EAN_8
+ ,BarcodeFormat.EAN_13
+ ,BarcodeFormat.ITF
+ ,BarcodeFormat.MAXICODE
+ ,BarcodeFormat.PDF_417
+ ,BarcodeFormat.QR_CODE
+ ,BarcodeFormat.RSS_14
+ ,BarcodeFormat.RSS_EXPANDED
+ ,BarcodeFormat.UPC_A
+ ,BarcodeFormat.UPC_E
+ ,BarcodeFormat.UPC_EAN_EXTENSION)
+ HINTS[DecodeHintType.TRY_HARDER] = BarcodeFormat.QR_CODE
+ HINTS[DecodeHintType.POSSIBLE_FORMATS] = allFormats
+ HINTS[DecodeHintType.CHARACTER_SET] = "utf-8"
+ }
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SpeedtestUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SpeedtestUtil.kt
new file mode 100644
index 00000000..5a0e5989
--- /dev/null
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SpeedtestUtil.kt
@@ -0,0 +1,142 @@
+package com.v2ray.ang.util
+
+import android.content.Context
+import android.os.SystemClock
+import android.text.TextUtils
+import android.util.Log
+import com.v2ray.ang.AppConfig
+import com.v2ray.ang.R
+import com.v2ray.ang.extension.responseLength
+import kotlinx.coroutines.isActive
+import libv2ray.Libv2ray
+import java.io.IOException
+import java.net.*
+import java.util.*
+import kotlin.coroutines.coroutineContext
+
+object SpeedtestUtil {
+
+ private val tcpTestingSockets = ArrayList()
+
+ suspend fun tcping(url: String, port: Int): Long {
+ var time = -1L
+ for (k in 0 until 2) {
+ val one = socketConnectTime(url, port)
+ if (!coroutineContext.isActive) {
+ break
+ }
+ if (one != -1L && (time == -1L || one < time)) {
+ time = one
+ }
+ }
+ return time
+ }
+
+ fun realPing(config: String): Long {
+ return try {
+ Libv2ray.measureOutboundDelay(config)
+ } catch (e: Exception) {
+ Log.d(AppConfig.ANG_PACKAGE, "realPing: $e")
+ -1L
+ }
+ }
+
+ fun ping(url: String): String {
+ try {
+ val command = "/system/bin/ping -c 3 $url"
+ val process = Runtime.getRuntime().exec(command)
+ val allText = process.inputStream.bufferedReader().use { it.readText() }
+ if (!TextUtils.isEmpty(allText)) {
+ val tempInfo = allText.substring(allText.indexOf("min/avg/max/mdev") + 19)
+ val temps = tempInfo.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ if (temps.count() > 0 && temps[0].length < 10) {
+ return temps[0].toFloat().toInt().toString() + "ms"
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ return "-1ms"
+ }
+
+ fun socketConnectTime(url: String, port: Int): Long {
+ try {
+ val socket = Socket()
+ synchronized(this) {
+ tcpTestingSockets.add(socket)
+ }
+ val start = System.currentTimeMillis()
+ socket.connect(InetSocketAddress(url, port),3000)
+ val time = System.currentTimeMillis() - start
+ synchronized(this) {
+ tcpTestingSockets.remove(socket)
+ }
+ socket.close()
+ return time
+ } catch (e: UnknownHostException) {
+ e.printStackTrace()
+ } catch (e: IOException) {
+ Log.d(AppConfig.ANG_PACKAGE, "socketConnectTime IOException: $e")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ return -1
+ }
+
+ fun closeAllTcpSockets() {
+ synchronized(this) {
+ tcpTestingSockets.forEach {
+ it?.close()
+ }
+ tcpTestingSockets.clear()
+ }
+ }
+
+ fun testConnection(context: Context, port: Int): String {
+ // return V2RayVpnService.measureV2rayDelay()
+ var result: String
+ var conn: HttpURLConnection? = null
+
+ try {
+ val url = URL("https",
+ "www.google.com",
+ "/generate_204")
+
+ conn = url.openConnection(
+ Proxy(Proxy.Type.HTTP,
+ InetSocketAddress("127.0.0.1", port))) as HttpURLConnection
+ conn.connectTimeout = 30000
+ conn.readTimeout = 30000
+ conn.setRequestProperty("Connection", "close")
+ conn.instanceFollowRedirects = false
+ conn.useCaches = false
+
+ val start = SystemClock.elapsedRealtime()
+ val code = conn.responseCode
+ val elapsed = SystemClock.elapsedRealtime() - start
+
+ if (code == 204 || code == 200 && conn.responseLength == 0L) {
+ result = context.getString(R.string.connection_test_available, elapsed)
+ } else {
+ throw IOException(context.getString(R.string.connection_test_error_status_code, code))
+ }
+ } catch (e: IOException) {
+ // network exception
+ Log.d(AppConfig.ANG_PACKAGE, "testConnection IOException: " + Log.getStackTraceString(e))
+ result = context.getString(R.string.connection_test_error, e.message)
+ } catch (e: Exception) {
+ // library exception, eg sumsung
+ Log.d(AppConfig.ANG_PACKAGE, "testConnection Exception: " + Log.getStackTraceString(e))
+ result = context.getString(R.string.connection_test_error, e.message)
+ } finally {
+ conn?.disconnect()
+ }
+
+ return result
+ }
+
+ fun getLibVersion(): String {
+ return Libv2ray.checkVersionX()
+ }
+
+}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt
index 804011c8..d814a956 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/Utils.kt
@@ -13,28 +13,28 @@ import java.util.*
import kotlin.collections.HashMap
import android.content.ClipData
import android.content.Intent
+import android.content.res.Configuration.UI_MODE_NIGHT_MASK
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.net.Uri
-import android.os.SystemClock
+import android.os.Build
+import android.os.LocaleList
import android.util.Log
import android.util.Patterns
import android.webkit.URLUtil
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
+import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.BuildConfig
import com.v2ray.ang.R
-import com.v2ray.ang.extension.responseLength
import com.v2ray.ang.extension.toast
-import com.v2ray.ang.service.V2RayServiceManager
-import kotlinx.coroutines.isActive
-import java.io.IOException
import java.net.*
-import kotlin.coroutines.coroutineContext
+import com.v2ray.ang.service.V2RayServiceManager
+import java.io.IOException
object Utils {
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
- private val tcpTestingSockets = ArrayList()
/**
* convert string to editalbe for kotlin
@@ -62,11 +62,16 @@ object Utils {
* parseInt
*/
fun parseInt(str: String): Int {
+ return parseInt(str, 0)
+ }
+
+ fun parseInt(str: String?, default: Int): Int {
+ str ?: return default
return try {
Integer.parseInt(str)
} catch (e: Exception) {
e.printStackTrace()
- 0
+ default
}
}
@@ -112,12 +117,12 @@ object Utils {
try {
return Base64.decode(text, Base64.NO_WRAP).toString(charset("UTF-8"))
} catch (e: Exception) {
- Log.i(AppConfig.ANG_PACKAGE, "Parse base64 standard failed $e")
+ Log.i(ANG_PACKAGE, "Parse base64 standard failed $e")
}
try {
return Base64.decode(text, Base64.NO_WRAP.or(Base64.URL_SAFE)).toString(charset("UTF-8"))
} catch (e: Exception) {
- Log.i(AppConfig.ANG_PACKAGE, "Parse base64 url safe failed $e")
+ Log.i(ANG_PACKAGE, "Parse base64 url safe failed $e")
}
return null
}
@@ -224,7 +229,7 @@ object Utils {
// addr = addr.toLowerCase()
val octets = addr.split('.').toTypedArray()
if (octets.size == 4) {
- if(octets[3].indexOf(":") > 0) {
+ if (octets[3].indexOf(":") > 0) {
addr = addr.substring(0, addr.indexOf(":"))
}
return isIpv4Address(addr)
@@ -312,7 +317,7 @@ object Utils {
fun urlDecode(url: String): String {
return try {
- URLDecoder.decode(url, "UTF-8")
+ URLDecoder.decode(URLDecoder.decode(url), "utf-8")
} catch (e: Exception) {
e.printStackTrace()
url
@@ -328,58 +333,6 @@ object Utils {
}
}
- fun testConnection(context: Context, port: Int): String {
- var result: String
- var conn: HttpURLConnection? = null
-
- try {
- val url = URL("https",
- "www.google.com",
- "/generate_204")
-
- conn = url.openConnection(
- Proxy(Proxy.Type.HTTP,
- InetSocketAddress("127.0.0.1", port + 1))) as HttpURLConnection
- conn.connectTimeout = 30000
- conn.readTimeout = 30000
- conn.setRequestProperty("Connection", "close")
- conn.instanceFollowRedirects = false
- conn.useCaches = false
-
- val start = SystemClock.elapsedRealtime()
- val code = conn.responseCode
- val elapsed = SystemClock.elapsedRealtime() - start
-
- if (code == 204 || code == 200 && conn.responseLength == 0L) {
- result = context.getString(R.string.connection_test_available, elapsed)
- } else {
- throw IOException(context.getString(R.string.connection_test_error_status_code, code))
- }
- } catch (e: IOException) {
- // network exception
- Log.d(AppConfig.ANG_PACKAGE,"testConnection IOException: "+Log.getStackTraceString(e))
- result = context.getString(R.string.connection_test_error, e.message)
- } catch (e: Exception) {
- // library exception, eg sumsung
- Log.d(AppConfig.ANG_PACKAGE,"testConnection Exception: "+Log.getStackTraceString(e))
- result = context.getString(R.string.connection_test_error, e.message)
- } finally {
- conn?.disconnect()
- }
-
- return result
- }
-
- /**
- * package path
- */
- fun packagePath(context: Context): String {
- var path = context.filesDir.toString()
- path = path.replace("files", "")
- //path += "tun2socks"
-
- return path
- }
/**
* readTextFromAssets
@@ -391,75 +344,33 @@ object Utils {
return content
}
- /**
- * ping
- */
- fun ping(url: String): String {
+ fun userAssetPath(context: Context?): String {
+ if (context == null)
+ return ""
+ val extDir = context.getExternalFilesDir(AppConfig.DIR_ASSETS)
+ ?: return context.getDir(AppConfig.DIR_ASSETS, 0).absolutePath
+ return extDir.absolutePath
+ }
+
+ fun getUrlContext(url: String, timeout: Int): String {
+ var result: String
+ var conn: HttpURLConnection? = null
+
try {
- val command = "/system/bin/ping -c 3 $url"
- val process = Runtime.getRuntime().exec(command)
- val allText = process.inputStream.bufferedReader().use { it.readText() }
- if (allText.isNotBlank()) {
- val tempInfo = allText.substring(allText.indexOf("min/avg/max/mdev") + 19)
- val temps = tempInfo.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
- if (temps.count() > 0 && temps[0].length < 10) {
- return temps[0].toFloat().toInt().toString() + "ms"
- }
- }
+ conn = URL(url).openConnection() as HttpURLConnection
+ conn.connectTimeout = timeout
+ conn.readTimeout = timeout
+ conn.setRequestProperty("Connection", "close")
+ conn.instanceFollowRedirects = false
+ conn.useCaches = false
+ //val code = conn.responseCode
+ result = conn.inputStream.bufferedReader().readText()
} catch (e: Exception) {
- e.printStackTrace()
- }
- return "-1ms"
- }
-
- /**
- * tcping
- */
- suspend fun tcping(url: String, port: Int): Long {
- var time = -1L
- for (k in 0 until 2) {
- val one = socketConnectTime(url, port)
- if (!coroutineContext.isActive) {
- break
- }
- if (one != -1L && (time == -1L || one < time)) {
- time = one
- }
- }
- return time
- }
-
- fun socketConnectTime(url: String, port: Int): Long {
- try {
- val socket = Socket()
- synchronized(this) {
- tcpTestingSockets.add(socket)
- }
- val start = System.currentTimeMillis()
- socket.connect(InetSocketAddress(url, port))
- val time = System.currentTimeMillis() - start
- synchronized(this) {
- tcpTestingSockets.remove(socket)
- }
- socket.close()
- return time
- } catch (e: UnknownHostException) {
- e.printStackTrace()
- } catch (e: IOException) {
- Log.d(AppConfig.ANG_PACKAGE, "socketConnectTime IOException: $e")
- } catch (e: Exception) {
- e.printStackTrace()
- }
- return -1
- }
-
- fun closeAllTcpSockets() {
- synchronized(this) {
- tcpTestingSockets.forEach {
- it?.close()
- }
- tcpTestingSockets.clear()
+ result = ""
+ } finally {
+ conn?.disconnect()
}
+ return result
}
@Throws(IOException::class)
@@ -478,6 +389,11 @@ object Utils {
}
}
+ fun getDarkModeStatus(context: Context): Boolean {
+ val mode = context.resources.configuration.uiMode and UI_MODE_NIGHT_MASK
+ return mode == UI_MODE_NIGHT_YES
+ }
+
fun getIpv6Address(address: String): String {
return if (isIpv6Address(address)) {
String.format("[%s]", address)
@@ -485,5 +401,27 @@ object Utils {
address
}
}
+
+ fun getLocale(context: Context): Locale =
+ when (settingsStorage?.decodeString(AppConfig.PREF_LANGUAGE) ?: "auto") {
+ "auto" -> getSysLocale()
+ "en" -> Locale("en")
+ "zh-rCN" -> Locale("zh", "CN")
+ "zh-rTW" -> Locale("zh", "TW")
+ "vi" -> Locale("vi")
+ else -> getSysLocale()
+ }
+
+ private fun getSysLocale(): Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ LocaleList.getDefault()[0]
+ } else {
+ Locale.getDefault()
+ }
+
+ fun fixIllegalUrl(str: String): String {
+ return str
+ .replace(" ","%20")
+ .replace("|","%7C")
+ }
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
index b487213d..f5177aca 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt
@@ -9,6 +9,7 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.dto.EConfigType
+import com.v2ray.ang.dto.ERoutingMode
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_NETWORK
import com.v2ray.ang.dto.V2rayConfig.Companion.HTTP
@@ -58,7 +59,8 @@ object V2rayConfigUtil {
//转成Json
val v2rayConfig = Gson().fromJson(assets, V2rayConfig::class.java) ?: return result
- //v2rayConfig.log.loglevel = settingsStorage?.decodeString(AppConfig.PREF_LOGLEVEL) ?: "warning"
+ v2rayConfig.log.loglevel = settingsStorage?.decodeString(AppConfig.PREF_LOGLEVEL)
+ ?: "warning"
inbounds(v2rayConfig)
@@ -89,8 +91,8 @@ object V2rayConfigUtil {
*/
private fun inbounds(v2rayConfig: V2rayConfig): Boolean {
try {
- //val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT) ?: AppConfig.PORT_SOCKS)
- //val httpPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT) ?: AppConfig.PORT_HTTP)
+ val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT), AppConfig.PORT_SOCKS.toInt())
+ val httpPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT), AppConfig.PORT_HTTP.toInt())
v2rayConfig.inbounds.forEach { curInbound ->
if (settingsStorage?.decodeBool(AppConfig.PREF_PROXY_SHARING) != true) {
@@ -98,7 +100,7 @@ object V2rayConfigUtil {
curInbound.listen = "127.0.0.1"
}
}
- v2rayConfig.inbounds[0].port = 10808
+ v2rayConfig.inbounds[0].port = socksPort
val fakedns = settingsStorage?.decodeBool(AppConfig.PREF_FAKE_DNS_ENABLED)
?: false
val sniffAllTlsAndHttp = settingsStorage?.decodeBool(AppConfig.PREF_SNIFFING_ENABLED, true)
@@ -111,7 +113,7 @@ object V2rayConfigUtil {
v2rayConfig.inbounds[0].sniffing?.destOverride?.add("fakedns")
}
- //v2rayConfig.inbounds[1].port = httpPort
+ v2rayConfig.inbounds[1].port = httpPort
// if (httpPort > 0) {
// val httpCopy = v2rayConfig.inbounds[0].copy()
@@ -149,7 +151,8 @@ object V2rayConfigUtil {
v2rayConfig.routing.domainStrategy = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_DOMAIN_STRATEGY)
?: "IPIfNonMatch"
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: "0"
+ v2rayConfig.routing.domainMatcher = "mph"
+ val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: ERoutingMode.GLOBAL_PROXY.value
// Hardcode googleapis.cn
val googleapisRoute = V2rayConfig.RoutingBean.RulesBean(
@@ -159,18 +162,26 @@ object V2rayConfigUtil {
)
when (routingMode) {
- "1" -> {
+ ERoutingMode.BYPASS_LAN.value -> {
routingGeo("ip", "private", AppConfig.TAG_DIRECT, v2rayConfig)
}
- "2" -> {
+ ERoutingMode.BYPASS_MAINLAND.value -> {
routingGeo("", "cn", AppConfig.TAG_DIRECT, v2rayConfig)
v2rayConfig.routing.rules.add(0, googleapisRoute)
}
- "3" -> {
+ ERoutingMode.BYPASS_LAN_MAINLAND.value -> {
routingGeo("ip", "private", AppConfig.TAG_DIRECT, v2rayConfig)
routingGeo("", "cn", AppConfig.TAG_DIRECT, v2rayConfig)
v2rayConfig.routing.rules.add(0, googleapisRoute)
}
+ ERoutingMode.GLOBAL_DIRECT.value -> {
+ val globalDirect = V2rayConfig.RoutingBean.RulesBean(
+ type = "field",
+ outboundTag = AppConfig.TAG_DIRECT,
+ port = "0-65535"
+ )
+ v2rayConfig.routing.rules.add(globalDirect)
+ }
}
} catch (e: Exception) {
e.printStackTrace()
@@ -281,11 +292,11 @@ object V2rayConfigUtil {
port = 53,
network = "tcp,udp")
- //val localDnsPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_LOCAL_DNS_PORT) ?: AppConfig.PORT_LOCAL_DNS)
+ val localDnsPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
v2rayConfig.inbounds.add(
V2rayConfig.InboundBean(
tag = "dns-in",
- port = 10807,
+ port = localDnsPort,
listen = "127.0.0.1",
protocol = "dokodemo-door",
settings = dnsInboundSettings,
@@ -335,15 +346,15 @@ object V2rayConfigUtil {
// domestic DNS
val directDomain = userRule2Domian(settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
?: "")
- val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: "0"
- if (directDomain.size > 0 || routingMode == "2" || routingMode == "3") {
+ val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: ERoutingMode.GLOBAL_PROXY.value
+ if (directDomain.size > 0 || routingMode == ERoutingMode.BYPASS_MAINLAND.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
val domesticDns = Utils.getDomesticDnsServers()
val geositeCn = arrayListOf("geosite:cn")
val geoipCn = arrayListOf("geoip:cn")
if (directDomain.size > 0) {
servers.add(V2rayConfig.DnsBean.ServersBean(domesticDns.first(), 53, directDomain, geoipCn))
}
- if (routingMode == "2" || routingMode == "3") {
+ if (routingMode == ERoutingMode.BYPASS_MAINLAND.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
servers.add(V2rayConfig.DnsBean.ServersBean(domesticDns.first(), 53, geositeCn, geoipCn))
}
if (Utils.isPureIpAddress(domesticDns.first())) {
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt
index c2b106c3..7b56bdf4 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt
@@ -1,35 +1,37 @@
package com.v2ray.ang.viewmodel
import android.app.Application
+import android.content.*
+import android.util.Log
+import android.view.LayoutInflater
+import android.widget.ArrayAdapter
+import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.util.Log
+import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig
+import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.R
-import com.v2ray.ang.dto.EConfigType
-import com.v2ray.ang.dto.ServerConfig
-import com.v2ray.ang.dto.V2rayConfig
+import com.v2ray.ang.databinding.DialogConfigFilterBinding
+import com.v2ray.ang.dto.*
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.*
import com.v2ray.ang.util.MmkvManager.KEY_ANG_CONFIGS
import kotlinx.coroutines.*
import java.util.*
-import java.util.concurrent.ConcurrentHashMap
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
private val serverRawStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SERVER_RAW, MMKV.MULTI_PROCESS_MODE) }
var serverList = MmkvManager.decodeServerList()
+ var subscriptionId: String = ""
+ var keywordFilter: String = ""
private set
- val serversCache = ConcurrentHashMap()
+ val serversCache = mutableListOf()
val isRunning by lazy { MutableLiveData() }
val updateListAction by lazy { MutableLiveData() }
val updateTestResultAction by lazy { MutableLiveData() }
@@ -45,65 +47,76 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
override fun onCleared() {
getApplication().unregisterReceiver(mMsgReceiver)
tcpingTestScope.coroutineContext[Job]?.cancelChildren()
- Utils.closeAllTcpSockets()
- Log.i(AppConfig.ANG_PACKAGE, "Main ViewModel is cleared")
+ SpeedtestUtil.closeAllTcpSockets()
+ Log.i(ANG_PACKAGE, "Main ViewModel is cleared")
super.onCleared()
}
fun reloadServerList() {
serverList = MmkvManager.decodeServerList()
- updateCache()
- updateListAction.value = -1
+ viewModelScope.launch(Dispatchers.Default) {
+ updateCache()
+ launch(Dispatchers.Main) {
+ updateListAction.value = -1
+ }
+ }
}
fun removeServer(guid: String) {
serverList.remove(guid)
MmkvManager.removeServer(guid)
+ serversCache.removeAt(getPosition(guid))
}
fun appendCustomConfigServer(server: String) {
val config = ServerConfig.create(EConfigType.CUSTOM)
config.remarks = System.currentTimeMillis().toString()
+ config.subscriptionId = subscriptionId
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
val key = MmkvManager.encodeServerConfig("", config)
serverRawStorage?.encode(key, server)
serverList.add(key)
- serversCache[key] = config
+ serversCache.add(ServersCache(key,config))
}
fun swapServer(fromPosition: Int, toPosition: Int) {
Collections.swap(serverList, fromPosition, toPosition)
+ Collections.swap(serversCache, fromPosition, toPosition)
mainStorage?.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList))
}
+ @Synchronized
fun updateCache() {
serversCache.clear()
- GlobalScope.launch(Dispatchers.Default) {
- serverList.forEach { guid ->
- MmkvManager.decodeServerConfig(guid)?.let {
- serversCache[guid] = it
- }
+ for (guid in serverList) {
+ val config = MmkvManager.decodeServerConfig(guid) ?: continue
+ if (subscriptionId.isNotEmpty() && subscriptionId != config.subscriptionId) {
+ continue
+ }
+
+ if (keywordFilter.isEmpty() || config.remarks.contains(keywordFilter)) {
+ serversCache.add(ServersCache(guid, config))
}
}
}
fun testAllTcping() {
tcpingTestScope.coroutineContext[Job]?.cancelChildren()
- Utils.closeAllTcpSockets()
+ SpeedtestUtil.closeAllTcpSockets()
MmkvManager.clearAllTestDelayResults()
updateListAction.value = -1 // update all
getApplication().toast(R.string.connection_test_testing)
- for (guid in serverList) {
- serversCache.getOrElse(guid) { MmkvManager.decodeServerConfig(guid) }?.getProxyOutbound()?.let { outbound ->
+ for (item in serversCache) {
+ item.config.getProxyOutbound()?.let { outbound ->
val serverAddress = outbound.getServerAddress()
val serverPort = outbound.getServerPort()
if (serverAddress != null && serverPort != null) {
tcpingTestScope.launch {
- val testResult = Utils.tcping(serverAddress, serverPort)
+ val testResult = SpeedtestUtil.tcping(serverAddress, serverPort)
launch(Dispatchers.Main) {
- MmkvManager.encodeServerTestDelayMillis(guid, testResult)
- updateListAction.value = serverList.indexOf(guid)
+ MmkvManager.encodeServerTestDelayMillis(item.guid, testResult)
+ updateListAction.value = getPosition(item.guid)
}
}
}
@@ -111,16 +124,84 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
}
}
- 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
+ fun testAllRealPing() {
+ MessageUtil.sendMsg2TestService(getApplication(), AppConfig.MSG_MEASURE_CONFIG_CANCEL, "")
+ MmkvManager.clearAllTestDelayResults()
+ updateListAction.value = -1 // update all
+
+ getApplication().toast(R.string.connection_test_testing)
+ viewModelScope.launch(Dispatchers.Default) { // without Dispatchers.Default viewModelScope will launch in main thread
+ for (item in serversCache) {
+ val config = V2rayConfigUtil.getV2rayConfig(getApplication(), item.guid)
+ if (config.status) {
+ MessageUtil.sendMsg2TestService(getApplication(), AppConfig.MSG_MEASURE_CONFIG, Pair(item.guid, config.content))
+ }
}
}
}
+ fun testCurrentServerRealPing() {
+ MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_MEASURE_DELAY, "")
+ }
+
+ fun filterConfig(context :Context) {
+ val subscriptions = MmkvManager.decodeSubscriptions()
+ val listId = subscriptions.map { it.first }.toList().toMutableList()
+ val listRemarks = subscriptions.map { it.second.remarks }.toList().toMutableList()
+ listRemarks += context.getString(R.string.filter_config_all)
+ val checkedItem = if (subscriptionId.isNotEmpty()) {
+ listId.indexOf(subscriptionId)
+ } else {
+ listRemarks.count() - 1
+ }
+
+ val ivBinding = DialogConfigFilterBinding.inflate(LayoutInflater.from(context))
+ ivBinding.spSubscriptionId.adapter = ArrayAdapter( context, android.R.layout.simple_spinner_dropdown_item, listRemarks)
+ ivBinding.spSubscriptionId.setSelection(checkedItem)
+ ivBinding.etKeyword.text = Utils.getEditable(keywordFilter)
+ val builder = AlertDialog.Builder(context).setView(ivBinding.root)
+ builder.setTitle(R.string.title_filter_config)
+ builder.setPositiveButton(R.string.tasker_setting_confirm) { dialogInterface: DialogInterface?, _: Int ->
+ try {
+ val position = ivBinding.spSubscriptionId.selectedItemPosition
+ subscriptionId = if (listRemarks.count() - 1 == position) {
+ ""
+ } else {
+ subscriptions[position].first
+ }
+ keywordFilter = ivBinding.etKeyword.text.toString()
+ reloadServerList()
+
+ dialogInterface?.dismiss()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ builder.show()
+// AlertDialog.Builder(context)
+// .setSingleChoiceItems(listRemarks.toTypedArray(), checkedItem) { dialog, i ->
+// try {
+// subscriptionId = if (listRemarks.count() - 1 == i) {
+// ""
+// } else {
+// subscriptions[i].first
+// }
+// reloadServerList()
+// dialog.dismiss()
+// } catch (e: Exception) {
+// e.printStackTrace()
+// }
+// }.show()
+ }
+
+ fun getPosition(guid: String) : Int {
+ serversCache.forEachIndexed { index, it ->
+ if (it.guid == guid)
+ return index
+ }
+ return -1
+ }
+
private val mMsgReceiver = object : BroadcastReceiver() {
override fun onReceive(ctx: Context?, intent: Intent?) {
when (intent?.getIntExtra("key", 0)) {
@@ -141,6 +222,14 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
AppConfig.MSG_STATE_STOP_SUCCESS -> {
isRunning.value = false
}
+ AppConfig.MSG_MEASURE_DELAY_SUCCESS -> {
+ updateTestResultAction.value = intent.getStringExtra("content")
+ }
+ AppConfig.MSG_MEASURE_CONFIG_SUCCESS -> {
+ val resultPair = intent.getSerializableExtra("content") as Pair
+ MmkvManager.encodeServerTestDelayMillis(resultPair.first, resultPair.second)
+ updateListAction.value = getPosition(resultPair.first)
+ }
}
}
}
diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
index daac06c3..2b40cc39 100644
--- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
+++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt
@@ -1,10 +1,10 @@
package com.v2ray.ang.viewmodel
import android.app.Application
-import androidx.lifecycle.AndroidViewModel
import android.content.SharedPreferences
-import androidx.preference.PreferenceManager
import android.util.Log
+import androidx.lifecycle.AndroidViewModel
+import androidx.preference.PreferenceManager
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
import com.v2ray.ang.util.MmkvManager
@@ -30,6 +30,11 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_VPN_DNS,
AppConfig.PREF_REMOTE_DNS,
AppConfig.PREF_DOMESTIC_DNS,
+ AppConfig.PREF_LOCAL_DNS_PORT,
+ AppConfig.PREF_SOCKS_PORT,
+ AppConfig.PREF_HTTP_PORT,
+ AppConfig.PREF_LOGLEVEL,
+ AppConfig.PREF_LANGUAGE,
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
AppConfig.PREF_ROUTING_MODE,
AppConfig.PREF_V2RAY_ROUTING_AGENT,
@@ -41,9 +46,11 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_PROXY_SHARING,
AppConfig.PREF_LOCAL_DNS_ENABLED,
AppConfig.PREF_FAKE_DNS_ENABLED,
- AppConfig.PREF_FORWARD_IPV6,
+ AppConfig.PREF_ALLOW_INSECURE,
+ AppConfig.PREF_PREFER_IPV6,
AppConfig.PREF_PER_APP_PROXY,
- AppConfig.PREF_BYPASS_APPS, -> {
+ AppConfig.PREF_BYPASS_APPS,
+ AppConfig.PREF_CONFIRM_REMOVE, -> {
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
}
AppConfig.PREF_SNIFFING_ENABLED -> {
diff --git a/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_direct.png b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_direct.png
new file mode 100644
index 00000000..a9fe7cdf
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_direct.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_name.png b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_name.png
new file mode 100644
index 00000000..1f0f31fc
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_name.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_proxy.png b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_proxy.png
new file mode 100644
index 00000000..048bb16a
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-hdpi/ic_stat_proxy.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_direct.png b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_direct.png
new file mode 100644
index 00000000..0f0d00c6
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_direct.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_name.png b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_name.png
new file mode 100644
index 00000000..ac443403
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_name.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_proxy.png b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_proxy.png
new file mode 100644
index 00000000..f0a39da4
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-mdpi/ic_stat_proxy.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_direct.png b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_direct.png
new file mode 100644
index 00000000..2dcd5d92
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_direct.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_name.png
new file mode 100644
index 00000000..7af529f1
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_proxy.png b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_proxy.png
new file mode 100644
index 00000000..36bba560
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xhdpi/ic_stat_proxy.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_direct.png b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_direct.png
new file mode 100644
index 00000000..f8bd77ef
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_direct.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
new file mode 100644
index 00000000..0ac2448f
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ
diff --git a/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_proxy.png b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_proxy.png
new file mode 100644
index 00000000..a10f0fe0
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xxhdpi/ic_stat_proxy.png differ
diff --git a/V2rayNG/app/src/main/res/drawable/ic_stat_direct.png b/V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_direct.png
similarity index 100%
rename from V2rayNG/app/src/main/res/drawable/ic_stat_direct.png
rename to V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_direct.png
diff --git a/V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png b/V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png
new file mode 100644
index 00000000..dd313da0
Binary files /dev/null and b/V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png differ
diff --git a/V2rayNG/app/src/main/res/drawable/ic_stat_proxy.png b/V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_proxy.png
similarity index 100%
rename from V2rayNG/app/src/main/res/drawable/ic_stat_proxy.png
rename to V2rayNG/app/src/main/res/drawable-xxxhdpi/ic_stat_proxy.png
diff --git a/V2rayNG/app/src/main/res/drawable/background_test_button.xml b/V2rayNG/app/src/main/res/drawable/background_test_button.xml
deleted file mode 100644
index ed2c5e68..00000000
--- a/V2rayNG/app/src/main/res/drawable/background_test_button.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml
new file mode 100644
index 00000000..171a9b30
--- /dev/null
+++ b/V2rayNG/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/V2rayNG/app/src/main/res/drawable/ic_fab_uncheck.png b/V2rayNG/app/src/main/res/drawable/ic_fab_uncheck.png
deleted file mode 100644
index 39a10413..00000000
Binary files a/V2rayNG/app/src/main/res/drawable/ic_fab_uncheck.png and /dev/null differ
diff --git a/V2rayNG/app/src/main/res/drawable/ic_file_white_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_file_white_24dp.xml
new file mode 100644
index 00000000..f7f9df2e
--- /dev/null
+++ b/V2rayNG/app/src/main/res/drawable/ic_file_white_24dp.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/drawable/ic_outline_filter_alt_white_24.xml b/V2rayNG/app/src/main/res/drawable/ic_outline_filter_alt_white_24.xml
new file mode 100644
index 00000000..6cb82eff
--- /dev/null
+++ b/V2rayNG/app/src/main/res/drawable/ic_outline_filter_alt_white_24.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/V2rayNG/app/src/main/res/drawable/ic_qu_scan_black_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_qu_scan_black_24dp.xml
index a31063ba..e0b32bf4 100644
--- a/V2rayNG/app/src/main/res/drawable/ic_qu_scan_black_24dp.xml
+++ b/V2rayNG/app/src/main/res/drawable/ic_qu_scan_black_24dp.xml
@@ -5,14 +5,14 @@
android:viewportHeight="48">
diff --git a/V2rayNG/app/src/main/res/drawable/ic_qu_settings_black_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_qu_settings_black_24dp.xml
index 01f193f6..063171a3 100644
--- a/V2rayNG/app/src/main/res/drawable/ic_qu_settings_black_24dp.xml
+++ b/V2rayNG/app/src/main/res/drawable/ic_qu_settings_black_24dp.xml
@@ -4,10 +4,10 @@
android:viewportHeight="1024"
android:viewportWidth="1024">
diff --git a/V2rayNG/app/src/main/res/drawable/ic_qu_switch_black_24dp.xml b/V2rayNG/app/src/main/res/drawable/ic_qu_switch_black_24dp.xml
index 6bc10fd8..97f8859d 100644
--- a/V2rayNG/app/src/main/res/drawable/ic_qu_switch_black_24dp.xml
+++ b/V2rayNG/app/src/main/res/drawable/ic_qu_switch_black_24dp.xml
@@ -9,7 +9,7 @@
android:bottom="2dp" />
-
-
+
-
\ No newline at end of file
+
diff --git a/V2rayNG/app/src/main/res/drawable/ic_shortcut_background.xml b/V2rayNG/app/src/main/res/drawable/ic_shortcut_background.xml
index 61d2d992..a62b720b 100644
--- a/V2rayNG/app/src/main/res/drawable/ic_shortcut_background.xml
+++ b/V2rayNG/app/src/main/res/drawable/ic_shortcut_background.xml
@@ -2,6 +2,6 @@
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/drawable/ic_start_busy.xml b/V2rayNG/app/src/main/res/drawable/ic_start_busy.xml
deleted file mode 100644
index f0154c37..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_start_busy.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_start_connected.xml b/V2rayNG/app/src/main/res/drawable/ic_start_connected.xml
deleted file mode 100644
index bc8c3664..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_start_connected.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_start_connected_black.xml b/V2rayNG/app/src/main/res/drawable/ic_start_connected_black.xml
deleted file mode 100644
index 90385316..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_start_connected_black.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_start_idle.xml b/V2rayNG/app/src/main/res/drawable/ic_start_idle.xml
deleted file mode 100644
index ef9b99d3..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_start_idle.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_v.xml b/V2rayNG/app/src/main/res/drawable/ic_v.xml
deleted file mode 100644
index cb4930cc..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_v.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_v_connected_black.xml b/V2rayNG/app/src/main/res/drawable/ic_v_connected_black.xml
deleted file mode 100644
index 0c216c12..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_v_connected_black.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/ic_v_idle.xml b/V2rayNG/app/src/main/res/drawable/ic_v_idle.xml
deleted file mode 100644
index 87f0cca1..00000000
--- a/V2rayNG/app/src/main/res/drawable/ic_v_idle.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
diff --git a/V2rayNG/app/src/main/res/drawable/nav_header_bg.png b/V2rayNG/app/src/main/res/drawable/nav_header_bg.png
index d383f6a5..82cb00af 100644
Binary files a/V2rayNG/app/src/main/res/drawable/nav_header_bg.png and b/V2rayNG/app/src/main/res/drawable/nav_header_bg.png differ
diff --git a/V2rayNG/app/src/main/res/layout/activity_bypass_list.xml b/V2rayNG/app/src/main/res/layout/activity_bypass_list.xml
index 7b1028db..9baff9a2 100644
--- a/V2rayNG/app/src/main/res/layout/activity_bypass_list.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_bypass_list.xml
@@ -1,113 +1,92 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_height="wrap_content" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_main.xml b/V2rayNG/app/src/main/res/layout/activity_main.xml
index 972af7c1..5f3c9e95 100644
--- a/V2rayNG/app/src/main/res/layout/activity_main.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_main.xml
@@ -1,7 +1,6 @@
+ android:layout_height="?attr/actionBarSize" />
-
+ android:fitsSystemWindows="true">
+ android:focusable="true"
+ android:nextFocusLeft="@+id/recycler_view">
-
+ android:textColor="@color/colorWhite" />
@@ -80,25 +75,25 @@
android:id="@+id/fabProgressCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="24dp"
- android:layout_gravity="bottom|end">
+ android:layout_gravity="bottom|end"
+ android:layout_marginBottom="24dp">
+ android:nextFocusLeft="@+id/layout_test"
+ android:src="@drawable/ic_stat_name"
+ app:layout_anchorGravity="bottom|right|end" />
@@ -111,23 +106,19 @@
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
- app:itemIconTint="@color/colorPrimary_dark"
- app:itemTextColor="@color/colorPrimary"
app:menu="@menu/menu_drawer" >
+ android:padding="2dp">
+ android:gravity="center" />
diff --git a/V2rayNG/app/src/main/res/layout/activity_none.xml b/V2rayNG/app/src/main/res/layout/activity_none.xml
index 1aa97aea..d7681698 100644
--- a/V2rayNG/app/src/main/res/layout/activity_none.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_none.xml
@@ -1,6 +1,5 @@
+ android:layout_height="match_parent">
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_custom_config.xml b/V2rayNG/app/src/main/res/layout/activity_server_custom_config.xml
index 4f0a5e68..2f1aefc9 100644
--- a/V2rayNG/app/src/main/res/layout/activity_server_custom_config.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_server_custom_config.xml
@@ -76,7 +76,5 @@
android:layout_marginTop="@dimen/layout_margin_top_height" />
-
-
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml b/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml
index 3f0af8fb..dba1c142 100644
--- a/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_server_shadowsocks.xml
@@ -94,7 +94,7 @@
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/edit_height"
- android:inputType="textPassword" />
+ android:inputType="text" />
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_socks.xml b/V2rayNG/app/src/main/res/layout/activity_server_socks.xml
index 6658178d..5f34c37c 100644
--- a/V2rayNG/app/src/main/res/layout/activity_server_socks.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_server_socks.xml
@@ -80,51 +80,51 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_margin_top_height"
+ android:orientation="vertical">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_lab_security4" />
+ android:id="@+id/et_security"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/edit_height"
+ android:inputType="text" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_margin_top_height"
+ android:orientation="vertical">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_lab_id4" />
+ android:id="@+id/et_id"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/edit_height"
+ android:inputType="text" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/layout_margin_top_height"
+ android:layout_marginTop="@dimen/layout_margin_top_height"
+ android:orientation="vertical" />
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml b/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml
new file mode 100644
index 00000000..fbf6bcaf
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/activity_server_trojan.xml
@@ -0,0 +1,272 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_vless.xml b/V2rayNG/app/src/main/res/layout/activity_server_vless.xml
new file mode 100644
index 00000000..07762d4a
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/activity_server_vless.xml
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml b/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml
index ff11d9f0..d73f92fc 100644
--- a/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_server_vmess.xml
@@ -98,6 +98,26 @@
+
+
+
+
+
+
+
+
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_lab_more_function"
+ android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_lab_network" />
+ android:id="@+id/sp_network"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/edit_height"
+ android:entries="@array/networks" />
+ android:entries="@array/streamsecuritys"
+ android:nextFocusDown="@+id/et_sni" />
+
+
+
+
+
+
+
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/layout_margin_top_height"
+ android:orientation="vertical">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/server_lab_allow_insecure" />
+ android:id="@+id/sp_allow_insecure"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/edit_height"
+ android:entries="@array/allowinsecures"
+ android:nextFocusUp="@+id/et_sni" />
-
-
-
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/activity_tasker.xml b/V2rayNG/app/src/main/res/layout/activity_tasker.xml
index 8994d841..5c798c37 100644
--- a/V2rayNG/app/src/main/res/layout/activity_tasker.xml
+++ b/V2rayNG/app/src/main/res/layout/activity_tasker.xml
@@ -45,4 +45,4 @@
android:choiceMode="singleChoice" />
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/dialog_config_filter.xml b/V2rayNG/app/src/main/res/layout/dialog_config_filter.xml
new file mode 100644
index 00000000..115371df
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/dialog_config_filter.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/layout/fragment_routing_settings.xml b/V2rayNG/app/src/main/res/layout/fragment_routing_settings.xml
index 815b3a31..45f2a305 100644
--- a/V2rayNG/app/src/main/res/layout/fragment_routing_settings.xml
+++ b/V2rayNG/app/src/main/res/layout/fragment_routing_settings.xml
@@ -26,11 +26,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:background="@android:drawable/edit_text"
android:gravity="top"
android:inputType="textMultiLine"
- android:maxLines="100"
- android:minLines="10"
+ android:maxLines="1000"
+ android:minLines="20"
android:scrollbars="vertical" />
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_bypass_list.xml b/V2rayNG/app/src/main/res/layout/item_recycler_bypass_list.xml
index d705e5eb..03ad10a7 100644
--- a/V2rayNG/app/src/main/res/layout/item_recycler_bypass_list.xml
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_bypass_list.xml
@@ -9,16 +9,16 @@
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_main.xml b/V2rayNG/app/src/main/res/layout/item_recycler_main.xml
index a0855c40..acae822a 100644
--- a/V2rayNG/app/src/main/res/layout/item_recycler_main.xml
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_main.xml
@@ -8,44 +8,45 @@
android:gravity="center_vertical">
+ android:orientation="horizontal">
-
+
+ android:orientation="vertical"
+ android:paddingStart="5dp">
-
+ android:id="@+id/tv_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:minLines="1"
+ android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
-
+ android:gravity="center"
+ android:nextFocusLeft="@+id/info_container"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_margin_spacing">
+ android:src="@drawable/ic_share_black_24dp"
+ app:tint="?attr/colorMainText" />
+ android:focusable="true"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_margin_spacing">
+ android:src="@drawable/ic_edit_black_24dp"
+ app:tint="?attr/colorMainText" />
+ android:focusable="true"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_margin_spacing">
+ android:src="@drawable/ic_delete_black_24dp"
+ app:tint="?attr/colorMainText" />
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml b/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
index aa370e41..a4467e27 100644
--- a/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_sub_setting.xml
@@ -1,5 +1,6 @@
+ card_view:cardCornerRadius="5dp">
-
+ android:id="@+id/chk_enable"
+ android:layout_width="10dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:orientation="vertical" />
+ android:id="@+id/tv_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
@@ -65,13 +67,13 @@
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true"
+ android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
- android:visibility="invisible"
- android:background="?android:attr/selectableItemBackground"
- android:clickable="true"
- android:focusable="true">
+ android:visibility="invisible">
+ android:gravity="center"
+ android:nextFocusLeft="@+id/info_container"
+ android:orientation="vertical"
+ android:padding="@dimen/layout_margin_spacing">
+ android:src="@drawable/ic_edit_black_24dp"
+ app:tint="?attr/colorMainText" />
diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_user_asset.xml b/V2rayNG/app/src/main/res/layout/item_recycler_user_asset.xml
new file mode 100644
index 00000000..54651771
--- /dev/null
+++ b/V2rayNG/app/src/main/res/layout/item_recycler_user_asset.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/layout/nav_header.xml b/V2rayNG/app/src/main/res/layout/nav_header.xml
index 8eeb7936..2f5d3ed6 100644
--- a/V2rayNG/app/src/main/res/layout/nav_header.xml
+++ b/V2rayNG/app/src/main/res/layout/nav_header.xml
@@ -4,21 +4,22 @@
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/nav_header_bg"
- android:gravity="bottom"
+ android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:theme="@style/ThemeOverlay.AppCompat.Dark">
-
+ android:paddingTop="@dimen/activity_vertical_margin">
+ android:textColor="@color/white"
+ android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
diff --git a/V2rayNG/app/src/main/res/layout/nav_toolbar.xml b/V2rayNG/app/src/main/res/layout/nav_toolbar.xml
index c77a5f07..262787df 100644
--- a/V2rayNG/app/src/main/res/layout/nav_toolbar.xml
+++ b/V2rayNG/app/src/main/res/layout/nav_toolbar.xml
@@ -2,14 +2,12 @@
+ android:layout_height="?android:attr/actionBarSize">
+ app:layout_scrollFlags="scroll|enterAlways" />
-
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/nav_view.xml b/V2rayNG/app/src/main/res/layout/nav_view.xml
index 8268c6e8..34fd03a3 100644
--- a/V2rayNG/app/src/main/res/layout/nav_view.xml
+++ b/V2rayNG/app/src/main/res/layout/nav_view.xml
@@ -6,6 +6,4 @@
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
- app:itemTextColor="@color/colorPrimary"
- app:itemIconTint="@color/colorPrimary_dark"
- app:menu="@menu/menu_drawer" />
+ app:menu="@menu/menu_drawer" />
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/layout/widget_switch.xml b/V2rayNG/app/src/main/res/layout/widget_switch.xml
index 5d4ec237..81d26fa6 100644
--- a/V2rayNG/app/src/main/res/layout/widget_switch.xml
+++ b/V2rayNG/app/src/main/res/layout/widget_switch.xml
@@ -11,5 +11,5 @@
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
- android:src="@drawable/ic_v" />
-
\ No newline at end of file
+ android:src="@drawable/ic_stat_name" />
+
diff --git a/V2rayNG/app/src/main/res/menu/menu_asset.xml b/V2rayNG/app/src/main/res/menu/menu_asset.xml
new file mode 100644
index 00000000..6a59f05a
--- /dev/null
+++ b/V2rayNG/app/src/main/res/menu/menu_asset.xml
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/menu/menu_bypass_list.xml b/V2rayNG/app/src/main/res/menu/menu_bypass_list.xml
index dae2bcf1..a7824754 100644
--- a/V2rayNG/app/src/main/res/menu/menu_bypass_list.xml
+++ b/V2rayNG/app/src/main/res/menu/menu_bypass_list.xml
@@ -1,15 +1,34 @@
\ No newline at end of file
+
+
+
+
+
+
diff --git a/V2rayNG/app/src/main/res/menu/menu_drawer.xml b/V2rayNG/app/src/main/res/menu/menu_drawer.xml
index a10ac0d6..42b81633 100644
--- a/V2rayNG/app/src/main/res/menu/menu_drawer.xml
+++ b/V2rayNG/app/src/main/res/menu/menu_drawer.xml
@@ -13,30 +13,29 @@
android:id="@+id/settings"
android:icon="@drawable/ic_settings_white_24dp"
android:title="@string/title_settings" />
-
+
+ android:id="@+id/promotion"
+ android:icon="@drawable/ic_whatshot_white_24dp"
+ android:title="@string/title_pref_promotion" />
+ android:id="@+id/logcat"
+ android:icon="@drawable/ic_logcat_white_24dp"
+ android:title="@string/title_logcat" />
-
+ android:id="@+id/feedback"
+ android:icon="@drawable/ic_feedback_white_24dp"
+ android:title="@string/title_pref_feedback" />
+ android:id="@+id/placeholder"
+ android:enabled="false"
+ android:title="" />
diff --git a/V2rayNG/app/src/main/res/menu/menu_logcat.xml b/V2rayNG/app/src/main/res/menu/menu_logcat.xml
index 42042a67..e7529dbd 100644
--- a/V2rayNG/app/src/main/res/menu/menu_logcat.xml
+++ b/V2rayNG/app/src/main/res/menu/menu_logcat.xml
@@ -1,14 +1,14 @@
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/menu/menu_main.xml b/V2rayNG/app/src/main/res/menu/menu_main.xml
index 445cf054..538074cf 100644
--- a/V2rayNG/app/src/main/res/menu/menu_main.xml
+++ b/V2rayNG/app/src/main/res/menu/menu_main.xml
@@ -4,7 +4,7 @@
-
+ app:showAsAction="ifRoom">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher.png b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher.png
index e3325fec..cb9b3d3d 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
index 4fa78dfd..4d38fcce 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 53e3a4c1..76cd6462 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/V2rayNG/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher.png b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 73d68777..aa289ac4 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
index bcd78b50..bac8f393 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index c344863d..010f682b 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/V2rayNG/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 0225c9df..3c04c3b5 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
index 7329ebc8..7da51749 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index bd041d1e..e24ac5db 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/V2rayNG/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 9450faa5..1fde9249 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
index 5deddcd7..2bc746a6 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index dd673eb4..448a4783 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/V2rayNG/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 0666a124..647b0a28 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 6e048168..dc7e3937 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index c5a9219d..ad44d89d 100644
Binary files a/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/V2rayNG/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/V2rayNG/app/src/main/res/values-sw360dp-v13/values-preference.xml b/V2rayNG/app/src/main/res/values-sw360dp-v13/values-preference.xml
index c19ba30b..99153624 100644
--- a/V2rayNG/app/src/main/res/values-sw360dp-v13/values-preference.xml
+++ b/V2rayNG/app/src/main/res/values-sw360dp-v13/values-preference.xml
@@ -1,6 +1,5 @@
-
false
0dp
-
+
\ No newline at end of file
diff --git a/ExtRes/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml
similarity index 100%
rename from ExtRes/values-vi/strings.xml
rename to V2rayNG/app/src/main/res/values-vi/strings.xml
diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
index dfa430f5..7c12fd00 100644
--- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
+++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml
@@ -1,6 +1,5 @@
- v2rayNG
开关
开关
初次使用此功能请先用APP添加配置
@@ -26,8 +25,10 @@
扫描二维码
从剪贴板导入
手动输入[Vmess]
+ 手动输入[VLESS]
手动输入[Shadowsocks]
手动输入[Socks]
+ 手动输入[Trojan]
自定义配置
从剪贴板导入自定义配置
从本地导入自定义配置
@@ -38,19 +39,25 @@
地址(address)
端口(port)
用户ID(id)
+ 额外ID(alterId)
加密方式(security)
传输协议(network)
- 功能设置(不清楚则保持默认值)
+ 底层传输方式(transport)
伪装类型(type)
gRPC 传输模式 (mode)
伪装域名(host)(host/ws host/h2 host)/QUIC 加密方式
path(ws path/h2 path)/QUIC 加密密钥/kcp seed/gRPC serviceName
- 底层传输安全(tls)
+ 传输层安全(tls)
跳过证书验证(allowInsecure)
+ SNI
服务器地址
服务器端口
密码
加密方式
+ 密码(可选)
+ 用户名(可选)
+ 加密(encryption)
+ 流控(flow)
成功
失败
没有数据
@@ -63,15 +70,24 @@
内容
剪贴板中没有数据
无效的网址
- 确保inbound有socks=10808,http=10809
+ 确保inbounds port和设置中的一致
+ 配置格式错误
+ Host(SNI)(可选)
+ 失败, 请使用文件管理器
+ 添加文件
+ 下载文件
+
正在加载
+ 搜索
全选
输入关键字
绕行模式
自动选中需代理应用
正在下载内容
+ 导出至剪贴板
+ 从剪贴板导入
设置
@@ -95,17 +111,13 @@
启用虚拟DNS
本地返回虚构解析结果 (减低延时 但个别应用可能无法使用)
- IPv6 路由
- 转发 IPv6 流量到远程服务器(测试)
+ IPv6优先
+ App优先使用IPv6地址连接服务器,同时开启VPN的IPv6路由
路由设置
域名策略
- 路由模式
- 自定义路由
-
- 捐赠
- 支持开发者
- 陆续增加一些试验性的进阶功能
+ 预定义规则
+ 自定义规则
远程DNS (可选)
DNS
@@ -115,6 +127,13 @@
境内DNS (可选)
DNS
+ 允许来自局域网的连接
+ 其他设备可以使用socks/http协议通过您的IP地址连接到代理,仅在受信任的网络中启用以避免未经授权的连接
+ 允许来自局域网的连接,请确保处于受信网络
+
+ 跳过证书验证(allowInsecure)
+ 传输层安全选tls时,默认跳过证书验证(allowInsecure)
+
SOCKS5代理端口
SOCKS5代理端口
@@ -124,6 +143,9 @@
本地DNS端口
本地DNS端口
+ 删除配置文件确认
+ 删除配置文件是否需要用户二次确认
+
反馈
反馈改进或漏洞至 GitHub
加入Telegram Group
@@ -132,26 +154,29 @@
推广
一些推广,点击查看详情(捐赠可去除)
+ 日志级别
模式
点此查看更多帮助
-
- 初始化错误:
- 无法查询到项目
- 错误:
- 错误,真实性验证失败.
- 感谢您的捐赠!
- 捐赠
- Paypal
+ 语言
Logcat
复制
- 删除
+ 清除
+ 服务重启
+ 删除全部配置
+ 删除无效配置(先测试)
导出全部(非自定义)配置至剪贴板
- 订阅设置
+ 订阅分组设置
备注
- 地址(url)
+ 可选地址(url)
+ 启用更新
更新订阅
- 测试所有配置延迟(Tcping)
+ 测试全部配置Tcping
+ 测试全部配置真连接
+ Geo 资源文件
+ 按测试结果排序
+ 过滤配置文件
+ 所有订阅分组
启动服务
确定
@@ -186,16 +211,12 @@
- - 全局
- - 绕过局域网地址
- - 绕过大陆地址
- - 绕过局域网及大陆地址
+ - 全局代理
+ - 绕过局域网地址而后代理
+ - 绕过大陆地址而后代理
+ - 绕过局域网及大陆地址而后代理
+ - 全局直连
- 代理共享
- 绑定代理入口ip到0.0.0.0
- 其他设备可以使用socks/http协议通过您的IP地址连接到代理\nHttp 代理: http://您的ip:10809\nSocks 代理: socks(4/5)://您的ip:10808\n仅在受信任的网络中启用以避免未经授权的连接
- 代理共享已启用,请确保处于受信网络
- 配置格式错误
- VPN
diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
index fc4f240c..927e1f05 100644
--- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
+++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml
@@ -1,77 +1,92 @@
- v2rayNG
開關
開關
- 首次使用此功能,請使用此應用程式新增組態
- Open navigation drawer
- Close navigation drawer
+ 首次使用此功能,請使用此應用程式新增伺服器
+ 開啟導覽匣
+ 關閉導覽匣
資料遷移成功!
資料遷移失敗!
停止
無法取得此權限
- 按一下瞭解更多
+ 瞭解更多
啟動服務
停止服務
啟動服務成功
啟動服務失敗
- 設定檔
+ 組態檔案
新增組態
儲存組態
刪除組態
- 自 QR Code 匯入組態
- 自剪貼簿匯入組態
+ 從 QR Code 匯入組態
+ 從剪貼簿匯入組態
手動鍵入 [Vmess]
+ 手動鍵入 [VLESS]
手動鍵入 [Shadowsocks]
手動鍵入 [Socks]
+ 手動鍵入 [Trojan]
自訂組態
- 自剪貼簿匯入自訂組態
- 自本機匯入自訂組態
- 自網址匯入自訂組態
- 掃描網址匯入自訂組態
+ 從剪貼簿匯入自訂組態
+ 從 URL 匯入自訂組態
+ 從 URL 匯入自訂組態
+ 掃描 URL 匯入自訂組態
確定刪除?
備註
位址
埠
使用者 ID
+ alterId
安全性
網路
- 更多功能
+ 底層傳輸方式 (transport)
標頭類型
gRPC 傳輸模式 (mode)
要求主機 (host)(host/ws host/h2 host)/QUIC 加密方式
path(ws path/h2 path)/QUIC 加密金鑰/kcp seed/gRPC serviceName
- 傳輸層安全性 (tls)
+ 傳輸層安全 (tls)
跳過憑證驗證 (allowInsecure)
+ SNI
伺服器位址
伺服器埠
密碼
加密方式
+ 密碼 (可選)
+ 使用者名稱 (可選)
+ 加密 (encryption)
+ 流程 (flow)
成功
失敗
無資料
通訊協定不正確
解碼失敗
- 選取一個設定檔
+ 選取一個組態檔
請安裝檔案總管。
自訂組態
- 無效設定檔
+ 無效組態
內容
剪貼簿內無資料
- 網址無效
- 確保 inbound 有 socks=10808,http=10809
+ URL 無效
+ 確保 inbounds port 和設定中的一致
+ 組態格式不正確
+ Host(SNI)(可選)
+ 失敗,請使用檔案總管
+ 新增檔案
+ 下載檔案
載入
+ 搜尋
全選
輸入關鍵字
略過模式
- 自動選中需要 Proxy 的應用
+ 自動選中需 Proxy 應用
正在下載內容
+ 匯出至剪貼簿
+ 從剪貼簿匯入
@@ -79,51 +94,57 @@
進階
VPN 設定
Proxy 個別應用程式
- 常規:勾選的App被代理,未勾選的直連;\n繞行模式:勾選的App直連,未勾選的被代理.\n不明白者在菜單中選擇自動選中需代理應用
+ 常規:勾選的 App 啟用 Proxy,未勾選的直接連線;\n繞行模式:勾選的 App 直接連線,未勾選的啟用 Proxy。\n可在選單中選擇自動選中需 Proxy 應用
啟用 Mux
- 啟用或許會加快網路速度,關閉或許會閃爍
+ 啟用或許會加快網路速度,切換或許會閃爍
啟用速度顯示
- 在通知中顯示當前速度\n小圖示顯示流量的轉送情況
+ 在通知中顯示當前速度\n小圖示顯示流量的轉送狀況
- 啟用網路監測
- 從封包中監測網域 (預設啟用)
+ 啟用流量監聽
+ 從流量中監聽網域 (預設啟用)
- 啟用本地 DNS
- DNS 請求匯入 core 由 DNS 模塊處理 (建議啟用,可能需要轉送略過局域網及中國大陸)
+ 啟用本機 DNS
+ DNS 請求匯入 core 由 DNS 模塊處理 (建議啟用,如果需要轉送略過區域網路及中國大陸)
- 啟用偽 DNS
- 本地返回偽造解析結果 (減低延時,但個別應用可能無法使用)
+ 啟用假 DNS
+ 本機退回假解析結果 (減低延時,但個別應用可能無法使用)
- IPv6 路由
- 向遠端重新導向 IPv6 流量 (測試)
+ IPv6 偏好
+ App 優先使用 IPv6 位址連線伺服器,同时開啟 VPN 的 IPv6 路由
轉送設定
網域策略
轉送模式
自訂轉送
- 捐助
- 向開發人員捐助
- 新增一些實驗性進階功能
-
遠端 DNS (可選)
DNS
VPN DNS (僅支援 IPv4/v6)
- 境内 DNS (可選)
+ 國內 DNS (可選)
DNS
+ 允許來自區域網路的連線
+ 其他裝置可以使用 socks/http 協定透過您的 IP 位址連線到 Proxy,僅在受信任的網路中啟用以避免未經授權的連線
+ 允許來自區域網路的連線,請確保處於受信網路
+
+ 跳過憑證驗證 (allowInsecure)
+ 傳輸層安全選 tls 時,預設跳過憑證驗證 (allowInsecure)
+
SOCKS5 Proxy 埠
SOCKS5 Proxy 埠
HTTP Proxy 埠
HTTP Proxy 埠
- 本地 DNS 埠
- 本地 DNS 埠
+ 本機 DNS 埠
+ 本機 DNS 埠
+
+ 刪除配置文件確認
+ 刪除配置文件是否需要用戶二次確認
意見回饋
前往 GitHub 回報錯誤
@@ -133,42 +154,45 @@
推廣
一些推廣,輕觸以檢視 (捐贈可去除)
+ 記錄層級
模式
- 點此查看更多幫助
-
- 錯誤設定:
- 未查詢到庫存
- 購買錯誤:
- 購買錯誤,真實性驗證失敗。
- 感謝您的捐助!
- 捐助
- Paypal
+ 輕觸以檢視說明
+ 語言
Logcat
複製
- 刪除
+ 清除
+ 服務重啟
+ 刪除全部組態
+ 刪除無效組態 (先偵測)
匯出全部 (非自訂) 組態至剪貼簿
- 訂閱設定
+ 訂閱分組設定
備註
- 位址 (url)
+ Optional URL
+ 啟用更新
更新訂閱
- 測試所有組態延遲 (Tcping)
+ 偵測所有組態 Tcping
+ 偵測所有組態真延遲
+ Geo 資源檔案
+ 依偵測結果排序
+ 過濾組態
+ 所有訂閱分組
啟動服務
確定
轉送設定
- 以半形逗號「,」分隔,記得儲存唷
+ 以半形逗號「,」分隔,並手動儲存
儲存
清除
掃描並取代
掃描並附加
設定預設轉送規則
- "檢查連線能力"
+ "測試連線能力"
"測試中……"
- "成功: %d 毫秒延遲"
- "偵測出網際網路連線失敗:%s"
+ "成功:%d ms延遲"
+ "測試網際網路連線失敗:%s"
"無法使用網際網路"
"錯誤碼:(#%d)"
"已連線,輕觸以檢查連線能力"
@@ -181,22 +205,18 @@
- - Proxy 網址或 IP
- - 直連網址或 IP
- - 已封鎖的網址或 IP
+ - Proxy URL 或 IP
+ - 直接連線 URL 或 IP
+ - 已封鎖的 URL 或 IP
- - 全域
- - 略過區域網路
- - 略過中國大陸
- - 略過區域網路及中國大陸
+ - 全域 Proxy
+ - 略過區域網路的 Proxy
+ - 略過中國大陸的 Proxy
+ - 略過區域網路及中國大陸的 Proxy
+ - 直接連線
- Proxy 共用
- 綁定 Proxy 入口 IP 到 0.0.0.0
- 其他裝置可以使用 socks/http 協定通過您的 IP 位址連線到 Proxy \nHttp Proxy:http://您的ip:10809\nSocks Proxy:socks(4/5)://您的ip:10808\n僅在受信任的網路中啟用以避免未經授權的連線
- Proxy 共用已啟用,請確保處於受信網路
- 組態格式錯誤
- VPN
diff --git a/V2rayNG/app/src/main/res/values/arrays.xml b/V2rayNG/app/src/main/res/values/arrays.xml
index 03e0f1ff..d4487fb6 100644
--- a/V2rayNG/app/src/main/res/values/arrays.xml
+++ b/V2rayNG/app/src/main/res/values/arrays.xml
@@ -71,6 +71,7 @@
- 1
- 2
- 3
+ - 4
@@ -137,4 +138,22 @@
- 208.0.0.0/4
- 240.0.0.0/4
+
+
+
+ - auto
+ - English
+ - 中文简体
+ - 中文繁體
+ - Tiếng Việt
+
+
+
+
+ - auto
+ - en
+ - zh-rCN
+ - zh-rTW
+ - vi
+
diff --git a/V2rayNG/app/src/main/res/values/attrs.xml b/V2rayNG/app/src/main/res/values/attrs.xml
new file mode 100644
index 00000000..1f970e54
--- /dev/null
+++ b/V2rayNG/app/src/main/res/values/attrs.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/values/colors.xml b/V2rayNG/app/src/main/res/values/colors.xml
index 0f46e604..a754f5d6 100644
--- a/V2rayNG/app/src/main/res/values/colors.xml
+++ b/V2rayNG/app/src/main/res/values/colors.xml
@@ -1,13 +1,24 @@
- #607D8B
- #455A64
- #CFD8DC
- #9E9E9E
- #212121
- #757575
- #FFFFFF
- #BDBDBD
- #185534
+ #009966
+ #FF0099
#247BA0
+ #009966
+ #999999
+ #CFD8DC
+ #212121
+
+
+
+ #2B2B2B
+ #161616
+ #D81B60
+ #FFFFFF
+ #000000
+
+ #2B2B2B
+ #161616
+ #12976F
+ #252525
+ #CCCCCC
diff --git a/V2rayNG/app/src/main/res/values/dimens.xml b/V2rayNG/app/src/main/res/values/dimens.xml
index 1b6eae66..d082409a 100644
--- a/V2rayNG/app/src/main/res/values/dimens.xml
+++ b/V2rayNG/app/src/main/res/values/dimens.xml
@@ -13,4 +13,4 @@
16dp
8dp
160dp
-
\ No newline at end of file
+
diff --git a/V2rayNG/app/src/main/res/values/ic_launcher_background.xml b/V2rayNG/app/src/main/res/values/ic_launcher_background.xml
index 6ddd41a2..c5d5899f 100644
--- a/V2rayNG/app/src/main/res/values/ic_launcher_background.xml
+++ b/V2rayNG/app/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #DEDEDE
+ #FFFFFF
\ No newline at end of file
diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml
index f6d5ec5c..6e047f2b 100644
--- a/V2rayNG/app/src/main/res/values/strings.xml
+++ b/V2rayNG/app/src/main/res/values/strings.xml
@@ -1,6 +1,6 @@
- v2rayNG
+ v2rayNG
Switch
Switch
First use of this feature, please use the app to add server
@@ -26,8 +26,10 @@
Import config from QRcode
Import config from Clipboard
Type manually[Vmess]
+ Type manually[VLESS]
Type manually[Shadowsocks]
Type manually[Socks]
+ Type manually[Trojan]
custom config
Import custom config from Clipboard
Import custom config from locally
@@ -38,19 +40,25 @@
address
port
id
+ alterId
security
Network
- more function
+ Transport
head type
gRPC mode
request host(host/ws host/h2 host)/QUIC security
path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName
tls
allowInsecure
+ SNI
address
port
password
security
+ Password(Optional)
+ User(Optional)
+ encryption
+ flow
Success
Failure
There is nothing
@@ -63,15 +71,23 @@
Content
There is no data in the clipboard
Invalid URL
- Ensure inbound has socks=10808,http=10809
+ Ensure inbounds port is consistent with the settings
+ Config malformed
+ Host(SNI)(Optional)
+ File copy failed, please use File Manager
+ Add files
+ Download files
Loading
+ Search
Select all
Enter keywords
Bypass Mode
Auto select proxy app
Downloading content
+ Export to Clipboard
+ Import from Clipboard
@@ -98,17 +114,13 @@
Enable fake DNS
local DNS returns fake IP address (faster, but it may not work for some apps)
- IPv6 Route
- Redirect IPv6 traffic to remote (BETA)
+ Prefer IPv6
+ Prefer IPv6 address and routes
Routing
Domain strategy
- Routing mode
- Custom routing
-
- Donate
- Donate developer
- Add some experimental advanced features
+ Predefined rules
+ Custom rules
Remote DNS (Optional)
DNS
@@ -118,6 +130,13 @@
Domestic DNS (Optional)
DNS
+ Allow connections from the LAN
+ Other devices can connect to proxy by your ip address through socks/http, Only enable in trusted network to avoid unauthorized connection
+ Allow connections from the LAN, Make sure you are in a trusted network
+
+ allowInsecure
+ When TLS, the default allowInsecure
+
SOCKS5 proxy port
SOCKS5 proxy port
@@ -127,6 +146,9 @@
Local DNS port
Local DNS port
+ Delete configuration file confirmation
+ Whether to delete the configuration file requires a second confirmation by the user
+
Feedback
Feedback enhancements or bugs to GitHub
Join Telegram Group
@@ -135,26 +157,29 @@
Promotion
Promotion,click for details(Donation can be removed)
+ Log Level
Mode
Click me for more help
-
- Error Setup:
- Error querying inventory
- Error Purchase:
- Error Purchase,Authenticity verification failed.
- Thank you for your donation!
- Donate
- Paypal
+ Language
Logcat
Copy
- Delete
+ Clear
+ Service restart
+ Delete all config
+ Delete invalid config(Test first)
Export non-custom configs to clipboard
- Subscription setting
+ Subscription group setting
remarks
- url
+ Optional URL
+ enable update
Update subscription
Tcping all configuration
+ Real delay all configuration
+ Geo asset files
+ Sorting by test results
+ Filter configuration file
+ All subscription groups
Start Service
Confirm
@@ -169,7 +194,7 @@
Check Connectivity
Testing…
- Success: HTTPS handshake took %dms
+ Success: HTTP connection took %dms
Fail to detect internet connection: %s
Internet Unavailable
Error code: #%d
@@ -189,16 +214,12 @@
- - Global
- - Bypassing the LAN address
- - Bypass mainland address
- - Bypassing LAN and mainland address
+ - Global proxy
+ - Bypassing the LAN address then proxy
+ - Bypass mainland address then proxy
+ - Bypassing LAN and mainland address then proxy
+ - Global direct
- Proxy sharing
- Bind inbound to 0.0.0.0
- Other devices can connect to proxy by your ip address through socks/http protocol\nHttp Proxy: http://yourIP:10809\nSocks Proxy: socks(4/5)://yourIP:10808\nOnly enable in trusted network to avoid unauthorized connection
- Proxy sharing enabled\nMake sure you are in a trusted network
- Config malformed
- VPN
diff --git a/V2rayNG/app/src/main/res/values/styles.xml b/V2rayNG/app/src/main/res/values/styles.xml
index ee224975..d775e998 100644
--- a/V2rayNG/app/src/main/res/values/styles.xml
+++ b/V2rayNG/app/src/main/res/values/styles.xml
@@ -1,4 +1,29 @@
+
+
+
+
+
+
+