This commit is contained in:
problematicconsumer
2023-07-06 17:18:41 +03:30
commit b617c95f62
352 changed files with 21017 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,57 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:label="hiddify"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="clash" />
<data android:scheme="clashmeta" />
<data android:host="install-config"/>
</intent-filter>
</activity>
<service
android:name=".HiddifyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:stopWithTask="false"
android:exported="false">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,317 @@
package com.hiddify.hiddify
import android.app.PendingIntent
import android.app.Service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
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.ProxyInfo
import android.net.VpnService
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.StrictMode
import android.util.Log
import androidx.annotation.RequiresApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.lang.ref.SoftReference
class HiddifyVpnService : VpnService() {
companion object {
const val TAG = "Hiddify/VpnService"
const val EVENT_TAG = "Hiddify/VpnServiceEvents"
private const val TUN2SOCKS = "libtun2socks.so"
private const val TUN_MTU = 9000
private const val TUN_GATEWAY = "172.19.0.1"
private const val TUN_ROUTER = "172.19.0.2"
private const val TUN_SUBNET_PREFIX = 30
private const val NET_ANY = "0.0.0.0"
private val HTTP_PROXY_LOCAL_LIST = listOf(
"localhost",
"*.local",
"127.*",
"10.*",
"172.16.*",
"172.17.*",
"172.18.*",
"172.19.*",
"172.2*",
"172.30.*",
"172.31.*",
"192.168.*"
)
}
private var vpnBroadcastReceiver: VpnState? = null
private var conn: ParcelFileDescriptor? = null
private lateinit var process: Process
private var isRunning = false
// prefs
private var includeAppPackages: Set<String> = HashSet()
fun getService(): Service {
return this
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startVpnService()
return START_STICKY
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "creating vpn service")
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
registerBroadcastReceiver()
VpnServiceManager.vpnService = SoftReference(this)
}
override fun onRevoke() {
Log.d(TAG, "vpn service revoked")
super.onRevoke()
stopVpnService()
}
override fun onDestroy() {
Log.d(TAG, "vpn service destroyed")
super.onDestroy()
broadcastVpnStatus(false)
VpnServiceManager.cancelNotification()
unregisterBroadcastReceiver()
}
private fun registerBroadcastReceiver() {
Log.d(TAG, "registering receiver in service")
vpnBroadcastReceiver = VpnState()
val intentFilter = IntentFilter(VpnState.ACTION_VPN_STATUS)
registerReceiver(vpnBroadcastReceiver, intentFilter)
}
private fun unregisterBroadcastReceiver() {
Log.d(TAG, "unregistering receiver in service")
if (vpnBroadcastReceiver != null) {
unregisterReceiver(vpnBroadcastReceiver)
vpnBroadcastReceiver = null
}
}
private fun broadcastVpnStatus(isVpnActive: Boolean) {
Log.d(TAG, "broadcasting status= $isVpnActive")
val intent = Intent(VpnState.ACTION_VPN_STATUS)
intent.putExtra(VpnState.IS_VPN_ACTIVE, isVpnActive)
sendBroadcast(intent)
}
@delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkRequest by lazy {
NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build()
}
private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
@delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkCallback by lazy {
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
setUnderlyingNetworks(arrayOf(network))
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
// it's a good idea to refresh capabilities
setUnderlyingNetworks(arrayOf(network))
}
override fun onLost(network: Network) {
setUnderlyingNetworks(null)
}
}
}
private fun startVpnService() {
val prepare = prepare(this)
if (prepare != null) {
return
}
with(Builder()) {
addAddress(TUN_GATEWAY, TUN_SUBNET_PREFIX)
setMtu(TUN_MTU)
addRoute(NET_ANY, 0)
addDnsServer(TUN_ROUTER)
allowBypass()
setBlocking(true)
setSession("Hiddify")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
setMetered(false)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && VpnServiceManager.prefs.systemProxy) {
setHttpProxy(
ProxyInfo.buildDirectProxy(
"127.0.0.1",
VpnServiceManager.prefs.httpPort,
HTTP_PROXY_LOCAL_LIST,
)
)
}
if (includeAppPackages.isEmpty()) {
addDisallowedApplication(packageName)
} else {
includeAppPackages.forEach {
addAllowedApplication(it)
}
}
setConfigureIntent(
PendingIntent.getActivity(
this@HiddifyVpnService,
0,
Intent().setComponent(ComponentName(packageName, "$packageName.MainActivity")),
pendingIntentFlags(PendingIntent.FLAG_UPDATE_CURRENT)
)
)
try {
conn?.close()
} catch (ignored: Exception) {
// ignored
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
} catch (e: Exception) {
e.printStackTrace()
}
}
try {
conn = establish()
isRunning = true
runTun2socks()
VpnServiceManager.showNotification()
Log.d(TAG, "vpn connection established")
broadcastVpnStatus(true)
} catch (e: Exception) {
Log.w(TAG, "failed to start vpn service: $e")
e.printStackTrace()
stopVpnService()
broadcastVpnStatus(false)
}
}
}
fun stopVpnService(isForced: Boolean = true) {
Log.d(TAG, "stopping vpn service, forced: [$isForced]")
isRunning = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
connectivity.unregisterNetworkCallback(defaultNetworkCallback)
} catch (ignored: Exception) {
// ignored
}
}
try {
Log.d(TAG, "destroying tun2socks")
process.destroy()
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
if(isForced) {
stopSelf()
try {
conn?.close()
conn = null
} catch (ignored: Exception) {
// ignored
}
}
Log.d(TAG, "vpn service stopped")
}
private fun runTun2socks() {
val cmd = arrayListOf(
File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
"--netif-ipaddr", TUN_ROUTER,
"--netif-netmask", "255.255.255.252",
"--socks-server-addr", "127.0.0.1:${VpnServiceManager.prefs.socksPort}",
"--tunmtu", TUN_MTU.toString(),
"--sock-path", "sock_path",//File(applicationContext.filesDir, "sock_path").absolutePath,
"--enable-udprelay",
"--loglevel", "notice")
Log.d(TAG, cmd.toString())
protect(conn!!.fd) // not sure
try {
val proBuilder = ProcessBuilder(cmd)
proBuilder.redirectErrorStream(true)
process = proBuilder
.directory(applicationContext.filesDir)
.start()
Thread(Runnable {
Log.d(TAG,"$TUN2SOCKS check")
process.waitFor()
Log.d(TAG,"$TUN2SOCKS exited")
if (isRunning) {
Log.d(packageName,"$TUN2SOCKS restart")
runTun2socks()
}
}).start()
Log.d(TAG, process.toString())
sendFd()
} catch (e: Exception) {
Log.d(TAG, e.toString())
}
}
private fun sendFd() {
val fd = conn!!.fileDescriptor
val path = File(applicationContext.filesDir, "sock_path").absolutePath
Log.d(TAG, path)
GlobalScope.launch(Dispatchers.IO) {
var tries = 0
while (true) try {
Thread.sleep(50L shl tries)
Log.d(TAG, "sendFd tries: $tries")
LocalSocket().use { localSocket ->
localSocket.connect(LocalSocketAddress(path, LocalSocketAddress.Namespace.FILESYSTEM))
localSocket.setFileDescriptorsForSend(arrayOf(fd))
localSocket.outputStream.write(42)
}
break
} catch (e: Exception) {
Log.d(TAG, e.toString())
if (tries > 5) break
tries += 1
}
}
}
private fun pendingIntentFlags(flags: Int, mutable: Boolean = false): Int {
return if (Build.VERSION.SDK_INT >= 24) {
if (Build.VERSION.SDK_INT > 30 && mutable) {
flags or PendingIntent.FLAG_MUTABLE
} else {
flags or PendingIntent.FLAG_IMMUTABLE
}
} else {
flags
}
}
}

