Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20ca554be2 | |||
| 25ba455656 | |||
| 17e7c62d53 | |||
| 6f0f2fdeda | |||
| 3c9c9b5a4c | |||
| e13024d6bb | |||
| 9d58edd31f | |||
| af7dfc3a43 | |||
| ca554e6ac4 | |||
| ec391d8689 | |||
| 6afd4d0549 | |||
| 957cf85362 | |||
| 881152e10a | |||
| 6e47ebb27a | |||
| a731e6c360 | |||
| d1466ba4b2 | |||
| 617f28f399 | |||
| c0ec0d9404 | |||
| 3419dc8837 | |||
| 786aaf823a | |||
| 1144183da4 | |||
| 5bf2fda990 | |||
| 993ee0b8d2 | |||
| 91b8284afd | |||
| ef9e0cc0d2 |
+3
-5
@@ -2,10 +2,8 @@ V2rayNG/app/src/main/res/layout/activity_inapp_buy.xml
|
|||||||
V2rayNG/app/src/main/assets/geoip.dat
|
V2rayNG/app/src/main/assets/geoip.dat
|
||||||
V2rayNG/app/src/main/assets/geosite.dat
|
V2rayNG/app/src/main/assets/geosite.dat
|
||||||
V2rayNG/app/src/main/java/com/v2ray/ang/InappBuyActivity.java
|
V2rayNG/app/src/main/java/com/v2ray/ang/InappBuyActivity.java
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
|
||||||
*.dat
|
*.dat
|
||||||
*.jks
|
*.jks
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
V2rayNG/app/release/output.json
|
||||||
V2rayNG/gradle/wrapper/gradle-wrapper.properties
|
.idea/
|
||||||
V2rayNG/app/release/output.json
|
.gradle/
|
||||||
@@ -24,7 +24,6 @@ type resolved struct {
|
|||||||
domain string
|
domain string
|
||||||
IPs []net.IP
|
IPs []net.IP
|
||||||
Port int
|
Port int
|
||||||
lastResolved time.Time
|
|
||||||
ipIdx uint8
|
ipIdx uint8
|
||||||
ipLock sync.Mutex
|
ipLock sync.Mutex
|
||||||
lastSwitched time.Time
|
lastSwitched time.Time
|
||||||
@@ -98,7 +97,7 @@ func (d *ProtectedDialer) PrepareResolveChan() {
|
|||||||
d.resolveChan = make(chan struct{})
|
d.resolveChan = make(chan struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ProtectedDialer) ResolveChan() chan struct{} {
|
func (d *ProtectedDialer) ResolveChan() <-chan struct{} {
|
||||||
return d.resolveChan
|
return d.resolveChan
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +137,9 @@ func (d *ProtectedDialer) lookupAddr(addr string) (*resolved, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rs := &resolved{
|
rs := &resolved{
|
||||||
domain: host,
|
domain: host,
|
||||||
IPs: IPs,
|
IPs: IPs,
|
||||||
Port: portnum,
|
Port: portnum,
|
||||||
lastResolved: time.Now(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rs, nil
|
return rs, nil
|
||||||
@@ -152,6 +150,7 @@ func (d *ProtectedDialer) PrepareDomain(domainName string, closeCh <-chan struct
|
|||||||
log.Printf("Preparing Domain: %s", domainName)
|
log.Printf("Preparing Domain: %s", domainName)
|
||||||
d.currentServer = domainName
|
d.currentServer = domainName
|
||||||
|
|
||||||
|
defer close(d.resolveChan)
|
||||||
maxRetry := 10
|
maxRetry := 10
|
||||||
for {
|
for {
|
||||||
if maxRetry == 0 {
|
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)
|
fd, err := d.getFd(dest.Network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -71,10 +71,7 @@ func (v *V2RayPoint) RunLoop() (err error) {
|
|||||||
if !v.status.IsRunning {
|
if !v.status.IsRunning {
|
||||||
v.closeChan = make(chan struct{})
|
v.closeChan = make(chan struct{})
|
||||||
v.dialer.PrepareResolveChan()
|
v.dialer.PrepareResolveChan()
|
||||||
go func() {
|
go v.dialer.PrepareDomain(v.DomainName, v.closeChan)
|
||||||
v.dialer.PrepareDomain(v.DomainName, v.closeChan)
|
|
||||||
close(v.dialer.ResolveChan())
|
|
||||||
}()
|
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
// wait until resolved
|
// wait until resolved
|
||||||
@@ -119,7 +116,7 @@ func (v V2RayPoint) QueryStats(tag string, direct string) int64 {
|
|||||||
if v.statsManager == nil {
|
if v.statsManager == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
counter := v.statsManager.GetCounter(fmt.Sprintf("inbound>>>%s>>>traffic>>>%s", tag, direct))
|
counter := v.statsManager.GetCounter(fmt.Sprintf("outbound>>>%s>>>traffic>>>%s", tag, direct))
|
||||||
if counter == nil {
|
if counter == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,34 +20,17 @@ android {
|
|||||||
versionName "1.0.2"
|
versionName "1.0.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
storeFile file("../key.jks")
|
|
||||||
keyAlias 'ang'
|
|
||||||
keyPassword '123456'
|
|
||||||
storePassword '123456'
|
|
||||||
}
|
|
||||||
debug {
|
|
||||||
storeFile file("../key.jks")
|
|
||||||
keyAlias 'ang'
|
|
||||||
keyPassword '123456'
|
|
||||||
storePassword '123456'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
zipAlignEnabled false
|
zipAlignEnabled false
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
signingConfig signingConfigs.release
|
|
||||||
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
zipAlignEnabled false
|
zipAlignEnabled false
|
||||||
shrinkResources false
|
shrinkResources false
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,4 +114,4 @@ repositories {
|
|||||||
flatDir {
|
flatDir {
|
||||||
dirs 'libs'
|
dirs 'libs'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,10 @@
|
|||||||
|
|
||||||
<activity android:name=".ui.SubEditActivity" />
|
<activity android:name=".ui.SubEditActivity" />
|
||||||
<activity android:name=".ui.ScScannerActivity" />
|
<activity android:name=".ui.ScScannerActivity" />
|
||||||
<activity android:name=".ui.ScSwitchActivity" />
|
<activity
|
||||||
|
android:name=".ui.ScSwitchActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar.Translucent" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.V2RayVpnService"
|
android:name=".service.V2RayVpnService"
|
||||||
@@ -93,16 +96,16 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<!--<receiver android:name=".receiver.WidgetProvider">-->
|
<receiver android:name=".receiver.WidgetProvider"
|
||||||
<!--<meta-data-->
|
android:process=":RunSoLibV2RayDaemon">
|
||||||
<!--android:name="android.appwidget.provider"-->
|
<meta-data
|
||||||
<!--android:resource="@xml/app_widget_provider" />-->
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/app_widget_provider" />
|
||||||
<!--<intent-filter>-->
|
<intent-filter>
|
||||||
<!--<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />-->
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
<!--<action android:name="com.v2ray.ang.action.widget.click" />-->
|
<action android:name="com.v2ray.ang.action.widget.click" />
|
||||||
<!--</intent-filter>-->
|
</intent-filter>
|
||||||
<!--</receiver>-->
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.QSTileService"
|
android:name=".service.QSTileService"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
android
|
||||||
com.android.chrome
|
com.android.chrome
|
||||||
com.google.android.googlequicksearchbox
|
com.google.android.googlequicksearchbox
|
||||||
com.google.android.apps.photos
|
com.google.android.apps.photos
|
||||||
@@ -193,4 +194,4 @@ tv.twitch.android.app
|
|||||||
com.shanga.walli
|
com.shanga.walli
|
||||||
com.whatsapp
|
com.whatsapp
|
||||||
com.wire
|
com.wire
|
||||||
com.simplehabit.simplehabitapp
|
com.simplehabit.simplehabitapp
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"system": {
|
"system": {
|
||||||
"statsInboundUplink": true,
|
"statsOutboundUplink": true,
|
||||||
"statsInboundDownlink": true
|
"statsOutboundDownlink": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inbounds": [{
|
"inbounds": [{
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ public interface ItemTouchHelperAdapter {
|
|||||||
boolean onItemMove(int fromPosition, int toPosition);
|
boolean onItemMove(int fromPosition, int toPosition);
|
||||||
|
|
||||||
|
|
||||||
|
void onItemMoveCompleted();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an item has been dismissed by a swipe.<br/>
|
* Called when an item has been dismissed by a swipe.<br/>
|
||||||
* <br/>
|
* <br/>
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
|||||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||||
super.clearView(recyclerView, viewHolder);
|
super.clearView(recyclerView, viewHolder);
|
||||||
|
|
||||||
|
mAdapter.onItemMoveCompleted();
|
||||||
|
|
||||||
viewHolder.itemView.setAlpha(ALPHA_FULL);
|
viewHolder.itemView.setAlpha(ALPHA_FULL);
|
||||||
|
|
||||||
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
if (viewHolder instanceof ItemTouchHelperViewHolder) {
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ package com.v2ray.ang.receiver
|
|||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetProvider
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import com.v2ray.ang.R
|
import com.v2ray.ang.R
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
import com.v2ray.ang.util.Utils
|
import com.v2ray.ang.util.Utils
|
||||||
import org.jetbrains.anko.toast
|
|
||||||
|
|
||||||
class WidgetProvider : AppWidgetProvider() {
|
class WidgetProvider : AppWidgetProvider() {
|
||||||
/**
|
/**
|
||||||
@@ -19,10 +18,21 @@ class WidgetProvider : AppWidgetProvider() {
|
|||||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
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 remoteViews = RemoteViews(context.packageName, R.layout.widget_switch)
|
||||||
val intent = Intent(AppConfig.BROADCAST_ACTION_WIDGET_CLICK)
|
val intent = Intent(context, WidgetProvider::class.java)
|
||||||
|
intent.setAction(AppConfig.BROADCAST_ACTION_WIDGET_CLICK)
|
||||||
val pendingIntent = PendingIntent.getBroadcast(context, R.id.layout_switch, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
val pendingIntent = PendingIntent.getBroadcast(context, R.id.layout_switch, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
|
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) {
|
for (appWidgetId in appWidgetIds) {
|
||||||
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
|
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
|
||||||
@@ -44,7 +54,9 @@ class WidgetProvider : AppWidgetProvider() {
|
|||||||
// context.toast(R.string.toast_services_start)
|
// context.toast(R.string.toast_services_start)
|
||||||
Utils.startVService(context)
|
Utils.startVService(context)
|
||||||
}
|
}
|
||||||
|
val manager = AppWidgetManager.getInstance(context)
|
||||||
|
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
|
||||||
|
!isRunning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class V2RayVpnService : VpnService() {
|
|||||||
const val NOTIFICATION_ID = 1
|
const val NOTIFICATION_ID = 1
|
||||||
const val NOTIFICATION_PENDING_INTENT_CONTENT = 0
|
const val NOTIFICATION_PENDING_INTENT_CONTENT = 0
|
||||||
const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
|
const val NOTIFICATION_PENDING_INTENT_STOP_V2RAY = 1
|
||||||
|
const val NOTIFICATION_ICON_THRESHOLD = 3000
|
||||||
|
|
||||||
fun startV2Ray(context: Context) {
|
fun startV2Ray(context: Context) {
|
||||||
val intent = Intent(context.applicationContext, V2RayVpnService::class.java)
|
val intent = Intent(context.applicationContext, V2RayVpnService::class.java)
|
||||||
@@ -130,6 +131,7 @@ class V2RayVpnService : VpnService() {
|
|||||||
// Configure a builder while parsing the parameters.
|
// Configure a builder while parsing the parameters.
|
||||||
val builder = Builder()
|
val builder = Builder()
|
||||||
val enableLocalDns = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
val enableLocalDns = defaultDPreference.getPrefBoolean(SettingsActivity.PREF_LOCAL_DNS_ENABLED, false)
|
||||||
|
val routingMode = defaultDPreference.getPrefString(SettingsActivity.PREF_ROUTING_MODE, "0")
|
||||||
|
|
||||||
parameters.split(" ")
|
parameters.split(" ")
|
||||||
.map { it.split(",") }
|
.map { it.split(",") }
|
||||||
@@ -138,7 +140,20 @@ class V2RayVpnService : VpnService() {
|
|||||||
'm' -> builder.setMtu(java.lang.Short.parseShort(it[1]).toInt())
|
'm' -> builder.setMtu(java.lang.Short.parseShort(it[1]).toInt())
|
||||||
's' -> builder.addSearchDomain(it[1])
|
's' -> builder.addSearchDomain(it[1])
|
||||||
'a' -> builder.addAddress(it[1], Integer.parseInt(it[2]))
|
'a' -> builder.addAddress(it[1], Integer.parseInt(it[2]))
|
||||||
'r' -> builder.addRoute(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]))
|
||||||
|
}
|
||||||
|
}
|
||||||
'd' -> builder.addDnsServer(it[1])
|
'd' -> builder.addDnsServer(it[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,9 +374,17 @@ class V2RayVpnService : VpnService() {
|
|||||||
mSubscription = null
|
mSubscription = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateNotification(contentText: String) {
|
private fun updateNotification(contentText: String, proxyTraffic: Long, directTraffic: Long) {
|
||||||
if (mBuilder != null) {
|
if (mBuilder != null) {
|
||||||
mBuilder?.setContentTitle(contentText)
|
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?.setContentText(contentText) // Emui4.1 need content text even if style is set as BigTextStyle
|
||||||
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
|
getNotificationManager().notify(NOTIFICATION_ID, mBuilder?.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,13 +405,19 @@ class V2RayVpnService : VpnService() {
|
|||||||
|
|
||||||
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
mSubscription = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
val uplink = v2rayPoint.queryStats("socks", "uplink")
|
val proxyUplink = v2rayPoint.queryStats("proxy", "uplink")
|
||||||
val downlink = v2rayPoint.queryStats("socks", "downlink")
|
val proxyDownlink = v2rayPoint.queryStats("proxy", "downlink")
|
||||||
val zero_speed = (uplink == 0L && downlink == 0L)
|
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 queryTime = System.currentTimeMillis()
|
||||||
if (!zero_speed || !last_zero_speed) {
|
if (!zero_speed || !last_zero_speed) {
|
||||||
updateNotification("${cf_name} • ${(uplink * 1000 / (queryTime - lastQueryTime)).toSpeedString()}↑" +
|
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
|
||||||
" ${(downlink * 1000 / (queryTime - lastQueryTime)).toSpeedString()}↓")
|
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)
|
||||||
}
|
}
|
||||||
last_zero_speed = zero_speed
|
last_zero_speed = zero_speed
|
||||||
lastQueryTime = queryTime
|
lastQueryTime = queryTime
|
||||||
@@ -403,7 +432,7 @@ class V2RayVpnService : VpnService() {
|
|||||||
mSubscription = null
|
mSubscription = null
|
||||||
|
|
||||||
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
|
val cf_name = defaultDPreference.getPrefString(AppConfig.PREF_CURR_CONFIG_NAME, "")
|
||||||
updateNotification(cf_name)
|
updateNotification(cf_name, 0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -265,4 +265,8 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
|||||||
updateSelectedItem(if (fromPosition < toPosition) fromPosition else toPosition)
|
updateSelectedItem(if (fromPosition < toPosition) fromPosition else toPosition)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onItemMoveCompleted() {
|
||||||
|
AngConfigManager.storeConfigFile()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.v2ray.ang.util
|
|||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import com.v2ray.ang.AppConfig
|
import com.v2ray.ang.AppConfig
|
||||||
@@ -16,12 +15,9 @@ import com.v2ray.ang.AppConfig.VMESS_PROTOCOL
|
|||||||
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.VmessQRCode
|
import com.v2ray.ang.dto.VmessQRCode
|
||||||
import com.v2ray.ang.extension.defaultDPreference
|
import java.net.URI
|
||||||
import org.jetbrains.anko.toast
|
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.net.*
|
|
||||||
import java.math.BigInteger
|
|
||||||
|
|
||||||
object AngConfigManager {
|
object AngConfigManager {
|
||||||
private lateinit var app: AngApplication
|
private lateinit var app: AngApplication
|
||||||
@@ -137,7 +133,7 @@ object AngConfigManager {
|
|||||||
} else if (index == toPosition) {
|
} else if (index == toPosition) {
|
||||||
angConfig.index = fromPosition
|
angConfig.index = fromPosition
|
||||||
}
|
}
|
||||||
storeConfigFile()
|
//storeConfigFile()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return -1
|
return -1
|
||||||
@@ -256,7 +252,11 @@ object AngConfigManager {
|
|||||||
if (server.startsWith(VMESS_PROTOCOL)) {
|
if (server.startsWith(VMESS_PROTOCOL)) {
|
||||||
|
|
||||||
val indexSplit = server.indexOf("?")
|
val indexSplit = server.indexOf("?")
|
||||||
if (indexSplit > 0) {
|
val newVmess = tryParseNewVmess(server)
|
||||||
|
if (newVmess != null) {
|
||||||
|
vmess = newVmess
|
||||||
|
vmess.subid = subid
|
||||||
|
} else if (indexSplit > 0) {
|
||||||
vmess = ResolveVmess4Kitsunebi(server)
|
vmess = ResolveVmess4Kitsunebi(server)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@@ -378,6 +378,61 @@ object AngConfigManager {
|
|||||||
return 0
|
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 {
|
private fun ResolveVmess4Kitsunebi(server: String): AngConfig.VmessBean {
|
||||||
|
|
||||||
val vmess = AngConfig.VmessBean()
|
val vmess = AngConfig.VmessBean()
|
||||||
@@ -739,7 +794,7 @@ object AngConfigManager {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
val removedSelectedServer =
|
val removedSelectedServer =
|
||||||
if (!TextUtils.isEmpty(subid) && configs.vmess[configs.index].subid.equals(subid))
|
if (!TextUtils.isEmpty(subid) && configs.vmess.count() > 0 && configs.vmess[configs.index].subid.equals(subid))
|
||||||
configs.vmess[configs.index]
|
configs.vmess[configs.index]
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
@@ -839,4 +894,4 @@ object AngConfigManager {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ object AppManagerUtil {
|
|||||||
val apps = ArrayList<AppInfo>()
|
val apps = ArrayList<AppInfo>()
|
||||||
|
|
||||||
for (pkg in packages) {
|
for (pkg in packages) {
|
||||||
if (!pkg.hasInternetPermission) continue
|
if (!pkg.hasInternetPermission && pkg.packageName != "android") continue
|
||||||
|
|
||||||
val applicationInfo = pkg.applicationInfo
|
val applicationInfo = pkg.applicationInfo
|
||||||
|
|
||||||
@@ -40,4 +40,4 @@ object AppManagerUtil {
|
|||||||
val permissions = requestedPermissions
|
val permissions = requestedPermissions
|
||||||
return permissions?.any { it == Manifest.permission.INTERNET } ?: false
|
return permissions?.any { it == Manifest.permission.INTERNET } ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?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>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?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.
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -1,12 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:id="@+id/layout_switch"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -14,16 +7,9 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:src="@mipmap/ic_launcher" />
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/ic_v" />
|
||||||
<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>
|
</LinearLayout>
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
<string name="summary_pref_mux_enabled">开启可能会加速,关闭可能会减少断流</string>
|
<string name="summary_pref_mux_enabled">开启可能会加速,关闭可能会减少断流</string>
|
||||||
|
|
||||||
<string name="title_pref_speed_enabled">启用速度显示</string>
|
<string name="title_pref_speed_enabled">启用速度显示</string>
|
||||||
<string name="summary_pref_speed_enabled">在通知中显示当前速度</string>
|
<string name="summary_pref_speed_enabled">在通知中显示当前速度\n小图标显示流量的路由情况</string>
|
||||||
|
|
||||||
<string name="title_pref_sniffing_enabled">启用流量探测</string>
|
<string name="title_pref_sniffing_enabled">启用流量探测</string>
|
||||||
<string name="summary_pref_sniffing_enabled">流量探测</string>
|
<string name="summary_pref_sniffing_enabled">流量探测</string>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
<string name="summary_pref_mux_enabled">啟用或許會加快網路速度,切換或許會閃爍</string>
|
<string name="summary_pref_mux_enabled">啟用或許會加快網路速度,切換或許會閃爍</string>
|
||||||
|
|
||||||
<string name="title_pref_speed_enabled">啟用速度顯示</string>
|
<string name="title_pref_speed_enabled">啟用速度顯示</string>
|
||||||
<string name="summary_pref_speed_enabled">在通知中顯示當前速度</string>
|
<string name="summary_pref_speed_enabled">在通知中顯示當前速度\n小圖標顯示流量的路由情況</string>
|
||||||
|
|
||||||
<string name="title_pref_sniffing_enabled">啟用流量探測</string>
|
<string name="title_pref_sniffing_enabled">啟用流量探測</string>
|
||||||
<string name="summary_pref_sniffing_enabled">流量探測</string>
|
<string name="summary_pref_sniffing_enabled">流量探測</string>
|
||||||
|
|||||||
@@ -66,4 +66,39 @@
|
|||||||
<item>IPIfNonMatch</item>
|
<item>IPIfNonMatch</item>
|
||||||
<item>IPOnDemand</item>
|
<item>IPOnDemand</item>
|
||||||
</string-array>
|
</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>
|
</resources>
|
||||||
|
|||||||
@@ -84,7 +84,8 @@
|
|||||||
<string name="summary_pref_mux_enabled">Enable maybe speed up network and switch network maybe flash</string>
|
<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="title_pref_speed_enabled">Enable speed display</string>
|
||||||
<string name="summary_pref_speed_enabled">Display current speed in the notification</string>
|
<string name="summary_pref_speed_enabled">Display current speed in the notification.\nNotification icon would change based on
|
||||||
|
usage.</string>
|
||||||
|
|
||||||
<string name="title_pref_sniffing_enabled">Enable Sniffing</string>
|
<string name="title_pref_sniffing_enabled">Enable Sniffing</string>
|
||||||
<string name="summary_pref_sniffing_enabled">Sniffing</string>
|
<string name="summary_pref_sniffing_enabled">Sniffing</string>
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBar.Translucent">
|
||||||
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||||
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#Tue Feb 25 12:40:41 CST 2020
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
|
||||||
Reference in New Issue
Block a user