Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
870950e807 | ||
|
|
e798cb3f42 | ||
|
|
b970f0bcff | ||
|
|
93b9a56428 | ||
|
|
eb8bd13266 | ||
|
|
d850c88c63 | ||
|
|
6bee795c0d | ||
|
|
d7d7e029e0 | ||
|
|
8efdab43d7 | ||
|
|
5e0235cf70 | ||
|
|
9f668b3da7 | ||
|
|
b2437279dc | ||
|
|
180b5efd93 | ||
|
|
dc31380cc2 | ||
|
|
1361e0dacf | ||
|
|
a45eb66bd1 | ||
|
|
508102cebe | ||
|
|
1d86dbb9f3 | ||
|
|
20ca554be2 | ||
|
|
25ba455656 | ||
|
|
17e7c62d53 | ||
|
|
6f0f2fdeda |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -2,10 +2,8 @@ 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
|
||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||
*.dat
|
||||
*.jks
|
||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
||||
V2rayNG/app/release/output.json
|
||||
V2rayNG/app/release/output.json
|
||||
.idea/
|
||||
.gradle/
|
||||
@@ -5,14 +5,15 @@ import (
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
IsRunning bool
|
||||
PackageName string
|
||||
IsRunning bool
|
||||
PackageName string
|
||||
PackageCodePath string
|
||||
|
||||
Vpoint v2core.Server
|
||||
}
|
||||
|
||||
func CheckVersion() int {
|
||||
return 20
|
||||
return 21
|
||||
}
|
||||
|
||||
func (v *Status) GetDataDir() string {
|
||||
@@ -20,7 +21,7 @@ func (v *Status) GetDataDir() string {
|
||||
}
|
||||
|
||||
func (v *Status) GetApp(name string) string {
|
||||
return v.PackageName + name
|
||||
return v.PackageCodePath + name
|
||||
}
|
||||
|
||||
func (v *Status) GetTun2socksArgs(localDNS bool, enableIPv6 bool) (ret []string) {
|
||||
|
||||
@@ -44,6 +44,7 @@ type V2RayPoint struct {
|
||||
closeChan chan struct{}
|
||||
|
||||
PackageName string
|
||||
PackageCodePath string
|
||||
DomainName string
|
||||
ConfigureFileContent string
|
||||
EnableLocalDNS bool
|
||||
@@ -67,6 +68,7 @@ func (v *V2RayPoint) RunLoop() (err error) {
|
||||
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{})
|
||||
@@ -233,7 +235,7 @@ func (v V2RayPoint) runTun2socks() error {
|
||||
|
||||
v.escorter.EscortingUp()
|
||||
go v.escorter.EscortRun(
|
||||
v.status.GetApp("tun2socks"),
|
||||
v.status.GetApp("libtun2socks.so"),
|
||||
v.status.GetTun2socksArgs(v.EnableLocalDNS, v.ForwardIpv6), "",
|
||||
v.SupportSet.SendFd)
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
compileSdkVersion Integer.parseInt("$compileSdkVer")
|
||||
buildToolsVersion buildToolsVer
|
||||
|
||||
compileOptions {
|
||||
targetCompatibility = "8"
|
||||
@@ -20,34 +20,17 @@ android {
|
||||
versionName "1.0.2"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
storeFile file("../key.jks")
|
||||
keyAlias 'ang'
|
||||
keyPassword '123456'
|
||||
storePassword '123456'
|
||||
}
|
||||
debug {
|
||||
storeFile file("../key.jks")
|
||||
keyAlias 'ang'
|
||||
keyPassword '123456'
|
||||
storePassword '123456'
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
shrinkResources false
|
||||
signingConfig signingConfigs.release
|
||||
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
zipAlignEnabled false
|
||||
shrinkResources false
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +114,4 @@ repositories {
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -135,4 +135,4 @@
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -1,196 +1,241 @@
|
||||
com.android.chrome
|
||||
com.google.android.googlequicksearchbox
|
||||
com.google.android.apps.photos
|
||||
com.google.android.youtube
|
||||
com.google.android.gm
|
||||
com.google.android.apps.plus
|
||||
com.android.vending
|
||||
com.google.android.inputmethod.latin
|
||||
com.google.android.apps.paidtasks
|
||||
com.google.android.keep
|
||||
com.google.android.gms.setup
|
||||
com. google.android. apps.magazines
|
||||
com.google.android.videos
|
||||
com. google.android.gms
|
||||
com.google.android.apps.books
|
||||
com.google.android.music
|
||||
com.google.android.play.games
|
||||
com.google.android.gsf
|
||||
com.google.android.gsf.login
|
||||
com.app.pornhub
|
||||
com.spotify.music
|
||||
org.thunderdog.challegram
|
||||
com.tumblr
|
||||
com.twitter.android
|
||||
com.xda.labs
|
||||
com.kapp.youtube.final
|
||||
com.google.android.ims
|
||||
com.wire
|
||||
mark.via.gp
|
||||
com.downloader.video.tumblr
|
||||
com.sololearn
|
||||
com.cygames.shadowverse
|
||||
com.felixfilip.scpae
|
||||
amanita_design.samorost3.gp
|
||||
com.devolver.reigns2
|
||||
com.utopia.pxview
|
||||
ch.protonmail.android
|
||||
com.perol.asdpl.pixivez
|
||||
com.pinterest
|
||||
com.paypal.android.p2pmobile
|
||||
com.arthurivanets.owly
|
||||
com.rubenmayayo.reddit
|
||||
com.rayark.cytus2
|
||||
com.rayark.pluto
|
||||
com.rayark.implosion
|
||||
com.fireproofstudios.theroom4
|
||||
com.netflix.mediaclient
|
||||
com.instagram.android
|
||||
com.google.android.apps.hangoutsdialer
|
||||
com.google.android.talk
|
||||
com.google.android.apps.plus
|
||||
com.google.android.apps.pdfviewer
|
||||
com.google.android.apps.magazines
|
||||
com.google.android.apps.nbu.files
|
||||
com.evernote
|
||||
net.tsapps.appsales
|
||||
com.google.android.apps.translate
|
||||
com.google.ar.lens
|
||||
com.google.android.apps.adm
|
||||
com.google.android.apps.googleassistant
|
||||
tw.com.gamer.android.activecenter
|
||||
org.telegram.plus
|
||||
com.brave.browser
|
||||
com.breel.wallpapers18
|
||||
com.teslacoilsw.launcher
|
||||
com.lastpass.lpandroid
|
||||
org.kustom.widget
|
||||
com.fooview.android.fooview
|
||||
com.google.android.apps.docs
|
||||
com.google.android.apps.maps
|
||||
com.facebook.services
|
||||
com.facebook.system
|
||||
com.facebook.katana
|
||||
com.nianticlabs.ingress.prime.qa
|
||||
com.vanced.android.youtube
|
||||
com.nianticproject.ingress
|
||||
com.quoord.tapatalkpro.activity
|
||||
org.mozilla.firefox
|
||||
com.reddit.frontpage
|
||||
com.google.android.apps.fitness
|
||||
android
|
||||
au.com.shiftyjelly.pocketcasts
|
||||
com.google.android.gms
|
||||
com.android.providers.telephony
|
||||
com.resilio.sync
|
||||
com.google.android.apps.googlevoice
|
||||
com.discord
|
||||
com.cradle.iitc_mobile
|
||||
bbc.mobile.news.ww
|
||||
be.mygod.vpnhotspot
|
||||
ch.protonmail.android
|
||||
co.wanqu.android
|
||||
com.alphainventor.filemanager
|
||||
com.amazon.kindle
|
||||
com.amazon.mshop.android.shopping
|
||||
com.android.chrome
|
||||
com.android.providers.downloads
|
||||
com.android.providers.downloads.ui
|
||||
com.android.providers.telephony
|
||||
com.android.settings
|
||||
com.android.vending
|
||||
com.android6park.m6park
|
||||
com.apkpure.aegon
|
||||
com.apkupdater
|
||||
com.app.pornhub
|
||||
com.arthurivanets.owly
|
||||
com.asahi.tida.tablet
|
||||
com.authy.authy
|
||||
com.avmovie
|
||||
com.ballistiq.artstation
|
||||
com.binance.dev
|
||||
com.bitly.app
|
||||
com.brave.browser
|
||||
com.brave.browser_beta
|
||||
com.breel.wallpapers18
|
||||
com.bvanced.android.youtube
|
||||
com.chrome.beta
|
||||
com.chrome.canary
|
||||
com.chrome.dev
|
||||
com.cl.newt66y
|
||||
com.cradle.iitc_mobile
|
||||
com.cygames.shadowverse
|
||||
com.devhd.feedly
|
||||
com.devolver.reigns2
|
||||
com.discord
|
||||
com.downloader.video.tumblr
|
||||
com.driverbrowser
|
||||
com.dropbox.android
|
||||
com.duolingo
|
||||
com.duckduckgo.mobile.android
|
||||
com.dv.adm
|
||||
com.estrongs.android.pop
|
||||
com.estrongs.android.pop.pro
|
||||
com.evernote
|
||||
com.facebook.katana
|
||||
com.facebook.lite
|
||||
com.facebook.mlite
|
||||
com.facebook.orca
|
||||
com.facebook.services
|
||||
com.facebook.system
|
||||
com.fastaccess.github
|
||||
com.felixfilip.scpae
|
||||
com.fireproofstudios.theroom4
|
||||
com.firstrowria.pushnotificationtester
|
||||
com.flyersoft.moonreaderp
|
||||
com.fooview.android.fooview
|
||||
com.fvd.eversync
|
||||
com.gameloft.android.anmp.glofta8hm
|
||||
com.gameloft.android.anmp.glofta9hm
|
||||
com.gianlu.aria2app
|
||||
com.github.yeriomin.yalpstore
|
||||
com.google.android.apps.adm
|
||||
com.google.android.apps.books
|
||||
com.google.android.apps.docs
|
||||
com.google.android.apps.docs.editors.sheets
|
||||
com.google.android.apps.fitness
|
||||
com.google.android.apps.googleassistant
|
||||
com.google.android.apps.googlevoice
|
||||
com.google.android.apps.hangoutsdialer
|
||||
com.google.android.apps.inbox
|
||||
com.google.android.apps.magazines
|
||||
com.google.android.apps.maps
|
||||
com.google.android.apps.nbu.files
|
||||
com.google.android.apps.paidtasks
|
||||
com.google.android.apps.pdfviewer
|
||||
com.google.android.apps.photos
|
||||
com.google.android.apps.plus
|
||||
com.google.android.apps.translate
|
||||
com.google.android.gm
|
||||
com.google.android.gms
|
||||
com.google.android.gms.setup
|
||||
com.google.android.googlequicksearchbox
|
||||
com.google.android.gsf
|
||||
com.google.android.gsf.login
|
||||
com.google.android.ims
|
||||
com.google.android.inputmethod.latin
|
||||
com.google.android.instantapps.supervisor
|
||||
com.google.android.keep
|
||||
com.google.android.music
|
||||
com.google.android.ogyoutube
|
||||
com.google.android.partnersetup
|
||||
com.google.android.play.games
|
||||
com.google.android.street
|
||||
com.google.android.syncadapters.calendar
|
||||
com.google.android.syncadapters.contacts
|
||||
com.google.android.talk
|
||||
com.google.android.tts
|
||||
com.google.android.videos
|
||||
com.google.android.youtube
|
||||
com.google.ar.lens
|
||||
com.hochan.coldsoup
|
||||
com.ifttt.ifttt
|
||||
com.imgur.mobile
|
||||
com.innologica.inoreader
|
||||
com.instagram.android
|
||||
com.instapaper.android
|
||||
com.jarvanh.vpntether
|
||||
com.kapp.youtube.final
|
||||
com.klinker.android.twitter_l
|
||||
com.lastpass.lpandroid
|
||||
com.linecorp.linelite
|
||||
com.lingodeer
|
||||
com.mediapods.tumbpods
|
||||
com.mgoogle.android.gms
|
||||
com.microsoft.emmx
|
||||
com.microsoft.office.powerpoint
|
||||
com.microsoft.skydrive
|
||||
com.mixplorer
|
||||
com.msd.consumerchinese
|
||||
com.msd.professionalchinese
|
||||
com.mss2011c.sharehelper
|
||||
com.netflix.mediaclient
|
||||
com.newin.nplayer.pro
|
||||
com.nianticlabs.ingress.prime.qa
|
||||
com.nianticproject.ingress
|
||||
com.ninefolders.hd3
|
||||
com.ninegag.android.app
|
||||
com.nintendo.zara
|
||||
com.nytimes.cn
|
||||
com.oasisfeng.island
|
||||
com.ocnt.liveapp.hw
|
||||
com.orekie.search
|
||||
com.patreon.android
|
||||
com.paypal.android.p2pmobile
|
||||
com.perol.asdpl.pixivez
|
||||
com.pinterest
|
||||
com.popularapp.periodcalendar
|
||||
com.popularapp.videodownloaderforinstagram
|
||||
com.pushbullet.android
|
||||
com.quoord.tapatalkpro.activity
|
||||
com.quora.android
|
||||
com.rayark.cytus2
|
||||
com.rayark.implosion
|
||||
com.rayark.pluto
|
||||
com.reddit.frontpage
|
||||
com.resilio.sync
|
||||
com.rhmsoft.edit
|
||||
com.rubenmayayo.reddit
|
||||
com.sec.android.app.sbrowser
|
||||
com.sec.android.app.sbrowser.beta
|
||||
com.shanga.walli
|
||||
com.simplehabit.simplehabitapp
|
||||
com.slack
|
||||
com.snaptube.premium
|
||||
com.sololearn
|
||||
com.sonelli.juicessh
|
||||
com.spotify.music
|
||||
com.tencent.huatuo
|
||||
com.termux
|
||||
com.teslacoilsw.launcher
|
||||
com.theinitium.news
|
||||
com.thomsonreuters.reuters
|
||||
com.thunkable.android.hritvik00.freenom
|
||||
com.topjohnwu.magisk
|
||||
com.tripadvisor.tripadvisor
|
||||
com.tumblr
|
||||
com.twitter.android
|
||||
com.u91porn
|
||||
com.u9porn
|
||||
com.ubisoft.dance.justdance2015companion
|
||||
com.utopia.pxview
|
||||
com.valvesoftware.android.steam.communimunity
|
||||
com.valvesoftware.android.steam.community
|
||||
com.vanced.android.youtube
|
||||
com.vimeo.android.videoapp
|
||||
com.vivaldi.browser
|
||||
com.vivaldi.browser.snapshot
|
||||
com.vkontakte.android
|
||||
com.whatsapp
|
||||
com.wire
|
||||
com.wuxiangai.refactor
|
||||
com.xda.labs
|
||||
com.xvideos.app
|
||||
com.yandex.browser
|
||||
com.yandex.browser.beta
|
||||
com.yandex.browser.alpha
|
||||
com.z28j.feel
|
||||
con.medium.reader
|
||||
de.apkgrabber
|
||||
de.robv.android.xposed.installer
|
||||
dk.tacit.android.foldersync.full
|
||||
es.rafalense.telegram.themes
|
||||
es.rafalense.themes
|
||||
flipboard.app
|
||||
fm.moon.app
|
||||
fr.gouv.etalab.mastodon
|
||||
github.tornaco.xposedmoduletest
|
||||
idm.internet.download.manager
|
||||
idm.internet.download.manager.plus
|
||||
io.github.javiewer
|
||||
io.github.skyhacker2.magnetsearch
|
||||
io.va.exposed
|
||||
it.mvilla.android.fenix2
|
||||
jp.bokete.app.android
|
||||
jp.naver.line.android
|
||||
jp.pxv.android
|
||||
luo.speedometergpspro
|
||||
mark.via.gp
|
||||
me.tshine.easymark
|
||||
net.teeha.android.url_shortener
|
||||
net.tsapps.appsales
|
||||
onion.fire
|
||||
org.fdroid.fdroid
|
||||
org.freedownloadmanager.fdm
|
||||
org.kustom.widget
|
||||
org.mozilla.fennec_aurora
|
||||
org.mozilla.fenix
|
||||
org.mozilla.fenix.nightly
|
||||
org.mozilla.firefox
|
||||
org.mozilla.firefox_beta
|
||||
org.mozilla.focus
|
||||
org.schabi.newpipe
|
||||
org.telegram.messenger
|
||||
org.telegram.multi
|
||||
org.telegram.plus
|
||||
org.thunderdog.challegram
|
||||
org.torproject.android
|
||||
org.torproject.torbrowser_alpha
|
||||
org.wikipedia
|
||||
org.xbmc.kodi
|
||||
pl.zdunex25.updater
|
||||
videodownloader.downloadvideo.downloader
|
||||
com.quora.android
|
||||
com.lingodeer
|
||||
org.wikipedia
|
||||
com.ninegag.android.app
|
||||
com.duolingo
|
||||
com.patreon.android
|
||||
com.valvesoftware.android.steam.communimunity
|
||||
co.wanqu.android
|
||||
jp.bokete.app.android
|
||||
com.vkontakte.android
|
||||
com.amazon.mshop.android.shopping
|
||||
com.ubisoft.dance.justdance2015companion
|
||||
com.gameloft.android.anmp.glofta8hm
|
||||
com.gameloft.android.anmp.glofta9hm
|
||||
com.binance.dev
|
||||
com.asahi.tida.tablet
|
||||
com.theinitium.news
|
||||
com.driverbrowser
|
||||
com.thomsonreuters.reuters
|
||||
com.nytimes.cn
|
||||
com.android.providers.downloads.ui
|
||||
com.avmovie
|
||||
bbc.mobile.news.ww
|
||||
org.mozilla.focus
|
||||
io.github.javiewer
|
||||
com.sonelli.juicessh
|
||||
con.medium.reader
|
||||
com.microsoft.skydrive
|
||||
com.valvesoftware.android.steam.community
|
||||
com.nintendo.zara
|
||||
org.torproject.torbrowser_alpha
|
||||
tv.twitch.android.app
|
||||
com.shanga.walli
|
||||
com.whatsapp
|
||||
com.wire
|
||||
com.simplehabit.simplehabitapp
|
||||
tw.com.gamer.android.activecenter
|
||||
videodownloader.downloadvideo.downloader
|
||||
uk.co.bbc.learningenglish
|
||||
com.ted.android
|
||||
|
||||
BIN
V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so
Normal file
BIN
V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so
Normal file
Binary file not shown.
BIN
V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so
Normal file
BIN
V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so
Normal file
Binary file not shown.
BIN
V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so
Normal file
BIN
V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so
Normal file
Binary file not shown.
BIN
V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so
Normal file
BIN
V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so
Normal file
Binary file not shown.
@@ -11,6 +11,7 @@ object AppConfig {
|
||||
const val PREF_CURR_CONFIG_GUID = "pref_v2ray_config_guid"
|
||||
const val PREF_CURR_CONFIG_NAME = "pref_v2ray_config_name"
|
||||
const val PREF_CURR_CONFIG_DOMAIN = "pref_v2ray_config_domain"
|
||||
const val PREF_CURR_CONFIG_OUTBOUND_TAGS = "pref_v2ray_config_outbound_tags"
|
||||
const val PREF_INAPP_BUY_IS_PREMIUM = "pref_inapp_buy_is_premium"
|
||||
const val VMESS_PROTOCOL: String = "vmess://"
|
||||
const val SS_PROTOCOL: String = "ss://"
|
||||
@@ -50,12 +51,4 @@ object AppConfig {
|
||||
const val MSG_STATE_STOP = 4
|
||||
const val MSG_STATE_STOP_SUCCESS = 41
|
||||
const val MSG_STATE_RESTART = 5
|
||||
|
||||
object EConfigType {
|
||||
val Vmess = 1
|
||||
val Custom = 2
|
||||
val Shadowsocks = 3
|
||||
val Socks = 4
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
12
V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/EConfigType.kt
Normal file
12
V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/EConfigType.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.v2ray.ang.dto
|
||||
|
||||
enum class EConfigType(val value: Int) {
|
||||
VMESS(1),
|
||||
CUSTOM(2),
|
||||
SHADOWSOCKS(3),
|
||||
SOCKS(4);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value: Int) = values().firstOrNull { it.value == value }
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,24 @@ data class V2rayConfig(
|
||||
}
|
||||
|
||||
data class MuxBean(var enabled: Boolean)
|
||||
|
||||
fun getServerAddress(): String? {
|
||||
if (protocol.equals(EConfigType.VMESS.name.toLowerCase())) {
|
||||
return settings?.vnext?.get(0)?.address
|
||||
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name.toLowerCase()) || protocol.equals(EConfigType.SOCKS.name.toLowerCase())) {
|
||||
return settings?.servers?.get(0)?.address
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getServerPort(): Int? {
|
||||
if (protocol.equals(EConfigType.VMESS.name.toLowerCase())) {
|
||||
return settings?.vnext?.get(0)?.port
|
||||
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name.toLowerCase()) || protocol.equals(EConfigType.SOCKS.name.toLowerCase())) {
|
||||
return settings?.servers?.get(0)?.port
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
//data class DnsBean(var servers: List<String>)
|
||||
|
||||
@@ -11,11 +11,14 @@ import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
import android.net.*
|
||||
import android.net.VpnService
|
||||
import android.os.*
|
||||
import android.os.Build
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.StrictMode
|
||||
import android.support.annotation.RequiresApi
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.util.Log
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.TAG_DIRECT
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.defaultDPreference
|
||||
import com.v2ray.ang.extension.toSpeedString
|
||||
@@ -24,16 +27,14 @@ import com.v2ray.ang.ui.PerAppProxyActivity
|
||||
import com.v2ray.ang.ui.SettingsActivity
|
||||
import com.v2ray.ang.util.MessageUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import go.Seq
|
||||
import libv2ray.Libv2ray
|
||||
import libv2ray.V2RayVPNServiceSupportsSet
|
||||
import org.jetbrains.anko.doAsync
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import java.io.File
|
||||
import java.lang.ref.SoftReference
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import go.Seq
|
||||
import org.jetbrains.anko.doAsync
|
||||
|
||||
class V2RayVpnService : VpnService() {
|
||||
companion object {
|
||||
@@ -103,6 +104,7 @@ class V2RayVpnService : VpnService() {
|
||||
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
|
||||
StrictMode.setThreadPolicy(policy)
|
||||
v2rayPoint.packageName = Utils.packagePath(applicationContext)
|
||||
v2rayPoint.packageCodePath = applicationContext.applicationInfo.nativeLibraryDir + "/"
|
||||
Seq.setContext(applicationContext)
|
||||
}
|
||||
|
||||
@@ -400,24 +402,34 @@ class V2RayVpnService : VpnService() {
|
||||
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
|
||||
val outboundTags = defaultDPreference.getPrefStringOrderedSet(AppConfig.PREF_CURR_CONFIG_OUTBOUND_TAGS, LinkedHashSet())
|
||||
outboundTags.remove(TAG_DIRECT)
|
||||
|
||||
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.subscribe {
|
||||
val proxyUplink = v2rayPoint.queryStats("proxy", "uplink")
|
||||
val proxyDownlink = v2rayPoint.queryStats("proxy", "downlink")
|
||||
val directUplink = v2rayPoint.queryStats("direct", "uplink")
|
||||
val directDownlink = v2rayPoint.queryStats("direct", "downlink")
|
||||
val zero_speed = (proxyUplink == 0L && proxyDownlink == 0L && directUplink == 0L && directDownlink == 0L)
|
||||
val queryTime = System.currentTimeMillis()
|
||||
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
|
||||
var proxyTotal = 0L
|
||||
val text = StringBuilder()
|
||||
outboundTags.forEach {
|
||||
val up = v2rayPoint.queryStats(it, "uplink")
|
||||
val down = v2rayPoint.queryStats(it, "downlink")
|
||||
if (up + down > 0) {
|
||||
appendSpeedString(text, it, up / sinceLastQueryInSeconds, down / sinceLastQueryInSeconds)
|
||||
proxyTotal += up + down
|
||||
}
|
||||
}
|
||||
val directUplink = v2rayPoint.queryStats(TAG_DIRECT, "uplink")
|
||||
val directDownlink = v2rayPoint.queryStats(TAG_DIRECT, "downlink")
|
||||
val zero_speed = (proxyTotal == 0L && directUplink == 0L && directDownlink == 0L)
|
||||
if (!zero_speed || !last_zero_speed) {
|
||||
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
|
||||
updateNotification("proxy\t• ${(proxyUplink / sinceLastQueryInSeconds).toLong().toSpeedString()}↑ " +
|
||||
"${(proxyDownlink / sinceLastQueryInSeconds).toLong().toSpeedString()}↓\n" +
|
||||
"direct\t• ${(directUplink / sinceLastQueryInSeconds).toLong().toSpeedString()}↑ " +
|
||||
"${(directDownlink / sinceLastQueryInSeconds).toLong().toSpeedString()}↓",
|
||||
proxyDownlink + proxyUplink, directDownlink + directUplink)
|
||||
if (proxyTotal == 0L) {
|
||||
appendSpeedString(text, outboundTags.firstOrNull(), 0.0, 0.0)
|
||||
}
|
||||
appendSpeedString(text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
|
||||
directDownlink / sinceLastQueryInSeconds)
|
||||
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
|
||||
}
|
||||
last_zero_speed = zero_speed
|
||||
lastQueryTime = queryTime
|
||||
@@ -425,6 +437,15 @@ class V2RayVpnService : VpnService() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun appendSpeedString(text: StringBuilder, name: String?, up: Double, down: Double) {
|
||||
var n = name ?: "no tag"
|
||||
n = n.substring(0, Math.min(n.length, 6))
|
||||
text.append(n)
|
||||
for (i in n.length..6 step 2) {
|
||||
text.append("\t")
|
||||
}
|
||||
text.append("• ${up.toLong().toSpeedString()}↑ ${down.toLong().toSpeedString()}↓\n")
|
||||
}
|
||||
|
||||
fun stopSpeedNotification() {
|
||||
if (mSubscription != null) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.support.v4.view.GravityCompat
|
||||
import android.support.v7.app.ActionBarDrawerToggle
|
||||
import android.support.v7.widget.helper.ItemTouchHelper
|
||||
import android.util.Log
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
//import com.v2ray.ang.InappBuyActivity
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -164,8 +165,8 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
importBatchConfig(data?.getStringExtra("SCAN_RESULT"))
|
||||
}
|
||||
REQUEST_FILE_CHOOSER -> {
|
||||
if (resultCode == RESULT_OK) {
|
||||
val uri = data!!.data
|
||||
val uri = data?.data
|
||||
if (resultCode == RESULT_OK && uri != null) {
|
||||
readContentFromUri(uri)
|
||||
}
|
||||
}
|
||||
@@ -252,16 +253,24 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
adapter.updateConfigList()
|
||||
}
|
||||
for (k in 0 until configs.vmess.count()) {
|
||||
if (configs.vmess[k].configType != AppConfig.EConfigType.Custom) {
|
||||
testingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||
configs.vmess[k].testResult = Utils.tcping(configs.vmess[k].address, configs.vmess[k].port)
|
||||
var serverAddress = configs.vmess[k].address
|
||||
var serverPort = configs.vmess[k].port
|
||||
if (configs.vmess[k].configType == EConfigType.CUSTOM.value) {
|
||||
val serverOutbound = V2rayConfigUtil.getCustomConfigServerOutbound(applicationContext, configs.vmess[k].guid)
|
||||
?: continue
|
||||
serverAddress = serverOutbound.getServerAddress() ?: continue
|
||||
serverPort = serverOutbound.getServerPort() ?: continue
|
||||
}
|
||||
testingJobs.add(GlobalScope.launch(Dispatchers.IO) {
|
||||
configs.vmess.getOrNull(k)?.let { // check null in case array is modified during testing
|
||||
it.testResult = Utils.tcping(serverAddress, serverPort)
|
||||
val myJob = coroutineContext[Job]
|
||||
launch(Dispatchers.Main) {
|
||||
testingJobs.remove(myJob)
|
||||
adapter.updateSelectedItem(k)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -451,9 +460,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
.subscribe {
|
||||
if (it) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val configText = inputStream.bufferedReader().readText()
|
||||
importCustomizeConfig(configText)
|
||||
contentResolver.openInputStream(uri).use {
|
||||
val configText = it?.bufferedReader()?.readText()
|
||||
importCustomizeConfig(configText)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
@@ -8,17 +8,19 @@ import android.view.ViewGroup
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.AngConfig
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.extension.defaultDPreference
|
||||
import com.v2ray.ang.helper.ItemTouchHelperAdapter
|
||||
import com.v2ray.ang.helper.ItemTouchHelperViewHolder
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.V2rayConfigUtil
|
||||
import kotlinx.android.synthetic.main.item_qrcode.view.*
|
||||
import kotlinx.android.synthetic.main.item_recycler_main.view.*
|
||||
import org.jetbrains.anko.*
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
import com.v2ray.ang.extension.defaultDPreference
|
||||
|
||||
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>()
|
||||
, ItemTouchHelperAdapter {
|
||||
@@ -49,7 +51,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
|
||||
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
|
||||
if (holder is MainViewHolder) {
|
||||
val configType = configs.vmess[position].configType
|
||||
val configType = EConfigType.fromInt(configs.vmess[position].configType)
|
||||
val remarks = configs.vmess[position].remarks
|
||||
val subid = configs.vmess[position].subid
|
||||
val address = configs.vmess[position].address
|
||||
@@ -67,39 +69,40 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
holder.subid.text = "S"
|
||||
}
|
||||
|
||||
if (configType == AppConfig.EConfigType.Vmess) {
|
||||
holder.type.text = "vmess"
|
||||
holder.statistics.text = "$address : $port"
|
||||
holder.layout_share.visibility = View.VISIBLE
|
||||
} else if (configType == AppConfig.EConfigType.Custom) {
|
||||
var shareOptions = share_method.asList()
|
||||
if (configType == EConfigType.CUSTOM) {
|
||||
holder.type.text = mActivity.getString(R.string.server_customize_config)
|
||||
holder.statistics.text = ""//mActivity.getString(R.string.server_customize_config)
|
||||
holder.layout_share.visibility = View.INVISIBLE
|
||||
} else if (configType == AppConfig.EConfigType.Shadowsocks) {
|
||||
holder.type.text = "shadowsocks"
|
||||
val serverOutbound = V2rayConfigUtil.getCustomConfigServerOutbound(mActivity.applicationContext, configs.vmess[position].guid)
|
||||
if (serverOutbound == null) {
|
||||
holder.statistics.text = ""
|
||||
} else {
|
||||
holder.statistics.text = "${serverOutbound.getServerAddress()} : ${serverOutbound.getServerPort()}"
|
||||
}
|
||||
shareOptions = shareOptions.takeLast(1)
|
||||
} else {
|
||||
holder.type.text = configType?.name?.toLowerCase()
|
||||
holder.statistics.text = "$address : $port"
|
||||
holder.layout_share.visibility = View.VISIBLE
|
||||
} else if (configType == AppConfig.EConfigType.Socks) {
|
||||
holder.type.text = "socks"
|
||||
holder.statistics.text = "$address : $port"
|
||||
holder.layout_share.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
holder.layout_share.setOnClickListener {
|
||||
mActivity.selector(null, share_method.asList()) { dialogInterface, i ->
|
||||
mActivity.selector(null, shareOptions) { dialogInterface, i ->
|
||||
try {
|
||||
when (i) {
|
||||
0 -> {
|
||||
val iv = mActivity.layoutInflater.inflate(R.layout.item_qrcode, null)
|
||||
iv.iv_qcode.setImageBitmap(AngConfigManager.share2QRCode(position))
|
||||
if (configType == EConfigType.CUSTOM) {
|
||||
shareFullContent(position)
|
||||
} else {
|
||||
val iv = mActivity.layoutInflater.inflate(R.layout.item_qrcode, null)
|
||||
iv.iv_qcode.setImageBitmap(AngConfigManager.share2QRCode(position))
|
||||
|
||||
mActivity.alert {
|
||||
customView {
|
||||
linearLayout {
|
||||
addView(iv)
|
||||
mActivity.alert {
|
||||
customView {
|
||||
linearLayout {
|
||||
addView(iv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
if (AngConfigManager.share2Clipboard(position) == 0) {
|
||||
@@ -108,15 +111,8 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
mActivity.toast(R.string.toast_failure)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
if (AngConfigManager.shareFullContent2Clipboard(position) == 0) {
|
||||
mActivity.toast(R.string.toast_success)
|
||||
} else {
|
||||
mActivity.toast(R.string.toast_failure)
|
||||
}
|
||||
}
|
||||
else ->
|
||||
mActivity.toast("else")
|
||||
2 -> shareFullContent(position)
|
||||
else -> mActivity.toast("else")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@@ -125,13 +121,13 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
}
|
||||
|
||||
holder.layout_edit.setOnClickListener {
|
||||
if (configType == AppConfig.EConfigType.Vmess) {
|
||||
if (configType == EConfigType.VMESS) {
|
||||
mActivity.startActivity<ServerActivity>("position" to position, "isRunning" to !changeable)
|
||||
} else if (configType == AppConfig.EConfigType.Custom) {
|
||||
} else if (configType == EConfigType.CUSTOM) {
|
||||
mActivity.startActivity<Server2Activity>("position" to position, "isRunning" to !changeable)
|
||||
} else if (configType == AppConfig.EConfigType.Shadowsocks) {
|
||||
} else if (configType == EConfigType.SHADOWSOCKS) {
|
||||
mActivity.startActivity<Server3Activity>("position" to position, "isRunning" to !changeable)
|
||||
} else if (configType == AppConfig.EConfigType.Socks) {
|
||||
} else if (configType == EConfigType.SOCKS) {
|
||||
mActivity.startActivity<Server4Activity>("position" to position, "isRunning" to !changeable)
|
||||
}
|
||||
}
|
||||
@@ -176,6 +172,14 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareFullContent(position: Int) {
|
||||
if (AngConfigManager.shareFullContent2Clipboard(position) == 0) {
|
||||
mActivity.toast(R.string.toast_success)
|
||||
} else {
|
||||
mActivity.toast(R.string.toast_failure)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
|
||||
when (viewType) {
|
||||
VIEW_TYPE_ITEM ->
|
||||
|
||||
@@ -119,10 +119,10 @@ class ScannerActivity : BaseActivity(), ZXingScannerView.ResultHandler {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
REQUEST_FILE_CHOOSER ->
|
||||
if (resultCode == RESULT_OK) {
|
||||
REQUEST_FILE_CHOOSER -> {
|
||||
val uri = data?.data
|
||||
if (resultCode == RESULT_OK && uri != null) {
|
||||
try {
|
||||
val uri = data!!.data
|
||||
val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
|
||||
val text = QRCodeDecoder.syncDecodeQRCode(bitmap)
|
||||
finished(text)
|
||||
@@ -131,6 +131,7 @@ class ScannerActivity : BaseActivity(), ZXingScannerView.ResultHandler {
|
||||
toast(e.message.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.v2ray.ang.AppConfig.SS_PROTOCOL
|
||||
import com.v2ray.ang.AppConfig.VMESS_PROTOCOL
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.AngConfig
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.dto.VmessQRCode
|
||||
import java.net.URI
|
||||
import java.net.URLDecoder
|
||||
@@ -65,7 +66,7 @@ object AngConfigManager {
|
||||
fun addServer(vmess: AngConfig.VmessBean, index: Int): Int {
|
||||
try {
|
||||
vmess.configVersion = 2
|
||||
vmess.configType = AppConfig.EConfigType.Vmess
|
||||
vmess.configType = EConfigType.VMESS.value
|
||||
|
||||
if (index >= 0) {
|
||||
//edit
|
||||
@@ -208,14 +209,14 @@ object AngConfigManager {
|
||||
return app.defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG, "")
|
||||
}
|
||||
|
||||
fun currConfigType(): Int {
|
||||
fun currConfigType(): EConfigType? {
|
||||
if (angConfig.index < 0
|
||||
|| angConfig.vmess.count() <= 0
|
||||
|| angConfig.index > angConfig.vmess.count() - 1
|
||||
) {
|
||||
return -1
|
||||
return null
|
||||
}
|
||||
return angConfig.vmess[angConfig.index].configType
|
||||
return EConfigType.fromInt(angConfig.vmess[angConfig.index].configType)
|
||||
}
|
||||
|
||||
fun currConfigName(): String {
|
||||
@@ -275,7 +276,7 @@ object AngConfigManager {
|
||||
return R.string.toast_incorrect_protocol
|
||||
}
|
||||
|
||||
vmess.configType = AppConfig.EConfigType.Vmess
|
||||
vmess.configType = EConfigType.VMESS.value
|
||||
vmess.security = "auto"
|
||||
vmess.network = "tcp"
|
||||
vmess.headerType = "none"
|
||||
@@ -478,7 +479,7 @@ object AngConfigManager {
|
||||
}
|
||||
|
||||
val vmess = angConfig.vmess[index]
|
||||
if (angConfig.vmess[index].configType == AppConfig.EConfigType.Vmess) {
|
||||
if (angConfig.vmess[index].configType == EConfigType.VMESS.value) {
|
||||
|
||||
val vmessQRCode = VmessQRCode()
|
||||
vmessQRCode.v = vmess.configVersion.toString()
|
||||
@@ -496,7 +497,7 @@ object AngConfigManager {
|
||||
val conf = VMESS_PROTOCOL + Utils.encode(json)
|
||||
|
||||
return conf
|
||||
} else if (angConfig.vmess[index].configType == AppConfig.EConfigType.Shadowsocks) {
|
||||
} else if (angConfig.vmess[index].configType == EConfigType.SHADOWSOCKS.value) {
|
||||
val remark = "#" + Utils.urlEncode(vmess.remarks)
|
||||
val url = String.format("%s:%s@%s:%s",
|
||||
vmess.security,
|
||||
@@ -504,7 +505,7 @@ object AngConfigManager {
|
||||
vmess.address,
|
||||
vmess.port)
|
||||
return SS_PROTOCOL + Utils.encode(url) + remark
|
||||
} else if (angConfig.vmess[index].configType == AppConfig.EConfigType.Socks) {
|
||||
} else if (angConfig.vmess[index].configType == EConfigType.SOCKS.value) {
|
||||
val remark = "#" + Utils.urlEncode(vmess.remarks)
|
||||
val url = String.format("%s:%s",
|
||||
vmess.address,
|
||||
@@ -613,7 +614,7 @@ object AngConfigManager {
|
||||
//add
|
||||
val vmess = AngConfig.VmessBean()
|
||||
vmess.configVersion = 2
|
||||
vmess.configType = AppConfig.EConfigType.Custom
|
||||
vmess.configType = EConfigType.CUSTOM.value
|
||||
vmess.guid = guid
|
||||
vmess.remarks = vmess.guid
|
||||
|
||||
@@ -716,7 +717,7 @@ object AngConfigManager {
|
||||
fun addCustomServer(vmess: AngConfig.VmessBean, index: Int): Int {
|
||||
try {
|
||||
vmess.configVersion = 2
|
||||
vmess.configType = AppConfig.EConfigType.Custom
|
||||
vmess.configType = EConfigType.CUSTOM.value
|
||||
|
||||
if (index >= 0) {
|
||||
//edit
|
||||
@@ -741,7 +742,7 @@ object AngConfigManager {
|
||||
fun addShadowsocksServer(vmess: AngConfig.VmessBean, index: Int): Int {
|
||||
try {
|
||||
vmess.configVersion = 2
|
||||
vmess.configType = AppConfig.EConfigType.Shadowsocks
|
||||
vmess.configType = EConfigType.SHADOWSOCKS.value
|
||||
|
||||
if (index >= 0) {
|
||||
//edit
|
||||
@@ -766,7 +767,7 @@ object AngConfigManager {
|
||||
fun addSocksServer(vmess: AngConfig.VmessBean, index: Int): Int {
|
||||
try {
|
||||
vmess.configVersion = 2
|
||||
vmess.configType = AppConfig.EConfigType.Socks
|
||||
vmess.configType = EConfigType.SOCKS.value
|
||||
|
||||
if (index >= 0) {
|
||||
//edit
|
||||
@@ -794,10 +795,16 @@ object AngConfigManager {
|
||||
return 0
|
||||
}
|
||||
val removedSelectedServer =
|
||||
if (!TextUtils.isEmpty(subid) && configs.vmess.count() > 0 && configs.vmess[configs.index].subid.equals(subid))
|
||||
configs.vmess[configs.index]
|
||||
else
|
||||
if (!TextUtils.isEmpty(subid)) {
|
||||
configs.vmess.getOrNull(configs.index)?.let {
|
||||
if (it.subid == subid) {
|
||||
return@let it
|
||||
}
|
||||
return@let null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
removeServerViaSubid(subid)
|
||||
|
||||
// var servers = server
|
||||
|
||||
@@ -16,7 +16,7 @@ object AppManagerUtil {
|
||||
val apps = ArrayList<AppInfo>()
|
||||
|
||||
for (pkg in packages) {
|
||||
if (!pkg.hasInternetPermission) continue
|
||||
if (!pkg.hasInternetPermission && pkg.packageName != "android") continue
|
||||
|
||||
val applicationInfo = pkg.applicationInfo
|
||||
|
||||
@@ -40,4 +40,4 @@ object AppManagerUtil {
|
||||
val permissions = requestedPermissions
|
||||
return permissions?.any { it == Manifest.permission.INTERNET } ?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,36 +14,25 @@ import kotlin.collections.HashMap
|
||||
import android.app.ActivityManager
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.content.res.AssetManager
|
||||
import android.net.Uri
|
||||
import android.os.SystemClock
|
||||
import android.text.TextUtils
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.view.View
|
||||
import android.webkit.URLUtil
|
||||
import com.v2ray.ang.AngApplication
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.extension.responseLength
|
||||
import com.v2ray.ang.extension.v2RayApplication
|
||||
import com.v2ray.ang.service.V2RayVpnService
|
||||
import com.v2ray.ang.ui.SettingsActivity
|
||||
import kotlinx.android.synthetic.main.activity_logcat.*
|
||||
import kotlinx.coroutines.isActive
|
||||
import me.dozen.dpreference.DPreference
|
||||
import org.jetbrains.anko.toast
|
||||
import org.jetbrains.anko.uiThread
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.net.*
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
import java.math.BigInteger
|
||||
import java.util.concurrent.TimeUnit
|
||||
import libv2ray.Libv2ray
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
@@ -106,7 +95,7 @@ object Utils {
|
||||
try {
|
||||
val cmb = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipData = ClipData.newPlainText(null, content)
|
||||
cmb.primaryClip = clipData
|
||||
cmb.setPrimaryClip(clipData)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@@ -324,7 +313,7 @@ object Utils {
|
||||
if (AngConfigManager.genStoreV2rayConfig(-1)) {
|
||||
val configContent = AngConfigManager.currGeneratedV2rayConfig()
|
||||
val configType = AngConfigManager.currConfigType()
|
||||
if (configType == AppConfig.EConfigType.Custom) {
|
||||
if (configType == EConfigType.CUSTOM) {
|
||||
try {
|
||||
Libv2ray.testConfig(configContent)
|
||||
} catch (e: Exception) {
|
||||
@@ -452,7 +441,6 @@ object Utils {
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* readTextFromAssets
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.v2ray.ang.util
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
@@ -14,6 +15,10 @@ import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.json.JSONArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.extension.defaultDPreference
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
object V2rayConfigUtil {
|
||||
private val requestObj: JsonObject by lazy {
|
||||
@@ -40,19 +45,10 @@ object V2rayConfigUtil {
|
||||
// return result
|
||||
// }
|
||||
|
||||
if (vmess.configType == AppConfig.EConfigType.Vmess) {
|
||||
result = getV2rayConfigType1(app, vmess)
|
||||
} else if (vmess.configType == AppConfig.EConfigType.Custom) {
|
||||
if (vmess.configType == EConfigType.CUSTOM.value) {
|
||||
result = getV2rayConfigType2(app, vmess)
|
||||
} else if (vmess.configType == AppConfig.EConfigType.Shadowsocks) {
|
||||
} else {
|
||||
result = getV2rayConfigType1(app, vmess)
|
||||
} else if (vmess.configType == AppConfig.EConfigType.Socks) {
|
||||
result = getV2rayConfigType1(app, vmess)
|
||||
}
|
||||
|
||||
val domainName = parseDomainName(result.content)
|
||||
if (!TextUtils.isEmpty(domainName)) {
|
||||
app.defaultDPreference.setPrefString(AppConfig.PREF_CURR_CONFIG_DOMAIN, domainName)
|
||||
}
|
||||
|
||||
Log.d("V2rayConfigUtilGoLog", result.content)
|
||||
@@ -63,6 +59,22 @@ object V2rayConfigUtil {
|
||||
}
|
||||
}
|
||||
|
||||
fun getCustomConfigServerOutbound(content: Context, guid: String): V2rayConfig.OutboundBean? {
|
||||
val jsonConfig = content.defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + guid, "")
|
||||
if (TextUtils.isEmpty(jsonConfig)) {
|
||||
return null
|
||||
}
|
||||
val v2rayConfig = Gson().fromJson(jsonConfig, V2rayConfig::class.java) ?: return null
|
||||
for (outbound in v2rayConfig.outbounds) {
|
||||
if (outbound.protocol.equals(EConfigType.VMESS.name.toLowerCase()) ||
|
||||
outbound.protocol.equals(EConfigType.SHADOWSOCKS.name.toLowerCase()) ||
|
||||
outbound.protocol.equals(EConfigType.SOCKS.name.toLowerCase())) {
|
||||
return outbound
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成v2ray的客户端配置文件
|
||||
*/
|
||||
@@ -115,6 +127,7 @@ object V2rayConfigUtil {
|
||||
val jsonConfig = app.defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + guid, "")
|
||||
result.status = true
|
||||
result.content = jsonConfig
|
||||
parseDomainNameAndTag(app, jsonConfig)
|
||||
return result
|
||||
|
||||
} catch (e: Exception) {
|
||||
@@ -163,8 +176,12 @@ object V2rayConfigUtil {
|
||||
try {
|
||||
val outbound = v2rayConfig.outbounds[0]
|
||||
|
||||
when (vmess.configType) {
|
||||
AppConfig.EConfigType.Vmess -> {
|
||||
val configType = EConfigType.fromInt(vmess.configType)
|
||||
if (configType != null) {
|
||||
outbound.protocol = configType.name.toLowerCase()
|
||||
}
|
||||
when (configType) {
|
||||
EConfigType.VMESS -> {
|
||||
outbound.settings?.servers = null
|
||||
|
||||
val vnext = v2rayConfig.outbounds[0].settings?.vnext?.get(0)
|
||||
@@ -182,10 +199,8 @@ object V2rayConfigUtil {
|
||||
|
||||
//远程服务器底层传输配置
|
||||
outbound.streamSettings = boundStreamSettings(vmess)
|
||||
|
||||
outbound.protocol = "vmess"
|
||||
}
|
||||
AppConfig.EConfigType.Shadowsocks -> {
|
||||
EConfigType.SHADOWSOCKS -> {
|
||||
outbound.settings?.vnext = null
|
||||
|
||||
val server = outbound.settings?.servers?.get(0)
|
||||
@@ -198,10 +213,8 @@ object V2rayConfigUtil {
|
||||
|
||||
//Mux
|
||||
outbound.mux?.enabled = false
|
||||
|
||||
outbound.protocol = "shadowsocks"
|
||||
}
|
||||
AppConfig.EConfigType.Socks -> {
|
||||
EConfigType.SOCKS -> {
|
||||
outbound.settings?.vnext = null
|
||||
|
||||
val server = outbound.settings?.servers?.get(0)
|
||||
@@ -210,21 +223,22 @@ object V2rayConfigUtil {
|
||||
|
||||
//Mux
|
||||
outbound.mux?.enabled = false
|
||||
|
||||
outbound.protocol = "socks"
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
var serverDomain: String
|
||||
if(Utils.isIpv6Address(vmess.address)) {
|
||||
serverDomain = String.format("[%s]:%s", vmess.address, vmess.port)
|
||||
val serverDomain = if (Utils.isIpv6Address(vmess.address)) {
|
||||
String.format("[%s]:%s", vmess.address, vmess.port)
|
||||
} else {
|
||||
serverDomain = String.format("%s:%s", vmess.address, vmess.port)
|
||||
String.format("%s:%s", vmess.address, vmess.port)
|
||||
}
|
||||
app.defaultDPreference.setPrefString(AppConfig.PREF_CURR_CONFIG_DOMAIN, serverDomain)
|
||||
|
||||
val tags = LinkedHashSet<String>()
|
||||
v2rayConfig.outbounds.forEach {
|
||||
if (!TextUtils.isEmpty(it.tag)) {
|
||||
tags.add(it.tag)
|
||||
}
|
||||
}
|
||||
app.defaultDPreference.setPrefStringOrderedSet(AppConfig.PREF_CURR_CONFIG_OUTBOUND_TAGS, tags)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
@@ -616,42 +630,58 @@ object V2rayConfigUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDomainName(jsonConfig: String): String {
|
||||
private fun parseDomainNameAndTag(app: AngApplication, jsonConfig: String) {
|
||||
try {
|
||||
val jObj = JSONObject(jsonConfig)
|
||||
var domainName: String
|
||||
var domainName = ""
|
||||
val tags = LinkedHashSet<String>()
|
||||
if (jObj.has("outbound")) {
|
||||
domainName = parseDomainName(jObj.optJSONObject("outbound"))
|
||||
if (!TextUtils.isEmpty(domainName)) {
|
||||
return domainName
|
||||
val (domain, tag) = parseDomainNameAndTag(jObj.optJSONObject("outbound"))
|
||||
domainName = domain
|
||||
if (!TextUtils.isEmpty(tag)) {
|
||||
tags.add(tag)
|
||||
}
|
||||
}
|
||||
if (jObj.has("outbounds")) {
|
||||
for (i in 0..(jObj.optJSONArray("outbounds").length() - 1)) {
|
||||
domainName = parseDomainName(jObj.optJSONArray("outbounds").getJSONObject(i))
|
||||
if (!TextUtils.isEmpty(domainName)) {
|
||||
return domainName
|
||||
val (domain, tag) = parseDomainNameAndTag(jObj.optJSONArray("outbounds").getJSONObject(i))
|
||||
if (!TextUtils.isEmpty(domain) && TextUtils.isEmpty(domainName)) {
|
||||
domainName = domain
|
||||
}
|
||||
if (!TextUtils.isEmpty(tag)) {
|
||||
tags.add(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jObj.has("outboundDetour")) {
|
||||
for (i in 0..(jObj.optJSONArray("outboundDetour").length() - 1)) {
|
||||
domainName = parseDomainName(jObj.optJSONArray("outboundDetour").getJSONObject(i))
|
||||
if (!TextUtils.isEmpty(domainName)) {
|
||||
return domainName
|
||||
val (domain, tag) = parseDomainNameAndTag(jObj.optJSONArray("outboundDetour").getJSONObject(i))
|
||||
if (!TextUtils.isEmpty(domain) && TextUtils.isEmpty(domainName)) {
|
||||
domainName = domain
|
||||
}
|
||||
if (!TextUtils.isEmpty(tag)) {
|
||||
tags.add(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!TextUtils.isEmpty(domainName)) {
|
||||
app.defaultDPreference.setPrefString(AppConfig.PREF_CURR_CONFIG_DOMAIN, domainName)
|
||||
}
|
||||
app.defaultDPreference.setPrefStringOrderedSet(AppConfig.PREF_CURR_CONFIG_OUTBOUND_TAGS, tags)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun parseDomainName(outbound: JSONObject): String {
|
||||
private fun parseDomainNameAndTag(outbound: JSONObject): Pair<String, String> {
|
||||
val tag = if (outbound.has("tag")) {
|
||||
outbound.getString("tag")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
try {
|
||||
if (outbound.has("settings")) {
|
||||
var vnext: JSONArray?
|
||||
val vnext: JSONArray?
|
||||
if (outbound.optJSONObject("settings").has("vnext")) {
|
||||
// vmess
|
||||
vnext = outbound.optJSONObject("settings").optJSONArray("vnext")
|
||||
@@ -659,22 +689,22 @@ object V2rayConfigUtil {
|
||||
// shadowsocks or socks
|
||||
vnext = outbound.optJSONObject("settings").optJSONArray("servers")
|
||||
} else {
|
||||
return ""
|
||||
return Pair("", tag)
|
||||
}
|
||||
for (i in 0..(vnext.length() - 1)) {
|
||||
val item = vnext.getJSONObject(i)
|
||||
val address = item.getString("address")
|
||||
val port = item.getString("port")
|
||||
if(Utils.isIpv6Address(address)) {
|
||||
return String.format("[%s]:%s", address, port)
|
||||
return Pair(String.format("[%s]:%s", address, port), tag)
|
||||
} else {
|
||||
return String.format("%s:%s", address, port)
|
||||
return Pair(String.format("%s:%s", address, port), tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return ""
|
||||
return Pair("", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
<string name="title_logcat">Logcat</string>
|
||||
<string name="logcat_copy">复制</string>
|
||||
<string name="logcat_delete">删除</string>
|
||||
<string name="title_export_all">导出全部配置至剪贴板</string>
|
||||
<string name="title_export_all">导出全部(非自定义)配置至剪贴板</string>
|
||||
<string name="title_sub_setting">订阅设置</string>
|
||||
<string name="sub_setting_remarks">备注</string>
|
||||
<string name="sub_setting_url">地址(url)</string>
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
<string name="title_logcat">Logcat</string>
|
||||
<string name="logcat_copy">複製</string>
|
||||
<string name="logcat_delete">刪除</string>
|
||||
<string name="title_export_all">匯出全部配置至剪貼簿</string>
|
||||
<string name="title_export_all">匯出全部(非自訂)配置至剪貼簿</string>
|
||||
<string name="title_sub_setting">訂閱設定</string>
|
||||
<string name="sub_setting_remarks">備註</string>
|
||||
<string name="sub_setting_url">位址(url)</string>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<string name="server_lab_network">network</string>
|
||||
<string name="server_lab_more_function">more function</string>
|
||||
<string name="server_lab_head_type">head type</string>
|
||||
<string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC securty</string>
|
||||
<string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC security</string>
|
||||
<string name="server_lab_path">path(ws path/h2 path)/QUIC key</string>
|
||||
<string name="server_lab_stream_security">tls</string>
|
||||
<string name="server_lab_allow_insecure">allowInsecure</string>
|
||||
@@ -138,7 +138,7 @@
|
||||
<string name="title_logcat">Logcat</string>
|
||||
<string name="logcat_copy">Copy</string>
|
||||
<string name="logcat_delete">Delete</string>
|
||||
<string name="title_export_all">Export all config to clipboard</string>
|
||||
<string name="title_export_all">Export non-custom configs to clipboard</string>
|
||||
<string name="title_sub_setting">Subscription setting</string>
|
||||
<string name="sub_setting_remarks">remarks</string>
|
||||
<string name="sub_setting_url">url</string>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion '28.0.3'
|
||||
compileSdkVersion Integer.parseInt("$compileSdkVer")
|
||||
buildToolsVersion buildToolsVer
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 17
|
||||
|
||||
@@ -2,7 +2,9 @@ package me.dozen.dpreference;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -45,10 +47,6 @@ public class DPreference {
|
||||
PrefAccessor.setInt(mContext, mName, key, value);
|
||||
}
|
||||
|
||||
public void setPrefStringSet(final String key, final Set<String> value) {
|
||||
PrefAccessor.setStringSet(mContext, mName, key, value);
|
||||
}
|
||||
|
||||
public int getPrefInt(final String key, final int defaultValue) {
|
||||
return PrefAccessor.getInt(mContext, mName, key, defaultValue);
|
||||
}
|
||||
@@ -61,10 +59,26 @@ public class DPreference {
|
||||
return PrefAccessor.getLong(mContext, mName, key, defaultValue);
|
||||
}
|
||||
|
||||
public void setPrefStringSet(final String key, final Set<String> value) {
|
||||
PrefAccessor.setStringSet(mContext, mName, key, value);
|
||||
}
|
||||
|
||||
public Set<String> getPrefStringSet(final String key, final Set<String> defaultValue) {
|
||||
return PrefAccessor.getStringSet(mContext, mName, key, defaultValue);
|
||||
}
|
||||
|
||||
public void setPrefStringOrderedSet(final String key, final LinkedHashSet<String> value) {
|
||||
PrefAccessor.setString(mContext, mName, key, StringSetConverter.encode(value));
|
||||
}
|
||||
|
||||
public LinkedHashSet<String> getPrefStringOrderedSet(final String key, final LinkedHashSet<String> defaultValue) {
|
||||
String value = PrefAccessor.getString(mContext, mName, key, "");
|
||||
if (TextUtils.isEmpty(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return StringSetConverter.decode(value);
|
||||
}
|
||||
|
||||
public void removePreference(final String key) {
|
||||
PrefAccessor.remove(mContext, mName, key);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class StringSetConverter {
|
||||
@@ -13,8 +14,8 @@ public class StringSetConverter {
|
||||
return gson.toJson(src);
|
||||
}
|
||||
|
||||
public static Set<String> decode(String json) {
|
||||
Type setType = new TypeToken<Set<String>>() {
|
||||
public static LinkedHashSet<String> decode(String json) {
|
||||
Type setType = new TypeToken<LinkedHashSet<String>>() {
|
||||
}.getType();
|
||||
return gson.fromJson(json, setType);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
|
||||
ankoVersion=0.10.8
|
||||
kotlinVersion=1.3.40
|
||||
supportLibVersion=28.0.0
|
||||
buildToolsVer=28.0.3
|
||||
compileSdkVer=28
|
||||
buildToolsVer=29.0.3
|
||||
compileSdkVer=29
|
||||
kotlin.incremental=true
|
||||
targetSdkVer=28
|
||||
targetSdkVer=29
|
||||
|
||||
6
V2rayNG/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
V2rayNG/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Tue Feb 25 12:40:41 CST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
|
||||
Reference in New Issue
Block a user