View File

@@ -0,0 +1,116 @@
package com.hiddify.hiddify
import android.content.Intent
import android.content.IntentFilter
import android.net.VpnService
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity(), MethodChannel.MethodCallHandler {
private lateinit var methodChannel: MethodChannel
private lateinit var eventChannel: EventChannel
private lateinit var methodResult: MethodChannel.Result
private var vpnBroadcastReceiver: VpnState? = null
companion object {
const val VPN_PERMISSION_REQUEST_CODE = 1001
enum class Action(val method: String) {
GrantPermission("grant_permission"),
StartProxy("start"),
StopProxy("stop"),
RefreshStatus("refresh_status"),
SetPrefs("set_prefs")
}
}
private fun registerBroadcastReceiver() {
Log.d(HiddifyVpnService.TAG, "registering broadcast receiver")
vpnBroadcastReceiver = VpnState()
val intentFilter = IntentFilter(VpnState.ACTION_VPN_STATUS)
registerReceiver(vpnBroadcastReceiver, intentFilter)
}
private fun unregisterBroadcastReceiver() {
Log.d(HiddifyVpnService.TAG, "unregistering broadcast receiver")
if (vpnBroadcastReceiver != null) {
unregisterReceiver(vpnBroadcastReceiver)
vpnBroadcastReceiver = null
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
methodChannel =
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, HiddifyVpnService.TAG)
methodChannel.setMethodCallHandler(this)
eventChannel = EventChannel(flutterEngine.dartExecutor.binaryMessenger, HiddifyVpnService.EVENT_TAG)
registerBroadcastReceiver()
eventChannel.setStreamHandler(vpnBroadcastReceiver)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
methodResult = result
@Suppress("UNCHECKED_CAST")
when (call.method) {
Action.GrantPermission.method -> {
grantVpnPermission()
}
Action.StartProxy.method -> {
VpnServiceManager.startVpnService(this)
result.success(true)
}
Action.StopProxy.method -> {
VpnServiceManager.stopVpnService()
result.success(true)
}
Action.RefreshStatus.method -> {
val statusIntent = Intent(VpnState.ACTION_VPN_STATUS)
statusIntent.putExtra(VpnState.IS_VPN_ACTIVE, VpnServiceManager.isRunning)
sendBroadcast(statusIntent)
result.success(true)
}
Action.SetPrefs.method -> {
val args = call.arguments as Map<String, Any>
VpnServiceManager.setPrefs(context, args)
result.success(true)
}
else -> {
result.notImplemented()
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterBroadcastReceiver()
}
private fun grantVpnPermission() {
val vpnPermissionIntent = VpnService.prepare(this)
if (vpnPermissionIntent == null) {
onActivityResult(VPN_PERMISSION_REQUEST_CODE, RESULT_OK, null)
} else {
startActivityForResult(vpnPermissionIntent, VPN_PERMISSION_REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == VPN_PERMISSION_REQUEST_CODE) {
methodResult.success(resultCode == RESULT_OK)
} else if (requestCode == 101010) {
methodResult.success(resultCode == RESULT_OK)
}
}
}

View File

@@ -0,0 +1,97 @@
package com.hiddify.hiddify
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.Intent
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import java.lang.ref.SoftReference
data class VpnServiceConfigs(val httpPort: Int = 12346, val socksPort: Int = 12347, val systemProxy: Boolean = true)
object VpnServiceManager {
private const val NOTIFICATION_ID = 1
private const val NOTIFICATION_CHANNEL_ID = "hiddify_vpn"
private const val NOTIFICATION_CHANNEL_NAME = "Hiddify VPN"
var vpnService: SoftReference<HiddifyVpnService>? = null
var prefs = VpnServiceConfigs()
var isRunning = false
private var mBuilder: NotificationCompat.Builder? = null
private var mNotificationManager: NotificationManager? = null
fun startVpnService(context: Context) {
val intent = Intent(context.applicationContext, HiddifyVpnService::class.java)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
fun stopVpnService() {
val service = vpnService?.get() ?: return
service.stopVpnService()
}
fun setPrefs(context: Context,args: Map<String, Any>) {
prefs = prefs.copy(
httpPort = args["httpPort"] as Int? ?: prefs.httpPort,
socksPort = args["socksPort"] as Int? ?: prefs.socksPort,
systemProxy = args["systemProxy"] as Boolean? ?: prefs.systemProxy,
)
if(isRunning) {
stopVpnService()
startVpnService(context)
}
}
fun showNotification() {
val service = vpnService?.get()?.getService() ?: return
val channelId = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
} else {
""
}
mBuilder = NotificationCompat.Builder(service, channelId)
.setSmallIcon(R.drawable.ic_stat_logo)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true)
.setShowWhen(false)
.setOnlyAlertOnce(true)
.setContentTitle("Hiddify")
.setContentText("Connected")
service.startForeground(NOTIFICATION_ID, mBuilder?.build())
}
fun cancelNotification() {
val service = vpnService?.get()?.getService() ?: return
service.stopForeground(true)
mBuilder = null
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String {
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
getNotificationManager()?.createNotificationChannel(
channel
)
return NOTIFICATION_CHANNEL_ID
}
private fun getNotificationManager(): NotificationManager? {
if (mNotificationManager == null) {
val service = vpnService?.get()?.getService() ?: return null
mNotificationManager = service.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
return mNotificationManager
}
}

View File

@@ -0,0 +1,34 @@
package com.hiddify.hiddify
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import io.flutter.plugin.common.EventChannel
class VpnState : BroadcastReceiver(), EventChannel.StreamHandler{
companion object {
const val ACTION_VPN_STATUS = "Hiddify.VpnState.ACTION_VPN_STATUS"
const val IS_VPN_ACTIVE = "isVpnActive"
}
private var eventSink: EventChannel.EventSink? = null
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}
override fun onCancel(arguments: Any?) {
eventSink = null
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == ACTION_VPN_STATUS) {
val isVpnActive = intent.getBooleanExtra(IS_VPN_ACTIVE, false)
Log.d(HiddifyVpnService.TAG, "send to flutter: status= $isVpnActive")
VpnServiceManager.isRunning = isVpnActive
eventSink?.success(isVpnActive)
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
<item>
<bitmap android:gravity="center" android:src="@drawable/splash"/>
</item>
</layer-list>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 956 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#ffffff</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#ffffff</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- exclude 127.0.0.0/8 169.254.0.0/16 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 -->
<string-array name="bypass_private_route" translatable="false">
<item>1.0.0.0/8</item>
<item>2.0.0.0/7</item>
<item>4.0.0.0/6</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/3</item>
<item>96.0.0.0/4</item>
<item>112.0.0.0/5</item>
<item>120.0.0.0/6</item>
<item>124.0.0.0/7</item>
<item>126.0.0.0/8</item>
<item>128.0.0.0/3</item>
<item>160.0.0.0/5</item>
<item>168.0.0.0/8</item>
<item>169.0.0.0/9</item>
<item>169.128.0.0/10</item>
<item>169.192.0.0/11</item>
<item>169.224.0.0/12</item>
<item>169.240.0.0/13</item>
<item>169.248.0.0/14</item>
<item>169.252.0.0/15</item>
<item>169.255.0.0/16</item>
<item>170.0.0.0/7</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>240.0.0.0/5</item>
<item>248.0.0.0/6</item>
<item>252.0.0.0/7</item>
<item>254.0.0.0/8</item>
<item>255.0.0.0/9</item>
<item>255.128.0.0/10</item>
<item>255.192.0.0/11</item>
<item>255.224.0.0/12</item>
<item>255.240.0.0/13</item>
<item>255.248.0.0/14</item>
<item>255.252.0.0/15</item>
<item>255.254.0.0/16</item>
<item>255.255.0.0/17</item>
<item>255.255.128.0/18</item>
<item>255.255.192.0/19</item>
<item>255.255.224.0/20</item>
<item>255.255.240.0/21</item>
<item>255.255.248.0/22</item>
<item>255.255.252.0/23</item>
<item>255.255.254.0/24</item>
<item>255.255.255.0/25</item>
<item>255.255.255.128/26</item>
<item>255.255.255.192/27</item>
<item>255.255.255.224/28</item>
<item>255.255.255.240/29</item>
<item>255.255.255.248/30</item>
<item>255.255.255.252/31</item>
<item>255.255.255.254/32</item>
</string-array>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>