Format code

This commit is contained in:
2dust committed 2024-08-17 19:40:04 +08:00
1 parent f646eff048
commit 51adca8568
87 files changed
+576 -338

No files matched your search

+3 -6
View File
@@ -68,12 +68,9 @@ android {
"universal"
output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk"
if(versionCodes.containsKey(abi))
{
if (versionCodes.containsKey(abi)) {
output.versionCodeOverride = (1000000 * versionCodes[abi]!!).plus(variant.versionCode)
}
else
{
} else {
return@forEach
}
}
@@ -92,7 +89,7 @@ android {
}
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar","*.jar"))))
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar", "*.jar"))))
testImplementation(libs.junit)
implementation(libs.flexbox)
+36 -20
View File
@@ -8,17 +8,28 @@
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"/>
android:xlargeScreens="true" />
<uses-sdk android:minSdkVersion="21" tools:overrideLibrary="com.blacksquircle.ui.editorkit"/>
<uses-sdk
android:minSdkVersion="21"
tools:overrideLibrary="com.blacksquircle.ui.editorkit" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- https://developer.android.com/about/versions/11/privacy/package-visibility -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
@@ -31,7 +42,7 @@
android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
android:minSdkVersion="34" />
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
@@ -53,12 +64,14 @@
android:theme="@style/AppThemeDayNight.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
@@ -119,12 +132,14 @@
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="v2rayng"/>
<data android:host="install-config"/>
<data android:host="install-sub"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="v2rayng" />
<data android:host="install-config" />
<data android:host="install-sub" />
</intent-filter>
</activity>
<activity
@@ -150,7 +165,8 @@
android:value="vpn" />
</service>
<service android:name=".service.V2RayProxyOnlyService"
<service
android:name=".service.V2RayProxyOnlyService"
android:exported="false"
android:label="@string/app_name"
android:foregroundServiceType="specialUse"
@@ -160,10 +176,10 @@
android:value="proxy" />
</service>
<service android:name=".service.V2RayTestService"
<service
android:name=".service.V2RayTestService"
android:exported="false"
android:process=":RunSoLibV2RayDaemon">
</service>
android:process=":RunSoLibV2RayDaemon"></service>
<receiver
android:exported="true"
@@ -234,7 +250,7 @@
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/cache_paths"/>
android:resource="@xml/cache_paths" />
</provider>
</application>
@@ -16,8 +16,8 @@
package com.v2ray.ang.helper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
/**
* Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
@@ -36,7 +36,6 @@ public interface ItemTouchHelperAdapter {
* @param fromPosition The start position of the moved item.
* @param toPosition Then resolved position of the moved item.
* @return True if the item was moved to the new adapter position.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
@@ -52,7 +51,6 @@ public interface ItemTouchHelperAdapter {
* adjusting the underlying data to reflect this removal.
*
* @param position The position of the item dismissed.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition()
*/
@@ -17,9 +17,10 @@
package com.v2ray.ang.helper;
import android.graphics.Canvas;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.NotNull;
@@ -7,16 +7,13 @@ import androidx.work.WorkManager
import com.tencent.mmkv.MMKV
import com.v2ray.ang.util.Utils
class AngApplication : MultiDexApplication()
{
companion object
{
class AngApplication : MultiDexApplication() {
companion object {
//const val PREF_LAST_VERSION = "pref_last_version"
lateinit var application: AngApplication
}
override fun attachBaseContext(base: Context?)
{
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
application = this
}
@@ -25,8 +22,7 @@ class AngApplication : MultiDexApplication()
.setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg")
.build()
override fun onCreate()
{
override fun onCreate() {
super.onCreate()
// LeakCanary.install(this)
@@ -140,6 +140,7 @@ object AppConfig {
const val RAY_NG_CHANNEL_NAME = "V2rayNG Background Service"
const val SUBSCRIPTION_UPDATE_CHANNEL = "subscription_update_channel"
const val SUBSCRIPTION_UPDATE_CHANNEL_NAME = "Subscription Update Service"
/** Protocols Scheme **/
const val VMESS = "vmess://"
const val CUSTOM = ""
@@ -2,8 +2,10 @@ package com.v2ray.ang.dto
import android.graphics.drawable.Drawable
data class AppInfo(val appName: String,
data class AppInfo(
val appName: String,
val packageName: String,
val appIcon: Drawable,
val isSystemApp: Boolean,
var isSelected: Int)
var isSelected: Int
)
@@ -6,7 +6,7 @@ import com.v2ray.ang.AppConfig
enum class EConfigType(val value: Int, val protocolScheme: String) {
VMESS(1, AppConfig.VMESS),
CUSTOM(2, AppConfig.CUSTOM),
SHADOWSOCKS(3,AppConfig.SHADOWSOCKS),
SHADOWSOCKS(3, AppConfig.SHADOWSOCKS),
SOCKS(4, AppConfig.SOCKS),
VLESS(5, AppConfig.VLESS),
TROJAN(6, AppConfig.TROJAN),
@@ -1,6 +1,6 @@
package com.v2ray.ang.dto
enum class ERoutingMode(val value: String ) {
enum class ERoutingMode(val value: String) {
GLOBAL_PROXY("0"),
BYPASS_LAN("1"),
BYPASS_MAINLAND("2"),
@@ -1,8 +1,8 @@
package com.v2ray.ang.dto
import com.v2ray.ang.AppConfig.TAG_PROXY
import com.v2ray.ang.AppConfig.TAG_BLOCKED
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.AppConfig.TAG_PROXY
import com.v2ray.ang.util.Utils
data class ServerConfig(
@@ -16,26 +16,38 @@ data class ServerConfig(
) {
companion object {
fun create(configType: EConfigType): ServerConfig {
when(configType) {
when (configType) {
EConfigType.VMESS, EConfigType.VLESS ->
return ServerConfig(
configType = configType,
outboundBean = V2rayConfig.OutboundBean(
protocol = configType.name.lowercase(),
settings = V2rayConfig.OutboundBean.OutSettingsBean(
vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
vnext = listOf(
V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())
)
)
),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()
)
)
EConfigType.CUSTOM ->
return ServerConfig(configType = configType)
EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN ->
return ServerConfig(
configType = configType,
outboundBean = V2rayConfig.OutboundBean(
protocol = configType.name.lowercase(),
settings = V2rayConfig.OutboundBean.OutSettingsBean(
servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())
),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()
)
)
EConfigType.WIREGUARD ->
return ServerConfig(
configType = configType,
@@ -44,7 +56,9 @@ data class ServerConfig(
settings = V2rayConfig.OutboundBean.OutSettingsBean(
secretKey = "",
peers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean())
)))
)
)
)
}
}
}
@@ -1,4 +1,6 @@
package com.v2ray.ang.dto
data class ServersCache(val guid: String,
val profile: ProfileItem)
data class ServersCache(
val guid: String,
val profile: ProfileItem
)
@@ -24,7 +24,8 @@ data class V2rayConfig(
var fakedns: Any? = null,
val browserForwarder: Any? = null,
var observatory: Any? = null,
var burstObservatory: Any? = null) {
var burstObservatory: Any? = null
) {
companion object {
const val DEFAULT_PORT = 443
const val DEFAULT_SECURITY = "auto"
@@ -36,10 +37,12 @@ data class V2rayConfig(
const val HTTP = "http"
}
data class LogBean(val access: String,
data class LogBean(
val access: String,
val error: String,
var loglevel: String?,
val dnsLog: Boolean? = null)
val dnsLog: Boolean? = null
)
data class InboundBean(
var tag: String,
@@ -49,30 +52,38 @@ data class V2rayConfig(
val settings: Any? = null,
val sniffing: SniffingBean?,
val streamSettings: Any? = null,
val allocate: Any? = null) {
val allocate: Any? = null
) {
data class InSettingsBean(val auth: String? = null,
data class InSettingsBean(
val auth: String? = null,
val udp: Boolean? = null,
val userLevel: Int? = null,
val address: String? = null,
val port: Int? = null,
val network: String? = null)
val network: String? = null
)
data class SniffingBean(var enabled: Boolean,
data class SniffingBean(
var enabled: Boolean,
val destOverride: ArrayList<String>,
val metadataOnly: Boolean? = null,
var routeOnly: Boolean? = null)
var routeOnly: Boolean? = null
)
}
data class OutboundBean(var tag: String = "proxy",
data class OutboundBean(
var tag: String = "proxy",
var protocol: String,
var settings: OutSettingsBean? = null,
var streamSettings: StreamSettingsBean? = null,
val proxySettings: Any? = null,
val sendThrough: String? = null,
var mux: MuxBean? = MuxBean(false)) {
var mux: MuxBean? = MuxBean(false)
) {
data class OutSettingsBean(var vnext: List<VnextBean>? = null,
data class OutSettingsBean(
var vnext: List<VnextBean>? = null,
var fragment: FragmentBean? = null,
var servers: List<ServersBean>? = null,
/*Blackhole*/
@@ -91,26 +102,33 @@ data class V2rayConfig(
var secretKey: String? = null,
val peers: List<WireGuardBean>? = null,
var reserved: List<Int>? = null,
var mtu :Int? = null
var mtu: Int? = null
) {
data class VnextBean(var address: String = "",
data class VnextBean(
var address: String = "",
var port: Int = DEFAULT_PORT,
var users: List<UsersBean>) {
var users: List<UsersBean>
) {
data class UsersBean(var id: String = "",
data class UsersBean(
var id: String = "",
var alterId: Int? = null,
var security: String = DEFAULT_SECURITY,
var level: Int = DEFAULT_LEVEL,
var encryption: String = "",
var flow: String = "")
var flow: String = ""
)
}
data class FragmentBean(var packets: String? = null,
data class FragmentBean(
var packets: String? = null,
var length: String? = null,
var interval: String? = null)
var interval: String? = null
)
data class ServersBean(var address: String = "",
data class ServersBean(
var address: String = "",
var method: String = "chacha20-poly1305",
var ota: Boolean = false,
var password: String = "",
@@ -119,21 +137,27 @@ data class V2rayConfig(
val email: String? = null,
var flow: String? = null,
val ivCheck: Boolean? = null,
var users: List<SocksUsersBean>? = null) {
var users: List<SocksUsersBean>? = null
) {
data class SocksUsersBean(var user: String = "",
data class SocksUsersBean(
var user: String = "",
var pass: String = "",
var level: Int = DEFAULT_LEVEL)
var level: Int = DEFAULT_LEVEL
)
}
data class Response(var type: String)
data class WireGuardBean(var publicKey: String = "",
var endpoint: String = "")
data class WireGuardBean(
var publicKey: String = "",
var endpoint: String = ""
)
}
data class StreamSettingsBean(var network: String = DEFAULT_NETWORK,
data class StreamSettingsBean(
var network: String = DEFAULT_NETWORK,
var security: String = "",
var tcpSettings: TcpSettingsBean? = null,
var kcpSettings: KcpSettingsBean? = null,
@@ -149,27 +173,36 @@ data class V2rayConfig(
var sockopt: SockoptBean? = null
) {
data class TcpSettingsBean(var header: HeaderBean = HeaderBean(),
val acceptProxyProtocol: Boolean? = null) {
data class HeaderBean(var type: String = "none",
data class TcpSettingsBean(
var header: HeaderBean = HeaderBean(),
val acceptProxyProtocol: Boolean? = null
) {
data class HeaderBean(
var type: String = "none",
var request: RequestBean? = null,
var response: Any? = null) {
data class RequestBean(var path: List<String> = ArrayList(),
var response: Any? = null
) {
data class RequestBean(
var path: List<String> = ArrayList(),
var headers: HeadersBean = HeadersBean(),
val version: String? = null,
val method: String? = null) {
data class HeadersBean(var Host: List<String>? = ArrayList(),
val method: String? = null
) {
data class HeadersBean(
var Host: List<String>? = ArrayList(),
@SerializedName("User-Agent")
val userAgent: List<String>? = null,
@SerializedName("Accept-Encoding")
val acceptEncoding: List<String>? = null,
val Connection: List<String>? = null,
val Pragma: String? = null)
val Pragma: String? = null
)
}
}
}
data class KcpSettingsBean(var mtu: Int = 1350,
data class KcpSettingsBean(
var mtu: Int = 1350,
var tti: Int = 50,
var uplinkCapacity: Int = 12,
var downlinkCapacity: Int = 100,
@@ -177,37 +210,50 @@ data class V2rayConfig(
var readBufferSize: Int = 1,
var writeBufferSize: Int = 1,
var header: HeaderBean = HeaderBean(),
var seed: String? = null) {
var seed: String? = null
) {
data class HeaderBean(var type: String = "none")
}
data class WsSettingsBean(var path: String = "",
data class WsSettingsBean(
var path: String = "",
var headers: HeadersBean = HeadersBean(),
val maxEarlyData: Int? = null,
val useBrowserForwarding: Boolean? = null,
val acceptProxyProtocol: Boolean? = null) {
val acceptProxyProtocol: Boolean? = null
) {
data class HeadersBean(var Host: String = "")
}
data class HttpupgradeSettingsBean(var path: String = "",
data class HttpupgradeSettingsBean(
var path: String = "",
var host: String = "",
val acceptProxyProtocol: Boolean? = null)
val acceptProxyProtocol: Boolean? = null
)
data class SplithttpSettingsBean(var path: String = "",
data class SplithttpSettingsBean(
var path: String = "",
var host: String = "",
val maxUploadSize: Int? = null,
val maxConcurrentUploads: Int? = null)
data class HttpSettingsBean(var host: List<String> = ArrayList(),
var path: String = "")
val maxConcurrentUploads: Int? = null
)
data class SockoptBean(var TcpNoDelay: Boolean? = null,
data class HttpSettingsBean(
var host: List<String> = ArrayList(),
var path: String = ""
)
data class SockoptBean(
var TcpNoDelay: Boolean? = null,
var tcpKeepAliveIdle: Int? = null,
var tcpFastOpen: Boolean? = null,
var tproxy: String? = null,
var mark: Int? = null,
var dialerProxy: String? = null)
var dialerProxy: String? = null
)
data class TlsSettingsBean(var allowInsecure: Boolean = false,
data class TlsSettingsBean(
var allowInsecure: Boolean = false,
var serverName: String = "",
val alpn: List<String>? = null,
val minVersion: String? = null,
@@ -222,24 +268,30 @@ data class V2rayConfig(
val show: Boolean = false,
var publicKey: String? = null,
var shortId: String? = null,
var spiderX: String? = null)
var spiderX: String? = null
)
data class QuicSettingBean(var security: String = "none",
data class QuicSettingBean(
var security: String = "none",
var key: String = "",
var header: HeaderBean = HeaderBean()) {
var header: HeaderBean = HeaderBean()
) {
data class HeaderBean(var type: String = "none")
}
data class GrpcSettingsBean(var serviceName: String = "",
data class GrpcSettingsBean(
var serviceName: String = "",
var authority: String? = null,
var multiMode: Boolean? = null,
var idle_timeout: Int? = null,
var health_check_timeout: Int? = null
)
fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?,
fun populateTransportSettings(
transport: String, headerType: String?, host: String?, path: String?, seed: String?,
quicSecurity: String?, key: String?, mode: String?, serviceName: String?,
authority: String?): String {
authority: String?
): String {
var sni = ""
network = transport
when (network) {
@@ -249,8 +301,8 @@ data class V2rayConfig(
tcpSetting.header.type = HTTP
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) {
val requestObj = TcpSettingsBean.HeaderBean.RequestBean()
requestObj.headers.Host = (host .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
requestObj.path = (path .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
requestObj.headers.Host = (host.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
requestObj.path = (path.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
tcpSetting.header.request = requestObj
sni = requestObj.headers.Host?.getOrNull(0) ?: sni
}
@@ -260,6 +312,7 @@ data class V2rayConfig(
}
tcpSettings = tcpSetting
}
"kcp" -> {
val kcpsetting = KcpSettingsBean()
kcpsetting.header.type = headerType ?: "none"
@@ -270,6 +323,7 @@ data class V2rayConfig(
}
kcpSettings = kcpsetting
}
"ws" -> {
val wssetting = WsSettingsBean()
wssetting.headers.Host = host.orEmpty()
@@ -277,6 +331,7 @@ data class V2rayConfig(
wssetting.path = path ?: "/"
wsSettings = wssetting
}
"httpupgrade" -> {
val httpupgradeSetting = HttpupgradeSettingsBean()
httpupgradeSetting.host = host.orEmpty()
@@ -284,6 +339,7 @@ data class V2rayConfig(
httpupgradeSetting.path = path ?: "/"
httpupgradeSettings = httpupgradeSetting
}
"splithttp" -> {
val splithttpSetting = SplithttpSettingsBean()
splithttpSetting.host = host.orEmpty()
@@ -291,14 +347,16 @@ data class V2rayConfig(
splithttpSetting.path = path ?: "/"
splithttpSettings = splithttpSetting
}
"h2", "http" -> {
network = "h2"
val h2Setting = HttpSettingsBean()
h2Setting.host = (host .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
h2Setting.host = (host.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
sni = h2Setting.host.getOrNull(0) ?: sni
h2Setting.path = path ?: "/"
httpSettings = h2Setting
}
"quic" -> {
val quicsetting = QuicSettingBean()
quicsetting.security = quicSecurity ?: "none"
@@ -306,6 +364,7 @@ data class V2rayConfig(
quicsetting.header.type = headerType ?: "none"
quicSettings = quicsetting
}
"grpc" -> {
val grpcSetting = GrpcSettingsBean()
grpcSetting.multiMode = mode == "multi"
@@ -320,8 +379,10 @@ data class V2rayConfig(
return sni
}
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?,
publicKey: String?, shortId: String?, spiderX: String?) {
fun populateTlsSettings(
streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?,
publicKey: String?, shortId: String?, spiderX: String?
) {
security = streamSecurity
val tlsSetting = TlsSettingsBean(
allowInsecure = allowInsecure,
@@ -342,18 +403,22 @@ data class V2rayConfig(
}
}
data class MuxBean(var enabled: Boolean,
data class MuxBean(
var enabled: Boolean,
var concurrency: Int = 8,
var xudpConcurrency: Int = 8,
var xudpProxyUDP443: String = "",)
var xudpProxyUDP443: String = "",
)
fun getServerAddress(): String? {
if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) {
|| protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.address
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) {
|| protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.address
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringBeforeLast(":")
@@ -363,11 +428,13 @@ data class V2rayConfig(
fun getServerPort(): Int? {
if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) {
|| protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.port
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) {
|| protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.port
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringAfterLast(":")?.toInt()
@@ -377,10 +444,12 @@ data class V2rayConfig(
fun getPassword(): String? {
if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) {
|| protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.users?.get(0)?.id
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) {
|| protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.password
} else if (protocol.equals(EConfigType.SOCKS.name, true)) {
return settings?.servers?.get(0)?.users?.get(0)?.pass
@@ -403,57 +472,82 @@ data class V2rayConfig(
if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)
|| protocol.equals(EConfigType.SHADOWSOCKS.name, true)) {
|| protocol.equals(EConfigType.SHADOWSOCKS.name, true)
) {
val transport = streamSettings?.network ?: return null
return when (transport) {
"tcp" -> {
val tcpSetting = streamSettings?.tcpSettings ?: return null
listOf(tcpSetting.header.type,
listOf(
tcpSetting.header.type,
tcpSetting.header.request?.headers?.Host?.joinToString().orEmpty(),
tcpSetting.header.request?.path?.joinToString().orEmpty())
tcpSetting.header.request?.path?.joinToString().orEmpty()
)
}
"kcp" -> {
val kcpSetting = streamSettings?.kcpSettings ?: return null
listOf(kcpSetting.header.type,
listOf(
kcpSetting.header.type,
"",
kcpSetting.seed.orEmpty())
kcpSetting.seed.orEmpty()
)
}
"ws" -> {
val wsSetting = streamSettings?.wsSettings ?: return null
listOf("",
listOf(
"",
wsSetting.headers.Host,
wsSetting.path)
wsSetting.path
)
}
"httpupgrade" -> {
val httpupgradeSetting = streamSettings?.httpupgradeSettings ?: return null
listOf("",
listOf(
"",
httpupgradeSetting.host,
httpupgradeSetting.path)
httpupgradeSetting.path
)
}
"splithttp" -> {
val splithttpSetting = streamSettings?.splithttpSettings ?: return null
listOf("",
listOf(
"",
splithttpSetting.host,
splithttpSetting.path)
splithttpSetting.path
)
}
"h2" -> {
val h2Setting = streamSettings?.httpSettings ?: return null
listOf("",
listOf(
"",
h2Setting.host.joinToString(),
h2Setting.path)
h2Setting.path
)
}
"quic" -> {
val quicSetting = streamSettings?.quicSettings ?: return null
listOf(quicSetting.header.type,
listOf(
quicSetting.header.type,
quicSetting.security,
quicSetting.key)
quicSetting.key
)
}
"grpc" -> {
val grpcSetting = streamSettings?.grpcSettings ?: return null
listOf(if (grpcSetting.multiMode == true) "multi" else "gun",
listOf(
if (grpcSetting.multiMode == true) "multi" else "gun",
grpcSetting.authority.orEmpty(),
grpcSetting.serviceName)
grpcSetting.serviceName
)
}
else -> null
}
}
@@ -461,24 +555,29 @@ data class V2rayConfig(
}
}
data class DnsBean(var servers: ArrayList<Any>? = null,
data class DnsBean(
var servers: ArrayList<Any>? = null,
var hosts: Map<String, Any>? = null,
val clientIp: String? = null,
val disableCache: Boolean? = null,
val queryStrategy: String? = null,
val tag: String? = null
) {
data class ServersBean(var address: String = "",
data class ServersBean(
var address: String = "",
var port: Int? = null,
var domains: List<String>? = null,
var expectIPs: List<String>? = null,
val clientIp: String? = null)
val clientIp: String? = null
)
}
data class RoutingBean(var domainStrategy: String,
data class RoutingBean(
var domainStrategy: String,
var domainMatcher: String? = null,
var rules: ArrayList<RulesBean>,
val balancers: List<Any>? = null) {
val balancers: List<Any>? = null
) {
data class RulesBean(
var ip: ArrayList<String>? = null,
@@ -497,8 +596,10 @@ data class V2rayConfig(
)
}
data class PolicyBean(var levels: Map<String, LevelBean>,
var system: Any? = null) {
data class PolicyBean(
var levels: Map<String, LevelBean>,
var system: Any? = null
) {
data class LevelBean(
var handshake: Int? = null,
var connIdle: Int? = null,
@@ -506,14 +607,17 @@ data class V2rayConfig(
var downlinkOnly: Int? = null,
val statsUserUplink: Boolean? = null,
val statsUserDownlink: Boolean? = null,
var bufferSize: Int? = null)
var bufferSize: Int? = null
)
}
data class FakednsBean(var ipPool: String = "198.18.0.0/15",
var poolSize: Int = 10000) // roughly 10 times smaller than total ip pool
data class FakednsBean(
var ipPool: String = "198.18.0.0/15",
var poolSize: Int = 10000
) // roughly 10 times smaller than total ip pool
fun getProxyOutbound(): OutboundBean? {
outbounds?.forEach { outbound ->
outbounds.forEach { outbound ->
EConfigType.entries.forEach {
if (outbound.protocol.equals(it.name, true)) {
return outbound
@@ -1,6 +1,7 @@
package com.v2ray.ang.dto
data class VmessQRCode(var v: String = "",
data class VmessQRCode(
var v: String = "",
var ps: String = "",
var add: String = "",
var port: String = "",
@@ -14,4 +15,5 @@ data class VmessQRCode(var v: String = "",
var tls: String = "",
var sni: String = "",
var alpn: String = "",
var fp: String = "")
var fp: String = ""
)
@@ -1,8 +1,6 @@
package com.v2ray.ang.extension
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.widget.Toast
import com.v2ray.ang.AngApplication
@@ -35,7 +35,8 @@ class WidgetProvider : AppWidgetProvider() {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
})
}
)
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
if (isRunning) {
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stop_24dp)
@@ -65,12 +66,17 @@ class WidgetProvider : AppWidgetProvider() {
AppWidgetManager.getInstance(context)?.let { manager ->
when (intent.getIntExtra("key", 0)) {
AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> {
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
true)
updateWidgetBackground(
context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
true
)
}
AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> {
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
false)
updateWidgetBackground(
context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
false
)
}
}
}
@@ -58,6 +58,7 @@ class QSTileService : TileService() {
Tile.STATE_INACTIVE -> {
Utils.startVServiceFromToggle(this)
}
Tile.STATE_ACTIVE -> {
Utils.stopVService(this)
}
@@ -74,15 +75,19 @@ class QSTileService : TileService() {
AppConfig.MSG_STATE_RUNNING -> {
context?.setState(Tile.STATE_ACTIVE)
}
AppConfig.MSG_STATE_NOT_RUNNING -> {
context?.setState(Tile.STATE_INACTIVE)
}
AppConfig.MSG_STATE_START_SUCCESS -> {
context?.setState(Tile.STATE_ACTIVE)
}
AppConfig.MSG_STATE_START_FAILURE -> {
context?.setState(Tile.STATE_INACTIVE)
}
AppConfig.MSG_STATE_STOP_SUCCESS -> {
context?.setState(Tile.STATE_INACTIVE)
}
@@ -21,7 +21,6 @@ import com.v2ray.ang.util.Utils
object SubscriptionUpdater {
class UpdateTask(context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
@@ -27,14 +27,14 @@ import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils
import com.v2ray.ang.util.V2rayConfigUtil
import go.Seq
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import libv2ray.Libv2ray
import libv2ray.V2RayPoint
import libv2ray.V2RayVPNServiceSupportsSet
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import java.lang.ref.SoftReference
import kotlin.math.min
@@ -206,18 +206,23 @@ object V2RayServiceManager {
MessageUtil.sendMsg2UI(serviceControl.getService(), AppConfig.MSG_STATE_NOT_RUNNING, "")
}
}
AppConfig.MSG_UNREGISTER_CLIENT -> {
// nothing to do
}
AppConfig.MSG_STATE_START -> {
// nothing to do
}
AppConfig.MSG_STATE_STOP -> {
serviceControl.stopService()
}
AppConfig.MSG_STATE_RESTART -> {
startV2rayPoint()
}
AppConfig.MSG_MEASURE_DELAY -> {
measureV2rayDelay()
}
@@ -228,6 +233,7 @@ object V2RayServiceManager {
Log.d(ANG_PACKAGE, "SCREEN_OFF, stop querying stats")
stopSpeedNotification()
}
Intent.ACTION_SCREEN_ON -> {
Log.d(ANG_PACKAGE, "SCREEN_ON, start querying stats")
startSpeedNotification()
@@ -270,25 +276,29 @@ object V2RayServiceManager {
private fun showNotification() {
val service = serviceControl?.get()?.getService() ?: return
val startMainIntent = Intent(service, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(service,
val contentPendingIntent = PendingIntent.getActivity(
service,
NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
})
}
)
val stopV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
stopV2RayIntent.`package` = ANG_PACKAGE
stopV2RayIntent.putExtra("key", AppConfig.MSG_STATE_STOP)
val stopV2RayPendingIntent = PendingIntent.getBroadcast(service,
val stopV2RayPendingIntent = PendingIntent.getBroadcast(
service,
NOTIFICATION_PENDING_INTENT_STOP_V2RAY, stopV2RayIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
})
}
)
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -307,9 +317,11 @@ object V2RayServiceManager {
.setShowWhen(false)
.setOnlyAlertOnce(true)
.setContentIntent(contentPendingIntent)
.addAction(R.drawable.ic_delete_24dp,
.addAction(
R.drawable.ic_delete_24dp,
service.getString(R.string.notification_action_stop_v2ray),
stopV2RayPendingIntent)
stopV2RayPendingIntent
)
//.build()
//mBuilder?.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) //取消震动,铃声其他都不好使
@@ -321,8 +333,10 @@ object V2RayServiceManager {
private fun createNotificationChannel(): String {
val channelId = AppConfig.RAY_NG_CHANNEL_ID
val channelName = AppConfig.RAY_NG_CHANNEL_NAME
val chan = NotificationChannel(channelId,
channelName, NotificationManager.IMPORTANCE_HIGH)
val chan = NotificationChannel(
channelId,
channelName, NotificationManager.IMPORTANCE_HIGH
)
chan.lightColor = Color.DKGRAY
chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
@@ -364,7 +378,8 @@ object V2RayServiceManager {
private fun startSpeedNotification() {
if (mDisposable == null &&
v2rayPoint.isRunning &&
settingsStorage?.decodeBool(AppConfig.PREF_SPEED_ENABLED) == true) {
settingsStorage?.decodeBool(AppConfig.PREF_SPEED_ENABLED) == true
) {
var lastZeroSpeed = false
val outboundTags = currentConfig?.getAllOutboundTags()
outboundTags?.remove(TAG_DIRECT)
@@ -390,8 +405,10 @@ object V2RayServiceManager {
if (proxyTotal == 0L) {
appendSpeedString(text, outboundTags?.firstOrNull(), 0.0, 0.0)
}
appendSpeedString(text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds)
appendSpeedString(
text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds
)
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
}
lastZeroSpeed = zeroSpeed
@@ -10,7 +10,11 @@ import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.SpeedtestUtil
import com.v2ray.ang.util.Utils
import go.Seq
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.launch
import libv2ray.Libv2ray
import java.util.concurrent.Executors
@@ -32,6 +36,7 @@ class V2RayTestService : Service() {
MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(contentPair.first, result))
}
}
MSG_MEASURE_CONFIG_CANCEL -> {
realTestScope.coroutineContext[Job]?.cancelChildren()
}
@@ -4,7 +4,13 @@ import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.*
import android.net.ConnectivityManager
import android.net.LocalSocket
import android.net.LocalSocketAddress
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.VpnService
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.StrictMode
@@ -19,7 +25,6 @@ import com.v2ray.ang.util.MyContextWrapper
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.lang.ref.SoftReference
@@ -197,14 +202,16 @@ class V2RayVpnService : VpnService(), ServiceControl {
private fun runTun2socks() {
val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT), AppConfig.PORT_SOCKS.toInt())
val cmd = arrayListOf(File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
val cmd = arrayListOf(
File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
"--netif-ipaddr", PRIVATE_VLAN4_ROUTER,
"--netif-netmask", "255.255.255.252",
"--socks-server-addr", "127.0.0.1:${socksPort}",
"--tunmtu", VPN_MTU.toString(),
"--sock-path", "sock_path",//File(applicationContext.filesDir, "sock_path").absolutePath,
"--enable-udprelay",
"--loglevel", "notice")
"--loglevel", "notice"
)
if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) {
cmd.add("--netif-ip6addr")
@@ -224,11 +231,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
.directory(applicationContext.filesDir)
.start()
Thread(Runnable {
Log.d(packageName,"$TUN2SOCKS check")
Log.d(packageName, "$TUN2SOCKS check")
process.waitFor()
Log.d(packageName,"$TUN2SOCKS exited")
Log.d(packageName, "$TUN2SOCKS exited")
if (isRunning) {
Log.d(packageName,"$TUN2SOCKS restart")
Log.d(packageName, "$TUN2SOCKS restart")
runTun2socks()
}
}).start()
@@ -275,7 +282,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
// val emptyInfo = VpnNetworkInfo()
// val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo)
// saveVpnNetworkInfo(configName, info)
isRunning = false;
isRunning = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
connectivity.unregisterNetworkCallback(defaultNetworkCallback)
@@ -21,7 +21,7 @@ import java.text.SimpleDateFormat
import java.util.Locale
class AboutActivity : BaseActivity() {
private val binding by lazy {ActivityAboutBinding.inflate(layoutInflater)}
private val binding by lazy { ActivityAboutBinding.inflate(layoutInflater) }
private val extDir by lazy { File(Utils.backupPath(this)) }
override fun onCreate(savedInstanceState: Bundle?) {
@@ -28,6 +28,7 @@ abstract class BaseActivity : AppCompatActivity() {
onBackPressedDispatcher.onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -84,10 +84,12 @@ class LogcatActivity : BaseActivity() {
toast(R.string.toast_success)
true
}
R.id.clear_all -> {
logcat(true)
true
}
else -> super.onOptionsItemSelected(item)
}
}
@@ -32,7 +32,6 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityMainBinding
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.isNetworkConnected
import com.v2ray.ang.extension.toast
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.service.V2RayServiceManager
@@ -29,8 +29,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import java.util.concurrent.TimeUnit
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>()
, ItemTouchHelperAdapter {
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>(), ItemTouchHelperAdapter {
companion object {
private const val VIEW_TYPE_ITEM = 1
private const val VIEW_TYPE_FOOTER = 2
@@ -95,7 +94,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
}
}
val strState = "${profile?.server?.dropLast(3)}*** : ${profile?.serverPort}"
val strState = "${profile.server?.dropLast(3)}*** : ${profile.serverPort}"
holder.itemMainBinding.tvStatistics.text = strState
@@ -21,10 +21,10 @@ import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.util.AppManagerUtil
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.Collator
class PerAppProxyActivity : BaseActivity() {
@@ -218,18 +218,22 @@ class PerAppProxyActivity : BaseActivity() {
it.notifyDataSetChanged()
true
} ?: false
R.id.select_proxy_app -> {
selectProxyApp()
true
}
R.id.import_proxy_app -> {
importProxyApp()
true
}
R.id.export_proxy_app -> {
exportProxyApp()
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -324,7 +328,8 @@ class PerAppProxyActivity : BaseActivity() {
if (key.isNotEmpty()) {
appsAll?.forEach {
if (it.appName.uppercase().indexOf(key) >= 0
|| it.packageName.uppercase().indexOf(key) >= 0) {
|| it.packageName.uppercase().indexOf(key) >= 0
) {
apps.add(it)
}
}
@@ -1,13 +1,12 @@
package com.v2ray.ang.ui
import android.view.LayoutInflater
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ItemRecyclerBypassListBinding
import com.v2ray.ang.dto.AppInfo
import java.util.*
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) :
RecyclerView.Adapter<PerAppProxyAdapter.BaseViewHolder>() {
@@ -34,8 +33,10 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
return when (viewType) {
VIEW_TYPE_HEADER -> {
val view = View(ctx)
view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0)
view.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0
)
BaseViewHolder(view)
}
// VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
@@ -1,10 +1,10 @@
package com.v2ray.ang.ui
import android.os.Bundle
import com.v2ray.ang.R
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayoutMediator
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityRoutingSettingsBinding
class RoutingSettingsActivity : BaseActivity() {
@@ -1,15 +1,19 @@
package com.v2ray.ang.ui
import android.Manifest
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.*
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.tbruyelle.rxpermissions3.RxPermissions
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
@@ -24,14 +28,17 @@ import kotlinx.coroutines.launch
class RoutingSettingsFragment : Fragment() {
private val binding by lazy { FragmentRoutingSettingsBinding.inflate(layoutInflater) }
companion object {
private const val routing_arg = "routing_arg"
}
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
return binding.root// inflater.inflate(R.layout.fragment_routing_settings, container, false)
}
@@ -63,22 +70,27 @@ class RoutingSettingsFragment : Fragment() {
saveRouting()
true
}
R.id.del_routing -> {
binding.etRoutingContent.text = null
true
}
R.id.scan_replace -> {
scanQRcode(true)
true
}
R.id.scan_append -> {
scanQRcode(false)
true
}
R.id.default_rules -> {
setDefaultRules()
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -130,9 +142,11 @@ class RoutingSettingsFragment : Fragment() {
AppConfig.PREF_V2RAY_ROUTING_AGENT -> {
tag = AppConfig.TAG_PROXY
}
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
tag = AppConfig.TAG_DIRECT
}
AppConfig.PREF_V2RAY_ROUTING_BLOCKED -> {
tag = AppConfig.TAG_BLOCKED
}
@@ -1,9 +1,9 @@
package com.v2ray.ang.ui
import com.v2ray.ang.R
import com.v2ray.ang.util.Utils
import android.os.Bundle
import com.v2ray.ang.R
import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
class ScSwitchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -1,11 +1,10 @@
package com.v2ray.ang.ui
import android.Manifest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
@@ -20,7 +19,7 @@ import io.github.g00fy2.quickie.QRResult
import io.github.g00fy2.quickie.ScanCustomCode
import io.github.g00fy2.quickie.config.ScannerConfig
class ScannerActivity : BaseActivity(){
class ScannerActivity : BaseActivity() {
private val scanQrCode = registerForActivityResult(ScanCustomCode(), ::handleResult)
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
@@ -33,7 +32,7 @@ class ScannerActivity : BaseActivity(){
}
}
private fun launchScan(){
private fun launchScan() {
scanQrCode.launch(
ScannerConfig.build {
setHapticSuccessFeedback(true) // enable (default) or disable haptic feedback when a barcode was detected
@@ -44,7 +43,7 @@ class ScannerActivity : BaseActivity(){
}
private fun handleResult(result: QRResult) {
if (result is QRResult.QRSuccess ) {
if (result is QRResult.QRSuccess) {
finished(result.content.rawValue.orEmpty())
} else {
finish()
@@ -54,7 +53,7 @@ class ScannerActivity : BaseActivity(){
private fun finished(text: String) {
val intent = Intent()
intent.putExtra("SCAN_RESULT", text)
setResult(AppCompatActivity.RESULT_OK, intent)
setResult(RESULT_OK, intent)
finish()
}
@@ -68,6 +67,7 @@ class ScannerActivity : BaseActivity(){
launchScan()
true
}
R.id.select_photo -> {
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES
@@ -88,6 +88,7 @@ class ScannerActivity : BaseActivity(){
}
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -109,7 +109,7 @@ class ServerCustomConfigActivity : BaseActivity() {
MmkvManager.removeServer(editGuid)
finish()
}
.setNegativeButton(android.R.string.no) {_, _ ->
.setNegativeButton(android.R.string.no) { _, _ ->
// do nothing
}
.show()
@@ -139,10 +139,12 @@ class ServerCustomConfigActivity : BaseActivity() {
deleteServer()
true
}
R.id.save_config -> {
saveServer()
true
}
else -> super.onOptionsItemSelected(item)
}
}
@@ -198,7 +198,8 @@ class SettingsActivity : BaseActivity() {
fragmentInterval?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")
autoUpdateCheck?.isChecked = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
autoUpdateInterval?.summary = settingsStorage.decodeString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
autoUpdateInterval?.summary =
settingsStorage.decodeString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL, AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
autoUpdateInterval?.isEnabled = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
socksPort?.summary = settingsStorage.decodeString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
@@ -350,12 +351,15 @@ class SettingsActivity : BaseActivity() {
updateFragmentInterval(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20"))
}
}
private fun updateFragmentPackets(value: String?) {
fragmentPackets?.summary = value.toString()
}
private fun updateFragmentLength(value: String?) {
fragmentLength?.summary = value.toString()
}
private fun updateFragmentInterval(value: String?) {
fragmentInterval?.summary = value.toString()
}
@@ -18,7 +18,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class SubEditActivity : BaseActivity() {
private val binding by lazy {ActivitySubEditBinding.inflate(layoutInflater)}
private val binding by lazy { ActivitySubEditBinding.inflate(layoutInflater) }
var del_config: MenuItem? = null
var save_config: MenuItem? = null
@@ -108,7 +108,7 @@ class SubEditActivity : BaseActivity() {
}
}
}
.setNegativeButton(android.R.string.no) {_, _ ->
.setNegativeButton(android.R.string.no) { _, _ ->
// do nothing
}
.show()
@@ -133,10 +133,12 @@ class SubEditActivity : BaseActivity() {
deleteServer()
true
}
R.id.save_config -> {
saveServer()
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -1,18 +1,16 @@
package com.v2ray.ang.ui
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ListView
import java.util.ArrayList
import com.v2ray.ang.R
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ListView
import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityTaskerBinding
import com.v2ray.ang.util.MmkvManager
@@ -39,8 +37,10 @@ class TaskerActivity : BaseActivity() {
lstGuid.add(key)
}
}
val adapter = ArrayAdapter(this,
android.R.layout.simple_list_item_single_choice, lstData)
val adapter = ArrayAdapter(
this,
android.R.layout.simple_list_item_single_choice, lstData
)
listview = findViewById<View>(R.id.listview) as ListView
listview?.adapter = adapter
@@ -88,7 +88,7 @@ class TaskerActivity : BaseActivity() {
intent.putExtra(AppConfig.TASKER_EXTRA_BUNDLE, extraBundle)
intent.putExtra(AppConfig.TASKER_EXTRA_STRING_BLURB, blurb)
setResult(AppCompatActivity.RESULT_OK, intent)
setResult(RESULT_OK, intent)
finish()
}
@@ -103,10 +103,12 @@ class TaskerActivity : BaseActivity() {
R.id.del_config -> {
true
}
R.id.save_config -> {
confirmFinish()
true
}
else -> super.onOptionsItemSelected(item)
}
@@ -83,6 +83,7 @@ class UserAssetActivity : BaseActivity() {
startActivity(intent)
true
}
R.id.download_file -> {
downloadGeoFiles()
true
@@ -237,15 +238,18 @@ class UserAssetActivity : BaseActivity() {
conn?.disconnect()
}
}
private fun addBuiltInGeoItems(assets: List<Pair<String, AssetUrlItem>>): List<Pair<String, AssetUrlItem>> {
val list = mutableListOf<Pair<String, AssetUrlItem>>()
builtInGeoFiles
.filter { geoFile -> assets.none { it.second.remarks == geoFile } }
.forEach {
list.add(Utils.getUuid() to AssetUrlItem(
list.add(
Utils.getUuid() to AssetUrlItem(
it,
AppConfig.GeoUrl + it
))
)
)
}
return list + assets
@@ -257,14 +261,15 @@ class UserAssetActivity : BaseActivity() {
ItemRecyclerUserAssetBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false)
false
)
)
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: UserAssetViewHolder, position: Int) {
var assets = MmkvManager.decodeAssetUrls();
assets = addBuiltInGeoItems(assets);
var assets = MmkvManager.decodeAssetUrls()
assets = addBuiltInGeoItems(assets)
val item = assets.getOrNull(position) ?: return
// file with name == item.second.remarks
val file = extDir.listFiles()?.find { it.name == item.second.remarks }
@@ -300,8 +305,8 @@ class UserAssetActivity : BaseActivity() {
}
override fun getItemCount(): Int {
var assets = MmkvManager.decodeAssetUrls();
assets = addBuiltInGeoItems(assets);
var assets = MmkvManager.decodeAssetUrls()
assets = addBuiltInGeoItems(assets)
return assets.size
}
}
@@ -112,7 +112,7 @@ class UserAssetUrlActivity : BaseActivity() {
MmkvManager.removeAssetUrl(editAssetId)
finish()
}
.setNegativeButton(android.R.string.no) {_, _ ->
.setNegativeButton(android.R.string.no) { _, _ ->
// do nothing
}
.show()
@@ -137,10 +137,12 @@ class UserAssetUrlActivity : BaseActivity() {
deleteServer()
true
}
R.id.save_config -> {
saveServer()
true
}
else -> super.onOptionsItemSelected(item)
}
}
@@ -140,7 +140,7 @@ object Utils {
}
fun getVpnDnsServers(): List<String> {
val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS)?:AppConfig.DNS_VPN
val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS) ?: AppConfig.DNS_VPN
return vpnDns.split(",").filter { isPureIpAddress(it) }
// allow empty, in that case dns will use system default
}
@@ -204,7 +204,8 @@ object Utils {
}
fun isIpv4Address(value: String): Boolean {
val regV4 = Regex("^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$")
val regV4 =
Regex("^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$")
return regV4.matches(value)
}
@@ -214,7 +215,8 @@ object Utils {
addr = addr.drop(1)
addr = addr.dropLast(addr.count() - addr.lastIndexOf("]"))
}
val regV6 = Regex("^((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7}$")
val regV6 =
Regex("^((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7}$")
return regV6.matches(addr)
}
@@ -300,8 +302,7 @@ object Utils {
* readTextFromAssets
*/
fun readTextFromAssets(context: Context?, fileName: String): String {
if(context == null)
{
if (context == null) {
return ""
}
val content = context.assets.open(fileName).bufferedReader().use {
@@ -370,8 +371,10 @@ object Utils {
conn.setRequestProperty("Connection", "close")
conn.setRequestProperty("User-agent", "v2rayNG/${BuildConfig.VERSION_NAME}")
url.userInfo?.let {
conn.setRequestProperty("Authorization",
"Basic ${encode(urlDecode(it))}")
conn.setRequestProperty(
"Authorization",
"Basic ${encode(urlDecode(it))}"
)
}
conn.useCaches = false
return conn.inputStream.use {
@@ -393,7 +396,7 @@ object Utils {
}
fun getIpv6Address(address: String?): String {
if(address == null){
if (address == null) {
return ""
}
return if (isIpv6Address(address) && !address.contains('[') && !address.contains(']')) {
@@ -427,8 +430,8 @@ object Utils {
fun fixIllegalUrl(str: String): String {
return str
.replace(" ","%20")
.replace("|","%7C")
.replace(" ", "%20")
.replace("|", "%7C")
}
fun removeWhiteSpace(str: String?): String? {
@@ -67,7 +67,7 @@ object ShadowsocksFmt {
private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean {
try {
val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment .orEmpty())
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
val method: String
val password: String
@@ -88,7 +88,7 @@ object ShadowsocksFmt {
password = base64Decode.substringAfter(":")
}
val query = Utils.urlDecode(uri.query .orEmpty())
val query = Utils.urlDecode(uri.query.orEmpty())
if (query != "") {
val queryPairs = HashMap<String, String>()
val pairs = query.split(";")
@@ -19,12 +19,12 @@ object TrojanFmt {
)
}
fun parseTrojan(str: String): ServerConfig? {
fun parseTrojan(str: String): ServerConfig {
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
val config = ServerConfig.create(EConfigType.TROJAN)
val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment .orEmpty())
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
var flow = ""
var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint
@@ -56,7 +56,7 @@ object TrojanFmt {
queryParam["authority"]
)
fingerprint = queryParam["fp"].orEmpty()
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure
allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
config.outboundBean?.streamSettings?.populateTlsSettings(
queryParam["security"] ?: V2rayConfig.TLS,
allowInsecure,
@@ -111,7 +111,7 @@ object TrojanFmt {
dicQuery["sid"] = tlsSetting.shortId.orEmpty()
}
if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX .orEmpty())
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
}
}
dicQuery["type"] =
@@ -30,7 +30,7 @@ object VlessFmt {
val streamSetting = config.outboundBean?.streamSettings ?: return null
config.remarks = Utils.urlDecode(uri.fragment .orEmpty())
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
vnext.address = uri.idnHost
vnext.port = uri.port
@@ -51,7 +51,7 @@ object VlessFmt {
queryParam["serviceName"],
queryParam["authority"]
)
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure
allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
streamSetting.populateTlsSettings(
queryParam["security"].orEmpty(),
allowInsecure,
@@ -102,7 +102,7 @@ object VlessFmt {
dicQuery["sid"] = tlsSetting.shortId.orEmpty()
}
if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX .orEmpty())
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
}
}
dicQuery["type"] =
@@ -121,7 +121,7 @@ object VmessFmt {
val streamSetting = config.outboundBean?.streamSettings ?: return null
config.remarks = Utils.urlDecode(uri.fragment .orEmpty())
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
vnext.address = uri.idnHost
vnext.port = uri.port
@@ -143,7 +143,7 @@ object VmessFmt {
queryParam["authority"]
)
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure
allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
streamSetting.populateTlsSettings(
queryParam["security"].orEmpty(),
allowInsecure,
@@ -13,7 +13,7 @@ object WireguardFmt {
val uri = URI(Utils.fixIllegalUrl(str))
if (uri.rawQuery != null) {
val config = ServerConfig.create(EConfigType.WIREGUARD)
config.remarks = Utils.urlDecode(uri.fragment .orEmpty())
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="1024">
<path
android:pathData="M537,85.3A85.3,85.3 0,0 1,597.3 110.3L828.3,341.3A85.3,85.3 0,0 1,853.3 401.7L853.3,810.7a128,128 0,0 1,-128 128L298.7,938.7a128,128 0,0 1,-128 -128L170.7,213.3a128,128 0,0 1,128 -128zM537,170.7L298.7,170.7a42.7,42.7 0,0 0,-42.7 42.7v597.3a42.7,42.7 0,0 0,42.7 42.7h426.7a42.7,42.7 0,0 0,42.7 -42.7L768,401.7L537,170.7zM512,384a42.7,42.7 0,0 1,42.4 37.7L554.7,426.7v85.3h85.3a42.7,42.7 0,0 1,5 85L640,597.3h-85.3v85.3a42.7,42.7 0,0 1,-85 5L469.3,682.7v-85.3L384,597.3a42.7,42.7 0,0 1,-5 -85L384,512h85.3v-85.3a42.7,42.7 0,0 1,42.7 -42.7z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
</vector>
@@ -5,11 +5,11 @@
android:viewportHeight="1024">
<path
android:pathData="M273.2,212.8h583.7L856.9,906.2h-583.7L273.2,212.8zM344.9,284.5L344.9,834.6h440.3L785.2,284.5h-440.3z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
<path
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
<path
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
</vector>
@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
<vector android:height="24dp"
android:tint="#FFFFFF"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
</vector>
@@ -5,8 +5,8 @@
android:viewportHeight="1024">
<path
android:pathData="M723.9,312c-13.2,-13.2 -34.7,-13.2 -47.9,0 -6.6,6.6 -9.9,15.3 -9.9,23.9 0,8.7 3.3,17.3 9.9,23.9 65.9,65.9 80.9,165.5 37.3,247.8 -4.9,9.2 -10.5,18.2 -16.9,26.8 -6.4,8.7 -12.9,16.4 -20,23.3 -13.4,13.1 -13.7,34.5 -0.6,47.9 13.1,13.4 34.5,13.7 47.9,0.6 9.7,-9.5 18.9,-20.2 27.3,-31.6 8.3,-11.2 15.7,-23 22.2,-35.2 57.5,-108.7 37.7,-240.3 -49.3,-327.4zM507.6,470c-0.2,-0.2 -0.4,-0.3 -0.7,-0.5 -0.8,-0.3 -1.7,-0.1 -2.3,0.5 -0.2,0.2 -0.3,0.4 -0.5,0.7 -0.1,0.3 -0.2,0.5 -0.2,0.8 0,0.6 0.3,1.1 0.6,1.5 0.2,0.2 0.4,0.3 0.7,0.5 0.3,0.1 0.5,0.2 0.8,0.2 0.6,0 1.1,-0.3 1.5,-0.6 0.4,-0.4 0.6,-1 0.6,-1.5 0,-0.3 -0.1,-0.5 -0.2,-0.8 0,-0.4 -0.2,-0.6 -0.3,-0.8z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
<path
android:pathData="M833.7,209.6c-13.2,-13.2 -34.5,-13.2 -47.6,0 -13.2,13.2 -13.2,34.5 0,47.6 122.3,122.3 140,314.4 42.1,456.6 -12.5,18.1 -26.5,35 -42.1,50.5 -6.6,6.6 -9.9,15.2 -9.9,23.8 0,8.6 3.3,17.2 9.9,23.8 13.2,13.2 34.5,13.2 47.6,0 18.4,-18.4 35.1,-38.5 49.9,-60C1000,583.1 979,355 833.7,209.6zM515.1,166.8c-48,-22.3 -102.9,-15.1 -143.4,19L176.6,349.9h-50.2c-31,0 -63.3,25.2 -63.3,56.3v209.4c0,31 32.2,56.3 63.3,56.3h50.2L371.7,836c24.9,21 55.4,31.8 86.2,31.8 19.3,0 38.7,-4.2 57.2,-12.8 48,-22.3 77.8,-69.1 77.8,-122L592.9,288.8c0,-52.9 -29.8,-99.6 -77.8,-122zM531.1,732.9c0,31.8 -17.2,52.9 -46.1,66.3 -28.9,13.4 -56.7,6.2 -81,-14.3L206.2,623.5c-4.9,-4.2 -11.2,-6.4 -17.6,-6.4h-60.2c-0.8,0 -1.5,-0.7 -1.5,-1.5L126.9,406.2c0,-0.8 0.7,-1.5 1.5,-1.5h60.2c6.5,0 12.7,-2.3 17.6,-6.4L412,237.7c24.4,-20.5 51.2,-24.7 80,-11.3 28.9,13.4 39.1,30.5 39.1,62.3v444.2z"
android:fillColor="#FFFFFFFF"/>
android:fillColor="#FFFFFFFF" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/>
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="1024">
<path
android:pathData="M537,85.3A85.3,85.3 0,0 1,597.3 110.3L828.3,341.3A85.3,85.3 0,0 1,853.3 401.7L853.3,810.7a128,128 0,0 1,-128 128L298.7,938.7a128,128 0,0 1,-128 -128L170.7,213.3a128,128 0,0 1,128 -128zM537,170.7L298.7,170.7a42.7,42.7 0,0 0,-42.7 42.7v597.3a42.7,42.7 0,0 0,42.7 42.7h426.7a42.7,42.7 0,0 0,42.7 -42.7L768,401.7L537,170.7zM512,384a42.7,42.7 0,0 1,42.4 37.7L554.7,426.7v85.3h85.3a42.7,42.7 0,0 1,5 85L640,597.3h-85.3v85.3a42.7,42.7 0,0 1,-85 5L469.3,682.7v-85.3L384,597.3a42.7,42.7 0,0 1,-5 -85L384,512h85.3v-85.3a42.7,42.7 0,0 1,42.7 -42.7z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
</vector>
@@ -5,11 +5,11 @@
android:viewportHeight="1024">
<path
android:pathData="M273.2,212.8h583.7L856.9,906.2h-583.7L273.2,212.8zM344.9,284.5L344.9,834.6h440.3L785.2,284.5h-440.3z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
<path
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
<path
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
</vector>
@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
<vector android:height="24dp"
android:tint="#000000"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
</vector>
@@ -5,8 +5,8 @@
android:viewportHeight="1024">
<path
android:pathData="M723.9,312c-13.2,-13.2 -34.7,-13.2 -47.9,0 -6.6,6.6 -9.9,15.3 -9.9,23.9 0,8.7 3.3,17.3 9.9,23.9 65.9,65.9 80.9,165.5 37.3,247.8 -4.9,9.2 -10.5,18.2 -16.9,26.8 -6.4,8.7 -12.9,16.4 -20,23.3 -13.4,13.1 -13.7,34.5 -0.6,47.9 13.1,13.4 34.5,13.7 47.9,0.6 9.7,-9.5 18.9,-20.2 27.3,-31.6 8.3,-11.2 15.7,-23 22.2,-35.2 57.5,-108.7 37.7,-240.3 -49.3,-327.4zM507.6,470c-0.2,-0.2 -0.4,-0.3 -0.7,-0.5 -0.8,-0.3 -1.7,-0.1 -2.3,0.5 -0.2,0.2 -0.3,0.4 -0.5,0.7 -0.1,0.3 -0.2,0.5 -0.2,0.8 0,0.6 0.3,1.1 0.6,1.5 0.2,0.2 0.4,0.3 0.7,0.5 0.3,0.1 0.5,0.2 0.8,0.2 0.6,0 1.1,-0.3 1.5,-0.6 0.4,-0.4 0.6,-1 0.6,-1.5 0,-0.3 -0.1,-0.5 -0.2,-0.8 0,-0.4 -0.2,-0.6 -0.3,-0.8z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
<path
android:pathData="M833.7,209.6c-13.2,-13.2 -34.5,-13.2 -47.6,0 -13.2,13.2 -13.2,34.5 0,47.6 122.3,122.3 140,314.4 42.1,456.6 -12.5,18.1 -26.5,35 -42.1,50.5 -6.6,6.6 -9.9,15.2 -9.9,23.8 0,8.6 3.3,17.2 9.9,23.8 13.2,13.2 34.5,13.2 47.6,0 18.4,-18.4 35.1,-38.5 49.9,-60C1000,583.1 979,355 833.7,209.6zM515.1,166.8c-48,-22.3 -102.9,-15.1 -143.4,19L176.6,349.9h-50.2c-31,0 -63.3,25.2 -63.3,56.3v209.4c0,31 32.2,56.3 63.3,56.3h50.2L371.7,836c24.9,21 55.4,31.8 86.2,31.8 19.3,0 38.7,-4.2 57.2,-12.8 48,-22.3 77.8,-69.1 77.8,-122L592.9,288.8c0,-52.9 -29.8,-99.6 -77.8,-122zM531.1,732.9c0,31.8 -17.2,52.9 -46.1,66.3 -28.9,13.4 -56.7,6.2 -81,-14.3L206.2,623.5c-4.9,-4.2 -11.2,-6.4 -17.6,-6.4h-60.2c-0.8,0 -1.5,-0.7 -1.5,-1.5L126.9,406.2c0,-0.8 0.7,-1.5 1.5,-1.5h60.2c6.5,0 12.7,-2.3 17.6,-6.4L412,237.7c24.4,-20.5 51.2,-24.7 80,-11.3 28.9,13.4 39.1,30.5 39.1,62.3v444.2z"
android:fillColor="#FF000000"/>
android:fillColor="#FF000000" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
</vector>
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
</vector>
@@ -1,4 +1,9 @@
<vector android:height="24dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M469.2,802.1l-81.7,-24.6L554.8,221.9l81.7,24.6L469.2,802.1zM362.7,654.5l-124.7,-141.7 124.8,-143.5 -64.4,-56 -173.8,199.8 174,197.7 64.1,-56.3zM899.4,513.1l-173.8,-199.8 -64.4,56 124.8,143.5 -124.7,141.7 64.1,56.4 174,-197.7z"/>
<vector android:height="24dp"
android:viewportHeight="1024"
android:viewportWidth="1024"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FF000000"
android:pathData="M469.2,802.1l-81.7,-24.6L554.8,221.9l81.7,24.6L469.2,802.1zM362.7,654.5l-124.7,-141.7 124.8,-143.5 -64.4,-56 -173.8,199.8 174,197.7 64.1,-56.3zM899.4,513.1l-173.8,-199.8 -64.4,56 124.8,143.5 -124.7,141.7 64.1,56.4 174,-197.7z" />
</vector>
@@ -51,7 +51,7 @@
app:tabTextAppearance="@style/TabLayoutTextStyle"
app:tabIndicatorFullWidth="false"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
android:layout_width="match_parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
@@ -79,7 +79,7 @@
android:minLines="1"
android:paddingStart="16dp"
android:text="@string/connection_test_pending"
android:textAppearance="@style/TextAppearance.AppCompat.Small"/>
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>
@@ -120,7 +120,7 @@
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:itemIconTint="@color/colorAccent"
app:menu="@menu/menu_drawer" >
app:menu="@menu/menu_drawer">
</com.google.android.material.navigation.NavigationView>
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
android:layout_height="match_parent"></RelativeLayout>
@@ -1,7 +1,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
@@ -133,16 +133,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_reserved1"
android:layout_width="60dp"
android:layout_height="@dimen/edit_height"
android:inputType="number" />
<EditText
android:id="@+id/et_reserved2"
android:layout_width="60dp"
android:layout_height="@dimen/edit_height"
android:inputType="number" />
<EditText
android:id="@+id/et_reserved3"
android:layout_width="60dp"
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -17,7 +16,7 @@
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_recycler_sub_setting"/>
tools:listitem="@layout/item_recycler_sub_setting" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.UserAssetUrlActivity">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.UserAssetUrlActivity">
<LinearLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -82,5 +82,5 @@ tools:context=".ui.UserAssetUrlActivity">
android:layout_marginTop="@dimen/layout_margin_top_height"
android:orientation="vertical" />
</LinearLayout>
</LinearLayout>
</ScrollView>
@@ -18,7 +18,7 @@
<Spinner
android:id="@+id/sp_subscriptionId"
android:layout_width="match_parent"
android:layout_height="@dimen/edit_height"/>
android:layout_height="@dimen/edit_height" />
</LinearLayout>
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/nav_header_bg"
@@ -1,6 +1,5 @@
<?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="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_horizontal_margin"
@@ -27,6 +26,7 @@
android:nextFocusDown="@+id/et_sni" />
</LinearLayout>
<LinearLayout
android:id="@+id/l2"
android:layout_width="match_parent"
@@ -47,6 +47,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout>
<LinearLayout
android:id="@+id/l3"
android:layout_width="match_parent"
@@ -67,6 +68,7 @@
android:nextFocusDown="@+id/sp_stream_alpn" />
</LinearLayout>
<LinearLayout
android:id="@+id/l4"
android:layout_width="match_parent"
@@ -87,11 +89,12 @@
android:nextFocusDown="@+id/sp_allow_insecure" />
</LinearLayout>
<LinearLayout
android:id="@+id/l5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
@@ -104,6 +107,7 @@
android:layout_height="@dimen/edit_height"
android:entries="@array/allowinsecures" />
</LinearLayout>
<LinearLayout
android:id="@+id/l6"
android:layout_width="match_parent"
@@ -124,6 +128,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout>
<LinearLayout
android:id="@+id/l7"
android:layout_width="match_parent"
@@ -144,6 +149,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout>
<LinearLayout
android:id="@+id/l8"
android:layout_width="match_parent"
+1 -1
View File
@@ -4,7 +4,7 @@
<item
android:icon="@drawable/ic_add_24dp"
android:title="@string/menu_item_add_asset"
app:showAsAction="ifRoom" >
app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/add_file"
@@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group
android:id="@+id/group_main">
<group android:id="@+id/group_main">
<item
android:id="@+id/sub_setting"
android:icon="@drawable/ic_subscriptions_24dp"
+1 -1
View File
@@ -6,7 +6,7 @@
android:icon="@drawable/ic_outline_filter_alt_24"
android:title="@string/menu_item_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView"/>
app:showAsAction="always|collapseActionView" />
<item
android:icon="@drawable/ic_add_24dp"
android:title="@string/menu_item_add_config"
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_banner_background"/>
<background android:drawable="@color/ic_banner_background" />
<foreground>
<inset android:drawable="@mipmap/ic_banner_foreground" android:inset="10%"/>
<inset
android:drawable="@mipmap/ic_banner_foreground"
android:inset="10%" />
</foreground>
</adaptive-icon>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>
</style>
+3 -1
View File
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="cache" path="/"/>
<cache-path
name="cache"
path="/" />
</paths>
@@ -1,9 +1,9 @@
package com.v2ray.ang;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
@@ -1,6 +1,8 @@
import org.junit.Assert.*
import org.junit.Test
import com.v2ray.ang.util.Utils
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class UtilTest {
@@ -13,27 +15,27 @@ class UtilTest {
fun test_isIpAddress() {
assertFalse(Utils.isIpAddress("114.113.112.266"))
assertFalse(Utils.isIpAddress("666.666.666.666"))
assertFalse(Utils.isIpAddress("256.0.0.0" ))
assertFalse(Utils.isIpAddress("::ffff:127.0.0.0.1" ))
assertFalse(Utils.isIpAddress("256.0.0.0"))
assertFalse(Utils.isIpAddress("::ffff:127.0.0.0.1"))
assertFalse(Utils.isIpAddress("baidu.com"))
assertFalse(Utils.isIpAddress(""))
assertTrue(Utils.isIpAddress("127.0.0.1" ))
assertTrue(Utils.isIpAddress("127.0.0.1:80" ))
assertTrue(Utils.isIpAddress("0.0.0.0/0" ))
assertTrue(Utils.isIpAddress("::1" ))
assertTrue(Utils.isIpAddress("[::1]:80" ))
assertTrue(Utils.isIpAddress("2605:2700:0:3::4713:93e3" ))
assertTrue(Utils.isIpAddress("[2605:2700:0:3::4713:93e3]:80" ))
assertTrue(Utils.isIpAddress("::ffff:192.168.173.22" ))
assertTrue(Utils.isIpAddress("[::ffff:192.168.173.22]:80" ))
assertTrue(Utils.isIpAddress("1::" ))
assertTrue(Utils.isIpAddress("::" ))
assertTrue(Utils.isIpAddress("::/0" ))
assertTrue(Utils.isIpAddress("10.24.56.0/24" ))
assertTrue(Utils.isIpAddress("2001:4321::1" ))
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::6666" ))
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::/64" ))
assertTrue(Utils.isIpAddress("127.0.0.1"))
assertTrue(Utils.isIpAddress("127.0.0.1:80"))
assertTrue(Utils.isIpAddress("0.0.0.0/0"))
assertTrue(Utils.isIpAddress("::1"))
assertTrue(Utils.isIpAddress("[::1]:80"))
assertTrue(Utils.isIpAddress("2605:2700:0:3::4713:93e3"))
assertTrue(Utils.isIpAddress("[2605:2700:0:3::4713:93e3]:80"))
assertTrue(Utils.isIpAddress("::ffff:192.168.173.22"))
assertTrue(Utils.isIpAddress("[::ffff:192.168.173.22]:80"))
assertTrue(Utils.isIpAddress("1::"))
assertTrue(Utils.isIpAddress("::"))
assertTrue(Utils.isIpAddress("::/0"))
assertTrue(Utils.isIpAddress("10.24.56.0/24"))
assertTrue(Utils.isIpAddress("2001:4321::1"))
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::6666"))
assertTrue(Utils.isIpAddress("240e:1234:abcd:12::/64"))
}
}