ui: raise min SDK to 24

The difference between the usage of 21 and 24 is not big enough to hold
on to all the baggage from API 21

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Harsh Shandilya
2025-10-20 18:22:36 +02:00
committed by Jason A. Donenfeld
parent 0d18e478ca
commit 3b6ab660a9
12 changed files with 15 additions and 83 deletions
@@ -24,12 +24,10 @@ import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll; import com.wireguard.util.NonNullForAll;
import java.net.InetAddress; import java.net.InetAddress;
import java.time.Instant;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@@ -45,7 +43,7 @@ public final class GoBackend implements Backend {
private static final int DNS_RESOLUTION_RETRIES = 10; private static final int DNS_RESOLUTION_RETRIES = 10;
private static final String TAG = "WireGuard/GoBackend"; private static final String TAG = "WireGuard/GoBackend";
@Nullable private static AlwaysOnCallback alwaysOnCallback; @Nullable private static AlwaysOnCallback alwaysOnCallback;
private static GhettoCompletableFuture<VpnService> vpnService = new GhettoCompletableFuture<>(); private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
private final Context context; private final Context context;
@Nullable private Config currentConfig; @Nullable private Config currentConfig;
@Nullable private Tunnel currentTunnel; @Nullable private Tunnel currentTunnel;
@@ -377,35 +375,6 @@ public final class GoBackend implements Backend {
void alwaysOnTriggered(); void alwaysOnTriggered();
} }
// TODO: When we finally drop API 21 and move to API 24, delete this and replace with the ordinary CompletableFuture.
private static final class GhettoCompletableFuture<V> {
private final LinkedBlockingQueue<V> completion = new LinkedBlockingQueue<>(1);
private final FutureTask<V> result = new FutureTask<>(completion::peek);
public boolean complete(final V value) {
final boolean offered = completion.offer(value);
if (offered)
result.run();
return offered;
}
public V get() throws ExecutionException, InterruptedException {
return result.get();
}
public V get(final long timeout, final TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {
return result.get(timeout, unit);
}
public boolean isDone() {
return !completion.isEmpty();
}
public GhettoCompletableFuture<V> newIncompleteFuture() {
return new GhettoCompletableFuture<>();
}
}
/** /**
* {@link android.net.VpnService} implementation for {@link GoBackend} * {@link android.net.VpnService} implementation for {@link GoBackend}
*/ */
+1 -1
View File
@@ -21,7 +21,7 @@ android {
namespace = pkg namespace = pkg
defaultConfig { defaultConfig {
applicationId = pkg applicationId = pkg
minSdk = 21 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = providers.gradleProperty("wireguardVersionCode").get().toInt() versionCode = providers.gradleProperty("wireguardVersionCode").get().toInt()
versionName = providers.gradleProperty("wireguardVersionName").get() versionName = providers.gradleProperty("wireguardVersionName").get()
@@ -32,7 +32,6 @@ import kotlinx.coroutines.launch
* system framework as necessary to update the appearance of the tile in the system UI, and to * system framework as necessary to update the appearance of the tile in the system UI, and to
* forward click events to the application. * forward click events to the application.
*/ */
@RequiresApi(Build.VERSION_CODES.N)
class QuickTileService : TileService() { class QuickTileService : TileService() {
private val onStateChangedCallback = OnStateChangedCallback() private val onStateChangedCallback = OnStateChangedCallback()
private val onTunnelChangedCallback = OnTunnelChangedCallback() private val onTunnelChangedCallback = OnTunnelChangedCallback()
@@ -72,10 +72,6 @@ class SettingsActivity : AppCompatActivity() {
darkTheme?.parent?.removePreference(darkTheme) darkTheme?.parent?.removePreference(darkTheme)
--preferenceScreen.initialExpandedChildrenCount --preferenceScreen.initialExpandedChildrenCount
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
val remoteApps = preferenceManager.findPreference<Preference>("allow_remote_control_intents")
remoteApps?.parent?.removePreference(remoteApps)
}
if (AdminKnobs.disableConfigExport) { if (AdminKnobs.disableConfigExport) {
val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter") val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter")
zipExporter?.parent?.removePreference(zipExporter) zipExporter?.parent?.removePreference(zipExporter)
@@ -22,7 +22,6 @@ import com.wireguard.android.backend.Tunnel
import com.wireguard.android.util.ErrorMessages import com.wireguard.android.util.ErrorMessages
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@RequiresApi(Build.VERSION_CODES.N)
class TunnelToggleActivity : AppCompatActivity() { class TunnelToggleActivity : AppCompatActivity() {
private val permissionActivityResultLauncher = private val permissionActivityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() } registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { toggleTunnelWithPermissionsResult() }
@@ -266,7 +266,6 @@ class TvMainActivity : AppCompatActivity() {
private suspend fun makeStorageRoots(): Collection<KeyedFile> = withContext(Dispatchers.IO) { private suspend fun makeStorageRoots(): Collection<KeyedFile> = withContext(Dispatchers.IO) {
cachedRoots?.let { return@withContext it } cachedRoots?.let { return@withContext it }
val list = HashSet<KeyedFile>() val list = HashSet<KeyedFile>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val storageManager: StorageManager = getSystemService() ?: return@withContext list val storageManager: StorageManager = getSystemService() ?: return@withContext list
list.addAll(storageManager.storageVolumes.mapNotNull { volume -> list.addAll(storageManager.storageVolumes.mapNotNull { volume ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -275,22 +274,6 @@ class TvMainActivity : AppCompatActivity() {
KeyedFile((StorageVolume::class.java.getMethod("getPathFile").invoke(volume) as File), volume.getDescription(this@TvMainActivity)) KeyedFile((StorageVolume::class.java.getMethod("getPathFile").invoke(volume) as File), volume.getDescription(this@TvMainActivity))
} }
}) })
} else {
@Suppress("DEPRECATION")
list.add(KeyedFile(Environment.getExternalStorageDirectory()))
try {
File("/storage").listFiles()?.forEach {
if (!it.isDirectory) return@forEach
try {
if (Environment.isExternalStorageRemovable(it)) {
list.add(KeyedFile(it))
}
} catch (_: Throwable) {
}
}
} catch (_: Throwable) {
}
}
cachedRoots = list cachedRoots = list
list list
} }
@@ -221,10 +221,9 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
manager.refreshTunnelStates() manager.refreshTunnelStates()
return@launch return@launch
} }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || !UserKnobs.allowRemoteControlIntents.first()) if (!UserKnobs.allowRemoteControlIntents.first())
return@launch return@launch
val state: Tunnel.State val state = when (action) {
state = when (action) {
"com.wireguard.android.action.SET_TUNNEL_UP" -> Tunnel.State.UP "com.wireguard.android.action.SET_TUNNEL_UP" -> Tunnel.State.UP
"com.wireguard.android.action.SET_TUNNEL_DOWN" -> Tunnel.State.DOWN "com.wireguard.android.action.SET_TUNNEL_DOWN" -> Tunnel.State.DOWN
else -> return@launch else -> return@launch
@@ -264,7 +264,7 @@ object Updater {
throw IOException("Update could not be fetched: ${connection.responseCode}") throw IOException("Update could not be fetched: ${connection.responseCode}")
var downloadedByteLen: ULong = 0UL var downloadedByteLen: ULong = 0UL
val totalByteLen = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) connection.contentLengthLong else connection.contentLength).toLong().toULong() val totalByteLen = connection.contentLengthLong.toULong()
val fileBytes = ByteArray(1024 * 32 /* 32 KiB */) val fileBytes = ByteArray(1024 * 32 /* 32 KiB */)
val digest = MessageDigest.getInstance("SHA-256") val digest = MessageDigest.getInstance("SHA-256")
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true) emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
@@ -31,9 +31,6 @@ object QuantityFormatter {
fun formatEpochAgo(epochMillis: Long): String { fun formatEpochAgo(epochMillis: Long): String {
var span = (System.currentTimeMillis() - epochMillis) / 1000 var span = (System.currentTimeMillis() - epochMillis) / 1000
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
return Application.get().applicationContext.getString(R.string.latest_handshake_ago, span.seconds.toString())
if (span <= 0L) if (span <= 0L)
return RelativeDateTimeFormatter.getInstance().format(RelativeDateTimeFormatter.Direction.PLAIN, RelativeDateTimeFormatter.AbsoluteUnit.NOW) return RelativeDateTimeFormatter.getInstance().format(RelativeDateTimeFormatter.Direction.PLAIN, RelativeDateTimeFormatter.AbsoluteUnit.NOW)
val measureFormat = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) val measureFormat = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE)
@@ -15,7 +15,6 @@ import androidx.annotation.ColorInt
import androidx.annotation.IntRange import androidx.annotation.IntRange
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.N)
class SlashDrawable(private val mDrawable: Drawable) : Drawable() { class SlashDrawable(private val mDrawable: Drawable) : Drawable() {
private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG) private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private val mPath = Path() private val mPath = Path()
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="AppThemeBase">
<item name="android:statusBarColor">?android:colorBackground</item>
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
</style>
</resources>
+2 -1
View File
@@ -12,7 +12,8 @@
<item name="materialCardViewStyle">@style/WireGuardTheme.MaterialCardView</item> <item name="materialCardViewStyle">@style/WireGuardTheme.MaterialCardView</item>
<item name="toolbarStyle">@style/WireGuardTheme.Toolbar</item> <item name="toolbarStyle">@style/WireGuardTheme.Toolbar</item>
<item name="bottomSheetDialogTheme">@style/WireGuardTheme.BottomSheetDialog</item> <item name="bottomSheetDialogTheme">@style/WireGuardTheme.BottomSheetDialog</item>
<item name="android:statusBarColor">@null</item> <item name="android:statusBarColor">?android:colorBackground</item>
<item name="android:windowLightStatusBar">@bool/light_status_bar</item>
</style> </style>
<!-- Various additional API-specific features in values-v*/styles.xml --> <!-- Various additional API-specific features in values-v*/styles.xml -->