Compare commits

..

13 Commits
1.0.1 ... 1.1.1

Author SHA1 Message Date
2dust
8bb0d6b175 Create Readme.md 2019-08-22 11:26:07 +08:00
2dust
3ae76fab72 add lib 2019-08-18 18:15:37 +08:00
2dust
46a63e8704 Create readme.txt 2019-08-18 18:14:52 +08:00
2dust
12f8b1584c Create issue_template.md 2019-08-14 07:55:48 +08:00
2dust
2b571e2a94 Merge pull request #44 from cutelua/dev
improved notification
2019-07-30 14:47:38 +08:00
cutelua
ba30697309 no need for USER_PRESENT 2019-07-11 09:19:30 +08:00
2dust
879e25bb82 sdk28 2019-07-10 14:24:09 +08:00
cutelua
17c858d24c only show speed if core isrunning 2019-07-09 15:58:36 +08:00
cutelua
71a6531835 stop speed query when screen off; resume when screen on 2019-07-09 14:32:47 +08:00
cutelua
5d760382d7 pass callback as V2RayPoint arg; stop on LowMemory 2019-07-09 13:06:28 +08:00
cutelua
4dda36673a allow go to shutdown VpnService 2019-07-09 11:43:31 +08:00
cutelua
5aca55cb8f only use title to show speed 2019-07-07 16:42:22 +08:00
cutelua
82f14f0d07 show total speed as notification title 2019-07-07 16:42:22 +08:00
39 changed files with 1527 additions and 108 deletions

28
.github/issue_template.md vendored Normal file
View File

@@ -0,0 +1,28 @@
在提出问题前请先自行排除服务器端问题,同时也请通过搜索确认是否有人提出过相同问题。
### 预期行为
描述你认为应该发生什么
### 实际行为
描述实际发生了什么
### 复现方法
1.
2.
3.
### 日志信息
<details>
通过 `adb logcat -s com.v2ray.ang GoLog V2rayConfigUtilGoLog Main` 获取日志。请自行删减日志中可能出现的敏感信息。
如果问题可重现,建议先执行`adb logcat -c`清空系统日志再执行上述命令,再操作重现问题。
```
在这里粘贴日志
```
</details>
### 环境信息
### 额外信息(可选)

View File

@@ -0,0 +1,26 @@
sudo: required
language: go
go:
- "1.12"
go_import_path: github.com/2dust/AndroidLibV2rayLite
git:
depth: 5
addons:
apt:
update: true
before_script:
- sudo ntpdate -u time.google.com
- date
- make all
- make downloadGoMobile
script:
- make BuildMobile
after_success:
deploy:
provider: releases
api_key: ${GH_TOKEN}
file:
- libv2ray.aar
skip_cleanup: true
on:
tags: true

View File

@@ -0,0 +1,63 @@
package CoreI
import (
v2core "v2ray.com/core"
)
type Status struct {
IsRunning bool
PackageName string
Vpoint v2core.Server
}
func CheckVersion() int {
return 20
}
func (v *Status) GetDataDir() string {
return v.PackageName
}
func (v *Status) GetApp(name string) string {
return v.PackageName + 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
}

View File

@@ -0,0 +1,34 @@
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
shippedBinary:
cd shippedBinarys; $(MAKE) shippedBinary
fetchDep:
-go get github.com/2dust/AndroidLibV2rayLite
go get github.com/2dust/AndroidLibV2rayLite
ANDROID_HOME=$(HOME)/android-sdk-linux
export ANDROID_HOME
PATH:=$(PATH):$(GOPATH)/bin
export PATH
downloadGoMobile:
go get golang.org/x/mobile/cmd/...
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/
gomobile init ;gomobile bind -v -tags json github.com/2dust/AndroidLibV2rayLite
BuildMobile:
@echo Stub
all: asset pb shippedBinary fetchDep
@echo DONE

View File

@@ -0,0 +1,87 @@
package Escort
import (
"os"
"os/exec"
"time"
"log"
"github.com/2dust/AndroidLibV2rayLite/CoreI"
)
func (v *Escorting) EscortRun(proc string, pt []string, additionalEnv string, sendFd func() int) {
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 count > 0 {
go func() {
time.Sleep(time.Second)
sendFd()
}()
}
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
}

View File

@@ -0,0 +1 @@
# AndroidLibV2rayLite

View File

