diff --git a/extensions/spoof-wifi/build.gradle.kts b/extensions/spoof-wifi/build.gradle.kts
new file mode 100644
index 000000000..4f8e643cd
--- /dev/null
+++ b/extensions/spoof-wifi/build.gradle.kts
@@ -0,0 +1,21 @@
+extension {
+ name = "extensions/all/connectivity/wifi/spoof/spoof-wifi.rve"
+}
+
+android {
+ namespace = "app.revanced.extension"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 21
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+}
+
+dependencies {
+ compileOnly(libs.annotation)
+}
diff --git a/extensions/spoof-wifi/src/main/AndroidManifest.xml b/extensions/spoof-wifi/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..7425a54c5
--- /dev/null
+++ b/extensions/spoof-wifi/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/extensions/spoof-wifi/src/main/java/app/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch.java b/extensions/spoof-wifi/src/main/java/app/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch.java
new file mode 100644
index 000000000..f266841d8
--- /dev/null
+++ b/extensions/spoof-wifi/src/main/java/app/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch.java
@@ -0,0 +1,431 @@
+package app.revanced.extension.all.connectivity.wifi.spoof;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.Build;
+import android.os.Handler;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+@RequiresApi(23)
+@SuppressWarnings({"deprecation", "unused"})
+public class SpoofWifiPatch {
+
+ // Used to check what the (real or fake) active network is (take a look at `hasTransport`).
+ private static ConnectivityManager CONNECTIVITY_MANAGER;
+
+ // If Wifi is not enabled, these are types that would pretend to be Wifi for android.net.Network (lower index = higher priority).
+ // This does not apply to android.net.NetworkInfo, because we can pretend that Wifi is always active there.
+ //
+ // VPN should be a fallback, because Reverse Tethering uses VPN.
+ private static final int[] FAKE_FALLBACK_NETWORKS = { NetworkCapabilities.TRANSPORT_ETHERNET, NetworkCapabilities.TRANSPORT_VPN };
+
+ // In order to initialize our own ConnectivityManager, if it isn't initialized yet.
+ public static Object getSystemService(Context context, String name) {
+ Object result = context.getSystemService(name);
+ if (CONNECTIVITY_MANAGER == null) {
+ if (context.getSystemService(Context.CONNECTIVITY_SERVICE) instanceof ConnectivityManager connectivityManager) {
+ CONNECTIVITY_MANAGER = connectivityManager;
+ }
+ }
+ return result;
+ }
+
+ // In order to initialize our own ConnectivityManager, if it isn't initialized yet.
+ public static Object getSystemService(Context context, Class> serviceClass) {
+ Object result = context.getSystemService(serviceClass);
+ if (CONNECTIVITY_MANAGER == null) {
+ if (context.getSystemService(Context.CONNECTIVITY_SERVICE) instanceof ConnectivityManager connectivityManager) {
+ CONNECTIVITY_MANAGER = connectivityManager;
+ }
+ }
+ return result;
+ }
+
+ // Simply always return Wifi as active network.
+ public static NetworkInfo getActiveNetworkInfo(ConnectivityManager connectivityManager) {
+ for (NetworkInfo networkInfo : connectivityManager.getAllNetworkInfo()) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return networkInfo;
+ }
+ }
+ return connectivityManager.getActiveNetworkInfo();
+ }
+
+ // Pretend Wifi is always connected.
+ public static boolean isConnected(NetworkInfo networkInfo) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return true;
+ }
+ return networkInfo.isConnected();
+ }
+
+ // Pretend Wifi is always connected.
+ public static boolean isConnectedOrConnecting(NetworkInfo networkInfo) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return true;
+ }
+ return networkInfo.isConnectedOrConnecting();
+ }
+
+ // Pretend Wifi is always available.
+ public static boolean isAvailable(NetworkInfo networkInfo) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return true;
+ }
+ return networkInfo.isAvailable();
+ }
+
+ // Pretend Wifi is always connected.
+ public static NetworkInfo.State getState(NetworkInfo networkInfo) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return NetworkInfo.State.CONNECTED;
+ }
+ return networkInfo.getState();
+ }
+
+ // Pretend Wifi is always connected.
+ public static NetworkInfo.DetailedState getDetailedState(NetworkInfo networkInfo) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return NetworkInfo.DetailedState.CONNECTED;
+ }
+ return networkInfo.getDetailedState();
+ }
+
+ // Pretend Wifi is enabled, so connection isn't metered.
+ public static boolean isActiveNetworkMetered(ConnectivityManager connectivityManager) {
+ return false;
+ }
+
+ // Returns the Wifi network, if Wifi is enabled.
+ // Otherwise if one of our fallbacks has a connection, return them.
+ // And as a last resort, return the default active network.
+ public static Network getActiveNetwork(ConnectivityManager connectivityManager) {
+ Network[] prioritizedNetworks = new Network[FAKE_FALLBACK_NETWORKS.length];
+ for (Network network : connectivityManager.getAllNetworks()) {
+ NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network);
+ if (networkCapabilities == null) {
+ continue;
+ }
+ if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return network;
+ }
+ if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ for (int i = 0; i < FAKE_FALLBACK_NETWORKS.length; i++) {
+ int transportType = FAKE_FALLBACK_NETWORKS[i];
+ if (networkCapabilities.hasTransport(transportType)) {
+ prioritizedNetworks[i] = network;
+ break;
+ }
+ }
+ }
+ }
+ for (Network network : prioritizedNetworks) {
+ if (network != null) {
+ return network;
+ }
+ }
+ return connectivityManager.getActiveNetwork();
+ }
+
+ // If the given network is a real or fake Wifi connection, return a Wifi network.
+ // Otherwise fallback to default implementation.
+ public static NetworkInfo getNetworkInfo(ConnectivityManager connectivityManager, Network network) {
+ NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network);
+ if (networkCapabilities != null && hasTransport(networkCapabilities, NetworkCapabilities.TRANSPORT_WIFI)) {
+ for (NetworkInfo networkInfo : connectivityManager.getAllNetworkInfo()) {
+ if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return networkInfo;
+ }
+ }
+ }
+ return connectivityManager.getNetworkInfo(network);
+ }
+
+ // If we are checking if the NetworkCapabilities use Wifi, return yes if
+ // - it is a real Wifi connection,
+ // - or the NetworkCapabilities are from a network pretending being a Wifi network.
+ // Otherwise fallback to default implementation.
+ public static boolean hasTransport(NetworkCapabilities networkCapabilities, int transportType) {
+ if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
+ if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return true;
+ }
+ if (CONNECTIVITY_MANAGER != null) {
+ Network activeNetwork = getActiveNetwork(CONNECTIVITY_MANAGER);
+ NetworkCapabilities activeNetworkCapabilities = CONNECTIVITY_MANAGER.getNetworkCapabilities(activeNetwork);
+ if (activeNetworkCapabilities != null) {
+ for (int fallbackTransportType : FAKE_FALLBACK_NETWORKS) {
+ if (activeNetworkCapabilities.hasTransport(fallbackTransportType) && networkCapabilities.hasTransport(fallbackTransportType)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return networkCapabilities.hasTransport(transportType);
+ }
+
+ // If the given network is a real or fake Wifi connection, pretend it has a connection (and some other things).
+ public static boolean hasCapability(NetworkCapabilities networkCapabilities, int capability) {
+ if (hasTransport(networkCapabilities, NetworkCapabilities.TRANSPORT_WIFI) && (
+ capability == NetworkCapabilities.NET_CAPABILITY_INTERNET
+ || capability == NetworkCapabilities.NET_CAPABILITY_FOREGROUND
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
+ || capability == NetworkCapabilities.NET_CAPABILITY_NOT_VPN
+ || capability == NetworkCapabilities.NET_CAPABILITY_TRUSTED
+ || capability == NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
+ return true;
+ }
+ return networkCapabilities.hasCapability(capability);
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(31)
+ public static void registerBestMatchingNetworkCallback(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.of(handler),
+ () -> connectivityManager.registerBestMatchingNetworkCallback(request, networkCallback, handler)
+ );
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(24)
+ public static void registerDefaultNetworkCallback(ConnectivityManager connectivityManager, ConnectivityManager.NetworkCallback networkCallback) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.empty(),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.empty(),
+ () -> connectivityManager.registerDefaultNetworkCallback(networkCallback)
+ );
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(26)
+ public static void registerDefaultNetworkCallback(ConnectivityManager connectivityManager, ConnectivityManager.NetworkCallback networkCallback, Handler handler) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.empty(),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.of(handler),
+ () -> connectivityManager.registerDefaultNetworkCallback(networkCallback, handler)
+ );
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ public static void registerNetworkCallback(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.empty(),
+ () -> connectivityManager.registerNetworkCallback(request, networkCallback)
+ );
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately.
+ public static void registerNetworkCallback(ConnectivityManager connectivityManager, NetworkRequest request, PendingIntent operation) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.empty(),
+ Utils.Option.of(operation),
+ Utils.Option.empty(),
+ () -> connectivityManager.registerNetworkCallback(request, operation)
+ );
+ }
+
+ // If it waits for Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(26)
+ public static void registerNetworkCallback(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.of(handler),
+ () -> connectivityManager.registerNetworkCallback(request, networkCallback, handler)
+ );
+ }
+
+ // If it requests Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ public static void requestNetwork(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.empty(),
+ () -> connectivityManager.requestNetwork(request, networkCallback)
+ );
+ }
+
+ // If it requests Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(26)
+ public static void requestNetwork(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, int timeoutMs) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.empty(),
+ () -> connectivityManager.requestNetwork(request, networkCallback, timeoutMs)
+ );
+ }
+
+ // If it requests Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(26)
+ public static void requestNetwork(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.of(handler),
+ () -> connectivityManager.requestNetwork(request, networkCallback, handler)
+ );
+ }
+
+ // If it requests Wifi connectivity, pretend it is fulfilled immediately.
+ public static void requestNetwork(ConnectivityManager connectivityManager, NetworkRequest request, PendingIntent operation) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.empty(),
+ Utils.Option.of(operation),
+ Utils.Option.empty(),
+ () -> connectivityManager.requestNetwork(request, operation)
+ );
+ }
+
+ // If it requests Wifi connectivity, pretend it is fulfilled immediately if we have an active network.
+ @RequiresApi(26)
+ public static void requestNetwork(ConnectivityManager connectivityManager, NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback, Handler handler, int timeoutMs) {
+ Utils.networkCallback(
+ connectivityManager,
+ Utils.Option.of(request),
+ Utils.Option.of(networkCallback),
+ Utils.Option.empty(),
+ Utils.Option.of(handler),
+ () -> connectivityManager.requestNetwork(request, networkCallback, handler, timeoutMs)
+ );
+ }
+
+ public static void unregisterNetworkCallback(ConnectivityManager connectivityManager, ConnectivityManager.NetworkCallback networkCallback) {
+ try {
+ connectivityManager.unregisterNetworkCallback(networkCallback);
+ } catch (IllegalArgumentException ignore) {
+ // ignore: NetworkCallback was not registered
+ }
+ }
+
+ public static void unregisterNetworkCallback(ConnectivityManager connectivityManager, PendingIntent operation) {
+ try {
+ connectivityManager.unregisterNetworkCallback(operation);
+ } catch (IllegalArgumentException ignore) {
+ // ignore: PendingIntent was not registered
+ }
+ }
+
+ private static class Utils {
+ private static class Option {
+ private final T value;
+ private final boolean isPresent;
+
+ private Option(T value, boolean isPresent) {
+ this.value = value;
+ this.isPresent = isPresent;
+ }
+
+ private static Option of(T value) {
+ return new Option<>(value, true);
+ }
+
+ private static Option empty() {
+ return new Option<>(null, false);
+ }
+ }
+
+ /**
+ * @return whether the device's API level is higher than a specific SDK version.
+ */
+ private static boolean isSDKAbove(int sdk) {
+ return Build.VERSION.SDK_INT >= sdk;
+ }
+
+ private static void networkCallback(
+ ConnectivityManager connectivityManager,
+ Option request,
+ Option networkCallback,
+ Option operation,
+ Option handler,
+ Runnable fallback
+ ) {
+ if(!request.isPresent || requestsWifiNetwork(request.value)) {
+ Runnable runnable = null;
+ if (networkCallback.isPresent && networkCallback.value != null) {
+ Network network = activeWifiNetwork(connectivityManager);
+ if (network != null) {
+ runnable = () -> networkCallback.value.onAvailable(network);
+ }
+ } else if (operation.isPresent && operation.value != null) {
+ runnable = () -> {
+ try {
+ operation.value.send();
+ } catch (PendingIntent.CanceledException ignore) {}
+ };
+ }
+ if (runnable != null) {
+ if (handler.isPresent) {
+ if (handler.value != null) {
+ handler.value.post(runnable);
+ return;
+ }
+ } else {
+ runnable.run();
+ return;
+ }
+ }
+ }
+ fallback.run();
+ }
+
+ // Returns an active (maybe fake) Wifi network if there is one, otherwise null.
+ private static Network activeWifiNetwork(ConnectivityManager connectivityManager) {
+ Network network = getActiveNetwork(connectivityManager);
+ NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network);
+ if (networkCapabilities != null && hasTransport(networkCapabilities, NetworkCapabilities.TRANSPORT_WIFI)) {
+ return network;
+ }
+ return null;
+ }
+
+ // Whether a Wifi network with connection is requested.
+ private static boolean requestsWifiNetwork(@Nullable NetworkRequest request) {
+ if (request != null && isSDKAbove(28)) {
+ return request.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ && (request.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ || request.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED));
+ }
+ return false;
+ }
+ }
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt
new file mode 100644
index 000000000..3758030cd
--- /dev/null
+++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt
@@ -0,0 +1,225 @@
+package app.revanced.patches.all.misc.connectivity.wifi.spoof
+
+import app.revanced.patcher.patch.bytecodePatch
+import app.revanced.patches.all.misc.transformation.IMethodCall
+import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
+import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
+
+internal const val EXTENSION_CLASS_DESCRIPTOR_PREFIX =
+ "Lapp/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch"
+
+internal const val EXTENSION_CLASS_DESCRIPTOR = "$EXTENSION_CLASS_DESCRIPTOR_PREFIX;"
+
+@Suppress("unused")
+val spoofWifiPatch = bytecodePatch(
+ name = "Spoof Wi-Fi connection",
+ description = "Spoofs an existing Wi-Fi connection.",
+ use = false,
+) {
+ extendWith("extensions/all/connectivity/wifi/spoof/spoof-wifi.rve")
+
+ dependsOn(
+ transformInstructionsPatch(
+ filterMap = { classDef, _, instruction, instructionIndex ->
+ filterMapInstruction35c(
+ EXTENSION_CLASS_DESCRIPTOR_PREFIX,
+ classDef,
+ instruction,
+ instructionIndex,
+ )
+ },
+ transform = { method, entry ->
+ val (methodType, instruction, instructionIndex) = entry
+ methodType.replaceInvokeVirtualWithExtension(
+ EXTENSION_CLASS_DESCRIPTOR,
+ method,
+ instruction,
+ instructionIndex,
+ )
+ },
+ ),
+ )
+}
+
+// Information about method calls we want to replace
+@Suppress("unused")
+private enum class MethodCall(
+ override val definedClassName: String,
+ override val methodName: String,
+ override val methodParams: Array,
+ override val returnType: String,
+) : IMethodCall {
+ GetSystemService1(
+ "Landroid/content/Context;",
+ "getSystemService",
+ arrayOf("Ljava/lang/String;"),
+ "Ljava/lang/Object;",
+ ),
+ GetSystemService2(
+ "Landroid/content/Context;",
+ "getSystemService",
+ arrayOf("Ljava/lang/Class;"),
+ "Ljava/lang/Object;",
+ ),
+ GetActiveNetworkInfo(
+ "Landroid/net/ConnectivityManager;",
+ "getActiveNetworkInfo",
+ arrayOf(),
+ "Landroid/net/NetworkInfo;",
+ ),
+ IsConnected(
+ "Landroid/net/NetworkInfo;",
+ "isConnected",
+ arrayOf(),
+ "Z",
+ ),
+ IsConnectedOrConnecting(
+ "Landroid/net/NetworkInfo;",
+ "isConnectedOrConnecting",
+ arrayOf(),
+ "Z",
+ ),
+ IsAvailable(
+ "Landroid/net/NetworkInfo;",
+ "isAvailable",
+ arrayOf(),
+ "Z",
+ ),
+ GetState(
+ "Landroid/net/NetworkInfo;",
+ "getState",
+ arrayOf(),
+ "Landroid/net/NetworkInfo\$State;",
+ ),
+ GetDetailedState(
+ "Landroid/net/NetworkInfo;",
+ "getDetailedState",
+ arrayOf(),
+ "Landroid/net/NetworkInfo\$DetailedState;",
+ ),
+ IsActiveNetworkMetered(
+ "Landroid/net/ConnectivityManager;",
+ "isActiveNetworkMetered",
+ arrayOf(),
+ "Z",
+ ),
+ GetActiveNetwork(
+ "Landroid/net/ConnectivityManager;",
+ "getActiveNetwork",
+ arrayOf(),
+ "Landroid/net/Network;",
+ ),
+ GetNetworkInfo(
+ "Landroid/net/ConnectivityManager;",
+ "getNetworkInfo",
+ arrayOf("Landroid/net/Network;"),
+ "Landroid/net/NetworkInfo;",
+ ),
+ HasTransport(
+ "Landroid/net/NetworkCapabilities;",
+ "hasTransport",
+ arrayOf("I"),
+ "Z",
+ ),
+ HasCapability(
+ "Landroid/net/NetworkCapabilities;",
+ "hasCapability",
+ arrayOf("I"),
+ "Z",
+ ),
+ RegisterBestMatchingNetworkCallback(
+ "Landroid/net/ConnectivityManager;",
+ "registerBestMatchingNetworkCallback",
+ arrayOf(
+ "Landroid/net/NetworkRequest;",
+ "Landroid/net/ConnectivityManager\$NetworkCallback;",
+ "Landroid/os/Handler;",
+ ),
+ "V",
+ ),
+ RegisterDefaultNetworkCallback1(
+ "Landroid/net/ConnectivityManager;",
+ "registerDefaultNetworkCallback",
+ arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
+ "V",
+ ),
+ RegisterDefaultNetworkCallback2(
+ "Landroid/net/ConnectivityManager;",
+ "registerDefaultNetworkCallback",
+ arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
+ "V",
+ ),
+ RegisterNetworkCallback1(
+ "Landroid/net/ConnectivityManager;",
+ "registerNetworkCallback",
+ arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
+ "V",
+ ),
+ RegisterNetworkCallback2(
+ "Landroid/net/ConnectivityManager;",
+ "registerNetworkCallback",
+ arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
+ "V",
+ ),
+ RegisterNetworkCallback3(
+ "Landroid/net/ConnectivityManager;",
+ "registerNetworkCallback",
+ arrayOf(
+ "Landroid/net/NetworkRequest;",
+ "Landroid/net/ConnectivityManager\$NetworkCallback;",
+ "Landroid/os/Handler;",
+ ),
+ "V",
+ ),
+ RequestNetwork1(
+ "Landroid/net/ConnectivityManager;",
+ "requestNetwork",
+ arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
+ "V",
+ ),
+ RequestNetwork2(
+ "Landroid/net/ConnectivityManager;",
+ "requestNetwork",
+ arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "I"),
+ "V",
+ ),
+ RequestNetwork3(
+ "Landroid/net/ConnectivityManager;",
+ "requestNetwork",
+ arrayOf(
+ "Landroid/net/NetworkRequest;",
+ "Landroid/net/ConnectivityManager\$NetworkCallback;",
+ "Landroid/os/Handler;",
+ ),
+ "V",
+ ),
+ RequestNetwork4(
+ "Landroid/net/ConnectivityManager;",
+ "requestNetwork",
+ arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
+ "V",
+ ),
+ RequestNetwork5(
+ "Landroid/net/ConnectivityManager;",
+ "requestNetwork",
+ arrayOf(
+ "Landroid/net/NetworkRequest;",
+ "Landroid/net/ConnectivityManager\$NetworkCallback;",
+ "Landroid/os/Handler;",
+ "I",
+ ),
+ "V",
+ ),
+ UnregisterNetworkCallback1(
+ "Landroid/net/ConnectivityManager;",
+ "unregisterNetworkCallback",
+ arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
+ "V",
+ ),
+ UnregisterNetworkCallback2(
+ "Landroid/net/ConnectivityManager;",
+ "unregisterNetworkCallback",
+ arrayOf("Landroid/app/PendingIntent;"),
+ "V",
+ ),
+}
diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/transformation/MethodCall.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/MethodCall.kt
similarity index 98%
rename from patches/src/main/kotlin/app/revanced/patches/shared/transformation/MethodCall.kt
rename to patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/MethodCall.kt
index 37213570e..a033333fb 100644
--- a/patches/src/main/kotlin/app/revanced/patches/shared/transformation/MethodCall.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/MethodCall.kt
@@ -1,4 +1,4 @@
-package app.revanced.patches.shared.transformation
+package app.revanced.patches.all.misc.transformation
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/transformation/TransformInstructionsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt
similarity index 84%
rename from patches/src/main/kotlin/app/revanced/patches/shared/transformation/TransformInstructionsPatch.kt
rename to patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt
index c01aa1456..7d5bcb0ad 100644
--- a/patches/src/main/kotlin/app/revanced/patches/shared/transformation/TransformInstructionsPatch.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/transformation/TransformInstructionsPatch.kt
@@ -1,4 +1,4 @@
-package app.revanced.patches.shared.transformation
+package app.revanced.patches.all.misc.transformation
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
@@ -8,10 +8,15 @@ import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
+private const val EXTENSION_NAME_SPACE_PATH =
+ "Lapp/revanced/extension/"
+
fun transformInstructionsPatch(
filterMap: (ClassDef, Method, Instruction, Int) -> T?,
transform: (MutableMethod, T) -> Unit,
executeBlock: BytecodePatchContext.() -> Unit = {},
+ // If the instructions of Extension are replaced, the patch may not work as intended.
+ skipExtension: Boolean = true,
) = bytecodePatch(
description = "transformInstructionsPatch"
) {
@@ -26,6 +31,9 @@ fun transformInstructionsPatch(
// Find all methods to patch
buildMap {
classes.forEach { classDef ->
+ if (skipExtension && classDef.type.startsWith(EXTENSION_NAME_SPACE_PATH)) {
+ return@forEach
+ }
val methods = buildList {
classDef.methods.forEach { method ->
// Since the Sequence executes lazily,
diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/openlinks/externally/OpenLinksExternallyPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/openlinks/externally/OpenLinksExternallyPatch.kt
index 4a7d1cd9a..d20e8e1a6 100644
--- a/patches/src/main/kotlin/app/revanced/patches/youtube/misc/openlinks/externally/OpenLinksExternallyPatch.kt
+++ b/patches/src/main/kotlin/app/revanced/patches/youtube/misc/openlinks/externally/OpenLinksExternallyPatch.kt
@@ -2,7 +2,7 @@ package app.revanced.patches.youtube.misc.openlinks.externally
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
-import app.revanced.patches.shared.transformation.transformInstructionsPatch
+import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.MISC_PATH
import app.revanced.patches.youtube.utils.patch.PatchList.OPEN_LINKS_EXTERNALLY