refactor(app): debloat 3.3.1 and fix startup restoration
Maintainer changes on top of PR #2 (Naveax). Reduces the release to two deliberate connection modes and resolves the issues found in review: - Lock-screen privacy: move VISIBILITY_PRIVATE and a generic publicVersion into MainActivity.updateVpnNotification. The PR's fix lived in an unreferenced class and never reached the live notification. - Haptics: restore the default to off, and reduce HapticSettings to a single success() on connect/disconnect via the native channel. - SOCKS5: make it a real proxyOnly local-proxy mode rather than a TUN connection under a different label. TUN stays the default. - Health probe: restore the idle-only guard so /health is no longer polled every 30s while connected. - Recovery: add a _connectionEpoch counter so connect() aborts an in-flight Extreme recovery. - Startup restoration: rebuild the recovery snapshot from the still-active session after an app-process restart (TUN), and surface an honest orphaned state with a Reconnect action in proxy mode. Drops per-app routing entirely. It only ever functioned in TUN -- addDisallowedApplication lives inside the VPN-interface setup that proxyOnly skips -- and its allowlist half had no Dart caller. Also removes flutter_local_notifications, the global tap-haptic surface, and unused runtime telemetry. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
a71161e7e5
commit
6fcde9dd7b
18 files changed
+271
-1027
No files matched your search
@@ -18,11 +18,6 @@
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<data android:scheme="https"/>
|
||||
</intent>
|
||||
<!-- App routing only enumerates launcher apps; QUERY_ALL_PACKAGES is not required. -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
|
||||
@@ -7,9 +7,6 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
@@ -26,14 +23,11 @@ import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.io.ByteArrayOutputStream
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
private val installerChannel = "com.revoltvpn.app/installer"
|
||||
private val notificationChannel = "com.revoltvpn.app/notification"
|
||||
private val hapticsChannel = "com.revoltvpn.app/haptics"
|
||||
private val appsChannel = "com.revoltvpn.app/apps"
|
||||
private val networkChannel = "com.revoltvpn.app/network"
|
||||
|
||||
private var notificationChannelReady = false
|
||||
@@ -75,15 +69,6 @@ class MainActivity : FlutterActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, appsChannel)
|
||||
.setMethodCallHandler { call, result ->
|
||||
if (call.method == "getLaunchableApps") {
|
||||
result.success(launchableApps())
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
EventChannel(flutterEngine.dartExecutor.binaryMessenger, networkChannel)
|
||||
.setStreamHandler(object : EventChannel.StreamHandler {
|
||||
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
|
||||
@@ -129,6 +114,14 @@ class MainActivity : FlutterActivity() {
|
||||
stopIntent.putExtra("COMMAND", AppConfigs.V2RAY_SERVICE_COMMANDS.STOP_SERVICE)
|
||||
val stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, flags)
|
||||
|
||||
// Public lock-screen preview: keep the VPN status visible but hide the
|
||||
// session countdown/speed so usage metadata never reaches the lock screen.
|
||||
val publicVersion = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.notification_status_icon)
|
||||
.setContentTitle("Revolt VPN")
|
||||
.setContentText("VPN is active")
|
||||
.build()
|
||||
|
||||
val builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.notification_status_icon)
|
||||
.setContentTitle(title)
|
||||
@@ -142,6 +135,8 @@ class MainActivity : FlutterActivity() {
|
||||
.setSilent(true)
|
||||
.setShowWhen(false)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
|
||||
.setPublicVersion(publicVersion)
|
||||
|
||||
if (launchIntent != null) {
|
||||
builder.setContentIntent(PendingIntent.getActivity(this, 0, launchIntent, flags))
|
||||
@@ -311,54 +306,6 @@ class MainActivity : FlutterActivity() {
|
||||
null
|
||||
}
|
||||
|
||||
private fun launchableApps(): List<Map<String, Any>> {
|
||||
val intent = Intent(Intent.ACTION_MAIN).apply {
|
||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
}
|
||||
|
||||
val resolved = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
packageManager.queryIntentActivities(
|
||||
intent,
|
||||
PackageManager.ResolveInfoFlags.of(0L),
|
||||
)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
packageManager.queryIntentActivities(intent, 0)
|
||||
}
|
||||
|
||||
return resolved
|
||||
.mapNotNull { info ->
|
||||
val appPackage = info.activityInfo?.packageName ?: return@mapNotNull null
|
||||
if (appPackage == packageName) return@mapNotNull null
|
||||
|
||||
val item = mutableMapOf<String, Any>(
|
||||
"packageName" to appPackage,
|
||||
"label" to info.loadLabel(packageManager).toString(),
|
||||
)
|
||||
appIconPng(info)?.let { item["icon"] = it }
|
||||
item
|
||||
}
|
||||
.distinctBy { it["packageName"] as String }
|
||||
.sortedBy { (it["label"] as String).lowercase() }
|
||||
}
|
||||
|
||||
private fun appIconPng(info: ResolveInfo): ByteArray? = try {
|
||||
val drawable = info.loadIcon(packageManager)
|
||||
val density = resources.displayMetrics.density
|
||||
val size = (48f * density).roundToInt().coerceIn(48, 144)
|
||||
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap)
|
||||
drawable.setBounds(0, 0, size, size)
|
||||
drawable.draw(canvas)
|
||||
|
||||
ByteArrayOutputStream().use { output ->
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, output)
|
||||
output.toByteArray()
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun performHaptic(kind: String): Boolean {
|
||||
return try {
|
||||
val vibrator: Vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
|
||||
Reference in new issue
Block a user