@@ -0,0 +1,279 @@
package VPN
import (
"context"
"errors"
"fmt"
"log"
"net"
"os"
"strings"
"sync"
"time"
"golang.org/x/sys/unix"
v2net "v2ray.com/core/common/net"
v2internet "v2ray.com/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
}
// 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
}

View File

@@ -0,0 +1,151 @@
package VPN
import (
"bufio"
"context"
"fmt"
"net"
"sync"
"testing"
"time"
v2net "v2ray.com/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())
})
}
}

View File

@@ -0,0 +1,47 @@
#!/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/shadowsocks/badvpn.git
git clone --depth=1 https://github.com/shadowsocks/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/shippedBinarys/ArchDep/arm/
install -v -m755 libs/arm64-v8a/tun2socks $__dir/shippedBinarys/ArchDep/arm64/
install -v -m755 libs/x86/tun2socks $__dir/shippedBinarys/ArchDep/386/
install -v -m755 libs/x86_64/tun2socks $__dir/shippedBinarys/ArchDep/amd64/
popd
pushd $__dir/shippedBinarys
make clean && make shippedBinary
popd
rm -rf $TMPDIR

View File

@@ -0,0 +1,81 @@
#!/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

View File

@@ -0,0 +1,255 @@
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"
"github.com/2dust/AndroidLibV2rayLite/shippedBinarys"
mobasset "golang.org/x/mobile/asset"
v2core "v2ray.com/core"
v2filesystem "v2ray.com/core/common/platform/filesystem"
v2stats "v2ray.com/core/features/stats"
v2serial "v2ray.com/core/infra/conf/serial"
_ "v2ray.com/core/main/distro/all"
v2internet "v2ray.com/core/transport/internet"
v2applog "v2ray.com/core/app/log"
v2commlog "v2ray.com/core/common/log"
)
const (
v2Assert = "v2ray.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
DomainName string
ConfigureFileContent string
EnableLocalDNS bool
ForwardIpv6 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
SendFd() 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
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()
v.SupportSet.Shutdown()
}
// 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 {
close(v.closeChan)
v.shutdownInit()
v.SupportSet.OnEmitStatus(0, "Closed")
}
return
}
//Delegate Funcation
func (v *V2RayPoint) GetIsRunning() bool {
return v.status.IsRunning
}
//Delegate Funcation
func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
if v.statsManager == nil {
return 0
}
counter := v.statsManager.GetCounter(fmt.Sprintf("inbound>>>%s>>>traffic>>>%s", tag, direct))
if counter == nil {
return 0
}
return counter.Set(0)
}
func (v *V2RayPoint) shutdownInit() {
v.status.IsRunning = false
v.status.Vpoint.Close()
v.status.Vpoint = nil
v.statsManager = nil
v.escorter.EscortingDown()
}
func (v *V2RayPoint) pointloop() error {
if err := v.runTun2socks(); err != nil {
log.Println(err)
return err
}
log.Printf("EnableLocalDNS: %v\nForwardIpv6: %v\nDomainName: %s",
v.EnableLocalDNS,
v.ForwardIpv6,
v.DomainName)
log.Println("loading v2ray config")
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")
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 {
shipb := shippedBinarys.FirstRun{Status: v.status}
if err := shipb.CheckAndExport(); err != nil {
log.Println(err)
return err
}
v.escorter.EscortingUp()
go v.escorter.EscortRun(
v.status.GetApp("tun2socks"),
v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "",
v.SupportSet.SendFd)
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())
}

View File

@@ -0,0 +1,3 @@
package libv2ray
//go:generate make all

View File

@@ -0,0 +1 @@
readme.txt

View File

@@ -0,0 +1,13 @@
Platdep=shippedBinary.386 shippedBinary.amd64 shippedBinary.arm64 shippedBinary.arm
shippedBinaryDep:
go get -u github.com/jteeuwen/go-bindata/...
shippedBinary.%:
go-bindata -nometadata -nomemcopy -pkg shippedBinarys -o ./binary_$*.go -tags $* ArchIndep/ ArchDep/$*/
shippedBinary:shippedBinaryDep $(Platdep)
@echo "Done"
clean:
-rm binary*

View File

