Compare commits

..

21 Commits
1.4.1 ... 1.4.6

Author SHA1 Message Date
2dust
45805d6df7 Merge pull request #644 from yuhan6665/clean-dependency
Clean dependency
2020-10-04 19:16:27 +08:00
2dust
4437e6699b Merge pull request #635 from rurirei/diff
issues of VPNService.kt
2020-10-04 19:16:14 +08:00
2dust
fa409f91e4 Merge pull request #626 from yuhan6665/go
Clean up tun2socks
2020-10-04 19:16:00 +08:00
yuhan6665
89be5f077b Say goodbye to Anko
replace with support lib PreferenceManager
replace LayoutInflater
2020-10-03 11:19:46 -04:00
yuhan6665
896889778f Replace Anko with support lib AlertDialog
replace some property setter
2020-10-03 11:19:46 -04:00
yuhan6665
10f705a8b2 Use standard startActivity 2020-10-03 11:19:46 -04:00
yuhan6665
2956fa2030 Replace doasync with Kotlin coroutine
Using a custom coroutine scope, we don't need to keep track of the
running job. We can simply call cancel children for the scope.
2020-10-03 11:19:46 -04:00
yuhan6665
c2a704a6ea Deprecate some anko function
- Replace toast with inline function
- Use standard startActivityForResult
2020-10-03 11:19:46 -04:00
yuhan6665
78cac0cd90 Replace divider with standard library
Also, cleanup some unused classes
2020-10-03 11:19:46 -04:00
Rurirei
3ffb2e8e05 catch exception for lateinit
PropertyNotInitialized exception needs catch for lateinit var
2020-10-03 20:23:43 +08:00
Rurirei
e2d667e0bb sendFd() should not called twice 2020-10-01 17:36:07 +08:00
Rurirei
3ae0777d7f useless bool 2020-10-01 17:07:51 +08:00
Rurirei
5e6348676c ignore err of registerNetworkConnectivity 2020-10-01 15:32:08 +08:00
2dust
df3f1ca3ef Merge pull request #620 from yuhan6665/up-version
Update dependencies
2020-09-29 08:05:46 +08:00
yuhan6665
94f2bec329 Clean up tun2socks 2020-09-27 23:17:47 -04:00
yuhan6665
c54d8fa43a Update dependencies
Fix a delegate annotation for Kotlin 1.4
2020-09-25 18:37:29 -04:00
2dust
5bbbdcf6f2 Merge pull request #610 from yuhan6665/fix-protect
Fix protect() when there is no service
2020-09-21 07:59:55 +08:00
yuhan6665
4abf20fa32 Fix protect() when there is no service 2020-09-20 19:00:14 -04:00
2dust
723727feb9 Merge pull request #607 from yuhan6665/help-proxy-mode
Help proxy mode
2020-09-19 18:56:15 +08:00
yuhan6665
2efd4b741c Add badge, wiki link and dev guide 2020-09-18 17:48:54 -04:00
yuhan6665
83aab0f880 Add help link in mode setting 2020-09-18 17:48:54 -04:00
43 changed files with 284 additions and 366 deletions

View File

@@ -8,9 +8,6 @@ asset:
# 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/geosite.dat > geosite.dat
# cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geoip.dat > geoip.dat # cd assets;curl https://raw.githubusercontent.com/2dust/AndroidLibV2rayLite/master/data/geoip.dat > geoip.dat
shippedBinary:
cd shippedBinarys; $(MAKE) shippedBinary
fetchDep: fetchDep:
-go get github.com/2dust/AndroidLibV2rayLite -go get github.com/2dust/AndroidLibV2rayLite
go get github.com/2dust/AndroidLibV2rayLite go get github.com/2dust/AndroidLibV2rayLite
@@ -30,5 +27,5 @@ downloadGoMobile:
BuildMobile: BuildMobile:
@echo Stub @echo Stub
all: asset pb shippedBinary fetchDep all: asset pb fetchDep
@echo DONE @echo DONE

View File

@@ -34,14 +34,10 @@ $NDK_HOME/ndk-build \
NDK_OUT=$TMPDIR/tmp \ NDK_OUT=$TMPDIR/tmp \
APP_SHORT_COMMANDS=false LOCAL_SHORT_COMMANDS=false -B -j4 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/armeabi-v7a/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/armeabi-v7a/libtun2socks.so
install -v -m755 libs/arm64-v8a/tun2socks $__dir/shippedBinarys/ArchDep/arm64/ install -v -m755 libs/arm64-v8a/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/arm64-v8a/libtun2socks.so
install -v -m755 libs/x86/tun2socks $__dir/shippedBinarys/ArchDep/386/ install -v -m755 libs/x86/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/x86/libtun2socks.so
install -v -m755 libs/x86_64/tun2socks $__dir/shippedBinarys/ArchDep/amd64/ install -v -m755 libs/x86_64/tun2socks $__dir/../V2rayNG/app/src/main/jniLibs/x86_64/libtun2socks.so
popd popd
pushd $__dir/shippedBinarys rm -rf $TMPDIR
make clean && make shippedBinary
popd
rm -rf $TMPDIR

View File

