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 @@ + + app:showAsAction="withText" /> - \ 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"> + + @@ -52,6 +59,25 @@ + + + + + + \ 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 @@ + + + + + + +