@@ -0,0 +1,69 @@
package shippedBinarys
import (
"log"
"os"
"strconv"
"github.com/2dust/AndroidLibV2rayLite/CoreI"
)
type FirstRun struct {
Status *CoreI.Status
}
func (v *FirstRun) checkIfRcExist() error {
datadir := v.Status.GetDataDir()
if _, err := os.Stat(datadir + strconv.Itoa(CoreI.CheckVersion())); !os.IsNotExist(err) {
log.Println("file exists")
return nil
}
IndepDir, err := AssetDir("ArchIndep")
log.Println(IndepDir)
if err != nil {
return err
}
for _, fn := range IndepDir {
log.Println(datadir+"ArchIndep/"+fn)
err := RestoreAsset(datadir, "ArchIndep/"+fn)
log.Println(err)
//GrantPremission
os.Chmod(datadir+"ArchIndep/"+fn, 0700)
log.Println(os.Remove(datadir + fn))
log.Println(os.Symlink(datadir+"ArchIndep/"+fn, datadir + fn))
}
DepDir, err := AssetDir("ArchDep")
log.Println(DepDir)
if err != nil {
return err
}
for _, fn := range DepDir {
DepDir2, err := AssetDir("ArchDep/" + fn)
log.Println("ArchDep/" + fn)
if err != nil {
return err
}
for _, FND := range DepDir2 {
log.Println(datadir+"ArchDep/"+fn+"/"+FND)
RestoreAsset(datadir, "ArchDep/"+fn+"/"+FND)
os.Chmod(datadir+"ArchDep/"+fn+"/"+FND, 0700)
log.Println(os.Remove(datadir + FND))
log.Println(os.Symlink(datadir+"ArchDep/"+fn+"/"+FND, datadir+FND))
}
}
s, _ := os.Create(datadir + strconv.Itoa(CoreI.CheckVersion()))
s.Close()
return nil
}
func (v *FirstRun) CheckAndExport() error {
return v.checkIfRcExist()
}

View File

@@ -0,0 +1,128 @@
# 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

View File

@@ -0,0 +1,79 @@
#!/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

View File

@@ -0,0 +1,32 @@
package libv2ray
// This struct creates our own log writer without datatime stamp
// As Android adds time stamps on each line
import (
"log"
"os"
v2commlog "v2ray.com/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)}
}
}

View File