@@ -11,7 +11,6 @@ import (
"github.com/2dust/AndroidLibV2rayLite/CoreI" "github.com/2dust/AndroidLibV2rayLite/CoreI"
"github.com/2dust/AndroidLibV2rayLite/Process/Escort" "github.com/2dust/AndroidLibV2rayLite/Process/Escort"
"github.com/2dust/AndroidLibV2rayLite/VPN" "github.com/2dust/AndroidLibV2rayLite/VPN"
"github.com/2dust/AndroidLibV2rayLite/shippedBinarys"
mobasset "golang.org/x/mobile/asset" mobasset "golang.org/x/mobile/asset"
v2core "v2ray.com/core" v2core "v2ray.com/core"
@@ -227,12 +226,6 @@ func NewV2RayPoint(s V2RayVPNServiceSupportsSet) *V2RayPoint {
} }
func (v V2RayPoint) runTun2socks() error { 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() v.escorter.EscortingUp()
go v.escorter.EscortRun( go v.escorter.EscortRun(
v.status.GetApp("libtun2socks.so"), v.status.GetApp("libtun2socks.so"),

View File

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

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

@@ -1,5 +1,25 @@
# v2rayNG # v2rayNG
A V2Ray client for Android
[![API](https://img.shields.io/badge/API-17%2B-yellow.svg?style=flat)](https://developer.android.com/about/versions/jelly-bean#android-4.2)
[![Kotlin Version](https://img.shields.io/badge/Kotlin-1.4.0-blue.svg)](https://kotlinlang.org)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayNG)](https://github.com/2dust/v2rayNG/commits/master)
[![CodeFactor](https://www.codefactor.io/repository/github/2dust/v2rayng/badge)](https://www.codefactor.io/repository/github/2dust/v2rayng)
[![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayNG/latest/total?logo=github)](https://github.com/2dust/v2rayNG/releases)
<a href="https://play.google.com/store/apps/details?id=com.v2ray.ang"> <a href="https://play.google.com/store/apps/details?id=com.v2ray.ang">
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" /> <img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
</a> </a>
### Usage
See our [wiki](https://github.com/2dust/v2rayNG/wiki)
### Development guide
Android project under V2rayNG folder can be compiled directly in Android Studio, or using Gradle wrapper. But the v2ray core inside the aar is (probably) outdated.
The aar can be compiled from the Golang project under AndroidLibV2rayLite folder. For a quick start, read guide for [Go Mobile](https://github.com/golang/go/wiki/Mobile)
and [Makefiles for Go Developers](https://tutorialedge.net/golang/makefiles-for-go-developers/)
v2rayNG can run on Android Emulators, with minimum Android 5.0

View File

@@ -62,14 +62,13 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.13'
testImplementation 'junit:junit:4.12'
implementation project(':dpreference') implementation project(':dpreference')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.2" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.2" // 1.3.x has compile error: implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
// More than one file was found with OS independent path 'META-INF/proguard/coroutines.pro'
// Android support library // Android support library
implementation "com.android.support:support-v4:$supportLibVersion" implementation "com.android.support:support-v4:$supportLibVersion"
@@ -79,22 +78,16 @@ dependencies {
implementation "com.android.support:preference-v7:$supportLibVersion" implementation "com.android.support:preference-v7:$supportLibVersion"
implementation "com.android.support:recyclerview-v7:$supportLibVersion" implementation "com.android.support:recyclerview-v7:$supportLibVersion"
implementation "com.android.support:multidex:1.0.3" implementation "com.android.support:multidex:1.0.3"
implementation 'com.android.support.constraint:constraint-layout:2.0.1'
// DSL // DSL
implementation "org.jetbrains.anko:anko-sdk15:$ankoVersion" implementation 'com.google.code.gson:gson:2.8.6'
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.5'
implementation 'io.reactivex:rxjava:1.3.4' implementation 'io.reactivex:rxjava:1.3.4'
implementation 'io.reactivex:rxandroid:1.2.1' implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar' implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar'
implementation 'com.dinuscxj:recycleritemdecoration:1.0.0'
implementation 'io.reactivex:rxkotlin:0.60.0'
implementation 'me.dm7.barcodescanner:core:1.9.8' implementation 'me.dm7.barcodescanner:core:1.9.8'
implementation 'me.dm7.barcodescanner:zxing:1.9.8' implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar' implementation 'com.github.jorgecastilloprz:fabprogresscircle:1.01@aar'
implementation 'com.beust:klaxon:3.0.1'
implementation 'com.android.support:multidex:1.0.3'
implementation(name: 'libv2ray', ext: 'aar') implementation(name: 'libv2ray', ext: 'aar')
//implementation(name: 'tun2socks', ext: 'aar') //implementation(name: 'tun2socks', ext: 'aar')

View File

@@ -1,10 +1,9 @@
package com.v2ray.ang package com.v2ray.ang
//import com.squareup.leakcanary.LeakCanary
import android.support.multidex.MultiDexApplication import android.support.multidex.MultiDexApplication
import android.support.v7.preference.PreferenceManager
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import me.dozen.dpreference.DPreference import me.dozen.dpreference.DPreference
import org.jetbrains.anko.defaultSharedPreferences
class AngApplication : MultiDexApplication() { class AngApplication : MultiDexApplication() {
companion object { companion object {
@@ -22,6 +21,7 @@ class AngApplication : MultiDexApplication() {
// LeakCanary.install(this) // LeakCanary.install(this)
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
firstRun = defaultSharedPreferences.getInt(PREF_LAST_VERSION, 0) != BuildConfig.VERSION_CODE firstRun = defaultSharedPreferences.getInt(PREF_LAST_VERSION, 0) != BuildConfig.VERSION_CODE
if (firstRun) if (firstRun)
defaultSharedPreferences.edit().putInt(PREF_LAST_VERSION, BuildConfig.VERSION_CODE).apply() defaultSharedPreferences.edit().putInt(PREF_LAST_VERSION, BuildConfig.VERSION_CODE).apply()

View File

@@ -38,6 +38,7 @@ object AppConfig {
const val androidpackagenamelistUrl = "https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt" const val androidpackagenamelistUrl = "https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt"
const val v2rayCustomRoutingListUrl = "https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/" const val v2rayCustomRoutingListUrl = "https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"
const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues" const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues"
const val v2rayNGWikiMode = "https://github.com/2dust/v2rayNG/wiki/Mode"
const val promotionUrl = "https://1.2345345.xyz/ads.html" const val promotionUrl = "https://1.2345345.xyz/ads.html"
const val DNS_AGENT = "1.1.1.1" const val DNS_AGENT = "1.1.1.1"

View File

@@ -2,6 +2,7 @@ package com.v2ray.ang.extension
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.widget.Toast
import com.v2ray.ang.AngApplication import com.v2ray.ang.AngApplication
import me.dozen.dpreference.DPreference import me.dozen.dpreference.DPreference
import org.json.JSONObject import org.json.JSONObject
@@ -17,6 +18,17 @@ val Context.v2RayApplication: AngApplication
val Context.defaultDPreference: DPreference val Context.defaultDPreference: DPreference
get() = v2RayApplication.defaultDPreference get() = v2RayApplication.defaultDPreference
inline fun Context.toast(message: Int): Toast = Toast
.makeText(this, message, Toast.LENGTH_SHORT)
.apply {
show()
}
inline fun Context.toast(message: CharSequence): Toast = Toast
.makeText(this, message, Toast.LENGTH_SHORT)
.apply {
show()
}
fun JSONObject.putOpt(pair: Pair<String, Any>) = putOpt(pair.first, pair.second)!! fun JSONObject.putOpt(pair: Pair<String, Any>) = putOpt(pair.first, pair.second)!!
fun JSONObject.putOpt(pairs: Map<String, Any>) = pairs.forEach { putOpt(it.key to it.value) } fun JSONObject.putOpt(pairs: Map<String, Any>) = pairs.forEach { putOpt(it.key to it.value) }

View File

@@ -88,7 +88,7 @@ object V2RayServiceManager {
} }
override fun protect(l: Long): Long { override fun protect(l: Long): Long {
val serviceControl = serviceControl?.get() ?: return 1 val serviceControl = serviceControl?.get() ?: return 0
return if (serviceControl.vpnProtect(l.toInt())) 0 else 1 return if (serviceControl.vpnProtect(l.toInt())) 0 else 1
} }

View File

@@ -16,7 +16,9 @@ import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.ui.PerAppProxyActivity import com.v2ray.ang.ui.PerAppProxyActivity
import com.v2ray.ang.ui.SettingsActivity import com.v2ray.ang.ui.SettingsActivity
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import org.jetbrains.anko.doAsync import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.lang.ref.SoftReference import java.lang.ref.SoftReference
@@ -32,7 +34,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
* *
* Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887 * Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
*/ */
private val defaultNetworkRequest by lazy @RequiresApi(Build.VERSION_CODES.P) { @delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkRequest by lazy {
NetworkRequest.Builder() NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
@@ -41,7 +44,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager } private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
private val defaultNetworkCallback by lazy @RequiresApi(Build.VERSION_CODES.P) { @delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkCallback by lazy {
object : ConnectivityManager.NetworkCallback() { object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) { override fun onAvailable(network: Network) {
setUnderlyingNetworks(arrayOf(network)) setUnderlyingNetworks(arrayOf(network))
@@ -56,8 +60,6 @@ class V2RayVpnService : VpnService(), ServiceControl {
} }
} }
private var listeningForDefaultNetwork = false
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@@ -151,8 +153,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback) try {
listeningForDefaultNetwork = true connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
} catch (ignored: Exception) {
// ignored
}
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
@@ -160,15 +165,20 @@ class V2RayVpnService : VpnService(), ServiceControl {
} }
// Create a new interface using the builder and save the parameters. // Create a new interface using the builder and save the parameters.
mInterface = builder.establish() try {
sendFd() mInterface = builder.establish()!!
} catch (e: Exception) {
// non-nullable lateinit var
e.printStackTrace()
stopV2Ray()
}
} }
private fun sendFd() { private fun sendFd() {
val fd = mInterface.fileDescriptor val fd = mInterface.fileDescriptor
val path = File(Utils.packagePath(applicationContext), "sock_path").absolutePath val path = File(Utils.packagePath(applicationContext), "sock_path").absolutePath
doAsync { GlobalScope.launch(Dispatchers.IO) {
var tries = 0 var tries = 0
while (true) try { while (true) try {
Thread.sleep(50L shl tries) Thread.sleep(50L shl tries)
@@ -198,9 +208,12 @@ class V2RayVpnService : VpnService(), ServiceControl {
// val emptyInfo = VpnNetworkInfo() // val emptyInfo = VpnNetworkInfo()
// val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo) // val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo)
// saveVpnNetworkInfo(configName, info) // saveVpnNetworkInfo(configName, info)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && listeningForDefaultNetwork) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
connectivity.unregisterNetworkCallback(defaultNetworkCallback) try {
listeningForDefaultNetwork = false connectivity.unregisterNetworkCallback(defaultNetworkCallback)
} catch (ignored: Exception) {
// ignored
}
} }
V2RayServiceManager.stopV2rayPoint() V2RayServiceManager.stopV2rayPoint()

View File

@@ -13,11 +13,7 @@ import android.support.v7.widget.Toolbar
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
//import com.v2ray.ang.InappBuyActivity
import com.v2ray.ang.R import com.v2ray.ang.R
import org.jetbrains.anko.startActivity
abstract class BaseDrawerActivity : BaseActivity() { abstract class BaseDrawerActivity : BaseActivity() {
companion object { companion object {
@@ -58,7 +54,7 @@ abstract class BaseDrawerActivity : BaseActivity() {
R.id.sub_setting -> activityClass = SubSettingActivity::class.java R.id.sub_setting -> activityClass = SubSettingActivity::class.java
R.id.settings -> activityClass = SettingsActivity::class.java R.id.settings -> activityClass = SettingsActivity::class.java
R.id.logcat -> { R.id.logcat -> {
startActivity<LogcatActivity>() startActivity(Intent(this@BaseDrawerActivity, LogcatActivity::class.java))
return return
} }
R.id.donate -> { R.id.donate -> {

View File

@@ -8,12 +8,12 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_logcat.* import kotlinx.android.synthetic.main.activity_logcat.*
import org.jetbrains.anko.doAsync import kotlinx.coroutines.Dispatchers
import org.jetbrains.anko.toast import kotlinx.coroutines.GlobalScope
import org.jetbrains.anko.uiThread import kotlinx.coroutines.launch
import java.io.IOException import java.io.IOException
import java.util.LinkedHashSet import java.util.LinkedHashSet
@@ -34,7 +34,7 @@ class LogcatActivity : BaseActivity() {
try { try {
pb_waiting.visibility = View.VISIBLE pb_waiting.visibility = View.VISIBLE
doAsync { GlobalScope.launch(Dispatchers.Default) {
if (shouldFlushLog) { if (shouldFlushLog) {
val lst = LinkedHashSet<String>() val lst = LinkedHashSet<String>()
lst.add("logcat") lst.add("logcat")
@@ -54,7 +54,7 @@ class LogcatActivity : BaseActivity() {
// InputStreamReader(process.inputStream)) // InputStreamReader(process.inputStream))
// val allText = bufferedReader.use(BufferedReader::readText) // val allText = bufferedReader.use(BufferedReader::readText)
val allText = process.inputStream.bufferedReader().use { it.readText() } val allText = process.inputStream.bufferedReader().use { it.readText() }
uiThread { launch(Dispatchers.Main) {
tv_logcat.text = allText tv_logcat.text = allText
tv_logcat.movementMethod = ScrollingMovementMethod() tv_logcat.movementMethod = ScrollingMovementMethod()
pb_waiting.visibility = View.GONE pb_waiting.visibility = View.GONE

View File

@@ -18,7 +18,6 @@ import android.view.KeyEvent
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.V2rayConfigUtil import com.v2ray.ang.util.V2rayConfigUtil
import org.jetbrains.anko.*
import java.lang.ref.SoftReference import java.lang.ref.SoftReference
import java.net.URL import java.net.URL
import android.content.IntentFilter import android.content.IntentFilter
@@ -30,7 +29,7 @@ import android.util.Log
import com.v2ray.ang.BuildConfig import com.v2ray.ang.BuildConfig
import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.defaultDPreference import com.v2ray.ang.extension.defaultDPreference
//import com.v2ray.ang.InappBuyActivity import com.v2ray.ang.extension.toast
import rx.Observable import rx.Observable
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -52,10 +51,10 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
field = value field = value
adapter.changeable = !value adapter.changeable = !value
if (value) { if (value) {
fab.imageResource = R.drawable.ic_v fab.setImageResource(R.drawable.ic_v)
tv_test_state.text = getString(R.string.connection_connected) tv_test_state.text = getString(R.string.connection_connected)
} else { } else {
fab.imageResource = R.drawable.ic_v_idle fab.setImageResource(R.drawable.ic_v_idle)
tv_test_state.text = getString(R.string.connection_not_connected) tv_test_state.text = getString(R.string.connection_not_connected)
} }
hideCircle() hideCircle()
@@ -63,7 +62,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
private val adapter by lazy { MainRecyclerAdapter(this) } private val adapter by lazy { MainRecyclerAdapter(this) }
private var mItemTouchHelper: ItemTouchHelper? = null private var mItemTouchHelper: ItemTouchHelper? = null
private val testingJobs = ArrayList<Job>() private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -90,9 +89,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
val socksPort = 10808//Utils.parseInt(defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808")) val socksPort = 10808//Utils.parseInt(defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
tv_test_state.text = getString(R.string.connection_test_testing) tv_test_state.text = getString(R.string.connection_test_testing)
doAsync { GlobalScope.launch(Dispatchers.IO) {
val result = Utils.testConnection(this@MainActivity, socksPort) val result = Utils.testConnection(this@MainActivity, socksPort)
uiThread { launch(Dispatchers.Main) {
tv_test_state.text = Utils.getEditable(result) tv_test_state.text = Utils.getEditable(result)
} }
} }
@@ -188,6 +187,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
return true return true
} }
private fun getOptionIntent() = Intent().putExtra("position", -1)
.putExtra("isRunning", isRunning)
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.import_qrcode -> { R.id.import_qrcode -> {
importQRcode(REQUEST_SCAN) importQRcode(REQUEST_SCAN)
@@ -198,17 +200,17 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
true true
} }
R.id.import_manually_vmess -> { R.id.import_manually_vmess -> {
startActivity<ServerActivity>("position" to -1, "isRunning" to isRunning) startActivity(getOptionIntent().setClass(this, ServerActivity::class.java))
adapter.updateConfigList() adapter.updateConfigList()
true true
} }
R.id.import_manually_ss -> { R.id.import_manually_ss -> {
startActivity<Server3Activity>("position" to -1, "isRunning" to isRunning) startActivity(getOptionIntent().setClass(this, Server3Activity::class.java))
adapter.updateConfigList() adapter.updateConfigList()
true true
} }
R.id.import_manually_socks -> { R.id.import_manually_socks -> {
startActivity<Server4Activity>("position" to -1, "isRunning" to isRunning) startActivity(getOptionIntent().setClass(this, Server4Activity::class.java))
adapter.updateConfigList() adapter.updateConfigList()
true true
} }
@@ -249,10 +251,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
} }
R.id.ping_all -> { R.id.ping_all -> {
testingJobs.forEach { tcpingTestScope.coroutineContext[Job]?.cancelChildren()
it.cancel()
}
testingJobs.clear()
Utils.closeAllTcpSockets() Utils.closeAllTcpSockets()
for (k in 0 until configs.vmess.count()) { for (k in 0 until configs.vmess.count()) {
configs.vmess[k].testResult = "" configs.vmess[k].testResult = ""
@@ -267,16 +266,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
serverAddress = serverOutbound.getServerAddress() ?: continue serverAddress = serverOutbound.getServerAddress() ?: continue
serverPort = serverOutbound.getServerPort() ?: continue serverPort = serverOutbound.getServerPort() ?: continue
} }
testingJobs.add(GlobalScope.launch(Dispatchers.IO) { tcpingTestScope.launch {
configs.vmess.getOrNull(k)?.let { // check null in case array is modified during testing configs.vmess.getOrNull(k)?.let { // check null in case array is modified during testing
it.testResult = Utils.tcping(serverAddress, serverPort) it.testResult = Utils.tcping(serverAddress, serverPort)
val myJob = coroutineContext[Job]
launch(Dispatchers.Main) { launch(Dispatchers.Main) {
testingJobs.remove(myJob)
adapter.updateSelectedItem(k) adapter.updateSelectedItem(k)
} }
} }
}) }
} }
true true
} }
@@ -306,7 +303,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.subscribe { .subscribe {
if (it) if (it)
startActivityForResult<ScannerActivity>(requestCode) startActivityForResult(Intent(this, ScannerActivity::class.java), requestCode)
else else
toast(R.string.toast_permission_denied) toast(R.string.toast_permission_denied)
} }
@@ -392,9 +389,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
toast(R.string.toast_invalid_url) toast(R.string.toast_invalid_url)
return false return false
} }
doAsync { GlobalScope.launch(Dispatchers.IO) {
val configText = URL(url).readText() val configText = try {
uiThread { URL(url).readText()
} catch (e: Exception) {
e.printStackTrace()
""
}
launch(Dispatchers.Main) {
importCustomizeConfig(configText) importCustomizeConfig(configText)
} }
} }
@@ -426,9 +428,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
continue continue
} }
Log.d("Main", url) Log.d("Main", url)
doAsync { GlobalScope.launch(Dispatchers.IO) {
val configText = URL(url).readText() val configText = try {
uiThread { URL(url).readText()
} catch (e: Exception) {
e.printStackTrace()
""
}
launch(Dispatchers.Main) {
importBatchConfig(Utils.decode(configText), id) importBatchConfig(Utils.decode(configText), id)
} }
} }
@@ -574,10 +581,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
when (item.itemId) { when (item.itemId) {
//R.id.server_profile -> activityClass = MainActivity::class.java //R.id.server_profile -> activityClass = MainActivity::class.java
R.id.sub_setting -> { R.id.sub_setting -> {
startActivity<SubSettingActivity>() startActivity(Intent(this, SubSettingActivity::class.java))
} }
R.id.settings -> { R.id.settings -> {
startActivity<SettingsActivity>("isRunning" to isRunning) startActivity(Intent(this, SettingsActivity::class.java)
.putExtra("isRunning", isRunning))
} }
R.id.feedback -> { R.id.feedback -> {
Utils.openUri(this, AppConfig.v2rayNGIssues) Utils.openUri(this, AppConfig.v2rayNGIssues)
@@ -589,7 +597,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
// startActivity<InappBuyActivity>() // startActivity<InappBuyActivity>()
} }
R.id.logcat -> { R.id.logcat -> {
startActivity<LogcatActivity>() startActivity(Intent(this, LogcatActivity::class.java))
} }
} }
drawer_layout.closeDrawer(GravityCompat.START) drawer_layout.closeDrawer(GravityCompat.START)

View File

@@ -1,15 +1,18 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.support.v7.app.AlertDialog
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.defaultDPreference import com.v2ray.ang.extension.toast
import com.v2ray.ang.helper.ItemTouchHelperAdapter import com.v2ray.ang.helper.ItemTouchHelperAdapter
import com.v2ray.ang.helper.ItemTouchHelperViewHolder import com.v2ray.ang.helper.ItemTouchHelperViewHolder
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
@@ -17,7 +20,6 @@ import com.v2ray.ang.util.Utils
import com.v2ray.ang.util.V2rayConfigUtil import com.v2ray.ang.util.V2rayConfigUtil
import kotlinx.android.synthetic.main.item_qrcode.view.* import kotlinx.android.synthetic.main.item_qrcode.view.*
import kotlinx.android.synthetic.main.item_recycler_main.view.* import kotlinx.android.synthetic.main.item_recycler_main.view.*
import org.jetbrains.anko.*
import rx.Observable import rx.Observable
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -60,7 +62,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
holder.name.text = remarks holder.name.text = remarks
holder.radio.isChecked = (position == configs.index) holder.radio.isChecked = (position == configs.index)
holder.itemView.backgroundColor = Color.TRANSPARENT holder.itemView.setBackgroundColor(Color.TRANSPARENT)
holder.test_result.text = test_result holder.test_result.text = test_result
if (TextUtils.isEmpty(subid)) { if (TextUtils.isEmpty(subid)) {
@@ -85,7 +87,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
} }
holder.layout_share.setOnClickListener { holder.layout_share.setOnClickListener {
mActivity.selector(null, shareOptions) { dialogInterface, i -> AlertDialog.Builder(mActivity).setItems(shareOptions.toTypedArray()) { _, i ->
try { try {
when (i) { when (i) {
0 -> { 0 -> {
@@ -94,14 +96,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
} else { } else {
val iv = mActivity.layoutInflater.inflate(R.layout.item_qrcode, null) val iv = mActivity.layoutInflater.inflate(R.layout.item_qrcode, null)
iv.iv_qcode.setImageBitmap(AngConfigManager.share2QRCode(position)) iv.iv_qcode.setImageBitmap(AngConfigManager.share2QRCode(position))
AlertDialog.Builder(mActivity).setView(iv).show()
mActivity.alert {
customView {
linearLayout {
addView(iv)
}
}
}.show()
} }
} }
1 -> { 1 -> {
@@ -117,18 +112,20 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
} }.show()
} }
holder.layout_edit.setOnClickListener { holder.layout_edit.setOnClickListener {
val intent = Intent().putExtra("position", position)
.putExtra("isRunning", !changeable)
if (configType == EConfigType.VMESS) { if (configType == EConfigType.VMESS) {
mActivity.startActivity<ServerActivity>("position" to position, "isRunning" to !changeable) mActivity.startActivity(intent.setClass(mActivity, ServerActivity::class.java))
} else if (configType == EConfigType.CUSTOM) { } else if (configType == EConfigType.CUSTOM) {
mActivity.startActivity<Server2Activity>("position" to position, "isRunning" to !changeable) mActivity.startActivity(intent.setClass(mActivity, Server2Activity::class.java))
} else if (configType == EConfigType.SHADOWSOCKS) { } else if (configType == EConfigType.SHADOWSOCKS) {
mActivity.startActivity<Server3Activity>("position" to position, "isRunning" to !changeable) mActivity.startActivity(intent.setClass(mActivity, Server3Activity::class.java))
} else if (configType == EConfigType.SOCKS) { } else if (configType == EConfigType.SOCKS) {
mActivity.startActivity<Server4Activity>("position" to position, "isRunning" to !changeable) mActivity.startActivity(intent.setClass(mActivity, Server4Activity::class.java))
} }
} }
holder.layout_remove.setOnClickListener { holder.layout_remove.setOnClickListener {
@@ -183,10 +180,10 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
when (viewType) { when (viewType) {
VIEW_TYPE_ITEM -> VIEW_TYPE_ITEM ->
return MainViewHolder(parent.context.layoutInflater return MainViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_recycler_main, parent, false)) .inflate(R.layout.item_recycler_main, parent, false))
else -> else ->
return FooterViewHolder(parent.context.layoutInflater return FooterViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_recycler_footer, parent, false)) .inflate(R.layout.item_recycler_footer, parent, false))
} }
} }

View File

@@ -4,6 +4,8 @@ import android.animation.Animator
import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
@@ -12,7 +14,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.animation.AccelerateInterpolator import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import com.dinuscxj.itemdecoration.LinearDividerItemDecoration
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.extension.defaultDPreference import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.util.AppManagerUtil import com.v2ray.ang.util.AppManagerUtil
@@ -25,11 +26,12 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.AppInfo import com.v2ray.ang.dto.AppInfo
import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.v2RayApplication import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import org.jetbrains.anko.doAsync import kotlinx.coroutines.Dispatchers
import org.jetbrains.anko.toast import kotlinx.coroutines.GlobalScope
import org.jetbrains.anko.uiThread import kotlinx.coroutines.launch
import java.net.URL import java.net.URL
class PerAppProxyActivity : BaseActivity() { class PerAppProxyActivity : BaseActivity() {
@@ -47,8 +49,7 @@ class PerAppProxyActivity : BaseActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
val dividerItemDecoration = LinearDividerItemDecoration( val dividerItemDecoration = DividerItemDecoration(this, LinearLayoutManager.VERTICAL)
this, LinearDividerItemDecoration.LINEAR_DIVIDER_VERTICAL)
recycler_view.addItemDecoration(dividerItemDecoration) recycler_view.addItemDecoration(dividerItemDecoration)
val blacklist = defaultDPreference.getPrefStringSet(PREF_PER_APP_PROXY_SET, null) val blacklist = defaultDPreference.getPrefStringSet(PREF_PER_APP_PROXY_SET, null)
@@ -220,9 +221,14 @@ class PerAppProxyActivity : BaseActivity() {
private fun selectProxyApp() { private fun selectProxyApp() {
toast(R.string.msg_downloading_content) toast(R.string.msg_downloading_content)
val url = AppConfig.androidpackagenamelistUrl val url = AppConfig.androidpackagenamelistUrl
doAsync { GlobalScope.launch(Dispatchers.IO) {
val content = URL(url).readText() val content = try {
uiThread { URL(url).readText()
} catch (e: Exception) {
e.printStackTrace()
""
}
launch(Dispatchers.Main) {
Log.d("selectProxyApp", content) Log.d("selectProxyApp", content)
selectProxyApp(content) selectProxyApp(content)
toast(R.string.toast_success) toast(R.string.toast_success)
@@ -276,4 +282,4 @@ class PerAppProxyActivity : BaseActivity() {
} }
return true return true
} }
} }

View File

@@ -2,14 +2,12 @@ package com.v2ray.ang.ui
import android.graphics.Color import android.graphics.Color
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AppInfo import com.v2ray.ang.dto.AppInfo
import kotlinx.android.synthetic.main.item_recycler_bypass_list.view.* import kotlinx.android.synthetic.main.item_recycler_bypass_list.view.*
import org.jetbrains.anko.image
import org.jetbrains.anko.layoutInflater
import org.jetbrains.anko.textColor
import java.util.* import java.util.*
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) : class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) :
@@ -45,7 +43,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
// VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater // VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
// .inflate(R.layout.item_recycler_bypass_list, parent, false)) // .inflate(R.layout.item_recycler_bypass_list, parent, false))
else -> AppViewHolder(ctx.layoutInflater else -> AppViewHolder(LayoutInflater.from(ctx)
.inflate(R.layout.item_recycler_bypass_list, parent, false)) .inflate(R.layout.item_recycler_bypass_list, parent, false))
} }
@@ -68,17 +66,17 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
fun bind(appInfo: AppInfo) { fun bind(appInfo: AppInfo) {
this.appInfo = appInfo this.appInfo = appInfo
icon.image = appInfo.appIcon icon.setImageDrawable(appInfo.appIcon)
// name.text = appInfo.appName // name.text = appInfo.appName
checkBox.isChecked = inBlacklist checkBox.isChecked = inBlacklist
package_name.text = appInfo.packageName package_name.text = appInfo.packageName
if (appInfo.isSystemApp) { if (appInfo.isSystemApp) {
name.text = String.format("** %1s", appInfo.appName) name.text = String.format("** %1s", appInfo.appName)
name.textColor = Color.RED name.setTextColor(Color.RED)
} else { } else {
name.text = appInfo.appName name.text = appInfo.appName
name.textColor = Color.DKGRAY name.setTextColor(Color.DKGRAY)
} }
itemView.setOnClickListener(this) itemView.setOnClickListener(this)
@@ -94,4 +92,4 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
} }
} }
} }
} }

View File

@@ -1,30 +1,24 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.Manifest import android.Manifest
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.text.TextUtils
import android.util.Log
import android.view.* import android.view.*
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.extension.defaultDPreference import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.fragment_routing_settings.* import kotlinx.android.synthetic.main.fragment_routing_settings.*
import org.jetbrains.anko.toast
import android.view.MenuInflater import android.view.MenuInflater
import com.tbruyelle.rxpermissions.RxPermissions import com.tbruyelle.rxpermissions.RxPermissions
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import org.jetbrains.anko.doAsync import com.v2ray.ang.extension.toast
import org.jetbrains.anko.startActivityForResult import kotlinx.coroutines.Dispatchers
import org.jetbrains.anko.support.v4.startActivityForResult import kotlinx.coroutines.GlobalScope
import org.jetbrains.anko.support.v4.toast import kotlinx.coroutines.launch
import org.jetbrains.anko.uiThread
import java.net.URL import java.net.URL
class RoutingSettingsFragment : Fragment() { class RoutingSettingsFragment : Fragment() {
companion object { companion object {
private const val routing_arg = "routing_arg" private const val routing_arg = "routing_arg"
@@ -96,7 +90,7 @@ class RoutingSettingsFragment : Fragment() {
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.subscribe { .subscribe {
if (it) if (it)
startActivityForResult<ScannerActivity>(requestCode) startActivityForResult(Intent(activity, ScannerActivity::class.java), requestCode)
else else
activity?.toast(R.string.toast_permission_denied) activity?.toast(R.string.toast_permission_denied)
} }
@@ -118,12 +112,17 @@ class RoutingSettingsFragment : Fragment() {
} }
} }
toast(R.string.msg_downloading_content) activity?.toast(R.string.msg_downloading_content)
doAsync { GlobalScope.launch(Dispatchers.IO) {
val content = URL(url).readText() val content = try {
uiThread { URL(url).readText()
et_routing_content.text = Utils.getEditable(content!!) } catch (e: Exception) {
toast(R.string.toast_success) e.printStackTrace()
""
}
launch(Dispatchers.Main) {
et_routing_content.text = Utils.getEditable(content)
activity?.toast(R.string.toast_success)
} }
} }
return true return true

View File

@@ -6,7 +6,7 @@ import com.tbruyelle.rxpermissions.RxPermissions
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import android.os.Bundle import android.os.Bundle
import org.jetbrains.anko.* import com.v2ray.ang.extension.toast
class ScScannerActivity : BaseActivity() { class ScScannerActivity : BaseActivity() {
companion object { companion object {
@@ -24,7 +24,7 @@ class ScScannerActivity : BaseActivity() {
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.subscribe { .subscribe {
if (it) if (it)
startActivityForResult<ScannerActivity>(requestCode) startActivityForResult(Intent(this, ScannerActivity::class.java), requestCode)
else else
toast(R.string.toast_permission_denied) toast(R.string.toast_permission_denied)
} }
@@ -43,10 +43,10 @@ class ScScannerActivity : BaseActivity() {
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
} }
startActivity<MainActivity>() startActivity(Intent(this, MainActivity::class.java))
} }
} }
finish() finish()
} }
} }

View File

@@ -7,23 +7,13 @@ import com.google.zxing.Result
import me.dm7.barcodescanner.zxing.ZXingScannerView import me.dm7.barcodescanner.zxing.ZXingScannerView
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.icu.util.TimeUnit
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
import com.tbruyelle.rxpermissions.RxPermissions import com.tbruyelle.rxpermissions.RxPermissions
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.QRCodeDecoder import com.v2ray.ang.util.QRCodeDecoder
import org.jetbrains.anko.toast
import rx.Observable
import android.os.SystemClock
import kotlinx.android.synthetic.main.activity_main.*
import rx.Observer
import rx.android.schedulers.AndroidSchedulers
import javax.xml.datatype.DatatypeConstants.SECONDS
class ScannerActivity : BaseActivity(), ZXingScannerView.ResultHandler { class ScannerActivity : BaseActivity(), ZXingScannerView.ResultHandler {
companion object { companion object {

View File

@@ -1,6 +1,7 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.Editable import android.text.Editable
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
@@ -10,13 +11,12 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.extension.defaultDPreference import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_server2.* import kotlinx.android.synthetic.main.activity_server2.*
import org.jetbrains.anko.*
import java.lang.Exception import java.lang.Exception
class Server2Activity : BaseActivity() { class Server2Activity : BaseActivity() {
companion object { companion object {
private const val REQUEST_SCAN = 1 private const val REQUEST_SCAN = 1
@@ -112,17 +112,16 @@ class Server2Activity : BaseActivity() {
*/ */
fun deleteServer(): Boolean { fun deleteServer(): Boolean {
if (edit_index >= 0) { if (edit_index >= 0) {
alert(R.string.del_config_comfirm) { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
positiveButton(android.R.string.ok) { .setPositiveButton(android.R.string.ok) { _, _ ->
if (AngConfigManager.removeServer(edit_index) == 0) { if (AngConfigManager.removeServer(edit_index) == 0) {
toast(R.string.toast_success) toast(R.string.toast_success)
finish() finish()
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
}
} }
} .show()
show()
}
} else { } else {
} }
return true return true
@@ -158,4 +157,4 @@ class Server2Activity : BaseActivity() {
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View File

@@ -1,16 +1,16 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_server3.* import kotlinx.android.synthetic.main.activity_server3.*
import org.jetbrains.anko.*
class Server3Activity : BaseActivity() { class Server3Activity : BaseActivity() {
companion object { companion object {
@@ -126,17 +126,16 @@ class Server3Activity : BaseActivity() {
*/ */
fun deleteServer(): Boolean { fun deleteServer(): Boolean {
if (edit_index >= 0) { if (edit_index >= 0) {
alert(R.string.del_config_comfirm) { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
positiveButton(android.R.string.ok) { .setPositiveButton(android.R.string.ok) { _, _ ->
if (AngConfigManager.removeServer(edit_index) == 0) { if (AngConfigManager.removeServer(edit_index) == 0) {
toast(R.string.toast_success) toast(R.string.toast_success)
finish() finish()
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
}
} }
} .show()
show()
}
} else { } else {
} }
return true return true
@@ -172,4 +171,4 @@ class Server3Activity : BaseActivity() {
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View File

@@ -1,16 +1,16 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_server4.* import kotlinx.android.synthetic.main.activity_server4.*
import org.jetbrains.anko.*
class Server4Activity : BaseActivity() { class Server4Activity : BaseActivity() {
companion object { companion object {
@@ -110,17 +110,16 @@ class Server4Activity : BaseActivity() {
*/ */
fun deleteServer(): Boolean { fun deleteServer(): Boolean {
if (edit_index >= 0) { if (edit_index >= 0) {
alert(R.string.del_config_comfirm) { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
positiveButton(android.R.string.ok) { .setPositiveButton(android.R.string.ok) { _, _ ->
if (AngConfigManager.removeServer(edit_index) == 0) { if (AngConfigManager.removeServer(edit_index) == 0) {
toast(R.string.toast_success) toast(R.string.toast_success)
finish() finish()
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
}
} }
} .show()
show()
}
} else { } else {
} }
return true return true
@@ -156,4 +155,4 @@ class Server4Activity : BaseActivity() {
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View File

@@ -1,16 +1,16 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_server.* import kotlinx.android.synthetic.main.activity_server.*
import org.jetbrains.anko.*
class ServerActivity : BaseActivity() { class ServerActivity : BaseActivity() {
companion object { companion object {
@@ -169,17 +169,16 @@ class ServerActivity : BaseActivity() {
*/ */
fun deleteServer(): Boolean { fun deleteServer(): Boolean {
if (edit_index >= 0) { if (edit_index >= 0) {
alert(R.string.del_config_comfirm) { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
positiveButton(android.R.string.ok) { .setPositiveButton(android.R.string.ok) { _, _ ->
if (AngConfigManager.removeServer(edit_index) == 0) { if (AngConfigManager.removeServer(edit_index) == 0) {
toast(R.string.toast_success) toast(R.string.toast_success)
finish() finish()
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
}
} }
} .show()
show()
}
} else { } else {
} }
return true return true
@@ -215,4 +214,4 @@ class ServerActivity : BaseActivity() {
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View File

@@ -1,13 +1,13 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v7.preference.* import android.support.v7.preference.*
import android.view.View
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import org.jetbrains.anko.defaultSharedPreferences
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.toast
class SettingsActivity : BaseActivity() { class SettingsActivity : BaseActivity() {
companion object { companion object {
@@ -70,7 +70,7 @@ class SettingsActivity : BaseActivity() {
// val feedback: Preference by lazy { findPreference(PREF_FEEDBACK) } // val feedback: Preference by lazy { findPreference(PREF_FEEDBACK) }
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) } // val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
private val mode: Preference by lazy { findPreference(AppConfig.PREF_MODE) } private val mode by lazy { findPreference(AppConfig.PREF_MODE) as ListPreference }
private fun restartProxy() { private fun restartProxy() {
Utils.stopVService(requireContext()) Utils.stopVService(requireContext())
@@ -88,7 +88,7 @@ class SettingsActivity : BaseActivity() {
if (isRunning()) { if (isRunning()) {
Utils.stopVService(requireContext()) Utils.stopVService(requireContext())
} }
activity?.startActivity<PerAppProxyActivity>() startActivity(Intent(activity, PerAppProxyActivity::class.java))
perAppProxy.isChecked = true perAppProxy.isChecked = true
true true
} }
@@ -125,7 +125,7 @@ class SettingsActivity : BaseActivity() {
routingCustom.setOnPreferenceClickListener { routingCustom.setOnPreferenceClickListener {
if (isRunning()) if (isRunning())
Utils.stopVService(requireContext()) Utils.stopVService(requireContext())
activity?.startActivity<RoutingSettingsActivity>() startActivity(Intent(activity, RoutingSettingsActivity::class.java))
false false
} }
@@ -164,6 +164,7 @@ class SettingsActivity : BaseActivity() {
updatePerAppProxy(newValue.toString()) updatePerAppProxy(newValue.toString())
true true
} }
mode.dialogLayoutResource = R.layout.preference_with_help_link
// donate.onClick { // donate.onClick {
// startActivity<InappBuyActivity>() // startActivity<InappBuyActivity>()
@@ -204,9 +205,10 @@ class SettingsActivity : BaseActivity() {
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
updatePerAppProxy(activity?.defaultSharedPreferences?.getString(AppConfig.PREF_MODE, "VPN")) val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
remoteDns.summary = activity?.defaultSharedPreferences?.getString(PREF_REMOTE_DNS, "") updatePerAppProxy(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN"))
domesticDns.summary = activity?.defaultSharedPreferences?.getString(PREF_DOMESTIC_DNS, "") remoteDns.summary = defaultSharedPreferences.getString(PREF_REMOTE_DNS, "")
domesticDns.summary = defaultSharedPreferences.getString(PREF_DOMESTIC_DNS, "")
if (remoteDns.summary == "") { if (remoteDns.summary == "") {
remoteDns.summary = AppConfig.DNS_AGENT remoteDns.summary = AppConfig.DNS_AGENT
@@ -221,14 +223,18 @@ class SettingsActivity : BaseActivity() {
} }
private fun updatePerAppProxy(mode: String?) { private fun updatePerAppProxy(mode: String?) {
val preference = activity?.defaultSharedPreferences ?: return
if (mode == "VPN") { if (mode == "VPN") {
perAppProxy.isEnabled = true perAppProxy.isEnabled = true
perAppProxy.isChecked = preference.getBoolean(PREF_PER_APP_PROXY, false) perAppProxy.isChecked = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(PREF_PER_APP_PROXY, false)
} else { } else {
perAppProxy.isEnabled = false perAppProxy.isEnabled = false
perAppProxy.isChecked = false perAppProxy.isChecked = false
} }
} }
} }
fun onModeHelpClicked(view: View) {
Utils.openUri(this, AppConfig.v2rayNGWikiMode)
}
} }

View File

@@ -1,16 +1,16 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_sub_edit.* import kotlinx.android.synthetic.main.activity_sub_edit.*
import org.jetbrains.anko.*
class SubEditActivity : BaseActivity() { class SubEditActivity : BaseActivity() {
@@ -95,17 +95,16 @@ class SubEditActivity : BaseActivity() {
*/ */
fun deleteServer(): Boolean { fun deleteServer(): Boolean {
if (edit_index >= 0) { if (edit_index >= 0) {
alert(R.string.del_config_comfirm) { AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
positiveButton(android.R.string.ok) { .setPositiveButton(android.R.string.ok) { _, _ ->
if (AngConfigManager.removeSubItem(edit_index) == 0) { if (AngConfigManager.removeSubItem(edit_index) == 0) {
toast(R.string.toast_success) toast(R.string.toast_success)
finish() finish()
} else { } else {
toast(R.string.toast_failure) toast(R.string.toast_failure)
}
} }
} .show()
show()
}
} else { } else {
} }
return true return true
@@ -135,4 +134,4 @@ class SubEditActivity : BaseActivity() {
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View File

@@ -1,12 +1,12 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.content.Intent
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import com.v2ray.ang.R import com.v2ray.ang.R
import kotlinx.android.synthetic.main.activity_sub_setting.* import kotlinx.android.synthetic.main.activity_sub_setting.*
import android.os.Bundle import android.os.Bundle
import org.jetbrains.anko.startActivity
class SubSettingActivity : BaseActivity() { class SubSettingActivity : BaseActivity() {
@@ -40,7 +40,9 @@ class SubSettingActivity : BaseActivity() {
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.add_config -> { R.id.add_config -> {
startActivity<SubEditActivity>("position" to -1) startActivity(Intent(this, SubEditActivity::class.java)
.putExtra("position", -1)
)
adapter.updateConfigList() adapter.updateConfigList()
true true
} }
@@ -48,4 +50,4 @@ class SubSettingActivity : BaseActivity() {
} }
} }

View File

@@ -1,14 +1,15 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager
import kotlinx.android.synthetic.main.item_recycler_sub_setting.view.* import kotlinx.android.synthetic.main.item_recycler_sub_setting.view.*
import org.jetbrains.anko.*
class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView.Adapter<SubSettingRecyclerAdapter.BaseViewHolder>() { class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView.Adapter<SubSettingRecyclerAdapter.BaseViewHolder>() {
@@ -28,17 +29,19 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
holder.name.text = remarks holder.name.text = remarks
holder.url.text = url holder.url.text = url
holder.itemView.backgroundColor = Color.TRANSPARENT holder.itemView.setBackgroundColor(Color.TRANSPARENT)
holder.layout_edit.setOnClickListener { holder.layout_edit.setOnClickListener {
mActivity.startActivity<SubEditActivity>("position" to position) mActivity.startActivity(Intent(mActivity, SubEditActivity::class.java)
.putExtra("position", position)
)
} }
} else { } else {
} }
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return MainViewHolder(parent.context.layoutInflater return MainViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_recycler_sub_setting, parent, false)) .inflate(R.layout.item_recycler_sub_setting, parent, false))
} }

View File

@@ -24,18 +24,17 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.responseLength import com.v2ray.ang.extension.responseLength
import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.v2RayApplication import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.service.V2RayServiceManager import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.ui.SettingsActivity import com.v2ray.ang.ui.SettingsActivity
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import me.dozen.dpreference.DPreference import me.dozen.dpreference.DPreference
import org.jetbrains.anko.toast
import java.io.IOException import java.io.IOException
import java.net.* import java.net.*
import libv2ray.Libv2ray import libv2ray.Libv2ray
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
object Utils { object Utils {
val tcpTestingSockets = ArrayList<Socket?>() val tcpTestingSockets = ArrayList<Socket?>()

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="onModeHelpClicked"
android:text="@string/title_mode_help"
android:textAlignment="textStart"
android:textStyle="italic" />

View File

@@ -17,17 +17,6 @@
<copyright>Copyright(C) 2008-2011 The Android Open Source Project</copyright> <copyright>Copyright(C) 2008-2011 The Android Open Source Project</copyright>
<license>Apache Software License 2.0</license> <license>Apache Software License 2.0</license>
</notice> </notice>
<notice>
<name>Apache Commons Validator</name>
<url>http://commons.apache.org/proper/commons-collections/</url>
<copyright>Copyright(C) 2001-2014 The Apache Software Foundation</copyright>
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>anko</name>
<url>https://github.com/Kotlin/anko</url>
<license>Apache Software License 2.0</license>
</notice>
<notice> <notice>
<name>Google Gson</name> <name>Google Gson</name>
<url>https://github.com/google/gson</url> <url>https://github.com/google/gson</url>
@@ -52,33 +41,9 @@
<copyright>Copyright 2015 Square, Inc.</copyright> <copyright>Copyright 2015 Square, Inc.</copyright>
<license>Apache Software License 2.0</license> <license>Apache Software License 2.0</license>
</notice> </notice>
<notice>
<name>ReactiveNetwork</name>
<url>https://github.com/pwittchen/ReactiveNetwork</url>
<copyright>Copyright 2016 Piotr Wittchen</copyright>
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>RecyclerItemDecoration</name>
<url>https://github.com/dinuscxj/RecyclerItemDecoration</url>
<copyright>Copyright 2015-2019 dinus</copyright>
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>RxKotlin</name>
<url>https://github.com/ReactiveX/RxKotlin</url>
<copyright>Copyright 2012 Netflix, Inc.</copyright>
<license>Apache Software License 2.0</license>
</notice>
<notice> <notice>
<name>RxPermissions</name> <name>RxPermissions</name>
<url>https://github.com/tbruyelle/RxPermissions</url> <url>https://github.com/tbruyelle/RxPermissions</url>
<license>Apache Software License 2.0</license> <license>Apache Software License 2.0</license>
</notice> </notice>
<notice> </notices>
<name>RecyclerItemDecoration</name>
<url>https://github.com/dinuscxj/RecyclerItemDecoration</url>
<copyright>Copyright 2015-2019 dinus</copyright>
<license>Apache Software License 2.0</license>
</notice>
</notices>

View File

@@ -123,6 +123,7 @@
<string name="summary_pref_promotion">一些推广,点击查看详情(捐赠可去除)</string> <string name="summary_pref_promotion">一些推广,点击查看详情(捐赠可去除)</string>
<string name="title_mode">模式</string> <string name="title_mode">模式</string>
<string name="title_mode_help">点此查看更多帮助</string>
<string name="donate_error_setup">初始化错误:</string> <string name="donate_error_setup">初始化错误:</string>
<string name="donate_error_inventory">无法查询到项目</string> <string name="donate_error_inventory">无法查询到项目</string>

View File

@@ -125,6 +125,7 @@
<string name="summary_pref_promotion">一些推廣,點擊查看詳情(捐款可去除)</string> <string name="summary_pref_promotion">一些推廣,點擊查看詳情(捐款可去除)</string>
<string name="title_mode">模式</string> <string name="title_mode">模式</string>
<string name="title_mode_help">點此查看更多幫助</string>
<string name="donate_error_setup">錯誤設定:</string> <string name="donate_error_setup">錯誤設定:</string>
<string name="donate_error_inventory">Error querying inventory</string> <string name="donate_error_inventory">Error querying inventory</string>

View File

@@ -125,6 +125,7 @@
<string name="summary_pref_promotion">Promotion,click for details(Donation can be removed)</string> <string name="summary_pref_promotion">Promotion,click for details(Donation can be removed)</string>
<string name="title_mode">Mode</string> <string name="title_mode">Mode</string>
<string name="title_mode_help">Click me for more help</string>
<string name="donate_error_setup">Error Setup:</string> <string name="donate_error_setup">Error Setup:</string>
<string name="donate_error_inventory">Error querying inventory</string> <string name="donate_error_inventory">Error querying inventory</string>

View File

@@ -7,7 +7,7 @@ buildscript {
maven { url 'https://maven.google.com' } maven { url 'https://maven.google.com' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.3' classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@@ -19,7 +19,7 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13'
implementation "com.android.support:support-annotations:$supportLibVersion" implementation "com.android.support:support-annotations:$supportLibVersion"
implementation 'com.google.code.gson:gson:2.7' implementation 'com.google.code.gson:gson:2.8.6'
} }

View File

@@ -13,8 +13,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Fri Jun 02 14:08:42 CST 2017 #Fri Jun 02 14:08:42 CST 2017
ankoVersion=0.10.8 kotlinVersion=1.4.0
kotlinVersion=1.3.40
supportLibVersion=28.0.0 supportLibVersion=28.0.0
buildToolsVer=29.0.3 buildToolsVer=29.0.3
compileSdkVer=29 compileSdkVer=29