Compare commits

..

24 Commits

Author SHA1 Message Date
2dust f25aaf43d7 Update V2RayVpnService.kt 2019-09-24 13:12:39 +08:00
2dust 3b365533fc Create libv2ray.aar 2019-09-02 08:48:17 +08:00
2dust a982327030 Update .gitignore 2019-09-02 08:48:11 +08:00
2dust 6ce12b2ea5 Update AndroidManifest.xml 2019-09-02 08:47:01 +08:00
2dust d7f3ed5182 Update BaseDrawerActivity.kt 2019-09-02 08:46:58 +08:00
2dust f519103b3e Update MainActivity.kt 2019-09-02 08:46:54 +08:00
2dust d7c40ee883 Update SettingsActivity.kt 2019-09-02 08:46:50 +08:00
2dust 809d50689b Update gradle.properties 2019-09-02 08:46:36 +08:00
2dust 042def7e83 Update V2RayVpnService.kt 2019-08-27 15:14:22 +08:00
2dust 8bb0d6b175 Create Readme.md 2019-08-22 11:26:07 +08:00
2dust 3ae76fab72 add lib 2019-08-18 18:15:37 +08:00
2dust 46a63e8704 Create readme.txt 2019-08-18 18:14:52 +08:00
2dust 12f8b1584c Create issue_template.md 2019-08-14 07:55:48 +08:00
2dust 2b571e2a94 Merge pull request #44 from cutelua/dev
improved notification
2019-07-30 14:47:38 +08:00
cutelua ba30697309 no need for USER_PRESENT 2019-07-11 09:19:30 +08:00
2dust 879e25bb82 sdk28 2019-07-10 14:24:09 +08:00
cutelua 17c858d24c only show speed if core isrunning 2019-07-09 15:58:36 +08:00
cutelua 71a6531835 stop speed query when screen off; resume when screen on 2019-07-09 14:32:47 +08:00
cutelua 5d760382d7 pass callback as V2RayPoint arg; stop on LowMemory 2019-07-09 13:06:28 +08:00
cutelua 4dda36673a allow go to shutdown VpnService 2019-07-09 11:43:31 +08:00
cutelua 5aca55cb8f only use title to show speed 2019-07-07 16:42:22 +08:00
cutelua 82f14f0d07 show total speed as notification title 2019-07-07 16:42:22 +08:00
2dust c0e968ac34 up ver 2019-07-01 13:22:48 +08:00
2dust 29d3fb710b ii 2019-05-15 10:17:59 +08:00
41 changed files with 234 additions and 626 deletions
+5 -10
View File
@@ -24,7 +24,6 @@ type resolved struct {
domain string
IPs []net.IP
Port int
lastResolved time.Time
ipIdx uint8
ipLock sync.Mutex
lastSwitched time.Time
@@ -98,7 +97,7 @@ func (d *ProtectedDialer) PrepareResolveChan() {
d.resolveChan = make(chan struct{})
}
func (d *ProtectedDialer) ResolveChan() chan struct{} {
func (d *ProtectedDialer) ResolveChan() <-chan struct{} {
return d.resolveChan
}
@@ -138,10 +137,9 @@ func (d *ProtectedDialer) lookupAddr(addr string) (*resolved, error) {
}
rs := &resolved{
domain: host,
IPs: IPs,
Port: portnum,
lastResolved: time.Now(),
domain: host,
IPs: IPs,
Port: portnum,
}
return rs, nil
@@ -152,6 +150,7 @@ func (d *ProtectedDialer) PrepareDomain(domainName string, closeCh <-chan struct
log.Printf("Preparing Domain: %s", domainName)
d.currentServer = domainName
defer close(d.resolveChan)
maxRetry := 10
for {
if maxRetry == 0 {
@@ -213,10 +212,6 @@ func (d *ProtectedDialer) Dial(ctx context.Context,
}
}
if time.Now().Sub(d.vServer.lastResolved) > time.Minute * 30 {
d.PrepareDomain(Address, nil)
}
fd, err := d.getFd(dest.Network)
if err != nil {
return nil, err
+2 -5
View File
@@ -71,10 +71,7 @@ func (v *V2RayPoint) RunLoop() (err error) {
if !v.status.IsRunning {
v.closeChan = make(chan struct{})
v.dialer.PrepareResolveChan()
go func() {
v.dialer.PrepareDomain(v.DomainName, v.closeChan)
close(v.dialer.ResolveChan())
}()
go v.dialer.PrepareDomain(v.DomainName, v.closeChan)
go func() {
select {
// wait until resolved
@@ -119,7 +116,7 @@ func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
if v.statsManager == nil {
return 0
}
counter := v.statsManager.GetCounter(fmt.Sprintf("outbound>>>%s>>>traffic>>>%s", tag, direct))
counter := v.statsManager.GetCounter(fmt.Sprintf("inbound>>>%s>>>traffic>>>%s", tag, direct))
if counter == nil {
return 0
}
+1
View File
@@ -3,3 +3,4 @@
<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" />
</a>
-5
View File
@@ -84,10 +84,6 @@ dependencies {
implementation project(':dpreference')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.2" // 1.3.x has compile error:
// More than one file was found with OS independent path 'META-INF/proguard/coroutines.pro'
// Android support library
implementation "com.android.support:support-v4:$supportLibVersion"
implementation "com.android.support:appcompat-v7:$supportLibVersion"
@@ -95,7 +91,6 @@ dependencies {
implementation "com.android.support:cardview-v7:$supportLibVersion"
implementation "com.android.support:preference-v7:$supportLibVersion"
implementation "com.android.support:recyclerview-v7:$supportLibVersion"
implementation "com.android.support:multidex:1.0.3"
// DSL
implementation "org.jetbrains.anko:anko-sdk15:$ankoVersion"
implementation "org.jetbrains.anko:anko-support-v4:$ankoVersion"
+10 -20
View File
@@ -2,16 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.v2ray.ang">
<supports-screens
android:anyDensity="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
@@ -93,16 +83,16 @@
android:value="true" />
</service>
<receiver android:name=".receiver.WidgetProvider"
android:process=":RunSoLibV2RayDaemon">
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_provider" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.v2ray.ang.action.widget.click" />
</intent-filter>
</receiver>
<!--<receiver android:name=".receiver.WidgetProvider">-->
<!--<meta-data-->
<!--android:name="android.appwidget.provider"-->
<!--android:resource="@xml/app_widget_provider" />-->
<!--<intent-filter>-->
<!--<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />-->
<!--<action android:name="com.v2ray.ang.action.widget.click" />-->
<!--</intent-filter>-->
<!--</receiver>-->
<service
android:name=".service.QSTileService"
@@ -13,8 +13,8 @@
}
},
"system": {
"statsOutboundUplink": true,
"statsOutboundDownlink": true
"statsInboundUplink": true,
"statsInboundDownlink": true
}
},
"inbounds": [{
@@ -43,8 +43,6 @@ public interface ItemTouchHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
void onItemMoveCompleted();
/**
* Called when an item has been dismissed by a swipe.<br/>
* <br/>
@@ -112,8 +112,6 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
mAdapter.onItemMoveCompleted();
viewHolder.itemView.setAlpha(ALPHA_FULL);
if (viewHolder instanceof ItemTouchHelperViewHolder) {
@@ -1,17 +1,16 @@
package com.v2ray.ang
import android.app.Application
//import com.squareup.leakcanary.LeakCanary
import android.support.multidex.MultiDexApplication
import com.v2ray.ang.util.AngConfigManager
import me.dozen.dpreference.DPreference
import org.jetbrains.anko.defaultSharedPreferences
class AngApplication : MultiDexApplication() {
class AngApplication : Application() {
companion object {
const val PREF_LAST_VERSION = "pref_last_version"
}
var curIndex = -1 //Current proxy that is opened. (Used to implement restart feature)
var firstRun = false
private set
@@ -64,21 +64,22 @@ data class V2rayConfig(
data class StreamSettingsBean(var network: String,
var security: String,
var tcpSettings: TcpSettingsBean?,
var kcpSettings: KcpSettingsBean?,
var wsSettings: WsSettingsBean?,
var httpSettings: HttpSettingsBean?,
var tlsSettings: TlsSettingsBean?,
var quicSettings: QuicSettingBean?
var tcpSettings: TcpsettingsBean?,
var kcpsettings: KcpsettingsBean?,
var wssettings: WssettingsBean?,
var httpsettings: HttpsettingsBean?,
var tlssettings: TlssettingsBean?,
var quicsettings: QuicsettingBean?
) {
data class TcpSettingsBean(var header: HeaderBean = HeaderBean()) {
data class TcpsettingsBean(var connectionReuse: Boolean = true,
var header: HeaderBean = HeaderBean()) {
data class HeaderBean(var type: String = "none",
var request: Any? = null,
var response: Any? = null)
}
data class KcpSettingsBean(var mtu: Int = 1350,
data class KcpsettingsBean(var mtu: Int = 1350,
var tti: Int = 20,
var uplinkCapacity: Int = 12,
var downlinkCapacity: Int = 100,
@@ -89,20 +90,20 @@ data class V2rayConfig(
data class HeaderBean(var type: String = "none")
}
data class WsSettingsBean(var path: String = "",
data class WssettingsBean(var connectionReuse: Boolean = true,
var path: String = "",
var headers: HeadersBean = HeadersBean()) {
data class HeadersBean(var Host: String = "")
}
data class HttpSettingsBean(var host: List<String> = ArrayList(),
var path: String = "")
data class HttpsettingsBean(var host: List<String> = ArrayList<String>(), var path: String = "")
data class TlsSettingsBean(var allowInsecure: Boolean = true,
data class TlssettingsBean(var allowInsecure: Boolean = true,
var serverName: String = "")
data class QuicSettingBean(var security: String = "none",
var key: String = "",
var header: HeaderBean = HeaderBean()) {
data class QuicsettingBean(var security: String = "none",
var key: String = "",
var header: HeaderBean = HeaderBean()) {
data class HeaderBean(var type: String = "none")
}
}
@@ -27,37 +27,34 @@ const val divisor = 1024F
fun Long.toSpeedString() = toTrafficString() + "/s"
fun Long.toTrafficString(): String {
if (this == 0L)
return "\t\t\t0\t B"
if (this < threshold)
return "${this.toFloat().toShortString()}\t B"
return "$this B"
val kib = this / divisor
if (kib < threshold)
return "${kib.toShortString()}\t KB"
return "${kib.toShortString()} KB"
val mib = kib / divisor
if (mib < threshold)
return "${mib.toShortString()}\t MB"
return "${mib.toShortString()} MB"
val gib = mib / divisor
if (gib < threshold)
return "${gib.toShortString()}\t GB"
return "${gib.toShortString()} GB"
val tib = gib / divisor
if (tib < threshold)
return "${tib.toShortString()}\t TB"
return "${tib.toShortString()} TB"
val pib = tib / divisor
if (pib < threshold)
return "${pib.toShortString()}\t PB"
return "${pib.toShortString()} PB"
return ""
}
private fun Float.toShortString(): String {
val s = "%.2f".format(this)
val s = toString()
if (s.length <= 4)
return s
return s.substring(0, 4).removeSuffix(".")
@@ -3,13 +3,14 @@ package com.v2ray.ang.receiver
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.RemoteViews
import com.v2ray.ang.R
import com.v2ray.ang.AppConfig
import com.v2ray.ang.util.Utils
import org.jetbrains.anko.toast
class WidgetProvider : AppWidgetProvider() {
/**
@@ -18,21 +19,10 @@ class WidgetProvider : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
val isRunning = Utils.isServiceRun(context, "com.v2ray.ang.service.V2RayVpnService")
updateWidgetBackground(context, appWidgetManager, appWidgetIds, isRunning)
}
private fun updateWidgetBackground(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, isRunning: Boolean) {
val remoteViews = RemoteViews(context.packageName, R.layout.widget_switch)
val intent = Intent(context, WidgetProvider::class.java)
intent.setAction(AppConfig.BROADCAST_ACTION_WIDGET_CLICK)
val intent = Intent(AppConfig.BROADCAST_ACTION_WIDGET_CLICK)
val pendingIntent = PendingIntent.getBroadcast(context, R.id.layout_switch, intent, PendingIntent.FLAG_UPDATE_CURRENT)
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
if (isRunning) {
remoteViews.setInt(R.id.layout_switch, "setBackgroundResource", R.drawable.ic_rounded_corner_theme);
} else {
remoteViews.setInt(R.id.layout_switch, "setBackgroundResource", R.drawable.ic_rounded_corner_grey);
}
for (appWidgetId in appWidgetIds) {
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
@@ -54,9 +44,7 @@ class WidgetProvider : AppWidgetProvider() {
// context.toast(R.string.toast_services_start)
Utils.startVService(context)
}
val manager = AppWidgetManager.getInstance(context)
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
!isRunning);
}
}
}
@@ -28,11 +28,15 @@ import libv2ray.Libv2ray
import libv2ray.V2RayVPNServiceSupportsSet
import rx.Observable
import rx.Subscription
import java.net.InetAddress
import java.io.IOException
import java.io.File
import java.io.FileDescriptor
import java.io.FileInputStream
import java.lang.ref.SoftReference
import android.os.Build
import android.annotation.TargetApi
import android.util.Log
import go.Seq
import org.jetbrains.anko.doAsync
class V2RayVpnService : VpnService() {
@@ -40,7 +44,6 @@ class V2RayVpnService : VpnService() {
const val NOTIFICATION_ID = 1
const val NOTIFICATION_PENDING_INTENT_CONTENT = 0
const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
const val NOTIFICATION_ICON_THRESHOLD = 3000
fun startV2Ray(context: Context) {
val intent = Intent(context.applicationContext, V2RayVpnService::class.java)
@@ -53,7 +56,6 @@ class V2RayVpnService : VpnService() {
}
private val v2rayPoint = Libv2ray.newV2RayPoint(V2RayCallback())
private var lastQueryTime = 0L
private lateinit var configContent: String
private lateinit var mInterface: ParcelFileDescriptor
val fd: Int get() = mInterface.fd
@@ -62,6 +64,7 @@ class V2RayVpnService : VpnService() {
private var mNotificationManager: NotificationManager? = null
/**
* Unfortunately registerDefaultNetworkCallback is going to return our VPN interface: https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
*
@@ -71,28 +74,25 @@ class V2RayVpnService : VpnService() {
*
* 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) {
NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build()
}
@TargetApi(28)
private val defaultNetworkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build()
private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
private val defaultNetworkCallback by lazy @RequiresApi(Build.VERSION_CODES.P) {
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
setUnderlyingNetworks(arrayOf(network))
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities?) {
// it's a good idea to refresh capabilities
setUnderlyingNetworks(arrayOf(network))
}
override fun onLost(network: Network) {
setUnderlyingNetworks(null)
}
@TargetApi(28)
private val defaultNetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
setUnderlyingNetworks(arrayOf(network))
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities?) {
// it's a good idea to refresh capabilities
setUnderlyingNetworks(arrayOf(network))
}
override fun onLost(network: Network) {
setUnderlyingNetworks(null)
}
}
private var listeningForDefaultNetwork = false
@@ -131,7 +131,6 @@ class V2RayVpnService : VpnService() {
// Configure a builder while parsing the parameters.
val builder = Builder()
val enableLocalDns = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
val routingMode = defaultDPreference.getPrefString(SettingsActivity.PREF_ROUTING_MODE, "0")
parameters.split(" ")
.map { it.split(",") }
@@ -140,20 +139,7 @@ class V2RayVpnService : VpnService() {
'm' -> builder.setMtu(java.lang.Short.parseShort(it[1]).toInt())
's' -> builder.addSearchDomain(it[1])
'a' -> builder.addAddress(it[1], Integer.parseInt(it[2]))
'r' -> {
if (routingMode == "1" || routingMode == "3") {
if (it[1] == "::") { //not very elegant, should move Vpn setting in Kotlin, simplify go code
builder.addRoute("2000::", 3)
} else {
resources.getStringArray(R.array.bypass_private_ip_address).forEach {
val addr = it.split('/')
builder.addRoute(addr[0], addr[1].toInt())
}
}
} else {
builder.addRoute(it[1], Integer.parseInt(it[2]))
}
}
'r' -> builder.addRoute(it[1], Integer.parseInt(it[2]))
'd' -> builder.addDnsServer(it[1])
}
}
@@ -190,7 +176,7 @@ class V2RayVpnService : VpnService() {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
listeningForDefaultNetwork = true
}
@@ -198,7 +184,6 @@ class V2RayVpnService : VpnService() {
// Create a new interface using the builder and save the parameters.
mInterface = builder.establish()
sendFd()
lastQueryTime = System.currentTimeMillis()
startSpeedNotification()
}
@@ -275,7 +260,7 @@ class V2RayVpnService : VpnService() {
// val emptyInfo = VpnNetworkInfo()
// val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo)
// saveVpnNetworkInfo(configName, info)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
if (Build.VERSION.SDK_INT >= 28) {
if (listeningForDefaultNetwork) {
connectivity.unregisterNetworkCallback(defaultNetworkCallback)
listeningForDefaultNetwork = false
@@ -297,19 +282,12 @@ class V2RayVpnService : VpnService() {
unregisterReceiver(mMsgReceive)
} catch (e: Exception) {
}
//stopSelf has to be called ahead of mInterface.close(). otherwise v2ray core cannot be stooped
//It's strage but true.
//This can be verified by putting stopself() behind and call stopLoop and startLoop
//in a row for several times. You will find that later created v2ray core report port in use
//which means the first v2ray core somehow failed to stop and release the port.
stopSelf()
try {
mInterface.close()
} catch (ignored: Exception) {
}
stopSelf()
}
}
@@ -374,16 +352,9 @@ class V2RayVpnService : VpnService() {
mSubscription = null
}
private fun updateNotification(contentText: String, proxyTraffic: Long, directTraffic: Long) {
private fun updateNotification(contentText: String) {
if (mBuilder != null) {
if (proxyTraffic < NOTIFICATION_ICON_THRESHOLD && directTraffic < NOTIFICATION_ICON_THRESHOLD) {
mBuilder?.setSmallIcon(R.drawable.ic_v)
} else if (proxyTraffic > directTraffic) {
mBuilder?.setSmallIcon(R.drawable.ic_stat_proxy)
} else {
mBuilder?.setSmallIcon(R.drawable.ic_stat_direct)
}
mBuilder?.setStyle(NotificationCompat.BigTextStyle().bigText(contentText))
mBuilder?.setContentTitle(contentText)
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
}
}
@@ -404,22 +375,13 @@ class V2RayVpnService : VpnService() {
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 uplink = v2rayPoint.queryStats("socks", "uplink")
val downlink = v2rayPoint.queryStats("socks", "downlink")
val zero_speed = (uplink == 0L && downlink == 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)
updateNotification("${cf_name}${(uplink / 3).toSpeedString()}${(downlink / 3).toSpeedString()}")
}
last_zero_speed = zero_speed
lastQueryTime = queryTime
}
}
}
@@ -431,7 +393,7 @@ class V2RayVpnService : VpnService() {
mSubscription = null
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
updateNotification(cf_name, 0, 0)
updateNotification(cf_name)
}
}
@@ -55,6 +55,7 @@ abstract class BaseDrawerActivity : BaseActivity() {
this@BaseDrawerActivity, R.anim.fade_in, R.anim.fade_out).toBundle()
var activityClass: Class<*>? = null
when (mItemToOpenWhenDrawerCloses) {
R.id.server_profile -> activityClass = MainActivity::class.java
R.id.sub_setting -> activityClass = SubSettingActivity::class.java
R.id.settings -> activityClass = SettingsActivity::class.java
R.id.logcat -> {
@@ -194,7 +195,9 @@ abstract class BaseDrawerActivity : BaseActivity() {
true
}
if (SubSettingActivity::class.java.isAssignableFrom(javaClass)) {
if (MainActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.server_profile)
} else if (SubSettingActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.sub_setting)
} else if (SettingsActivity::class.java.isAssignableFrom(javaClass)) {
navigationView.setCheckedItem(R.id.settings)
@@ -1,8 +1,6 @@
package com.v2ray.ang.ui
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.method.ScrollingMovementMethod
import android.view.Menu
import android.view.MenuItem
@@ -26,22 +24,15 @@ class LogcatActivity : BaseActivity() {
title = getString(R.string.title_logcat)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
logcat(false)
logcat()
}
private fun logcat(shouldFlushLog: Boolean) {
private fun logcat() {
try {
pb_waiting.visibility = View.VISIBLE
doAsync {
if (shouldFlushLog) {
val lst = LinkedHashSet<String>()
lst.add("logcat")
lst.add("-c")
val process = Runtime.getRuntime().exec(lst.toTypedArray())
process.waitFor()
}
val lst = LinkedHashSet<String>()
lst.add("logcat")
lst.add("-d")
@@ -58,11 +49,9 @@ class LogcatActivity : BaseActivity() {
tv_logcat.text = allText
tv_logcat.movementMethod = ScrollingMovementMethod()
pb_waiting.visibility = View.GONE
Handler(Looper.getMainLooper()).post { sv_logcat.fullScroll(View.FOCUS_DOWN) }
}
}
} catch (e: IOException) {
e.printStackTrace()
}
}
@@ -77,10 +66,7 @@ class LogcatActivity : BaseActivity() {
toast(R.string.toast_success)
true
}
R.id.delete -> {
logcat(true)
true
}
else -> super.onOptionsItemSelected(item)
}
}
@@ -33,7 +33,6 @@ import rx.android.schedulers.AndroidSchedulers
import java.util.concurrent.TimeUnit
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.util.AngConfigManager.configs
import kotlinx.coroutines.*
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
companion object {
@@ -59,7 +58,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
private val adapter by lazy { MainRecyclerAdapter(this) }
private var mItemTouchHelper: ItemTouchHelper? = null
private val testingJobs = ArrayList<Job>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -234,7 +232,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
R.id.export_all -> {
if (AngConfigManager.shareAll2Clipboard() == 0) {
//remove toast, otherwise it will block previous warning message
toast(R.string.toast_success)
} else {
toast(R.string.toast_failure)
}
@@ -242,25 +240,18 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
R.id.ping_all -> {
testingJobs.forEach {
it.cancel()
}
testingJobs.clear()
Utils.closeAllTcpSockets()
for (k in 0 until configs.vmess.count()) {
configs.vmess[k].testResult = ""
adapter.updateConfigList()
}
for (k in 0 until configs.vmess.count()) {
if (configs.vmess[k].configType != AppConfig.EConfigType.Custom) {
testingJobs.add(GlobalScope.launch(Dispatchers.IO) {
doAsync {
configs.vmess[k].testResult = Utils.tcping(configs.vmess[k].address, configs.vmess[k].port)
val myJob = coroutineContext[Job]
launch(Dispatchers.Main) {
testingJobs.remove(myJob)
uiThread {
adapter.updateSelectedItem(k)
}
})
}
}
}
true
@@ -579,4 +570,4 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
}
}
@@ -265,8 +265,4 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
updateSelectedItem(if (fromPosition < toPosition) fromPosition else toPosition)
return true
}
override fun onItemMoveCompleted() {
AngConfigManager.storeConfigFile()
}
}
@@ -1,11 +1,9 @@
package com.v2ray.ang.ui
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import com.google.gson.Gson
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.extension.defaultDPreference
@@ -14,7 +12,6 @@ import com.v2ray.ang.util.AngConfigManager
import com.v2ray.ang.util.Utils
import kotlinx.android.synthetic.main.activity_server2.*
import org.jetbrains.anko.*
import java.lang.Exception
class Server2Activity : BaseActivity() {
@@ -53,7 +50,7 @@ class Server2Activity : BaseActivity() {
*/
fun bindingServer(vmess: AngConfig.VmessBean): Boolean {
et_remarks.text = Utils.getEditable(vmess.remarks)
tv_content.text = Editable.Factory.getInstance().newEditable(defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + edit_guid, ""))
tv_content.text = defaultDPreference.getPrefString(AppConfig.ANG_CONFIG + edit_guid, "")
return true
}
@@ -69,40 +66,21 @@ class Server2Activity : BaseActivity() {
* save server config
*/
fun saveServer(): Boolean {
var saveSuccess: Boolean
val vmess = configs.vmess[edit_index]
vmess.remarks = et_remarks.text.toString()
if (TextUtils.isEmpty(vmess.remarks)) {
toast(R.string.server_lab_remarks)
saveSuccess = false
return false
}
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
toast(R.string.toast_success)
saveSuccess = true
} else {
toast(R.string.toast_failure)
saveSuccess = false
}
try {
Gson().fromJson<Object>(tv_content.text.toString(), Object::class.java)
} catch (e: Exception) {
e.printStackTrace()
toast(R.string.toast_malformed_josn)
saveSuccess = false
}
if (saveSuccess) {
//update config
defaultDPreference.setPrefString(AppConfig.ANG_CONFIG + edit_guid, tv_content.text.toString())
finish()
return true
} else {
toast(R.string.toast_failure)
return false
}
}
@@ -4,8 +4,10 @@ import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.preference.*
import com.v2ray.ang.AngApplication
import android.preference.CheckBoxPreference
import android.preference.EditTextPreference
import android.preference.Preference
import android.preference.PreferenceFragment
import com.v2ray.ang.BuildConfig
//import com.v2ray.ang.InappBuyActivity
import com.v2ray.ang.R
@@ -27,7 +29,6 @@ class SettingsActivity : BaseActivity() {
// const val PREF_MUX_ENAimport libv2ray.Libv2rayBLED = "pref_mux_enabled"
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
const val PREF_SNIFFING_ENABLED = "pref_sniffing_enabled"
const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled"
const val PREF_LOCAL_DNS_ENABLED = "pref_local_dns_enabled"
const val PREF_REMOTE_DNS = "pref_remote_dns"
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
@@ -58,19 +59,12 @@ class SettingsActivity : BaseActivity() {
class SettingsFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {
val perAppProxy by lazy { findPreference(PREF_PER_APP_PROXY) as CheckBoxPreference }
val sppedEnabled by lazy { findPreference(PREF_SPEED_ENABLED) as CheckBoxPreference }
val sniffingEnabled by lazy { findPreference(PREF_SNIFFING_ENABLED) as CheckBoxPreference }
val proxySharing by lazy { findPreference(PREF_PROXY_SHARING) as CheckBoxPreference }
val domainStrategy by lazy { findPreference(PREF_ROUTING_DOMAIN_STRATEGY) as ListPreference }
val routingMode by lazy { findPreference(PREF_ROUTING_MODE) as ListPreference }
val forwardIpv6 by lazy { findPreference(PREF_FORWARD_IPV6) as CheckBoxPreference }
val enableLocalDns by lazy { findPreference(PREF_LOCAL_DNS_ENABLED) as CheckBoxPreference }
val domesticDns by lazy { findPreference(PREF_DOMESTIC_DNS) as EditTextPreference }
val remoteDns by lazy { findPreference(PREF_REMOTE_DNS) as EditTextPreference }
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
val remoteDns by lazy { findPreference(PREF_REMOTE_DNS) as EditTextPreference }
val domesticDns by lazy { findPreference(PREF_DOMESTIC_DNS) as EditTextPreference }
val enableLocalDns by lazy { findPreference(PREF_LOCAL_DNS_ENABLED) as CheckBoxPreference }
val forwardIpv6 by lazy { findPreference(PREF_FORWARD_IPV6) as CheckBoxPreference }
// val socksPort by lazy { findPreference(PREF_SOCKS_PORT) as EditTextPreference }
// val httpPort by lazy { findPreference(PREF_HTTP_PORT) as EditTextPreference }
@@ -82,95 +76,14 @@ class SettingsActivity : BaseActivity() {
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
val version: Preference by lazy { findPreference(PREF_VERSION) }
private fun restartProxy() {
Utils.stopVService(activity)
Utils.startVService(activity)
}
private fun isRunning(): Boolean {
return Utils.isServiceRun(activity, "com.v2ray.ang.service.V2RayVpnService")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_settings)
var app = activity.application as AngApplication
perAppProxy.setOnPreferenceClickListener {
if (isRunning()) {
Utils.stopVService(activity)
}
startActivity<PerAppProxyActivity>()
perAppProxy.isChecked = true
true
}
sppedEnabled.setOnPreferenceClickListener {
if (isRunning())
restartProxy()
true
}
sniffingEnabled.setOnPreferenceClickListener {
if (isRunning())
restartProxy()
true
}
proxySharing.setOnPreferenceClickListener {
if (proxySharing.isChecked)
toast(R.string.toast_warning_pref_proxysharing)
if (isRunning())
restartProxy()
true
}
domainStrategy.setOnPreferenceChangeListener { _, _ ->
if (isRunning())
restartProxy()
true
}
routingMode.setOnPreferenceChangeListener { _, _ ->
if (isRunning())
restartProxy()
true
}
routingCustom.onClick {
if (isRunning())
Utils.stopVService(activity)
startActivity<RoutingSettingsActivity>()
}
forwardIpv6.setOnPreferenceClickListener {
if (isRunning())
restartProxy()
true
}
enableLocalDns.setOnPreferenceClickListener {
if (isRunning())
restartProxy()
true
}
domesticDns.setOnPreferenceChangeListener { preference, any ->
// domesticDns.summary = any as String
val nval = any as String
domesticDns.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
if (isRunning())
restartProxy()
true
}
remoteDns.setOnPreferenceChangeListener { preference, any ->
// remoteDns.summary = any as String
val nval = any as String
remoteDns.summary = if (nval == "") AppConfig.DNS_AGENT else nval
if (isRunning())
restartProxy()
true
}
// donate.onClick {
// startActivity<InappBuyActivity>()
// }
@@ -197,7 +110,24 @@ class SettingsActivity : BaseActivity() {
// }
// }
perAppProxy.setOnPreferenceClickListener {
startActivity<PerAppProxyActivity>()
perAppProxy.isChecked = true
false
}
remoteDns.setOnPreferenceChangeListener { preference, any ->
// remoteDns.summary = any as String
val nval = any as String
remoteDns.summary = if (nval == "") AppConfig.DNS_AGENT else nval
true
}
domesticDns.setOnPreferenceChangeListener { preference, any ->
// domesticDns.summary = any as String
val nval = any as String
domesticDns.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
true
}
// socksPort.setOnPreferenceChangeListener { preference, any ->
// socksPort.summary = any as String
// true
@@ -2,6 +2,7 @@ package com.v2ray.ang.util
import android.graphics.Bitmap
import android.text.TextUtils
import android.util.Log
import com.google.gson.Gson
import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig
@@ -15,9 +16,12 @@ import com.v2ray.ang.AppConfig.VMESS_PROTOCOL
import com.v2ray.ang.R
import com.v2ray.ang.dto.AngConfig
import com.v2ray.ang.dto.VmessQRCode
import java.net.URI
import com.v2ray.ang.extension.defaultDPreference
import org.jetbrains.anko.toast
import java.net.URLDecoder
import java.util.*
import java.net.*
import java.math.BigInteger
object AngConfigManager {
private lateinit var app: AngApplication
@@ -100,7 +104,16 @@ object AngConfigManager {
angConfig.vmess.removeAt(index)
//移除的是活动的
adjustIndexForRemovalAt(index)
if (angConfig.index == index) {
if (angConfig.vmess.count() > 0) {
angConfig.index = 0
} else {
angConfig.index = -1
}
} else if (index < angConfig.index)//移除活动之前的
{
angConfig.index--
}
storeConfigFile()
} catch (e: Exception) {
@@ -110,19 +123,6 @@ object AngConfigManager {
return 0
}
private fun adjustIndexForRemovalAt(index: Int) {
if (angConfig.index == index) {
if (angConfig.vmess.count() > 0) {
angConfig.index = 0
} else {
angConfig.index = -1
}
} else if (index < angConfig.index)//移除活动之前的
{
angConfig.index--
}
}
fun swapServer(fromPosition: Int, toPosition: Int): Int {
try {
Collections.swap(angConfig.vmess, fromPosition, toPosition)
@@ -133,7 +133,7 @@ object AngConfigManager {
} else if (index == toPosition) {
angConfig.index = fromPosition
}
//storeConfigFile()
storeConfigFile()
} catch (e: Exception) {
e.printStackTrace()
return -1
@@ -147,15 +147,13 @@ object AngConfigManager {
fun setActiveServer(index: Int): Int {
try {
if (index < 0 || index > angConfig.vmess.count() - 1) {
app.curIndex = -1
return -1
}
angConfig.index = index
app.curIndex = index
storeConfigFile()
} catch (e: Exception) {
e.printStackTrace()
app.curIndex = -1
return -1
}
return 0
@@ -241,7 +239,7 @@ object AngConfigManager {
/**
* import config form qrcode or...
*/
fun importConfig(server: String?, subid: String, removedSelectedServer: AngConfig.VmessBean?): Int {
fun importConfig(server: String?, subid: String): Int {
try {
if (server == null || TextUtils.isEmpty(server)) {
return R.string.toast_none_data
@@ -252,11 +250,7 @@ object AngConfigManager {
if (server.startsWith(VMESS_PROTOCOL)) {
val indexSplit = server.indexOf("?")
val newVmess = tryParseNewVmess(server)
if (newVmess != null) {
vmess = newVmess
vmess.subid = subid
} else if (indexSplit > 0) {
if (indexSplit > 0) {
vmess = ResolveVmess4Kitsunebi(server)
} else {
@@ -365,12 +359,6 @@ object AngConfigManager {
} else {
return R.string.toast_incorrect_protocol
}
if (removedSelectedServer != null &&
vmess.subid.equals(removedSelectedServer.subid) &&
vmess.address.equals(removedSelectedServer.address) &&
vmess.port.equals(removedSelectedServer.port)) {
setActiveServer(configs.vmess.count() - 1)
}
} catch (e: Exception) {
e.printStackTrace()
return -1
@@ -378,61 +366,6 @@ object AngConfigManager {
return 0
}
fun tryParseNewVmess(uri: String): AngConfig.VmessBean? {
return runCatching {
val uri = URI(uri)
check(uri.scheme == "vmess")
val (_, protocol, tlsStr, uuid, alterId) =
Regex("(tcp|http|ws|kcp|quic)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})-([0-9]+)")
.matchEntire(uri.userInfo)?.groupValues
?: error("parse user info fail.")
val tls = tlsStr.isNotBlank()
val queryParam = uri.rawQuery.split("&")
.map { it.split("=").let { (k, v) -> k to URLDecoder.decode(v, "utf-8")!! } }
.toMap()
val vmess = AngConfig.VmessBean()
vmess.address = uri.host
vmess.port = uri.port
vmess.id = uuid
vmess.alterId = alterId.toInt()
vmess.streamSecurity = if (tls) "tls" else ""
vmess.remarks = uri.fragment
vmess.security = "auto"
// TODO: allowInsecure not supported
when (protocol) {
"tcp" -> {
vmess.network = "tcp"
vmess.headerType = queryParam["type"] ?: "none"
vmess.requestHost = queryParam["host"] ?: ""
}
"http" -> {
vmess.network = "h2"
vmess.path = queryParam["path"]?.takeIf { it.trim() != "/" } ?: ""
vmess.requestHost = queryParam["host"]?.split("|")?.get(0) ?: ""
}
"ws" -> {
vmess.network = "ws"
vmess.path = queryParam["path"]?.takeIf { it.trim() != "/" } ?: ""
vmess.requestHost = queryParam["host"]?.split("|")?.get(0) ?: ""
}
"kcp" -> {
vmess.network = "kcp"
vmess.headerType = queryParam["type"] ?: "none"
vmess.path = queryParam["seed"] ?: ""
}
"quic" -> {
vmess.network = "quic"
vmess.requestHost = queryParam["security"] ?: "none"
vmess.headerType = queryParam["type"] ?: "none"
vmess.path = queryParam["key"] ?: ""
}
}
vmess
}.getOrNull()
}
private fun ResolveVmess4Kitsunebi(server: String): AngConfig.VmessBean {
val vmess = AngConfig.VmessBean()
@@ -793,11 +726,6 @@ object AngConfigManager {
if (servers == null) {
return 0
}
val removedSelectedServer =
if (!TextUtils.isEmpty(subid) && configs.vmess.count() > 0 && configs.vmess[configs.index].subid.equals(subid))
configs.vmess[configs.index]
else
null
removeServerViaSubid(subid)
// var servers = server
@@ -808,7 +736,7 @@ object AngConfigManager {
var count = 0
servers.lines()
.forEach {
val resId = importConfig(it, subid, removedSelectedServer)
val resId = importConfig(it, subid)
if (resId == 0) {
count++
}
@@ -848,7 +776,6 @@ object AngConfigManager {
for (k in configs.vmess.count() - 1 downTo 0) {
if (configs.vmess[k].subid.equals(subid)) {
angConfig.vmess.removeAt(k)
adjustIndexForRemovalAt(k)
}
}
@@ -894,4 +821,4 @@ object AngConfigManager {
return 0
}
}
}
@@ -27,11 +27,9 @@ import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
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
@@ -45,13 +43,10 @@ import java.util.regex.Pattern
import java.math.BigInteger
import java.util.concurrent.TimeUnit
import libv2ray.Libv2ray
import kotlin.coroutines.coroutineContext
object Utils {
val tcpTestingSockets = ArrayList<Socket?>()
/**
* convert string to editalbe for kotlin
*
@@ -316,11 +311,7 @@ object Utils {
* startVService
*/
fun startVService(context: Context): Boolean {
if (context.v2RayApplication.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
context.toast(R.string.toast_warning_pref_proxysharing_short)
}else{
context.toast(R.string.toast_services_start)
}
context.toast(R.string.toast_services_start)
if (AngConfigManager.genStoreV2rayConfig(-1)) {
val configContent = AngConfigManager.currGeneratedV2rayConfig()
val configType = AngConfigManager.currConfigType()
@@ -344,7 +335,6 @@ object Utils {
*/
fun startVService(context: Context, guid: String): Boolean {
val index = AngConfigManager.getIndexViaGuid(guid)
context.v2RayApplication.curIndex=index
return startVService(context, index)
}
@@ -487,13 +477,10 @@ object Utils {
/**
* tcping
*/
suspend fun tcping(url: String, port: Int): String {
fun tcping(url: String, port: Int): String {
var time = -1L
for (k in 0 until 2) {
val one = socketConnectTime(url, port)
if (!coroutineContext.isActive) {
break
}
if (one != -1L )
if(time == -1L || one < time) {
time = one
@@ -504,35 +491,19 @@ object Utils {
fun socketConnectTime(url: String, port: Int): Long {
try {
val socket = Socket()
synchronized(this) {
tcpTestingSockets.add(socket)
}
val start = System.currentTimeMillis()
socket.connect(InetSocketAddress(url, port))
val socket = Socket(url, port)
val time = System.currentTimeMillis() - start
synchronized(this) {
tcpTestingSockets.remove(socket)
}
socket.close()
return time
} catch (e: UnknownHostException) {
e.printStackTrace()
} catch (e: IOException) {
Log.d(AppConfig.ANG_PACKAGE, "socketConnectTime IOException: $e")
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return -1
}
fun closeAllTcpSockets() {
synchronized(this) {
tcpTestingSockets.forEach {
it?.close()
}
tcpTestingSockets.clear()
}
}
}
@@ -9,6 +9,7 @@ import com.v2ray.ang.AngApplication
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.AngConfig.VmessBean
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.extension.defaultDPreference
import com.v2ray.ang.ui.SettingsActivity
import org.json.JSONException
import org.json.JSONObject
@@ -128,12 +129,6 @@ object V2rayConfigUtil {
*/
private fun inbounds(vmess: VmessBean, v2rayConfig: V2rayConfig, app: AngApplication): Boolean {
try {
v2rayConfig.inbounds.forEach { curInbound ->
if (!app.defaultDPreference.getPrefBoolean(SettingsActivity.PREF_PROXY_SHARING, false)) {
//bind all inbounds to localhost if the user requests
curInbound.listen = "127.0.0.1"
}
}
v2rayConfig.inbounds[0].port = 10808
// val socksPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_SOCKS_PORT, "10808"))
// val lanconnPort = Utils.parseInt(app.defaultDPreference.getPrefString(SettingsActivity.PREF_HTTP_PORT, ""))
@@ -245,7 +240,7 @@ object V2rayConfigUtil {
//streamSettings
when (streamSettings.network) {
"kcp" -> {
val kcpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.KcpSettingsBean()
val kcpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean()
kcpsettings.mtu = 1350
kcpsettings.tti = 50
kcpsettings.uplinkCapacity = 12
@@ -253,33 +248,34 @@ object V2rayConfigUtil {
kcpsettings.congestion = false
kcpsettings.readBufferSize = 1
kcpsettings.writeBufferSize = 1
kcpsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.KcpSettingsBean.HeaderBean()
kcpsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.KcpsettingsBean.HeaderBean()
kcpsettings.header.type = vmess.headerType
streamSettings.kcpSettings = kcpsettings
streamSettings.kcpsettings = kcpsettings
}
"ws" -> {
val wssettings = V2rayConfig.OutboundBean.StreamSettingsBean.WsSettingsBean()
val wssettings = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean()
wssettings.connectionReuse = true
val host = vmess.requestHost.trim()
val path = vmess.path.trim()
if (!TextUtils.isEmpty(host)) {
wssettings.headers = V2rayConfig.OutboundBean.StreamSettingsBean.WsSettingsBean.HeadersBean()
wssettings.headers = V2rayConfig.OutboundBean.StreamSettingsBean.WssettingsBean.HeadersBean()
wssettings.headers.Host = host
}
if (!TextUtils.isEmpty(path)) {
wssettings.path = path
}
streamSettings.wsSettings = wssettings
streamSettings.wssettings = wssettings
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlsSettingsBean()
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlssettingsBean()
tlssettings.allowInsecure = true
if (!TextUtils.isEmpty(host)) {
tlssettings.serverName = host
}
streamSettings.tlsSettings = tlssettings
streamSettings.tlssettings = tlssettings
}
"h2" -> {
val httpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.HttpSettingsBean()
val httpsettings = V2rayConfig.OutboundBean.StreamSettingsBean.HttpsettingsBean()
val host = vmess.requestHost.trim()
val path = vmess.path.trim()
@@ -287,30 +283,31 @@ object V2rayConfigUtil {
httpsettings.host = host.split(",").map { it.trim() }
}
httpsettings.path = path
streamSettings.httpSettings = httpsettings
streamSettings.httpsettings = httpsettings
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlsSettingsBean()
val tlssettings = V2rayConfig.OutboundBean.StreamSettingsBean.TlssettingsBean()
tlssettings.allowInsecure = true
streamSettings.tlsSettings = tlssettings
streamSettings.tlssettings = tlssettings
}
"quic" -> {
val quicsettings = V2rayConfig.OutboundBean.StreamSettingsBean.QuicSettingBean()
val quicsettings = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean()
val host = vmess.requestHost.trim()
val path = vmess.path.trim()
quicsettings.security = host
quicsettings.key = path
quicsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.QuicSettingBean.HeaderBean()
quicsettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.QuicsettingBean.HeaderBean()
quicsettings.header.type = vmess.headerType
streamSettings.quicSettings = quicsettings
streamSettings.quicsettings = quicsettings
}
else -> {
//tcp带http伪装
if (vmess.headerType == "http") {
val tcpSettings = V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean()
tcpSettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean()
val tcpSettings = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean()
tcpSettings.connectionReuse = true
tcpSettings.header = V2rayConfig.OutboundBean.StreamSettingsBean.TcpsettingsBean.HeaderBean()
tcpSettings.header.type = vmess.headerType
// if (requestObj.has("headers")
@@ -550,7 +547,7 @@ object V2rayConfigUtil {
mux = null))
}
// DNS routing
// DNS routing
v2rayConfig.routing.rules.add(0, V2rayConfig.RoutingBean.RulesBean(
type = "field",
outboundTag = AppConfig.TAG_DIRECT,
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@color/secondary_text" />
<item android:state_focused="true"
android:drawable="@color/secondary_text" />
<item android:state_hovered="true"
android:drawable="@color/secondary_text" />
<item android:drawable="@color/colorPrimary_text" />
</selector>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/accent"/>
<corners android:radius="20dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#009963"/>
<corners android:radius="20dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -54,10 +54,8 @@
android:id="@+id/layout_test"
android:layout_width="match_parent"
android:layout_height="@dimen/connection_test_height"
android:background="@drawable/background_test_button"
android:gravity="center|left"
android:clickable="true"
android:focusable="true">
android:background="@color/colorPrimary_text"
android:gravity="center|left">
<TextView
android:id="@+id/tv_test_state"
@@ -94,8 +92,6 @@
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:src="@drawable/ic_v_idle"
android:clickable="true"
android:focusable="true"
app:layout_anchorGravity="bottom|right|end" />
</com.github.jorgecastilloprz.FABProgressCircle>
@@ -68,15 +68,20 @@
android:text="@string/server_lab_content"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<EditText
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:text="" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:layout_marginBottom="@dimen/layout_margin_top_height"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
@@ -2,10 +2,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
android:gravity="center_vertical">
<android.support.v7.widget.AppCompatImageView
android:id="@+id/icon"
@@ -43,7 +40,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:paddingEnd="6dp"
@@ -9,6 +9,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="horizontal"
card_view:cardCornerRadius="5dp">
<LinearLayout
@@ -17,11 +21,7 @@
android:layout_height="@dimen/server_height"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:nextFocusRight="@+id/layout_share">
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
@@ -111,14 +111,10 @@
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="@dimen/server_height"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:nextFocusLeft="@+id/info_container">
android:paddingEnd="@dimen/layout_margin_right_height">
<ImageView
android:layout_width="wrap_content"
@@ -130,13 +126,10 @@
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="@dimen/server_height"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
android:paddingEnd="@dimen/layout_margin_right_height">
<ImageView
android:layout_width="@dimen/png_height"
@@ -148,13 +141,10 @@
<LinearLayout
android:id="@+id/layout_remove"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_height="@dimen/server_height"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
android:paddingEnd="@dimen/layout_margin_right_height">
<ImageView
android:layout_width="@dimen/png_height"
@@ -6,7 +6,6 @@
android:gravity="center_vertical">
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/item_cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp"
@@ -14,8 +13,7 @@
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:orientation="horizontal"
card_view:cardCornerRadius="5dp"
android:nextFocusRight="@+id/layout_edit">
card_view:cardCornerRadius="5dp">
<LinearLayout
android:id="@+id/info_container"
@@ -64,14 +62,11 @@
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="@dimen/server_height"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
android:visibility="invisible"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
android:paddingEnd="@dimen/layout_margin_right_height"
android:visibility="invisible">
<ImageView
android:layout_width="@dimen/png_height"
@@ -83,14 +78,10 @@
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="@dimen/server_height"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:nextFocusLeft="@+id/item_cardview">
android:paddingEnd="@dimen/layout_margin_right_height">
<ImageView
android:layout_width="@dimen/png_height"
@@ -1,5 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -7,9 +14,16 @@
android:gravity="center"
android:orientation="vertical">
<ImageView
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="10dp"
android:src="@drawable/ic_v" />
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/app_widget_name"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>
@@ -4,7 +4,12 @@
tools:showIn="navigation_view">
<group
android:id="@+id/group_main">
android:id="@+id/group_main"
android:checkableBehavior="single">
<item
android:id="@+id/server_profile"
android:icon="@drawable/ic_description_white_24dp"
android:title="@string/title_server" />
<item
android:id="@+id/sub_setting"
android:icon="@drawable/ic_subscriptions_white_24dp"
@@ -6,9 +6,4 @@
android:icon="@drawable/ic_copy_white"
android:title="@string/logcat_copy"
app:showAsAction="always" />
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/logcat_delete"
app:showAsAction="ifRoom" />
</menu>
@@ -83,7 +83,7 @@
<string name="summary_pref_mux_enabled">开启可能会加速,关闭可能会减少断流</string>
<string name="title_pref_speed_enabled">启用速度显示</string>
<string name="summary_pref_speed_enabled">在通知中显示当前速度\n小图标显示流量的路由情况</string>
<string name="summary_pref_speed_enabled">在通知中显示当前速度</string>
<string name="title_pref_sniffing_enabled">启用流量探测</string>
<string name="summary_pref_sniffing_enabled">流量探测</string>
@@ -135,7 +135,6 @@
<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_sub_setting">订阅设置</string>
<string name="sub_setting_remarks">备注</string>
@@ -181,10 +180,5 @@
<item>绕过大陆地址</item>
<item>绕过局域网及大陆地址</item>
</string-array>
<string name="title_pref_proxy_sharing_enabled">代理共享</string>
<string name="summary_pref_proxy_sharing_enabled">绑定代理入口ip到0.0.0.0</string>
<string name="toast_warning_pref_proxysharing">其他设备可以使用socks/http协议通过您的IP地址连接到代理\nHttp 代理: http://您的ip:10809\nSocks 代理: socks(4/5)://您的ip:10808\n仅在受信任的网络中启用以避免未经授权的连接</string>
<string name="toast_warning_pref_proxysharing_short">代理共享已启用,请确保处于受信网络</string>
<string name="toast_malformed_josn">配置格式错误</string>
</resources>
@@ -17,7 +17,7 @@
<string name="toast_services_failure">啟動服務失敗</string>
<!--ServerActivity-->
<string name="title_server">設定檔</string>
<string name="title_server">組態</string>
<string name="menu_item_add_config">新增組態</string>
<string name="menu_item_save_config">儲存組態</string>
<string name="menu_item_del_config">刪除組態</string>
@@ -57,7 +57,7 @@
<string name="title_file_chooser">選取一個設定檔</string>
<string name="toast_require_file_manager">請安裝檔案總管。</string>
<string name="server_customize_config">自訂組態</string>
<string name="toast_config_file_invalid">無效設定檔</string>
<string name="toast_config_file_invalid">無效組態</string>
<string name="server_lab_content">內容</string>
<string name="toast_none_data_clipboard">剪貼簿內無資料</string>
<string name="toast_invalid_url">網址無效</string>
@@ -84,7 +84,7 @@
<string name="summary_pref_mux_enabled">啟用或許會加快網路速度,切換或許會閃爍</string>
<string name="title_pref_speed_enabled">啟用速度顯示</string>
<string name="summary_pref_speed_enabled">在通知中顯示當前速度\n小圖標顯示流量的路由情況</string>
<string name="summary_pref_speed_enabled">在通知中顯示當前速度</string>
<string name="title_pref_sniffing_enabled">啟用流量探測</string>
<string name="summary_pref_sniffing_enabled">流量探測</string>
@@ -104,17 +104,17 @@
<string name="summary_pref_donate">向開發人員捐款</string>
<string name="donate_detail">新增一些實驗性進階功能</string>
<string name="title_pref_remote_dns">遠端DNS (可)</string>
<string name="title_pref_remote_dns">遠端DNS (可)</string>
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_domestic_dns">境内DNS (可,僅本地DNS模式下生效)</string>
<string name="title_pref_domestic_dns">境内DNS (可,僅本地DNS模式下生效)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_socks_port">SOCKS5代理連接埠</string>
<string name="summary_pref_socks_port">SOCKS5代理連接埠</string>
<string name="title_pref_socks_port">SOCKS5代理端口</string>
<string name="summary_pref_socks_port">SOCKS5代理端口</string>
<string name="title_pref_http_port">HTTP代理連接埠</string>
<string name="summary_pref_http_port">HTTP代理連接埠</string>
<string name="title_pref_http_port">HTTP代理端口</string>
<string name="summary_pref_http_port">HTTP代理端口</string>
<string name="title_pref_feedback">回饋</string>
@@ -137,7 +137,6 @@
<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_sub_setting">訂閱設定</string>
<string name="sub_setting_remarks">備註</string>
@@ -154,7 +153,7 @@
<string name="routing_settings_delete">清除</string>
<string name="routing_settings_scan_replace">掃描並取代</string>
<string name="routing_settings_scan_append">掃描並附加</string>
<string name="routing_settings_default_rules">設置預設路由規則</string>
<string name="routing_settings_default_rules">設置默認路由規則</string>
<string name="connection_test_pending">"檢查連線能力"</string>
<string name="connection_test_testing">"測試中……"</string>
@@ -179,13 +178,8 @@
<string-array name="routing_mode">
<item>全球</item>
<item>略過域網</item>
<item>略過域網</item>
<item>略過中國大陸</item>
<item>略過域網及中國大陸</item>
<item>略過域網及中國大陸</item>
</string-array>
<string name="title_pref_proxy_sharing_enabled">代理共享</string>
<string name="summary_pref_proxy_sharing_enabled">綁定代理入口ip到0.0.0.0</string>
<string name="toast_warning_pref_proxysharing">其他設備可以使用socks/http協定通過您的IP地址連接到代理\nHttp 代理: http://您的ip:10809\nSocks 代理: socks(4/5)://您的ip:10808\n僅在受信任的網路中啟用以避免未經授權的連接</string>
<string name="toast_warning_pref_proxysharing_short">代理共享已啟用,請確保處於受信網路</string>
<string name="toast_malformed_josn">配置格式錯誤</string>
</resources>
@@ -66,39 +66,4 @@
<item>IPIfNonMatch</item>
<item>IPOnDemand</item>
</string-array>
<!-- minimum list https://serverfault.com/a/304791 -->
<string-array name="bypass_private_ip_address" translatable="false">
<item>0.0.0.0/5</item>
<item>8.0.0.0/7</item>
<item>11.0.0.0/8</item>
<item>12.0.0.0/6</item>
<item>16.0.0.0/4</item>
<item>32.0.0.0/3</item>
<item>64.0.0.0/2</item>
<item>128.0.0.0/3</item>
<item>160.0.0.0/5</item>
<item>168.0.0.0/6</item>
<item>172.0.0.0/12</item>
<item>172.32.0.0/11</item>
<item>172.64.0.0/10</item>
<item>172.128.0.0/9</item>
<item>173.0.0.0/8</item>
<item>174.0.0.0/7</item>
<item>176.0.0.0/4</item>
<item>192.0.0.0/9</item>
<item>192.128.0.0/11</item>
<item>192.160.0.0/13</item>
<item>192.169.0.0/16</item>
<item>192.170.0.0/15</item>
<item>192.172.0.0/14</item>
<item>192.176.0.0/12</item>
<item>192.192.0.0/10</item>
<item>193.0.0.0/8</item>
<item>194.0.0.0/7</item>
<item>196.0.0.0/6</item>
<item>200.0.0.0/5</item>
<item>208.0.0.0/4</item>
<item>224.0.0.0/3</item>
</string-array>
</resources>
@@ -3,7 +3,6 @@
<dimen name="bypass_list_header_height">50dp</dimen>
<dimen name="layout_margin_top_height">16dp</dimen>
<dimen name="layout_margin_right_height">16dp</dimen>
<dimen name="layout_margin_spacing">8dp</dimen>
<dimen name="edit_height">50dp</dimen>
<dimen name="png_height">24dp</dimen>
<dimen name="server_height">72dp</dimen>
+1 -8
View File
@@ -84,8 +84,7 @@
<string name="summary_pref_mux_enabled">Enable maybe speed up network and switch network maybe flash</string>
<string name="title_pref_speed_enabled">Enable speed display</string>
<string name="summary_pref_speed_enabled">Display current speed in the notification.\nNotification icon would change based on
usage.</string>
<string name="summary_pref_speed_enabled">Display current speed in the notification</string>
<string name="title_pref_sniffing_enabled">Enable Sniffing</string>
<string name="summary_pref_sniffing_enabled">Sniffing</string>
@@ -137,7 +136,6 @@
<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_sub_setting">Subscription setting</string>
<string name="sub_setting_remarks">remarks</string>
@@ -183,10 +181,5 @@
<item>Bypass mainland address</item>
<item>Bypassing LAN and mainland address</item>
</string-array>
<string name="title_pref_proxy_sharing_enabled">Proxy sharing</string>
<string name="summary_pref_proxy_sharing_enabled">Bind inbound to 0.0.0.0</string>
<string name="toast_warning_pref_proxysharing">Other devices can connect to proxy by your ip address through socks/http protocol\nHttp Proxy: http://yourIP:10809\nSocks Proxy: socks(4/5)://yourIP:10808\nOnly enable in trusted network to avoid unauthorized connection</string>
<string name="toast_warning_pref_proxysharing_short">Proxy sharing enabled\nMake sure you are in a trusted network</string>
<string name="toast_malformed_josn">Config malformed</string>
</resources>
@@ -22,13 +22,6 @@
android:summary="@string/summary_pref_sniffing_enabled"
android:title="@string/title_pref_sniffing_enabled" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_proxy_sharing_enabled"
android:onClick="proxySharingOnClick"
android:summary="@string/summary_pref_proxy_sharing_enabled"
android:title="@string/title_pref_proxy_sharing_enabled" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_pref_routing">