@@ -3,8 +3,8 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
compileSdkVersion 28
buildToolsVersion '28.0.3'
compileOptions {
targetCompatibility = "8"
@@ -16,8 +16,8 @@ android {
minSdkVersion 17
targetSdkVersion Integer.parseInt("$targetSdkVer")
multiDexEnabled true
versionCode 210
versionName "1.0.1"
versionCode 212
versionName "1.0.2"
}
signingConfigs {
@@ -96,7 +96,7 @@ dependencies {
implementation "org.jetbrains.anko:anko-support-v4:$ankoVersion"
implementation "org.jetbrains.anko:anko-appcompat-v7:$ankoVersion"
implementation "org.jetbrains.anko:anko-design:$ankoVersion"
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'io.reactivex:rxjava:1.3.4'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'

View File

@@ -0,0 +1 @@
https://github.com/2dust/v2rayNG/tree/master/AndroidLibV2rayLite

View File

@@ -9,7 +9,7 @@
<!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
<application
android:name=".AngApplication"

View File

@@ -55,8 +55,7 @@ class V2RayVpnService : VpnService() {
}
}
private val v2rayPoint = Libv2ray.newV2RayPoint()
private val v2rayCallback = V2RayCallback()
private val v2rayPoint = Libv2ray.newV2RayPoint(V2RayCallback())
private lateinit var configContent: String
private lateinit var mInterface: ParcelFileDescriptor
val fd: Int get() = mInterface.fd
@@ -110,9 +109,13 @@ class V2RayVpnService : VpnService() {
stopV2Ray()
}
override fun onLowMemory() {
stopV2Ray()
super.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
cancelNotification()
}
@@ -180,22 +183,11 @@ class V2RayVpnService : VpnService() {
// Create a new interface using the builder and save the parameters.
mInterface = builder.establish()
sendFd()
if (defaultDPreference.getPrefBoolean(SettingsActivity.PREF_SPEED_ENABLED, false)) {
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
.subscribe {
val uplink = v2rayPoint.queryStats("socks", "uplink")
val downlink = v2rayPoint.queryStats("socks", "downlink")
updateNotification("${(uplink / 3).toSpeedString()}${(downlink / 3).toSpeedString()}")
}
}
startSpeedNotification()
}
fun shutdown() {
try {
mInterface.close()
} catch (ignored: Exception) {
}
stopV2Ray(true)
}
fun sendFd() {
@@ -231,12 +223,15 @@ class V2RayVpnService : VpnService() {
if (!v2rayPoint.isRunning) {
try {
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE))
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_SERVICE)
mFilter.addAction(Intent.ACTION_SCREEN_ON)
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
mFilter.addAction(Intent.ACTION_USER_PRESENT)
registerReceiver(mMsgReceive, mFilter)
} catch (e: Exception) {
}
configContent = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
v2rayPoint.supportSet = v2rayCallback
v2rayPoint.configureFileContent = configContent
v2rayPoint.enableLocalDNS = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
v2rayPoint.forwardIpv6 = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_FORWARD_IPV6, false)
@@ -321,7 +316,6 @@ class V2RayVpnService : VpnService() {
mBuilder = NotificationCompat.Builder(applicationContext, channelId)
.setSmallIcon(R.drawable.ic_v)
.setContentTitle(defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, ""))
.setContentText(getString(R.string.notification_action_more))
.setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true)
.setShowWhen(false)
@@ -359,7 +353,7 @@ class V2RayVpnService : VpnService() {
private fun updateNotification(contentText: String) {
if (mBuilder != null) {
mBuilder?.setContentText(contentText)
mBuilder?.setContentTitle(contentText)
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
}
}
@@ -371,8 +365,41 @@ class V2RayVpnService : VpnService() {
return mNotificationManager!!
}
fun startSpeedNotification() {
if (mSubscription == null &&
v2rayPoint.isRunning &&
defaultDPreference.getPrefBoolean(SettingsActivity.PREF_SPEED_ENABLED, false)) {
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
var last_zero_speed = false
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
.subscribe {
val uplink = v2rayPoint.queryStats("socks", "uplink")
val downlink = v2rayPoint.queryStats("socks", "downlink")
val zero_speed = (uplink == 0L && downlink == 0L)
if (!zero_speed || !last_zero_speed) {
updateNotification("${cf_name}${(uplink / 3).toSpeedString()}${(downlink / 3).toSpeedString()}")
}
last_zero_speed = zero_speed
}
}
}
fun stopSpeedNotification() {
if (mSubscription != null) {
mSubscription?.unsubscribe() //stop queryStats
mSubscription = null
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
updateNotification(cf_name)
}
}
private inner class V2RayCallback : V2RayVPNServiceSupportsSet {
override fun shutdown(): Long {
// called by go
// shutdown the whole vpn service
try {
this@V2RayVpnService.shutdown()
return 0
@@ -447,6 +474,17 @@ class V2RayVpnService : VpnService() {
vpnService?.startV2ray()
}
}
when (intent?.action) {
Intent.ACTION_SCREEN_OFF -> {
Log.d(AppConfig.ANG_PACKAGE, "SCREEN_OFF, stop querying stats")
vpnService?.stopSpeedNotification()
}
Intent.ACTION_SCREEN_ON -> {
Log.d(AppConfig.ANG_PACKAGE, "SCREEN_ON, start querying stats")
vpnService?.startSpeedNotification()
}
}
}
}
}

View File

