fix: Use deprecated members to ensure backwards compatibility

By migrating to early to new APIs of ReVanced Patcher, if you were to use old versions of ReVanced Patcher, you would get compatibility issues. By using deprecated members until most have updated ReVanced Patcher, we can ensure seamless migration.
This commit is contained in:
oSumAtrIX 2024-02-22 00:05:41 +01:00
parent 930dc297c1
commit 083bd40092
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
24 changed files with 174 additions and 108 deletions

View File

@ -1746,7 +1746,6 @@ public final class app/revanced/util/ResourceUtilsKt {
public static final fun asSequence (Lorg/w3c/dom/NodeList;)Lkotlin/sequences/Sequence; public static final fun asSequence (Lorg/w3c/dom/NodeList;)Lkotlin/sequences/Sequence;
public static final fun childElementsSequence (Lorg/w3c/dom/Node;)Lkotlin/sequences/Sequence; public static final fun childElementsSequence (Lorg/w3c/dom/Node;)Lkotlin/sequences/Sequence;
public static final fun copyResources (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;[Lapp/revanced/util/ResourceGroup;)V public static final fun copyResources (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;[Lapp/revanced/util/ResourceGroup;)V
public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/Document;Lapp/revanced/patcher/util/Document;)Ljava/lang/AutoCloseable;
public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/DomFileEditor;Lapp/revanced/patcher/util/DomFileEditor;)Ljava/lang/AutoCloseable; public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/DomFileEditor;Lapp/revanced/patcher/util/DomFileEditor;)Ljava/lang/AutoCloseable;
public static final fun doRecursively (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V public static final fun doRecursively (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V

View File

@ -14,7 +14,9 @@ object ExportAllActivitiesPatch : ResourcePatch() {
private const val EXPORTED_FLAG = "android:exported" private const val EXPORTED_FLAG = "android:exported"
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val activities = document.getElementsByTagName("activity") val activities = document.getElementsByTagName("activity")
for (i in 0..activities.length) { for (i in 0..activities.length) {

View File

@ -14,7 +14,9 @@ object PredictiveBackGesturePatch : ResourcePatch() {
private const val FLAG = "android:enableOnBackInvokedCallback" private const val FLAG = "android:enableOnBackInvokedCallback"
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
with(document.getElementsByTagName("application").item(0)) { with(document.getElementsByTagName("application").item(0)) {
if (attributes.getNamedItem(FLAG) != null) return@with if (attributes.getNamedItem(FLAG) != null) return@with

View File

@ -13,7 +13,9 @@ import org.w3c.dom.Element
@Suppress("unused") @Suppress("unused")
object EnableAndroidDebuggingPatch : ResourcePatch() { object EnableAndroidDebuggingPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = val applicationNode =
document document
.getElementsByTagName("application") .getElementsByTagName("application")

View File

@ -16,10 +16,12 @@ import java.io.File
@Suppress("unused") @Suppress("unused")
object OverrideCertificatePinningPatch : ResourcePatch() { object OverrideCertificatePinningPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
val resXmlDirectory = context.get("res/xml", false) val resXmlDirectory = context.get("res/xml")
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist. // Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = document.getElementsByTagName("application").item(0) as Element val applicationNode = document.getElementsByTagName("application").item(0) as Element
if (!applicationNode.hasAttribute("networkSecurityConfig")) { if (!applicationNode.hasAttribute("networkSecurityConfig")) {

View File

@ -52,7 +52,9 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable {
} }
override fun close() = override fun close() =
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val replacementPackageName = packageNameOption.value val replacementPackageName = packageNameOption.value
val manifest = document.getElementsByTagName("manifest").item(0) as Element val manifest = document.getElementsByTagName("manifest").item(0) as Element

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.Document import app.revanced.patcher.util.DomFileEditor
import app.revanced.patches.all.misc.resources.AddResourcesPatch.resources import app.revanced.patches.all.misc.resources.AddResourcesPatch.resources
import app.revanced.util.* import app.revanced.util.*
import app.revanced.util.resource.ArrayResource import app.revanced.util.resource.ArrayResource
@ -92,8 +92,10 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
// instead of overwriting it. // instead of overwriting it.
// This covers the example case such as adding strings and arrays of the same value. // This covers the example case such as adding strings and arrays of the same value.
getOrPut(value, ::mutableMapOf).apply { getOrPut(value, ::mutableMapOf).apply {
context.document[stream].use { context.xmlEditor[stream].use { editor ->
it.getElementsByTagName("app").asSequence().forEach { app -> val document = editor.file
document.getElementsByTagName("app").asSequence().forEach { app ->
val appId = app.attributes.getNamedItem("id").textContent val appId = app.attributes.getNamedItem("id").textContent
getOrPut(appId, ::mutableMapOf).apply { getOrPut(appId, ::mutableMapOf).apply {
@ -237,7 +239,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
* This is called after all patches that depend on [AddResourcesPatch] have been executed. * This is called after all patches that depend on [AddResourcesPatch] have been executed.
*/ */
override fun close() { override fun close() {
operator fun MutableMap<String, Pair<Document, Node>>.invoke( operator fun MutableMap<String, Pair<DomFileEditor, Node>>.invoke(
value: Value, value: Value,
resource: BaseResource, resource: BaseResource,
) { ) {
@ -253,16 +255,18 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
getOrPut(resourceFileName) { getOrPut(resourceFileName) {
val targetFile = val targetFile =
context.get("res/$value/$resourceFileName.xml", false).also { context.get("res/$value/$resourceFileName.xml").also {
it.parentFile?.mkdirs() it.parentFile?.mkdirs()
it.createNewFile() it.createNewFile()
} }
context.document[targetFile.path].let { document -> context.xmlEditor[targetFile.path].let { editor ->
val document = editor.file
// Save the target node here as well // Save the target node here as well
// in order to avoid having to call document.getNode("resources") // in order to avoid having to call document.getNode("resources")
// but also save the document so that it can be closed later. // but also save the document so that it can be closed later.
document to document.getNode("resources") editor to document.getNode("resources")
} }
}.let { (_, targetNode) -> }.let { (_, targetNode) ->
targetNode.addResource(resource) { invoke(value, it) } targetNode.addResource(resource) { invoke(value, it) }
@ -276,7 +280,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
// This is done to prevent having to open the files for every resource that is added. // This is done to prevent having to open the files for every resource that is added.
// Instead, it is cached once and reused for resources of the same value. // Instead, it is cached once and reused for resources of the same value.
// This map is later accessed to close all documents for the current resource value. // This map is later accessed to close all documents for the current resource value.
val documents = mutableMapOf<String, Pair<Document, Node>>() val documents = mutableMapOf<String, Pair<DomFileEditor, Node>>()
resources.forEach { resource -> documents(value, resource) } resources.forEach { resource -> documents(value, resource) }

View File

@ -8,7 +8,9 @@ import org.w3c.dom.Element
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.") @Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() { internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
// get the application node // get the application node
val applicationNode = val applicationNode =
document document

View File

@ -15,7 +15,9 @@ import org.w3c.dom.Element
@Suppress("unused") @Suppress("unused")
object RemoveBroadcastsRestrictionPatch : ResourcePatch() { object RemoveBroadcastsRestrictionPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = val applicationNode =
document document
.getElementsByTagName("application") .getElementsByTagName("application")

View File

@ -9,8 +9,10 @@ object HideBannerPatch : ResourcePatch() {
private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml" private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml"
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document[RESOURCE_FILE_PATH].use { context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
it.getElementsByTagName("merge").item(0).childNodes.apply { val document = editor.file
document.getElementsByTagName("merge").item(0).childNodes.apply {
val attributes = arrayOf("height", "width") val attributes = arrayOf("height", "width")
for (i in 1 until length) { for (i in 1 until length) {

View File

@ -60,7 +60,9 @@ abstract class BaseGmsCoreSupportResourcePatch(
appendChild(child) appendChild(child)
} }
document["AndroidManifest.xml"].use { document -> xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = val applicationNode =
document document
.getElementsByTagName("application") .getElementsByTagName("application")
@ -92,8 +94,8 @@ abstract class BaseGmsCoreSupportResourcePatch(
private fun ResourceContext.patchManifest() { private fun ResourceContext.patchManifest() {
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName) val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
val manifest = this.get("AndroidManifest.xml", false).readText() val manifest = this.get("AndroidManifest.xml").readText()
this.get("AndroidManifest.xml", false).writeText( this.get("AndroidManifest.xml").writeText(
manifest.replace( manifest.replace(
"package=\"$fromPackageName", "package=\"$fromPackageName",
"package=\"$packageName", "package=\"$packageName",

View File

@ -16,14 +16,16 @@ object ResourceMappingPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// save the file in memory to concurrently read from // save the file in memory to concurrently read from
val resourceXmlFile = context.get("res/values/public.xml", false).readBytes() val resourceXmlFile = context.get("res/values/public.xml").readBytes()
// create a synchronized list to store the resource mappings // create a synchronized list to store the resource mappings
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>()) val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
for (threadIndex in 0 until THREAD_COUNT) { for (threadIndex in 0 until THREAD_COUNT) {
threadPoolExecutor.execute thread@{ threadPoolExecutor.execute thread@{
context.document[resourceXmlFile.inputStream()].use { document -> context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val document = editor.file
val resources = document.documentElement.childNodes val resources = document.documentElement.childNodes
val resourcesLength = resources.length val resourcesLength = resources.length
val jobSize = resourcesLength / THREAD_COUNT val jobSize = resourcesLength / THREAD_COUNT

View File

@ -51,13 +51,17 @@ abstract class BaseSettingsResourcePatch(
// Add the root preference to an existing fragment if needed. // Add the root preference to an existing fragment if needed.
rootPreference?.let { (intentPreference, fragment) -> rootPreference?.let { (intentPreference, fragment) ->
context.document["res/xml/$fragment.xml"].use { context.xmlEditor["res/xml/$fragment.xml"].use { editor ->
it.getNode("PreferenceScreen").addPreference(intentPreference) val document = editor.file
document.getNode("PreferenceScreen").addPreference(intentPreference)
} }
} }
// Add all preferences to the ReVanced fragment. // Add all preferences to the ReVanced fragment.
context.document["res/xml/revanced_prefs.xml"].use { document -> context.xmlEditor["res/xml/revanced_prefs.xml"].use { editor ->
val document = editor.file
val revancedPreferenceScreenNode = document.getNode("PreferenceScreen") val revancedPreferenceScreenNode = document.getNode("PreferenceScreen")
forEach { revancedPreferenceScreenNode.addPreference(it) } forEach { revancedPreferenceScreenNode.addPreference(it) }
} }

View File

@ -54,7 +54,9 @@ object CustomThemePatch : ResourcePatch() {
val accentColor = accentColor!! val accentColor = accentColor!!
val accentColorPressed = accentColorPressed!! val accentColorPressed = accentColorPressed!!
context.document["res/values/colors.xml"].use { document -> context.xmlEditor["res/values/colors.xml"].use { editor ->
val document = editor.file
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
for (i in 0 until resourcesNode.childNodes.length) { for (i in 0 until resourcesNode.childNodes.length) {

View File

@ -16,7 +16,7 @@ import java.nio.file.Files
@Suppress("unused") @Suppress("unused")
object DynamicColorPatch : ResourcePatch() { object DynamicColorPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
val resDirectory = context.get("res", false) val resDirectory = context.get("res")
if (!resDirectory.isDirectory) throw PatchException("The res folder can not be found.") if (!resDirectory.isDirectory) throw PatchException("The res folder can not be found.")
val valuesV31Directory = resDirectory.resolve("values-v31") val valuesV31Directory = resDirectory.resolve("values-v31")
@ -35,7 +35,9 @@ object DynamicColorPatch : ResourcePatch() {
} }
} }
context.document["res/values-v31/colors.xml"].use { document -> context.xmlEditor["res/values-v31/colors.xml"].use { editor ->
val document = editor.file
mapOf( mapOf(
"ps__twitter_blue" to "@color/twitter_blue", "ps__twitter_blue" to "@color/twitter_blue",
"ps__twitter_blue_pressed" to "@color/twitter_blue_fill_pressed", "ps__twitter_blue_pressed" to "@color/twitter_blue_fill_pressed",
@ -55,7 +57,9 @@ object DynamicColorPatch : ResourcePatch() {
} }
} }
context.document["res/values-night-v31/colors.xml"].use { document -> context.xmlEditor["res/values-night-v31/colors.xml"].use { editor ->
val document = editor.file
mapOf( mapOf(
"twitter_blue" to "@android:color/system_accent1_200", "twitter_blue" to "@android:color/system_accent1_200",
"twitter_blue_fill_pressed" to "@android:color/system_accent1_300", "twitter_blue_fill_pressed" to "@android:color/system_accent1_300",

View File

@ -81,7 +81,7 @@ object CustomBrandingPatch : ResourcePatch() {
}.let { resourceGroups -> }.let { resourceGroups ->
if (icon != REVANCED_ICON) { if (icon != REVANCED_ICON) {
val path = File(icon) val path = File(icon)
val resourceDirectory = context.get("res", false) val resourceDirectory = context.get("res")
resourceGroups.forEach { group -> resourceGroups.forEach { group ->
val fromDirectory = path.resolve(group.resourceDirectoryName) val fromDirectory = path.resolve(group.resourceDirectoryName)
@ -102,7 +102,7 @@ object CustomBrandingPatch : ResourcePatch() {
appName?.let { name -> appName?.let { name ->
// Change the app name. // Change the app name.
val manifest = context.get("AndroidManifest.xml", false) val manifest = context.get("AndroidManifest.xml")
manifest.writeText( manifest.writeText(
manifest.readText() manifest.readText()
.replace( .replace(

View File

@ -71,7 +71,7 @@ object ChangeHeaderPatch : ResourcePatch() {
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
// The directories to copy the header to. // The directories to copy the header to.
val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull { val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull {
context.get("res", false).resolve(it).takeIf(File::exists) context.get("res").resolve(it).takeIf(File::exists)
} }
// The files to replace in the target directories. // The files to replace in the target directories.
val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName -> val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName ->
@ -120,7 +120,7 @@ object ChangeHeaderPatch : ResourcePatch() {
// For each source folder, copy the files to the target resource directories. // For each source folder, copy the files to the target resource directories.
sourceFolders.forEach { dpiSourceFolder -> sourceFolders.forEach { dpiSourceFolder ->
val targetDpiFolder = context.get("res", false).resolve(dpiSourceFolder.name) val targetDpiFolder = context.get("res").resolve(dpiSourceFolder.name)
if (!targetDpiFolder.exists()) return@forEach if (!targetDpiFolder.exists()) return@forEach
val imgSourceFiles = dpiSourceFolder.listFiles { file -> file.isFile }!! val imgSourceFiles = dpiSourceFolder.listFiles { file -> file.isFile }!!

View File

@ -37,7 +37,9 @@ object PlayerControlsBackgroundPatch : ResourcePatch() {
private const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" private const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml"
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
context.document[RESOURCE_FILE_PATH].use { document -> context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
val document = editor.file
document.doRecursively node@{ node -> document.doRecursively node@{ node ->
if (node !is Element) return@node if (node !is Element) return@node

View File

@ -29,7 +29,9 @@ internal object SeekbarColorResourcePatch : ResourcePatch() {
findColorResource("inline_time_bar_played_not_highlighted_color") findColorResource("inline_time_bar_played_not_highlighted_color")
// Edit the resume playback drawable and replace the progress bar with a custom drawable // Edit the resume playback drawable and replace the progress bar with a custom drawable
context.document["res/drawable/resume_playback_progressbar_drawable.xml"].use { document -> context.xmlEditor["res/drawable/resume_playback_progressbar_drawable.xml"].use { editor ->
val document = editor.file
val layerList = document.getElementsByTagName("layer-list").item(0) as Element val layerList = document.getElementsByTagName("layer-list").item(0) as Element
val progressNode = layerList.getElementsByTagName("item").item(1) as Element val progressNode = layerList.getElementsByTagName("item").item(1) as Element
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) { if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {

View File

@ -65,12 +65,14 @@ internal object SponsorBlockResourcePatch : ResourcePatch() {
)!! )!!
var modifiedControlsLayout = false var modifiedControlsLayout = false
val targetDocument = context.document["res/layout/youtube_controls_layout.xml"] val editor = context.xmlEditor["res/layout/youtube_controls_layout.xml"]
"RelativeLayout".copyXmlNode( "RelativeLayout".copyXmlNode(
context.document[hostingResourceStream], context.xmlEditor[hostingResourceStream],
targetDocument, editor,
).also { ).also {
val children = targetDocument.getElementsByTagName("RelativeLayout").item(0).childNodes val document = editor.file
val children = document.getElementsByTagName("RelativeLayout").item(0).childNodes
// Replace the startOf with the voting button view so that the button does not overlap // Replace the startOf with the voting button view so that the button does not overlap
for (i in 1 until children.length) { for (i in 1 until children.length) {

View File

@ -35,7 +35,9 @@ internal object ThemeResourcePatch : ResourcePatch() {
) )
// Edit theme colors via resources. // Edit theme colors via resources.
context.document["res/values/colors.xml"].use { document -> context.xmlEditor["res/values/colors.xml"].use { editor ->
val document = editor.file
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
val children = resourcesNode.childNodes val children = resourcesNode.childNodes
@ -76,8 +78,10 @@ internal object ThemeResourcePatch : ResourcePatch() {
) )
splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile -> splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile ->
context.document[resourceFile].use { context.xmlEditor[resourceFile].use { editor ->
val layerList = it.getElementsByTagName("layer-list").item(0) as Element val document = editor.file
val layerList = document.getElementsByTagName("layer-list").item(0) as Element
val childNodes = layerList.childNodes val childNodes = layerList.childNodes
for (i in 0 until childNodes.length) { for (i in 0 until childNodes.length) {
@ -99,11 +103,13 @@ internal object ThemeResourcePatch : ResourcePatch() {
colorName: String, colorName: String,
colorValue: String, colorValue: String,
) { ) {
context.document[resourceFile].use { context.xmlEditor[resourceFile].use { editor ->
val resourcesNode = it.getElementsByTagName("resources").item(0) as Element val document = editor.file
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild( resourcesNode.appendChild(
it.createElement("color").apply { document.createElement("color").apply {
setAttribute("name", colorName) setAttribute("name", colorName)
setAttribute("category", "color") setAttribute("category", "color")
textContent = colorValue textContent = colorValue

View File

@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.playercontrols
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.Document import app.revanced.patcher.util.DomFileEditor
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
import java.io.Closeable import java.io.Closeable
@ -18,14 +18,13 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable {
private var lastLeftOf = "fullscreen_button" private var lastLeftOf = "fullscreen_button"
private lateinit var resourceContext: ResourceContext private lateinit var resourceContext: ResourceContext
private lateinit var targetDocument: Document private lateinit var targetDocumentEditor: DomFileEditor
override fun execute(context: ResourceContext) { override fun execute(context: ResourceContext) {
resourceContext = context resourceContext = context
targetDocument = context.document[TARGET_RESOURCE] targetDocumentEditor = context.xmlEditor[TARGET_RESOURCE]
bottomUiContainerResourceId = bottomUiContainerResourceId = ResourceMappingPatch.resourceMappings
ResourceMappingPatch.resourceMappings
.single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id .single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id
} }
@ -35,21 +34,21 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable {
* @param resourceDirectoryName The name of the directory containing the hosting resource. * @param resourceDirectoryName The name of the directory containing the hosting resource.
*/ */
fun addControls(resourceDirectoryName: String) { fun addControls(resourceDirectoryName: String) {
val sourceDocument = val sourceDocumentEditor = resourceContext.xmlEditor[
resourceContext.document[
this::class.java.classLoader.getResourceAsStream( this::class.java.classLoader.getResourceAsStream(
"$resourceDirectoryName/host/layout/$TARGET_RESOURCE_NAME", "$resourceDirectoryName/host/layout/$TARGET_RESOURCE_NAME",
)!!, )!!,
] ]
val sourceDocument = sourceDocumentEditor.file
val targetDocument = targetDocumentEditor.file
val targetElement = "android.support.constraint.ConstraintLayout" val targetElementTag = "android.support.constraint.ConstraintLayout"
val hostElements = sourceDocument.getElementsByTagName(targetElement).item(0).childNodes val sourceElements = sourceDocument.getElementsByTagName(targetElementTag).item(0).childNodes
val targetElement = targetDocument.getElementsByTagName(targetElementTag).item(0)
val destinationElement = targetDocument.getElementsByTagName(targetElement).item(0) for (index in 1 until sourceElements.length) {
val element = sourceElements.item(index).cloneNode(true)
for (index in 1 until hostElements.length) {
val element = hostElements.item(index).cloneNode(true)
// If the element has no attributes there's no point to adding it to the destination. // If the element has no attributes there's no point to adding it to the destination.
if (!element.hasAttributes()) continue if (!element.hasAttributes()) continue
@ -65,10 +64,10 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable {
// Add the element. // Add the element.
targetDocument.adoptNode(element) targetDocument.adoptNode(element)
destinationElement.appendChild(element) targetElement.appendChild(element)
} }
sourceDocument.close() sourceDocumentEditor.close()
} }
override fun close() = targetDocument.close() override fun close() = targetDocumentEditor.close()
} }

View File

@ -43,7 +43,9 @@ object SettingsResourcePatch : BaseSettingsResourcePatch(
// Modify the manifest and add a data intent filter to the LicenseActivity. // Modify the manifest and add a data intent filter to the LicenseActivity.
// Some devices freak out if undeclared data is passed to an intent, // Some devices freak out if undeclared data is passed to an intent,
// and this change appears to fix the issue. // and this change appears to fix the issue.
context.document["AndroidManifest.xml"].use { document -> context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
// A xml regular-expression would probably work better than this manual searching. // A xml regular-expression would probably work better than this manual searching.
val manifestNodes = document.getElementsByTagName("manifest").item(0).childNodes val manifestNodes = document.getElementsByTagName("manifest").item(0).childNodes
for (i in 0..manifestNodes.length) { for (i in 0..manifestNodes.length) {

View File

@ -1,7 +1,6 @@
package app.revanced.util package app.revanced.util
import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.util.Document
import app.revanced.patcher.util.DomFileEditor import app.revanced.patcher.util.DomFileEditor
import app.revanced.util.resource.BaseResource import app.revanced.util.resource.BaseResource
import org.w3c.dom.Node import org.w3c.dom.Node
@ -50,7 +49,7 @@ fun ResourceContext.copyResources(
sourceResourceDirectory: String, sourceResourceDirectory: String,
vararg resources: ResourceGroup, vararg resources: ResourceGroup,
) { ) {
val targetResourceDirectory = this.get("res", false) val targetResourceDirectory = this.get("res")
for (resourceGroup in resources) { for (resourceGroup in resources) {
resourceGroup.resources.forEach { resource -> resourceGroup.resources.forEach { resource ->
@ -86,28 +85,23 @@ fun ResourceContext.iterateXmlNodeChildren(
resource: String, resource: String,
targetTag: String, targetTag: String,
callback: (node: Node) -> Unit, callback: (node: Node) -> Unit,
) = document[classLoader.getResourceAsStream(resource)!!].use { ) = xmlEditor[classLoader.getResourceAsStream(resource)!!].use { editor ->
val stringsNode = it.getElementsByTagName(targetTag).item(0).childNodes val document = editor.file
val stringsNode = document.getElementsByTagName(targetTag).item(0).childNodes
for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i)) for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i))
} }
/** // TODO: After the migration to the new patcher, remove the following code and replace it with the commented code below.
* Copies the specified node of the source [Document] to the target [Document]. fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable {
* @param source the source [Document]. val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes
* @param target the target [Document]-
* @return AutoCloseable that closes the [Document]s.
*/
fun String.copyXmlNode(
source: Document,
target: Document,
): AutoCloseable {
val hostNodes = source.getElementsByTagName(this).item(0).childNodes
val destinationNode = target.getElementsByTagName(this).item(0) val destinationResourceFile = target.file
val destinationNode = destinationResourceFile.getElementsByTagName(this).item(0)
for (index in 0 until hostNodes.length) { for (index in 0 until hostNodes.length) {
val node = hostNodes.item(index).cloneNode(true) val node = hostNodes.item(index).cloneNode(true)
target.adoptNode(node) destinationResourceFile.adoptNode(node)
destinationNode.appendChild(node) destinationNode.appendChild(node)
} }
@ -117,18 +111,44 @@ fun String.copyXmlNode(
} }
} }
@Deprecated( // /**
"Use copyXmlNode(Document, Document) instead.", // * Copies the specified node of the source [Document] to the target [Document].
ReplaceWith( // * @param source the source [Document].
"this.copyXmlNode(source.file as Document, target.file as Document)", // * @param target the target [Document]-
"app.revanced.patcher.util.Document", // * @return AutoCloseable that closes the [Document]s.
"app.revanced.patcher.util.Document", // */
), // fun String.copyXmlNode(
) // source: Document,
fun String.copyXmlNode( // target: Document,
source: DomFileEditor, // ): AutoCloseable {
target: DomFileEditor, // val hostNodes = source.getElementsByTagName(this).item(0).childNodes
) = this.copyXmlNode(source.file as Document, target.file as Document) //
// val destinationNode = target.getElementsByTagName(this).item(0)
//
// for (index in 0 until hostNodes.length) {
// val node = hostNodes.item(index).cloneNode(true)
// target.adoptNode(node)
// destinationNode.appendChild(node)
// }
//
// return AutoCloseable {
// source.close()
// target.close()
// }
// }
// @Deprecated(
// "Use copyXmlNode(Document, Document) instead.",
// ReplaceWith(
// "this.copyXmlNode(source.file as Document, target.file as Document)",
// "app.revanced.patcher.util.Document",
// "app.revanced.patcher.util.Document",
// ),
// )
// fun String.copyXmlNode(
// source: DomFileEditor,
// target: DomFileEditor,
// ) = this.copyXmlNode(source.file as Document, target.file as Document)
/** /**
* Add a resource node child. * Add a resource node child.
@ -143,4 +163,4 @@ internal fun Node.addResource(
appendChild(resource.serialize(ownerDocument, resourceCallback)) appendChild(resource.serialize(ownerDocument, resourceCallback))
} }
internal fun Document?.getNode(tagName: String) = this!!.getElementsByTagName(tagName).item(0) internal fun org.w3c.dom.Document.getNode(tagName: String) = this.getElementsByTagName(tagName).item(0)