@@ -98,7 +98,7 @@ class PerAppProxyActivity : BaseActivity() {
recycler_view.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) {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
dst += dy
if (dst > threshold) {
header_view.hide()

View File

@@ -62,6 +62,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
val icon = itemView.icon!!
val name = itemView.name!!
val package_name = itemView.package_name!!
val checkBox = itemView.check_box!!
fun bind(appInfo: AppInfo) {
@@ -71,10 +72,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
// name.text = appInfo.appName
checkBox.isChecked = inBlacklist
// name.textColor = mActivity.resources.getColor(if (appInfo.isSystemApp)
// R.color.color_highlight_material else R.color.abc_secondary_text_material_light)
package_name.text = appInfo.packageName
if (appInfo.isSystemApp) {
name.text = String.format("** %1s", appInfo.appName)
name.textColor = Color.RED

View File

@@ -34,7 +34,7 @@ class SettingsActivity : BaseActivity() {
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
// const val PREF_SOCKS_PORT = "pref_socks_port"
// const val PREF_LANCONN_PORT = "pref_lanconn_port"
// const val PREF_HTTP_PORT = "pref_http_port"
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
const val PREF_ROUTING_MODE = "pref_routing_mode"
@@ -67,7 +67,7 @@ class SettingsActivity : BaseActivity() {
val forwardIpv6 by lazy { findPreference(PREF_FORWARD_IPV6) as CheckBoxPreference }
// val socksPort by lazy { findPreference(PREF_SOCKS_PORT) as EditTextPreference }
// val lanconnPort by lazy { findPreference(PREF_LANCONN_PORT) as EditTextPreference }
// val httpPort by lazy { findPreference(PREF_HTTP_PORT) as EditTextPreference }
val routingCustom: Preference by lazy { findPreference(PREF_ROUTING_CUSTOM) }
// val donate: Preference by lazy { findPreference(PREF_DONATE) }
@@ -132,8 +132,8 @@ class SettingsActivity : BaseActivity() {
// socksPort.summary = any as String
// true
// }
// lanconnPort.setOnPreferenceChangeListener { preference, any ->
// lanconnPort.summary = any as String
// httpPort.setOnPreferenceChangeListener { preference, any ->
// httpPort.summary = any as String
// true
// }
@@ -156,7 +156,7 @@ class SettingsActivity : BaseActivity() {
}
// socksPort.summary = defaultSharedPreferences.getString(PREF_SOCKS_PORT, "10808")
// lanconnPort.summary = defaultSharedPreferences.getString(PREF_LANCONN_PORT, "")
// lanconnPort.summary = defaultSharedPreferences.getString(PREF_HTTP_PORT, "")
defaultSharedPreferences.registerOnSharedPreferenceChangeListener(this)
}

View File

@@ -131,7 +131,7 @@ object V2rayConfigUtil {
try {
v2rayConfig.inbounds[0].port = 10808
// val socksPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_LANCONN_PORT, ""))
// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_HTTP_PORT, ""))
// if (socksPort > 0) {
// v2rayConfig.inbounds[0].port = socksPort

View File

@@ -54,7 +54,7 @@
android:layout_toLeftOf="@id/switch_per_app_proxy"
android:layout_toStartOf="@id/switch_per_app_proxy"
android:text="@string/title_pref_per_app_proxy"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</RelativeLayout>
@@ -81,7 +81,7 @@
android:layout_toLeftOf="@id/switch_bypass_apps"
android:layout_toStartOf="@id/switch_bypass_apps"
android:text="@string/switch_bypass_apps_mode"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</RelativeLayout>

View File

@@ -8,25 +8,41 @@
android:id="@+id/icon"
android:layout_width="46dp"
android:layout_height="46dp"
android:paddingEnd="10dp"
android:paddingStart="14dp"
android:paddingLeft="14dp"
android:paddingRight="10dp"
android:paddingStart="14dp" />
android:paddingEnd="10dp"
android:paddingRight="10dp" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/name"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0" />
android:layout_height="46dp"
android:layout_weight="1.0"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="@dimen/layout_margin_right_height"
android:paddingEnd="@dimen/layout_margin_right_height">
<android.support.v7.widget.AppCompatTextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/package_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
<android.support.v7.widget.AppCompatCheckBox
android:id="@+id/check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:paddingEnd="6dp"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:paddingRight="6dp"
android:paddingStart="2dp" />
android:paddingEnd="6dp"
android:paddingRight="6dp" />
</LinearLayout>

View File

@@ -112,8 +112,8 @@
<string name="title_pref_socks_port">SOCKS5代理端口</string>
<string name="summary_pref_socks_port">SOCKS5代理端口</string>
<string name="title_pref_lanconn_port">HTTP代理端口(0=不允许)</string>
<string name="summary_pref_lanconn_port">HTTP代理端口</string>
<string name="title_pref_http_port">HTTP代理端口</string>
<string name="summary_pref_http_port">HTTP代理端口</string>
<string name="title_pref_feedback">反馈</string>
<string name="summary_pref_feedback">反馈改进或漏洞至 GitHub</string>

View File

@@ -113,8 +113,8 @@
<string name="title_pref_socks_port">SOCKS5代理端口</string>
<string name="summary_pref_socks_port">SOCKS5代理端口</string>
<string name="title_pref_lanconn_port">HTTP代理端口(0=不允許)</string>
<string name="summary_pref_lanconn_port">HTTP代理端口</string>
<string name="title_pref_http_port">HTTP代理端口</string>
<string name="summary_pref_http_port">HTTP代理端口</string>
<string name="title_pref_feedback">回饋</string>

View File

@@ -113,8 +113,8 @@
<string name="title_pref_socks_port">SOCKS5 proxy port</string>
<string name="summary_pref_socks_port">SOCKS5 proxy port</string>
<string name="title_pref_lanconn_port">HTTP proxy port(0=not allowed)</string>
<string name="summary_pref_lanconn_port">HTTP proxy port</string>
<string name="title_pref_http_port">HTTP proxy port</string>
<string name="summary_pref_http_port">HTTP proxy port</string>
<string name="title_pref_feedback">Feedback</string>
<string name="summary_pref_feedback">Feedback enhancements or bugs to GitHub</string>

View File

@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/title_settings">
<!--<CheckBoxPreference-->
<!--android:key="pref_bypass_mainland"-->
<!--android:summary="@string/summary_pref_bypass_mainland"-->
<!--android:title="@string/title_pref_bypass_mainland" />-->
<CheckBoxPreference
android:key="pref_per_app_proxy"
android:summary="@string/summary_pref_per_app_proxy"
@@ -28,45 +24,6 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_advanced">
<CheckBoxPreference
android:key="pref_forward_ipv6"
android:summary="@string/summary_pref_forward_ipv6"
android:title="@string/title_pref_forward_ipv6" />
<CheckBoxPreference
android:key="pref_local_dns_enabled"
android:summary="@string/summary_pref_local_dns_enabled"
android:title="@string/title_pref_local_dns_enabled" />
<EditTextPreference
android:key="pref_domestic_dns"
android:summary="@string/summary_pref_domestic_dns"
android:title="@string/title_pref_domestic_dns" />
<EditTextPreference
android:key="pref_remote_dns"
android:summary="@string/summary_pref_remote_dns"
android:title="@string/title_pref_remote_dns" />
<!--<EditTextPreference-->
<!--android:enabled="false"-->
<!--android:defaultValue="10808"-->
<!--android:key="pref_socks_port"-->
<!--android:summary="@string/summary_pref_socks_port"-->
<!--android:title="@string/title_pref_socks_port" />-->
<!--<EditTextPreference-->
<!--android:defaultValue="0"-->
<!--android:key="pref_lanconn_port"-->
<!--android:summary="@string/summary_pref_lanconn_port"-->
<!--android:title="@string/title_pref_lanconn_port" />-->
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_pref_routing">
<ListPreference
android:defaultValue="IPIfNonMatch"
@@ -88,15 +45,47 @@
android:key="pref_routing_custom"
android:summary="@string/title_pref_routing_custom"
android:title="@string/title_pref_routing_custom" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_advanced">
<CheckBoxPreference
android:key="pref_forward_ipv6"
android:summary="@string/summary_pref_forward_ipv6"
android:title="@string/title_pref_forward_ipv6" />
<CheckBoxPreference
android:key="pref_local_dns_enabled"
android:summary="@string/summary_pref_local_dns_enabled"
android:title="@string/title_pref_local_dns_enabled" />
<EditTextPreference
android:key="pref_domestic_dns"
android:summary="@string/summary_pref_domestic_dns"
android:title="@string/title_pref_domestic_dns" />
<EditTextPreference
android:key="pref_remote_dns"
android:summary="@string/summary_pref_remote_dns"
android:title="@string/title_pref_remote_dns" />
<Preference
android:key="pref_socks_port"
android:summary="10808"
android:title="@string/title_pref_socks_port" />
<Preference
android:key="pref_http_port"
android:summary="10809"
android:title="@string/title_pref_http_port" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_about">
<!--<Preference-->
<!--android:key="pref_donate"-->
<!--android:summary="@string/summary_pref_donate"-->
<!--android:title="@string/title_pref_donate" />-->
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_about">
<!--<Preference-->
<!--android:key="pref_licenses"-->
<!--android:title="@string/notices_title" />-->

View File

@@ -1,8 +1,8 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 17

View File

@@ -14,9 +14,9 @@
# org.gradle.parallel=true
#Fri Jun 02 14:08:42 CST 2017
ankoVersion=0.10.8
kotlinVersion=1.3.10
supportLibVersion=27.1.1
buildToolsVer=27.0.3
compileSdkVer=27
kotlinVersion=1.3.40
supportLibVersion=28.0.0
buildToolsVer=28.0.3
compileSdkVer=28
kotlin.incremental=true
targetSdkVer=27
targetSdkVer=28