This commit is contained in:
oSumAtrIX
2026-01-23 23:00:57 +01:00
parent c1a8045ebb
commit 8c72146bb9
46 changed files with 514 additions and 555 deletions

View File

@@ -1,19 +1,17 @@
@file:Suppress("ObjectPropertyName")
package app.revanced.patches.all.misc.network
import app.revanced.patcher.patch.creatingResourcePatch
import app.revanced.patches.all.misc.debugging.enableAndroidDebuggingPatch
import app.revanced.patches.all.misc.debugging.`Enable Android debugging`
import app.revanced.util.Utils.trimIndentMultiline
import org.w3c.dom.Element
import java.io.File
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Override certificate pinning` by creatingResourcePatch(
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
use = false,
) {
dependsOn(enableAndroidDebuggingPatch)
dependsOn(`Enable Android debugging`)
apply {
val resXmlDirectory = get("res/xml")

View File

@@ -13,11 +13,10 @@ import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.util.*
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Enable ROM signature spoofing` = creatingResourcePatch(
name = "",
description = "Spoofs the signature via the manifest meta-data \"fake-signature\". " +
"This patch only works with ROMs that support signature spoofing.",
"This patch only works with ROMs that support signature spoofing.",
use = false,
) {
val signatureOrPath by stringOption(
@@ -37,7 +36,6 @@ val `Enable ROM signature spoofing` = creatingResourcePatch(
}
val manifest = document.getNode("manifest").appendChild(permission)
val fakeSignatureMetadata = document.createElement("meta-data").apply {
setAttribute("android:name", "fake-signature")
setAttribute("android:value", parseSignature(signatureOrPath!!))
@@ -68,15 +66,17 @@ private fun parseSignature(optionValue: String): String? {
val hexFormat = HexFormat.of()
val signature = (if (result.isVerifiedUsingV3Scheme) {
result.v3SchemeSigners[0].certificate
} else if (result.isVerifiedUsingV2Scheme) {
result.v2SchemeSigners[0].certificate
} else if (result.isVerifiedUsingV1Scheme) {
result.v1SchemeSigners[0].certificate
} else {
return null
}).encoded
val signature = (
if (result.isVerifiedUsingV3Scheme) {
result.v3SchemeSigners[0].certificate
} else if (result.isVerifiedUsingV2Scheme) {
result.v2SchemeSigners[0].certificate
} else if (result.isVerifiedUsingV1Scheme) {
result.v1SchemeSigners[0].certificate
} else {
return null
}
).encoded
return hexFormat.formatHex(signature)
} catch (_: IOException) {
@@ -87,4 +87,4 @@ private fun parseSignature(optionValue: String): String? {
}
return null
}
}

View File

@@ -1,8 +1,9 @@
package app.revanced.patches.crunchyroll.ads
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
internal val BytecodePatchContext.videoUrlReadyToStringMethod by gettingFirstMutableMethodDeclaratively(
"VideoUrlReady(url=", ", enableAds="
)
internal val videoUrlReadyToStringMethodMatch = firstMethodComposite {
instructions("VideoUrlReady(url="(), ", enableAds="())
}

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.crunchyroll.ads
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.instructions
@@ -13,34 +12,36 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch {
compatibleWith("com.crunchyroll.crunchyroid")
apply {
// Get obfuscated "enableAds" field from toString method.
val enableAdsField = videoUrlReadyToStringMethod.let {
val strIndex = videoUrlReadyToStringMethod.stringMatches.last().index // TODO
val fieldIndex = it.indexOfFirstInstruction(strIndex, Opcode.IGET_BOOLEAN)
it.getInstruction<ReferenceInstruction>(fieldIndex).getReference<FieldReference>()!!
val enableAdsField = videoUrlReadyToStringMethodMatch.method.apply {
val stringIndex = videoUrlReadyToStringMethodMatch.indices.last()
val fieldIndex = indexOfFirstInstruction(stringIndex, Opcode.IGET_BOOLEAN)
getInstruction<ReferenceInstruction>(fieldIndex).getReference<FieldReference>()!!
}
// Remove final access flag on field.
videoUrlReadyToStringMethod.classDef.fields
videoUrlReadyToStringMethodMatch.classDef.fields
.first { it.name == enableAdsField.name }
.removeFlags(AccessFlags.FINAL)
// Override enableAds field in non-default constructor.
val constructor = videoUrlReadyToStringMethod.classDef.methods.first {
val constructor = videoUrlReadyToStringMethodMatch.classDef.methods.first {
AccessFlags.CONSTRUCTOR.isSet(it.accessFlags) && it.parameters.isNotEmpty()
}
constructor.addInstructions(
constructor.instructions.count() - 1,
"""
move-object/from16 v0, p0
const/4 v1, 0x0
iput-boolean v1, v0, $enableAdsField
"""
""",
)
}
}
}

View File

@@ -5,10 +5,7 @@ import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Matches the class found in [initializeEnergyConfigMethod].
*/
internal val BytecodePatchContext.initializeEnergyConfigMethod by gettingFirstMutableMethodDeclaratively {
internal val initializeEnergyConfigMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
opcodes(Opcode.RETURN_VOID)
}

View File

@@ -5,27 +5,24 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.findFieldFromToString
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Skip energy recharge ads` by creatingBytecodePatch(
description = "Skips watching ads to recharge energy."
description = "Skips watching ads to recharge energy.",
) {
compatibleWith("com.duolingo")
apply {
initializeEnergyConfigMethod
.match(energyConfigToStringMethod.classDef) // TODO
.method.apply {
val energyField = energyConfigToStringMethod
.findFieldFromToString("energy=")
val insertIndex = initializeEnergyConfigMethod.patternMatch.startIndex // TODO
initializeEnergyConfigMethodMatch.match(energyConfigToStringMethod.classDef).method.apply {
val energyField = energyConfigToStringMethod.findFieldFromToString("energy=")
val insertIndex = initializeEnergyConfigMethodMatch.indices.first() // TODO
addInstructions(
insertIndex,
"""
const/16 v0, 99
iput v0, p0, $energyField
"""
)
}
addInstructions(
insertIndex,
"""
const/16 v0, 99
iput v0, p0, $energyField
""",
)
}
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.baseModelMapperMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.baseModelMapperMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Lcom/facebook/graphql/modelutil/BaseModelWithTree;")
parameterTypes("Ljava/lang/Class", "I", "I")
@@ -17,7 +17,7 @@ internal val BytecodePatchContext.baseModelMapperMethod by gettingFirstMutableMe
Opcode.IF_EQ,
)
}
internal val BytecodePatchContext.getSponsoredDataModelTemplateMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.getSponsoredDataModelTemplateMethod by gettingFirstMethodDeclaratively {
definingClass("Lcom/facebook/graphql/model/GraphQLFBMultiAdsFeedUnit;")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("L")
@@ -29,9 +29,8 @@ internal val BytecodePatchContext.getSponsoredDataModelTemplateMethod by getting
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT,
)
}
internal val BytecodePatchContext.getStoryVisibilityMethod by gettingFirstMutableMethodDeclaratively("This should not be called for base class object") {
internal val getStoryVisibilityMethodMatch = firstMethodComposite("This should not be called for base class object") {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
opcodes(
@@ -43,4 +42,4 @@ internal val BytecodePatchContext.getStoryVisibilityMethod by gettingFirstMutabl
Opcode.IF_NEZ,
Opcode.CONST,
)
}
}

View File

@@ -10,13 +10,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Hide 'Sponsored Stories'` by creatingBytecodePatch {
compatibleWith("com.facebook.katana"("490.0.0.63.82"))
apply {
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod
val baseModelMapperMethod = baseModelMapperFingerprint.originalMethod
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateMethod
val baseModelWithTreeType = baseModelMapperMethod.returnType
val graphQlStoryClassDescriptor = "Lcom/facebook/graphql/model/GraphQLStory;"
@@ -26,7 +25,7 @@ val `Hide 'Sponsored Stories'` by creatingBytecodePatch {
// could change in future version, we need to extract them and call the base implementation directly.
val getSponsoredDataHelperMethod = ImmutableMethod(
getStoryVisibilityFingerprint.originalClassDef.type,
getStoryVisibilityMethodMatch.immutableClassDef.type,
"getSponsoredData",
listOf(ImmutableMethodParameter(graphQlStoryClassDescriptor, null, null)),
baseModelWithTreeType,
@@ -60,12 +59,12 @@ val `Hide 'Sponsored Stories'` by creatingBytecodePatch {
)
}
getStoryVisibilityFingerprint.classDef.methods.add(getSponsoredDataHelperMethod)
getStoryVisibilityMethodMatch.classDef.methods.add(getSponsoredDataHelperMethod)
// Check if the parameter type is GraphQLStory and if sponsoredDataModelGetter returns a non-null value.
// If so, hide the story by setting the visibility to StoryVisibility.GONE.
getStoryVisibilityFingerprint.method.addInstructionsWithLabels(
getStoryVisibilityFingerprint.instructionMatches.first().index,
getStoryVisibilityMethodMatch.method.addInstructionsWithLabels(
getStoryVisibilityMethodMatch.indices.first(),
"""
instance-of v0, p0, $graphQlStoryClassDescriptor
if-eqz v0, :resume_normal

View File

@@ -1,12 +1,9 @@
package app.revanced.patches.googlerecorder.restrictions
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
internal val onApplicationCreateFingerprint = fingerprint {
strings("com.google.android.feature.PIXEL_2017_EXPERIENCE")
custom { method, classDef ->
if (method.name != "onCreate") return@custom false
classDef.endsWith("RecorderApplication;")
}
internal val onApplicationCreateMethodMatch = firstMethodComposite {
name("onCreate")
definingClass("RecorderApplication"::endsWith)
instructions("com.google.android.feature.PIXEL_2017_EXPERIENCE"())
}

View File

@@ -6,16 +6,16 @@ import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Remove device restrictions` by creatingBytecodePatch(
description = "Removes restrictions from using the app on any device. Requires mounting patched app over original.",
) {
compatibleWith("com.google.android.apps.recorder")
apply {
val featureStringIndex = onApplicationCreateFingerprint.stringMatches.first().index
val featureStringIndex = onApplicationCreateMethodMatch.indices.first()
onApplicationCreateFingerprint.method.apply {
onApplicationCreateMethodMatch.method.apply {
// Remove check for device restrictions.
removeInstructions(featureStringIndex - 2, 5)

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.instagram.hide.explore
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
internal const val EXPLORE_KEY_TO_BE_HIDDEN = "sectional_items"
internal val exploreResponseJsonParserFingerprint = fingerprint {
strings(EXPLORE_KEY_TO_BE_HIDDEN, "ExploreTopicalFeedResponse")
custom { method, _ -> method.name == "parseFromJson" }
internal val exploreResponseJsonParserMethodMatch = firstMethodComposite("ExploreTopicalFeedResponse") {
name("parseFromJson")
instructions("sectional_items"())
}

View File

@@ -1,31 +1,11 @@
package app.revanced.patches.instagram.hide.explore
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.creatingBytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
context(BytecodePatchContext)
internal fun Fingerprint.replaceJsonFieldWithBogus(
key: String,
) {
val targetStringIndex = stringMatches.first { match -> match.string == key }.index
val targetStringRegister = method.getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
/**
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
* This way the feeds array will never be populated.
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
*/
method.replaceInstruction(
targetStringIndex,
"const-string v$targetStringRegister, \"BOGUS\"",
)
}
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Hide explore feed` by creatingBytecodePatch(
description = "Hides posts and reels from the explore/search page.",
use = false,
@@ -33,6 +13,11 @@ val `Hide explore feed` by creatingBytecodePatch(
compatibleWith("com.instagram.android")
apply {
exploreResponseJsonParserFingerprint.replaceJsonFieldWithBogus(EXPLORE_KEY_TO_BE_HIDDEN)
exploreResponseJsonParserMethodMatch.method.apply {
val targetStringIndex = exploreResponseJsonParserMethodMatch.indices.first()
val targetStringRegister = getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
replaceInstruction(targetStringIndex, "const-string v$targetStringRegister, \"BOGUS\"")
}
}
}

View File

@@ -1,16 +1,15 @@
package app.revanced.patches.instagram.hide.stories
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.Opcode
internal val getOrCreateAvatarViewFingerprint = fingerprint {
parameters()
returns("L")
custom { method, classDef ->
classDef.type == "Lcom/instagram/reels/ui/views/reelavatar/RecyclerReelAvatarView;"
}
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL // Add View (Story)
)
}
internal val getOrCreateAvatarViewMethod = firstMethodComposite {
definingClass("Lcom/instagram/reels/ui/views/reelavatar/RecyclerReelAvatarView;")
parameterTypes()
returnType("L")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL, // Add View (Story).
)
}

View File

@@ -3,18 +3,17 @@ package app.revanced.patches.instagram.hide.stories
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Hide Stories from Home` by creatingBytecodePatch(
description = "Hides Stories from the main page, by removing the buttons.",
use = false
use = false,
) {
compatibleWith("com.instagram.android")
apply {
val addStoryMethod = getOrCreateAvatarViewFingerprint.method // Creates Story
val addStoryEndIndex = getOrCreateAvatarViewFingerprint.patternMatch.endIndex
val addStoryEndIndex = getOrCreateAvatarViewMethod.indices.last()
// Remove addView of Story.
addStoryMethod.removeInstruction(addStoryEndIndex)
getOrCreateAvatarViewMethod.method.removeInstruction(addStoryEndIndex)
}
}
}

View File

@@ -1,6 +1,9 @@
package app.revanced.patches.instagram.hide.suggestions
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.unorderedAllOf
internal val FEED_ITEM_KEYS_TO_BE_HIDDEN = arrayOf(
"clips_netego",
@@ -12,6 +15,11 @@ internal val FEED_ITEM_KEYS_TO_BE_HIDDEN = arrayOf(
"suggested_users",
)
internal val feedItemParseFromJsonFingerprint = fingerprint {
strings(*FEED_ITEM_KEYS_TO_BE_HIDDEN, "FeedItem")
internal val feedItemParseFromJsonMethodMatch = firstMethodComposite("FeedItem") {
instructions(
predicates = unorderedAllOf(
predicates =
FEED_ITEM_KEYS_TO_BE_HIDDEN.map { it.invoke() }.toTypedArray(),
),
)
}

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.instagram.hide.suggestions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.hide.explore.replaceJsonFieldWithBogus
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Hide suggested content` by creatingBytecodePatch(
description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).",
use = false,
@@ -11,8 +13,12 @@ val `Hide suggested content` by creatingBytecodePatch(
compatibleWith("com.instagram.android")
apply {
FEED_ITEM_KEYS_TO_BE_HIDDEN.forEach { key ->
feedItemParseFromJsonFingerprint.replaceJsonFieldWithBogus(key)
feedItemParseFromJsonMethodMatch.method.apply {
feedItemParseFromJsonMethodMatch.indices.forEach { targetStringIndex ->
val targetStringRegister = getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
replaceInstruction(targetStringIndex, "const-string v$targetStringRegister, \"BOGUS\"")
}
}
}
}

View File

@@ -18,47 +18,48 @@ internal val playerOverlayChipFingerprint = fingerprint {
literal { playerOverlayChip }
}
internal val historyMenuItemFingerprint = fingerprint {
internal val BytecodePatchContext.historyMenuItemMethod by gettingFirstMutableMethodDeclaratively {
definingClass {
it.methods.count()
methods.count()
}
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Landroid/view/Menu;")
returnType("V")
parameterTypes("Landroid/view/Menu;")
opcodes(
Opcode.INVOKE_INTERFACE,
Opcode.RETURN_VOID
Opcode.RETURN_VOID,
)
literal { historyMenuItem }
historyMenuItem()
custom { _, classDef ->
classDef.methods.count() == 5
}
}
internal val historyMenuItemOfflineTabFingerprint = fingerprint {
internal val BytecodePatchContext.historyMenuItemOfflineTabMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Landroid/view/Menu;")
returnType("V")
parameterTypes("Landroid/view/Menu;")
opcodes(
Opcode.INVOKE_INTERFACE,
Opcode.RETURN_VOID
Opcode.RETURN_VOID,
)
custom { method, _ ->
method.containsLiteralInstruction(historyMenuItem) &&
method.containsLiteralInstruction(offlineSettingsMenuItem)
custom {
instructions.matchIndexed("literals", items = unorderedAllOf(historyMenuItem(), offlineSettingsMenuItem()))
}
}
internal val searchActionViewFingerprint = fingerprint {
internal val BytecodePatchContext.searchActionViewMethod by gettingFirstMutableMethodDeclaratively {
definingClass("/SearchActionProvider;"::endsWith)
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/view/View;")
parameters()
literal { searchButton }
custom { _, classDef ->
classDef.type.endsWith("/SearchActionProvider;")
}
returnType("Landroid/view/View;")
parameterTypes()
searchButton()
}
internal val topBarMenuItemImageViewFingerprint = fingerprint {
internal val BytecodePatchContext.topBarMenuItemImageViewMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/view/View;")
parameters()
literal { topBarMenuItemImageView }
returnType("Landroid/view/View;")
parameterTypes()
topBarMenuItemImageView()
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.photomath.detection.signature.signatureDetectionPatch
import app.revanced.patches.photomath.misc.unlock.bookpoint.enableBookpointPatch
@Suppress("unused")
@Suppress("unused", "ObjectPropertyName")
val `Unlock plus` by creatingBytecodePatch {
dependsOn(signatureDetectionPatch, enableBookpointPatch)

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.toInstructions
import app.revanced.patches.reddit.customclients.spoofClientPatch
import com.android.tools.smali.dexlib2.AccessFlags
@@ -11,7 +12,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "infinity://localhost") {
compatibleWith(
"ml.docilealligator.infinityforreddit",
"ml.docilealligator.infinityforreddit.plus",
"ml.docilealligator.infinityforreddit.patreon"
"ml.docilealligator.infinityforreddit.patreon",
)
val clientId by clientIdOption

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.shared.misc.mapping
import app.revanced.patcher.Predicate
import app.revanced.patcher.IndexedMatcherPredicate
import app.revanced.patcher.extensions.wideLiteral
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.resourcePatch
@@ -35,10 +35,10 @@ enum class ResourceType(val value: String) {
XML("xml"),
;
operator fun invoke(name: String): Predicate<Instruction> {
val id = getResourceId(this, name)
operator fun invoke(name: String): IndexedMatcherPredicate<Instruction> {
val id = get(name)
return { wideLiteral == id }
return { _, _, _ -> wideLiteral == id }
}
/**
@@ -60,13 +60,6 @@ data class ResourceElement(val type: ResourceType, val name: String, val id: Lon
private lateinit var resourceMappings: MutableMap<String, ResourceElement>
/**
* @return A resource id of the given resource type and name.
* @throws PatchException if the resource is not found.
*/
fun getResourceId(type: ResourceType, name: String) = resourceMappings[type.value + name]?.id
?: throw PatchException("Could not find resource type: $type name: $name")
val resourceMappingPatch = resourcePatch {
apply {
// Use a stream of the file, since no modifications are done

View File

@@ -1,9 +1,10 @@
package app.revanced.patches.youtube.interaction.seekbar
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
@@ -30,9 +31,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
SwitchPreference("revanced_disable_precise_seeking_gesture"),
)
allowSwipingUpGestureFingerprint.match(
swipingUpGestureParentFingerprint.originalClassDef,
).method.apply {
swipingUpGestureParentMethod.immutableClassDef.getAllowSwipingUpGestureMethod().apply {
addInstructionsWithLabels(
0,
"""
@@ -45,9 +44,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
)
}
showSwipingUpGuideFingerprint.match(
swipingUpGestureParentFingerprint.originalClassDef,
).method.apply {
swipingUpGestureParentMethod.immutableClassDef.getShowSwipingUpGuideMethod().apply {
addInstructionsWithLabels(
0,
"""

View File

@@ -2,12 +2,21 @@ package app.revanced.patches.youtube.interaction.seekbar
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.InstructionLocation.MatchAfterWithin
import app.revanced.patcher.accessFlags
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.methodCall
import app.revanced.patcher.newInstance
import app.revanced.patcher.opcode
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater
@@ -18,35 +27,36 @@ import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.reference.StringReference
internal val swipingUpGestureParentFingerprint = fingerprint {
returns("Z")
parameters()
internal val BytecodePatchContext.swipingUpGestureParentMethod by gettingFirstMethodDeclaratively {
returnType("Z")
parameterTypes()
instructions(
literal(45379021) // Swipe up fullscreen feature flag
45379021L(), // Swipe up fullscreen feature flag
)
}
/**
* Resolves using the class found in [swipingUpGestureParentFingerprint].
* Resolves using the class found in [swipingUpGestureParentMethod].
*/
internal val showSwipingUpGuideFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getShowSwipingUpGuideMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.FINAL)
returns("Z")
parameters()
instructions(
literal(1)
)
returnType("Z")
parameterTypes()
instructions(1L())
}
/**
* Resolves using the class found in [swipingUpGestureParentFingerprint].
* Resolves using the class found in [swipingUpGestureParentMethod].
*/
internal val allowSwipingUpGestureFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getAllowSwipingUpGestureMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("L")
returnType("V")
parameterTypes("L")
}
internal val disableFastForwardLegacyFingerprint = fingerprint {
@@ -54,7 +64,7 @@ internal val disableFastForwardLegacyFingerprint = fingerprint {
parameters()
opcodes(Opcode.MOVE_RESULT)
// Intent start flag only used in the subscription activity
literal {45411330}
literal { 45411330 }
}
internal val disableFastForwardGestureFingerprint = fingerprint {
@@ -77,17 +87,17 @@ internal val customTapAndHoldFingerprint = fingerprint {
returns("V")
parameters()
instructions(
literal(2.0f)
2.0f(),
)
custom { method, _ ->
// Code is found in different methods with different strings.
val findSearchLandingKey = (is_19_34_or_greater && !is_19_47_or_greater)
|| (is_20_19_or_greater && !is_20_20_or_greater) || is_20_31_or_greater
val findSearchLandingKey = (is_19_34_or_greater && !is_19_47_or_greater) ||
(is_20_19_or_greater && !is_20_20_or_greater) || is_20_31_or_greater
method.name == "run" && method.indexOfFirstInstruction {
val string = getReference<StringReference>()?.string
string == "Failed to easy seek haptics vibrate."
|| (findSearchLandingKey && string == "search_landing_cache_key")
string == "Failed to easy seek haptics vibrate." ||
(findSearchLandingKey && string == "search_landing_cache_key")
} >= 0
}
}
@@ -120,15 +130,18 @@ internal val seekbarTappingFingerprint = fingerprint {
returns("Z")
parameters("Landroid/view/MotionEvent;")
instructions(
literal(Int.MAX_VALUE),
Int.MAX_VALUE(),
newInstance("Landroid/graphics/Point;"),
methodCall(smali = "Landroid/graphics/Point;-><init>(II)V", location = MatchAfterImmediately()),
methodCall(smali = "Lj\$/util/Optional;->of(Ljava/lang/Object;)Lj\$/util/Optional;", location = MatchAfterImmediately()),
methodCall(
smali = "Lj\$/util/Optional;->of(Ljava/lang/Object;)Lj\$/util/Optional;",
location = MatchAfterImmediately(),
),
opcode(Opcode.MOVE_RESULT_OBJECT, location = MatchAfterImmediately()),
fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Lj\$/util/Optional;", location = MatchAfterImmediately()),
opcode(Opcode.INVOKE_VIRTUAL, location = MatchAfterWithin(10))
opcode(Opcode.INVOKE_VIRTUAL, location = MatchAfterWithin(10)),
)
custom { method, _ -> method.name == "onTouchEvent" }
}
@@ -146,20 +159,18 @@ internal val slideToSeekFingerprint = fingerprint {
literal { 67108864 }
}
internal val fullscreenSeekbarThumbnailsQualityFingerprint = fingerprint {
internal val BytecodePatchContext.fullscreenSeekbarThumbnailsQualityMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters()
returnType("Z")
parameterTypes()
instructions(
literal(45399684L) // Video stream seekbar thumbnails feature flag.
45399684L(), // Video stream seekbar thumbnails feature flag.
)
}
internal val fullscreenLargeSeekbarFeatureFlagFingerprint = fingerprint {
internal val fullscreenLargeSeekbarFeatureFlagMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters()
instructions(
literal(45691569)
)
returnType("Z")
parameterTypes()
instructions(45691569L())
}

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.interaction.seekbar
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@@ -11,8 +12,8 @@ import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.seekbarFingerprint
import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint
import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch
import app.revanced.patches.youtube.shared.seekbarMethod
import app.revanced.util.insertLiteralOverride
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;"
@@ -37,7 +38,7 @@ val hideSeekbarPatch = bytecodePatch(
SwitchPreference("revanced_fullscreen_large_seekbar"),
)
seekbarOnDrawFingerprint.match(seekbarFingerprint.originalClassDef).method.addInstructionsWithLabels(
getSeekbarOnDrawMethodMatch().match(seekbarMethod.immutableClassDef).method.addInstructionsWithLabels(
0,
"""
const/4 v0, 0x0
@@ -51,7 +52,7 @@ val hideSeekbarPatch = bytecodePatch(
)
if (is_20_28_or_greater) {
fullscreenLargeSeekbarFeatureFlagFingerprint.let {
fullscreenLargeSeekbarFeatureFlagMethodMatch.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->useFullscreenLargeSeekbar(Z)Z"

View File

@@ -13,13 +13,12 @@ import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import java.util.logging.Logger
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
val seekbarThumbnailsPatch = bytecodePatch(
description = "Adds an option to use high quality fullscreen seekbar thumbnails."
description = "Adds an option to use high quality fullscreen seekbar thumbnails.",
) {
dependsOn(
sharedExtensionPatch,
@@ -38,7 +37,7 @@ val seekbarThumbnailsPatch = bytecodePatch(
if (is_19_17_or_greater) {
PreferenceScreen.SEEKBAR.addPreferences(
SwitchPreference("revanced_seekbar_thumbnails_high_quality")
SwitchPreference("revanced_seekbar_thumbnails_high_quality"),
)
} else {
PreferenceScreen.SEEKBAR.addPreferences(
@@ -46,8 +45,8 @@ val seekbarThumbnailsPatch = bytecodePatch(
SwitchPreference(
key = "revanced_seekbar_thumbnails_high_quality",
summaryOnKey = "revanced_seekbar_thumbnails_high_quality_legacy_summary_on",
summaryOffKey = "revanced_seekbar_thumbnails_high_quality_legacy_summary_on"
)
summaryOffKey = "revanced_seekbar_thumbnails_high_quality_legacy_summary_on",
),
)
fullscreenSeekbarThumbnailsFingerprint.method.apply {
@@ -60,13 +59,13 @@ val seekbarThumbnailsPatch = bytecodePatch(
}
}
fullscreenSeekbarThumbnailsQualityFingerprint.method.addInstructions(
fullscreenSeekbarThumbnailsQualityMethod.addInstructions(
0,
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->useHighQualityFullscreenThumbnails()Z
move-result v0
return v0
"""
""",
)
}
}

View File

@@ -15,6 +15,6 @@ internal val swipeControlsHostActivityFingerprint = fingerprint {
internal val swipeChangeVideoFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
instructions(
literal(45631116L) // Swipe to change fullscreen video feature flag.
45631116L(), // Swipe to change fullscreen video feature flag.
)
}

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.youtube.layout.buttons.navigation
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.addString
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcode
import app.revanced.patcher.addString
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -26,7 +26,7 @@ internal val createPivotBarFingerprint = fingerprint {
)
instructions(
methodCall(definingClass = "Landroid/widget/TextView;", name = "setText"),
opcode(Opcode.RETURN_VOID)
opcode(Opcode.RETURN_VOID),
)
}
@@ -34,7 +34,7 @@ internal val animatedNavigationTabsFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(45680008L)
45680008L(),
)
}
@@ -42,7 +42,7 @@ internal val translucentNavigationStatusBarFeatureFlagFingerprint = fingerprint
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(45400535L) // Translucent status bar feature flag.
45400535L(), // Translucent status bar feature flag.
)
}
@@ -53,7 +53,7 @@ internal val translucentNavigationButtonsFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
instructions(
literal(45630927L) // Translucent navigation bar buttons feature flag.
45630927L(), // Translucent navigation bar buttons feature flag.
)
}
@@ -64,6 +64,6 @@ internal val translucentNavigationButtonsSystemFeatureFlagFingerprint = fingerpr
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(45632194L) // Translucent system buttons feature flag.
45632194L(), // Translucent system buttons feature flag.
)
}

View File

@@ -1,38 +1,33 @@
package app.revanced.patches.youtube.layout.buttons.overlay
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.shared.misc.mapping.ResourceType.IndexedMatcherPredicateExtension.invoke
import com.android.tools.smali.dexlib2.AccessFlags
internal val mediaRouteButtonFingerprint = fingerprint {
parameters("I")
custom { methodDef, _ ->
methodDef.definingClass.endsWith("/MediaRouteButton;") && methodDef.name == "setVisibility"
}
internal val BytecodePatchContext.mediaRouteButtonMethod by gettingFirstMutableMethodDeclaratively {
name("setVisibility")
definingClass("/MediaRouteButton;"::endsWith)
parameterTypes("I")
}
internal val castButtonPlayerFeatureFlagFingerprint = fingerprint {
returns("Z")
instructions(
literal(45690091),
)
internal val castButtonPlayerFeatureFlagMethodMatch = firstMethodComposite {
returnType("Z")
instructions(45690091L())
}
internal val castButtonActionFeatureFlagFingerprint = fingerprint {
returns("Z")
instructions(
literal(45690090),
)
internal val castButtonActionFeatureFlagMethodMatch = firstMethodComposite {
returnType("Z")
instructions(45690090L())
}
internal val inflateControlsGroupLayoutStubFingerprint = fingerprint {
internal val inflateControlsGroupLayoutStubMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters()
returns("V")
parameterTypes()
returnType("V")
instructions(
ResourceType.ID("youtube_controls_button_group_layout_stub"),
methodCall(name = "inflate"),
method("inflate"),
)
}

View File

@@ -11,7 +11,7 @@ import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.layoutConstructorFingerprint
import app.revanced.patches.youtube.shared.getLayoutConstructorMethodMatch
import app.revanced.patches.youtube.shared.subtitleButtonControllerFingerprint
import app.revanced.util.*
import com.android.tools.smali.dexlib2.Opcode
@@ -22,16 +22,17 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/HidePlayerOverlayButtonsPatch;"
@Suppress("ObjectPropertyName")
val `Hide player overlay buttons` by creatingBytecodePatch(
description = "Adds options to hide the player Cast, Autoplay, Captions, Previous & Next buttons, and the player " +
"control buttons background.",
"control buttons background.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
resourceMappingPatch, // Used by fingerprints.
versionCheckPatch
versionCheckPatch,
)
compatibleWith(
@@ -40,7 +41,7 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@@ -56,44 +57,38 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
// region Hide player next/previous button.
layoutConstructorFingerprint.let {
it.clearMatch() // Fingerprint is shared with other patches.
getLayoutConstructorMethodMatch().let {
val insertIndex = it.indices.last()
val viewRegister = it.method.getInstruction<FiveRegisterInstruction>(insertIndex).registerC
it.method.apply {
val insertIndex = it.instructionMatches.last().index
val viewRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
addInstruction(
insertIndex,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR" +
"->hidePreviousNextButtons(Landroid/view/View;)V",
)
}
it.method.addInstruction(
insertIndex,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR" +
"->hidePreviousNextButtons(Landroid/view/View;)V",
)
}
// endregion
// region Hide cast button.
mediaRouteButtonFingerprint.method.addInstructions(
mediaRouteButtonMethod.addInstructions(
0,
"""
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getCastButtonOverrideV2(I)I
move-result p1
"""
""",
)
if (is_20_28_or_greater) {
arrayOf(
castButtonPlayerFeatureFlagFingerprint,
castButtonActionFeatureFlagFingerprint
).forEach { fingerprint ->
fingerprint.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->getCastButtonOverrideV2(Z)Z"
)
}
castButtonPlayerFeatureFlagMethodMatch,
castButtonActionFeatureFlagMethodMatch,
).forEach { match ->
match.method.insertLiteralOverride(
match.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->getCastButtonOverrideV2(Z)Z",
)
}
}
@@ -114,7 +109,7 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
// region Hide autoplay button.
layoutConstructorFingerprint.method.apply {
getLayoutConstructorMethodMatch().method.apply {
val constIndex = indexOfFirstResourceIdOrThrow("autonav_toggle")
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
@@ -122,8 +117,8 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
val gotoIndex = indexOfFirstInstructionOrThrow(constIndex) {
val parameterTypes = getReference<MethodReference>()?.parameterTypes
opcode == Opcode.INVOKE_VIRTUAL &&
parameterTypes?.size == 2 &&
parameterTypes.first() == "Landroid/view/ViewStub;"
parameterTypes?.size == 2 &&
parameterTypes.first() == "Landroid/view/ViewStub;"
} + 1
addInstructionsWithLabels(
@@ -141,7 +136,7 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
// region Hide player control buttons background.
inflateControlsGroupLayoutStubFingerprint.let {
inflateControlsGroupLayoutStubMethodMatch.let {
it.method.apply {
val insertIndex = it.instructionMatches.last().index + 1
val freeRegister = findFreeRegister(insertIndex)
@@ -153,7 +148,7 @@ val `Hide player overlay buttons` by creatingBytecodePatch(
# The result of the inflate method is by default not moved to a register after the method is called.
move-result-object v$freeRegister
invoke-static { v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->hidePlayerControlButtonsBackground(Landroid/view/View;)V
"""
""",
)
}
}

View File

@@ -115,7 +115,7 @@ internal val shortsExperimentalPlayerFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45677719L),
45677719L(),
)
}
@@ -124,6 +124,6 @@ internal val renderNextUIFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45649743L),
45649743L(),
)
}

View File

@@ -28,7 +28,7 @@ internal const val MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY = 45644360L
internal val miniplayerModernConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
instructions(
literal(45623000L), // Magic number found in the constructor.
45623000L(), // Magic number found in the constructor.
)
}
@@ -93,7 +93,7 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = fingerprint {
returns("V")
parameters("L")
instructions(
literal(ytOutlinePictureInPictureWhite24),
ytOutlinePictureInPictureWhite24(),
)
}
@@ -149,8 +149,8 @@ internal val miniplayerMinimumSizeFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
instructions(
ResourceType.DIMEN("miniplayer_max_size"),
literal(192), // Default miniplayer width constant.
literal(128), // Default miniplayer height constant.
192(), // Default miniplayer width constant.
128(), // Default miniplayer height constant.
)
}
@@ -196,7 +196,7 @@ internal val miniplayerOnCloseHandlerFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(MINIPLAYER_DISABLED_FEATURE_KEY),
MINIPLAYER_DISABLED_FEATURE_KEY(),
)
}

View File

@@ -1,29 +1,29 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike
import app.revanced.patcher.addString
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.addString
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val dislikeFingerprint = fingerprint {
returns("V")
instructions(
addString("like/dislike")
addString("like/dislike"),
)
}
internal val likeFingerprint = fingerprint {
returns("V")
instructions(
addString("like/like")
addString("like/like"),
)
}
internal val removeLikeFingerprint = fingerprint {
returns("V")
instructions(
addString("like/removelike")
addString("like/removelike"),
)
}
@@ -65,7 +65,7 @@ internal val rollingNumberMeasureStaticLabelParentFingerprint = fingerprint {
returns("Ljava/lang/String;")
parameters()
instructions(
addString("RollingNumberFontProperties{paint=")
addString("RollingNumberFontProperties{paint="),
)
}
@@ -92,14 +92,14 @@ internal val rollingNumberTextViewFingerprint = fingerprint {
)
custom { _, classDef ->
classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" || classDef.superclass ==
"Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;"
"Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;"
}
}
internal val textComponentConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PRIVATE)
instructions(
addString("TextComponent")
addString("TextComponent"),
)
}
@@ -107,7 +107,7 @@ internal val textComponentDataFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("L", "L")
instructions(
addString("text")
addString("text"),
)
custom { _, classDef ->
classDef.fields.find { it.type == "Ljava/util/BitSet;" } != null
@@ -122,7 +122,7 @@ internal val textComponentLookupFingerprint = fingerprint {
returns("L")
parameters("L")
instructions(
addString("")
addString(""),
)
}
@@ -130,7 +130,7 @@ internal val textComponentFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.FINAL)
returns("Z")
parameters()
instructions (
literal(45675738L)
instructions(
45675738L(),
)
}
}

View File

@@ -17,7 +17,7 @@ internal val fullscreenSeekbarThumbnailsFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters()
instructions(
literal(45398577),
45398577(),
)
}
@@ -66,7 +66,7 @@ internal val watchHistoryMenuUseProgressDrawableFingerprint = fingerprint {
instructions(
methodCall("Landroid/widget/ProgressBar;", "setMax"),
opcode(Opcode.MOVE_RESULT),
literal(-1712394514),
-1712394514(),
)
}

View File

@@ -1,11 +1,7 @@
package app.revanced.patches.youtube.layout.shortsplayer
import app.revanced.patcher.addString
import app.revanced.patcher.checkCast
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patches.shared.misc.mapping.ResourceType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -15,17 +11,15 @@ import com.android.tools.smali.dexlib2.Opcode
* the obfuscated name of the videoId() method in PlaybackStartDescriptor.
* 20.38 and lower.
*/
internal val playbackStartFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters(
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
)
internal val playbackStartFeatureFlagMethodMatch = firstMethodComposite {
returnType("Z")
parameterTypes("Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;")
instructions(
methodCall(
definingClass = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
returnType = "Ljava/lang/String;",
),
literal(45380134L),
method {
definingClass == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" &&
returnType == "Ljava/lang/String;"
},
45380134L(),
)
}
@@ -34,31 +28,35 @@ internal val playbackStartFeatureFlagFingerprint = fingerprint {
* the obfuscated name of the videoId() method in PlaybackStartDescriptor.
* 20.39+
*/
internal val watchPanelVideoIdFingerprint = fingerprint {
returns("Ljava/lang/String;")
parameters()
internal val watchPanelVideoIdMethodMatch = firstMethodComposite {
returnType("Ljava/lang/String;")
parameterTypes()
instructions(
fieldAccess(
opcode = Opcode.IGET_OBJECT,
type = "Lcom/google/android/apps/youtube/app/common/player/queue/WatchPanelId;",
allOf(
Opcode.IGET_OBJECT(),
field { type == "Lcom/google/android/apps/youtube/app/common/player/queue/WatchPanelId;" },
),
checkCast("Lcom/google/android/apps/youtube/app/common/player/queue/DefaultWatchPanelId;"),
methodCall(
definingClass = "Lcom/google/android/apps/youtube/app/common/player/queue/DefaultWatchPanelId;",
returnType = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
),
methodCall(
definingClass = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
returnType = "Ljava/lang/String;",
allOf(
Opcode.CHECK_CAST(),
type("Lcom/google/android/apps/youtube/app/common/player/queue/DefaultWatchPanelId;"),
),
method {
definingClass == "Lcom/google/android/apps/youtube/app/common/player/queue/DefaultWatchPanelId;" &&
returnType == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"
},
method {
definingClass == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" &&
returnType == "Ljava/lang/String;"
},
)
}
// Pre 19.25
internal val shortsPlaybackIntentLegacyFingerprint = fingerprint {
internal val shortsPlaybackIntentLegacyMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters(
returnType("V")
parameterTypes(
"L",
"Ljava/util/Map;",
"J",
@@ -67,18 +65,18 @@ internal val shortsPlaybackIntentLegacyFingerprint = fingerprint {
"Ljava/util/Map;",
)
instructions(
methodCall(returnType = "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"),
method { returnType == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" },
// None of these strings are unique.
addString("com.google.android.apps.youtube.app.endpoint.flags"),
addString("ReelWatchFragmentArgs"),
addString("reels_fragment_descriptor"),
"com.google.android.apps.youtube.app.endpoint.flags"(),
"ReelWatchFragmentArgs"(),
"reels_fragment_descriptor"(),
)
}
internal val shortsPlaybackIntentFingerprint = fingerprint {
internal val BytecodePatchContext.shortsPlaybackIntentMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL)
returns("V")
parameters(
returnType("V")
parameterTypes(
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
"Ljava/util/Map;",
"J",
@@ -86,16 +84,14 @@ internal val shortsPlaybackIntentFingerprint = fingerprint {
)
instructions(
// None of these strings are unique.
addString("com.google.android.apps.youtube.app.endpoint.flags"),
addString("ReelWatchFragmentArgs"),
addString("reels_fragment_descriptor"),
"com.google.android.apps.youtube.app.endpoint.flags"(),
"ReelWatchFragmentArgs"(),
"reels_fragment_descriptor"(),
)
}
internal val exitVideoPlayerFingerprint = fingerprint {
returns("V")
parameters()
instructions(
ResourceType.ID("mdx_drawer_layout"),
)
internal val BytecodePatchContext.exitVideoPlayerMethod by gettingFirstMutableMethodDeclaratively {
returnType("V")
parameterTypes()
instructions(ResourceType.ID("mdx_drawer_layout"))
}

View File

@@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@@ -41,7 +40,7 @@ val `Open Shorts in regular player` by creatingBytecodePatch(
openVideosFullscreenHookPatch,
navigationBarHookPatch,
versionCheckPatch,
resourceMappingPatch
resourceMappingPatch,
)
compatibleWith(
@@ -50,31 +49,31 @@ val `Open Shorts in regular player` by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
addResources("youtube", "layout.shortsplayer.shortsPlayerTypePatch")
PreferenceScreen.SHORTS.addPreferences(
ListPreference("revanced_shorts_player_type")
ListPreference("revanced_shorts_player_type"),
)
// Activity is used as the context to launch an Intent.
mainActivityOnCreateMethod.method.addInstruction(
mainActivityOnCreateMethod.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V",
"setMainActivity(Landroid/app/Activity;)V",
)
// Find the obfuscated method name for PlaybackStartDescriptor.videoId()
val (videoIdStartMethod, videoIdIndex) = if (is_20_39_or_greater) {
watchPanelVideoIdFingerprint.let {
it.method to it.instructionMatches.last().index
watchPanelVideoIdMethodMatch.let {
it.method to it.indices.last()
}
} else {
playbackStartFeatureFlagFingerprint.let {
it.method to it.instructionMatches.first().index
playbackStartFeatureFlagMethodMatch.let {
it.method to it.indices.first()
}
}
val playbackStartVideoIdMethodName = navigate(videoIdStartMethod).to(videoIdIndex).stop().name
@@ -93,24 +92,24 @@ val `Open Shorts in regular player` by creatingBytecodePatch(
"""
if (is_19_25_or_greater) {
shortsPlaybackIntentFingerprint.method.addInstructionsWithLabels(
shortsPlaybackIntentMethod.addInstructionsWithLabels(
0,
"""
move-object/from16 v0, p1
${extensionInstructions(0, 1)}
"""
""",
)
} else {
shortsPlaybackIntentLegacyFingerprint.let {
shortsPlaybackIntentLegacyMethodMatch.let {
it.method.apply {
val index = it.instructionMatches.first().index
val index = it.indices.first()
val playbackStartRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
val insertIndex = index + 2
val freeRegister = findFreeRegister(insertIndex, playbackStartRegister)
addInstructionsWithLabels(
insertIndex,
extensionInstructions(playbackStartRegister, freeRegister)
extensionInstructions(playbackStartRegister, freeRegister),
)
}
}
@@ -119,7 +118,7 @@ val `Open Shorts in regular player` by creatingBytecodePatch(
// Fix issue with back button exiting the app instead of minimizing the player.
// Without this change this issue can be difficult to reproduce, but seems to occur
// most often with 'open video in regular player' and not open in fullscreen player.
exitVideoPlayerFingerprint.method.apply {
exitVideoPlayerMethod.apply {
// Method call for Activity.finish()
val finishIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
@@ -135,7 +134,7 @@ val `Open Shorts in regular player` by creatingBytecodePatch(
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->overrideBackPressToExit(Z)Z
move-result v$register
"""
""",
)
}
}

View File

@@ -1,63 +1,48 @@
package app.revanced.patches.youtube.layout.sponsorblock
import app.revanced.patcher.InstructionLocation.*
import app.revanced.patcher.checkCast
import app.revanced.patcher.fingerprint
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcode
import app.revanced.patcher.*
import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.youtube.shared.seekbarFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import app.revanced.patches.youtube.shared.seekbarMethod
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val appendTimeFingerprint = fingerprint {
internal val appendTimeMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;")
returnType("V")
parameterTypes("Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;", "Ljava/lang/CharSequence;")
instructions(
ResourceType.STRING("total_time"),
methodCall(smali = "Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String;"),
opcode(Opcode.MOVE_RESULT_OBJECT, MatchAfterImmediately()),
method { toString() == "Landroid/content/res/Resources;->getString(I[Ljava/lang/Object;)Ljava/lang/String;" },
after(Opcode.MOVE_RESULT_OBJECT()),
)
}
internal val controlsOverlayFingerprint = fingerprint {
returns("V")
parameters()
internal val controlsOverlayMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes()
instructions(
ResourceType.ID("inset_overlay_view_layout"),
checkCast("Landroid/widget/FrameLayout;", MatchAfterWithin(20)),
ResourceType.ID.invoke("inset_overlay_view_layout"),
afterAtMost(20, allOf(Opcode.CHECK_CAST(), type("Landroid/widget/FrameLayout;"))),
)
}
/**
* Resolves to the class found in [seekbarFingerprint].
* Resolves to the class found in [seekbarMethod].
*/
internal val rectangleFieldInvalidatorFingerprint = fingerprint {
returns("V")
parameters()
internal val rectangleFieldInvalidatorMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes()
instructions(method("invalidate"))
}
internal val adProgressTextViewVisibilityMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes("Z")
instructions(
methodCall(name = "invalidate"),
method {
name == "setVisibility" && definingClass ==
"Lcom/google/android/libraries/youtube/ads/player/ui/AdProgressTextView;"
},
)
}
internal val adProgressTextViewVisibilityFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Z")
custom { method, _ ->
indexOfAdProgressTextViewVisibilityInstruction(method) >= 0
}
}
internal fun indexOfAdProgressTextViewVisibilityInstruction(method: Method) = method.indexOfFirstInstructionReversed {
val reference = getReference<MethodReference>()
reference?.definingClass ==
"Lcom/google/android/libraries/youtube/ads/player/ui/AdProgressTextView;" &&
reference.name == "setVisibility"
}

View File

@@ -3,6 +3,7 @@ package app.revanced.patches.youtube.layout.sponsorblock
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
@@ -19,9 +20,9 @@ import app.revanced.patches.youtube.misc.playercontrols.playerControlsPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.layoutConstructorFingerprint
import app.revanced.patches.youtube.shared.seekbarFingerprint
import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint
import app.revanced.patches.youtube.shared.getLayoutConstructorMethodMatch
import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch
import app.revanced.patches.youtube.shared.seekbarMethod
import app.revanced.patches.youtube.video.information.onCreateHook
import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.patches.youtube.video.information.videoTimeHook
@@ -52,13 +53,13 @@ private val sponsorBlockResourcePatch = resourcePatch {
key = "revanced_settings_screen_10_sponsorblock",
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = emptySet(), // Preferences are added by custom class at runtime.
tag = "app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup"
tag = "app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup",
),
PreferenceCategory(
key = "revanced_sb_stats",
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = emptySet(), // Preferences are added by custom class at runtime.
tag = "app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockStatsPreferenceCategory"
tag = "app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockStatsPreferenceCategory",
),
PreferenceCategory(
key = "revanced_sb_about",
@@ -68,9 +69,9 @@ private val sponsorBlockResourcePatch = resourcePatch {
key = "revanced_sb_about_api",
tag = "app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockAboutPreference",
selectable = true,
)
)
)
),
),
),
)
arrayOf(
@@ -91,7 +92,7 @@ private val sponsorBlockResourcePatch = resourcePatch {
"revanced_sb_logo_bold.xml",
"revanced_sb_publish.xml",
"revanced_sb_voting.xml",
)
),
).forEach { resourceGroup ->
copyResources("sponsorblock", resourceGroup)
}
@@ -131,7 +132,7 @@ val SponsorBlock by creatingBytecodePatch(
"20.14.43",
"20.21.37",
"20.31.40",
)
),
)
apply {
@@ -143,17 +144,15 @@ val SponsorBlock by creatingBytecodePatch(
hookBackgroundPlayVideoId(
EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR +
"->setCurrentVideoId(Ljava/lang/String;)V",
"->setCurrentVideoId(Ljava/lang/String;)V",
)
// Set seekbar draw rectangle.
val rectangleFieldName: FieldReference
rectangleFieldInvalidatorFingerprint.match(
seekbarFingerprint.originalClassDef
).let {
rectangleFieldInvalidatorMethodMatch.match(seekbarMethod.immutableClassDef).let {
it.method.apply {
val rectangleIndex = indexOfFirstInstructionReversedOrThrow(
it.instructionMatches.first().index
it.indices.first(),
) {
getReference<FieldReference>()?.type == "Landroid/graphics/Rect;"
}
@@ -163,19 +162,17 @@ val SponsorBlock by creatingBytecodePatch(
// Seekbar drawing.
// Shared fingerprint and indexes may have changed.
seekbarOnDrawFingerprint.clearMatch()
// Cannot match using original immutable class because
// class may have been modified by other patches
seekbarOnDrawFingerprint.match(seekbarFingerprint.classDef).let {
getSeekbarOnDrawMethodMatch().match(seekbarMethod.immutableClassDef).let {
it.method.apply {
// Set seekbar thickness.
val thicknessIndex = it.instructionMatches.last().index
val thicknessIndex = it.indices.last()
val thicknessRegister = getInstruction<OneRegisterInstruction>(thicknessIndex).registerA
addInstruction(
thicknessIndex + 1,
"invoke-static { v$thicknessRegister }, " +
"$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSeekbarThickness(I)V",
"$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSeekbarThickness(I)V",
)
// Find the drawCircle call and draw the segment before it.
@@ -189,8 +186,8 @@ val SponsorBlock by creatingBytecodePatch(
addInstruction(
drawCircleIndex,
"invoke-static { v$canvasInstanceRegister, v$centerYRegister }, " +
"$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->" +
"drawSegmentTimeBars(Landroid/graphics/Canvas;F)V",
"$EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->" +
"drawSegmentTimeBars(Landroid/graphics/Canvas;F)V",
)
// Set seekbar bounds.
@@ -200,7 +197,7 @@ val SponsorBlock by creatingBytecodePatch(
move-object/from16 v0, p0
iget-object v0, v0, $rectangleFieldName
invoke-static { v0 }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSeekbarRectangle(Landroid/graphics/Rect;)V
"""
""",
)
}
}
@@ -213,9 +210,9 @@ val SponsorBlock by creatingBytecodePatch(
injectVisibilityCheckCall(EXTENSION_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR)
// Append the new time to the player layout.
appendTimeFingerprint.let {
appendTimeMethodMatch.let {
it.method.apply {
val index = it.instructionMatches.last().index
val index = it.indices.last()
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
@@ -223,7 +220,7 @@ val SponsorBlock by creatingBytecodePatch(
"""
invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
""",
)
}
}
@@ -232,8 +229,9 @@ val SponsorBlock by creatingBytecodePatch(
onCreateHook(EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "initialize")
// Initialize the SponsorBlock view.
controlsOverlayFingerprint.match(layoutConstructorFingerprint.originalClassDef).let {
val checkCastIndex = it.instructionMatches.last().index
controlsOverlayMethodMatch.match(getLayoutConstructorMethodMatch().immutableClassDef).let {
val checkCastIndex = it.indices.last()
it.method.apply {
val frameLayoutRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
@@ -243,13 +241,13 @@ val SponsorBlock by creatingBytecodePatch(
}
}
adProgressTextViewVisibilityFingerprint.method.apply {
val index = indexOfAdProgressTextViewVisibilityInstruction(this)
val register = getInstruction<FiveRegisterInstruction>(index).registerD
adProgressTextViewVisibilityMethodMatch.let {
val setVisibilityIndex = it.indices.first()
val register = it.method.getInstruction<FiveRegisterInstruction>(setVisibilityIndex).registerD
addInstructionsAtControlFlowLabel(
index,
"invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setAdProgressTextVisibility(I)V"
it.method.addInstructionsAtControlFlowLabel(
setVisibilityIndex,
"invoke-static { v$register }, $EXTENSION_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setAdProgressTextVisibility(I)V",
)
}
}

View File

@@ -1,25 +1,25 @@
package app.revanced.patches.youtube.layout.startpage
import app.revanced.patcher.addString
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.addString
import com.android.tools.smali.dexlib2.Opcode
internal val intentActionFingerprint = fingerprint {
parameters("Landroid/content/Intent;")
instructions(
addString("has_handled_intent")
addString("has_handled_intent"),
)
}
internal val browseIdFingerprint = fingerprint {
returns("Lcom/google/android/apps/youtube/app/common/ui/navigation/PaneDescriptor;")
//parameters() // 20.30 and earlier is no parameters. 20.31+ parameter is L.
// parameters() // 20.30 and earlier is no parameters. 20.31+ parameter is L.
instructions(
addString("FEwhat_to_watch"),
literal(512),
fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Ljava/lang/String;")
512(),
fieldAccess(opcode = Opcode.IPUT_OBJECT, type = "Ljava/lang/String;"),
)
}

View File

@@ -2,12 +2,12 @@ package app.revanced.patches.youtube.layout.startupshortsreset
import app.revanced.patcher.InstructionLocation.*
import app.revanced.patcher.StringComparisonType
import app.revanced.patcher.addString
import app.revanced.patcher.checkCast
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcode
import app.revanced.patcher.addString
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -23,7 +23,7 @@ internal val userWasInShortsAlternativeFingerprint = fingerprint {
methodCall(smali = "Ljava/lang/Boolean;->booleanValue()Z", location = MatchAfterImmediately()),
opcode(Opcode.MOVE_RESULT, MatchAfterImmediately()),
// 20.40+ string was merged into another string and is a partial match.
addString("userIsInShorts: ", comparison = StringComparisonType.CONTAINS, location = MatchAfterWithin(15))
addString("userIsInShorts: ", comparison = StringComparisonType.CONTAINS, location = MatchAfterWithin(15)),
)
}
@@ -35,7 +35,7 @@ internal val userWasInShortsLegacyFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Ljava/lang/Object;")
instructions(
addString("Failed to read user_was_in_shorts proto after successful warmup")
addString("Failed to read user_was_in_shorts proto after successful warmup"),
)
}
@@ -47,6 +47,6 @@ internal val userWasInShortsConfigFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45358360L)
45358360L(),
)
}

View File

@@ -7,7 +7,7 @@ import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
internal val useGradientLoadingScreenFingerprint = fingerprint {
instructions(
literal(45412406L)
45412406L(),
)
}
@@ -16,9 +16,9 @@ internal val splashScreenStyleFingerprint = fingerprint {
parameters("Landroid/os/Bundle;")
instructions(
anyInstruction(
literal(1074339245), // 20.30+
literal(269032877L) // 20.29 and lower.
)
1074339245(), // 20.30+
269032877L(), // 20.29 and lower.
),
)
custom { method, classDef ->
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE

View File

@@ -1,18 +1,18 @@
package app.revanced.patches.youtube.misc.litho.filter
import app.revanced.patcher.addString
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.addString
import app.revanced.util.containsLiteralInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val componentCreateFingerprint = fingerprint {
instructions(
addString("Element missing correct type extension"),
addString("Element missing type")
addString("Element missing type"),
)
}
@@ -31,12 +31,12 @@ internal val protobufBufferReferenceFingerprint = fingerprint {
fieldAccess(
opcode = Opcode.IGET_OBJECT,
definingClass = "this",
type = "Lcom/google/android/libraries/elements/adl/UpbMessage;"
type = "Lcom/google/android/libraries/elements/adl/UpbMessage;",
),
methodCall(
definingClass = "Lcom/google/android/libraries/elements/adl/UpbMessage;",
name = "jniDecode"
)
name = "jniDecode",
),
)
}
@@ -56,7 +56,7 @@ internal val emptyComponentFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.CONSTRUCTOR)
parameters()
instructions(
addString("EmptyComponent")
addString("EmptyComponent"),
)
custom { _, classDef ->
classDef.methods.filter { AccessFlags.STATIC.isSet(it.accessFlags) }.size == 1
@@ -77,13 +77,13 @@ internal val lithoComponentNameUpbFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45631264L)
45631264L(),
)
}
internal val lithoConverterBufferUpbFeatureFlagFingerprint = fingerprint {
returns("L")
instructions(
literal(45419603L)
45419603L(),
)
}

View File

@@ -107,7 +107,7 @@ internal val playerBottomControlsExploderFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45643739L),
45643739L(),
)
}
@@ -116,7 +116,7 @@ internal val playerTopControlsExperimentalLayoutFeatureFlagFingerprint = fingerp
returns("I")
parameters()
instructions(
literal(45629424L),
45629424L(),
)
}
@@ -125,7 +125,7 @@ internal val playerControlsLargeOverlayButtonsFeatureFlagFingerprint = fingerpri
returns("Z")
parameters()
instructions(
literal(45709810L),
45709810L(),
)
}
@@ -134,7 +134,7 @@ internal val playerControlsFullscreenLargeButtonsFeatureFlagFingerprint = finger
returns("Z")
parameters()
instructions(
literal(45686474L),
45686474L(),
)
}
@@ -143,6 +143,6 @@ internal val playerControlsButtonStrokeFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45713296),
45713296(),
)
}

View File

@@ -30,7 +30,7 @@ internal val cairoFragmentConfigFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(45532100L),
45532100L(),
opcode(Opcode.MOVE_RESULT, location = MatchAfterWithin(10)),
)
}
@@ -42,6 +42,6 @@ internal val boldIconsFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters()
instructions(
literal(45685201L),
45685201L(),
)
}

View File

@@ -1,26 +1,27 @@
package app.revanced.patches.youtube.shared
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.accessFlags
import app.revanced.patcher.addString
import app.revanced.patcher.after
import app.revanced.patcher.allOf
import app.revanced.patcher.definingClass
import app.revanced.patcher.field
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.firstMethodDeclaratively
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instruction
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.method
import app.revanced.patcher.name
import app.revanced.patcher.opcode
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patcher.type
import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.shared.misc.mapping.ResourceType.IndexedMatcherPredicateExtension.invoke
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -41,14 +42,21 @@ internal val conversionContextFingerprintToString = fingerprint {
}
}
internal val layoutConstructorFingerprint = fingerprint {
internal fun getLayoutConstructorMethodMatch() = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
returnType("V")
parameterTypes()
val methodParameterTypePrefixes = listOf("Landroid/view/View;", "I")
instructions(
literal(159962),
159962L(),
ResourceType.ID("player_control_previous_button_touch_area"),
ResourceType.ID("player_control_next_button_touch_area"),
methodCall(parameters = listOf("Landroid/view/View;", "I")),
method {
parameterTypes.size == 2 &&
parameterTypes.zip(methodParameterTypePrefixes).all { (a, b) -> a.startsWith(b) }
},
)
}
@@ -102,22 +110,20 @@ internal val rollingNumberTextViewAnimationUpdateFingerprint = fingerprint {
}
}
internal val seekbarFingerprint = fingerprint {
returns("V")
instructions(
addString("timed_markers_width"),
)
internal val BytecodePatchContext.seekbarMethod by gettingFirstMethodDeclaratively {
returnType("V")
instructions("timed_markers_width"())
}
/**
* Matches to _mutable_ class found in [seekbarFingerprint].
* Matches to _mutable_ class found in [seekbarMethod].
*/
internal val seekbarOnDrawFingerprint = fingerprint {
internal fun getSeekbarOnDrawMethodMatch() = firstMethodComposite {
name("onDraw")
instructions(
methodCall(smali = "Ljava/lang/Math;->round(F)I"),
opcode(Opcode.MOVE_RESULT, location = MatchAfterImmediately()),
method { toString() == "Ljava/lang/Math;->round(F)I" },
after(Opcode.MOVE_RESULT()),
)
custom { method, _ -> method.name == "onDraw" }
}
internal val subtitleButtonControllerFingerprint = fingerprint {

View File

@@ -30,7 +30,7 @@ internal val serverSideMaxSpeedFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
instructions(
literal(45719140L),
45719140L(),
)
}
@@ -42,7 +42,7 @@ internal val speedArrayGeneratorFingerprint = fingerprint {
methodCall(name = "size", returnType = "I"),
newInstance("Ljava/text/DecimalFormat;"),
addString("0.0#"),
literal(7),
7(),
opcode(Opcode.NEW_ARRAY),
fieldAccess(definingClass = "/PlayerConfigModel;", type = "[F"),
)
@@ -56,8 +56,8 @@ internal val speedLimiterFingerprint = fingerprint {
returns("V")
parameters("F", "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;")
instructions(
literal(0.25f),
literal(4.0f),
0.25f(),
4.0f(),
)
}

View File

@@ -14,7 +14,7 @@ internal val videoIdFingerprint = fingerprint {
instructions(
methodCall(
definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;",
returnType = "Ljava/lang/String;"
returnType = "Ljava/lang/String;",
),
opcode(Opcode.MOVE_RESULT_OBJECT),
)
@@ -27,19 +27,21 @@ internal val videoIdBackgroundPlayFingerprint = fingerprint {
instructions(
methodCall(
definingClass = "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;",
returnType = "Ljava/lang/String;"
returnType = "Ljava/lang/String;",
),
opcode(Opcode.MOVE_RESULT_OBJECT),
opcode(Opcode.IPUT_OBJECT),
opcode(Opcode.MONITOR_EXIT),
opcode(Opcode.RETURN_VOID),
opcode(Opcode.MONITOR_EXIT),
opcode(Opcode.RETURN_VOID)
opcode(Opcode.RETURN_VOID),
)
custom { method, classDef ->
method.implementation != null &&
(classDef.methods.count() == 17 // 20.39 and lower.
|| classDef.methods.count() == 16) // 20.40+
(
classDef.methods.count() == 17 || // 20.39 and lower.
classDef.methods.count() == 16
) // 20.40+
}
}
@@ -48,6 +50,6 @@ internal val videoIdParentFingerprint = fingerprint {
returns("[L")
parameters("L")
instructions(
literal(524288L)
524288L(),
)
}

View File

@@ -1,9 +1,9 @@
package app.revanced.util
import app.revanced.patcher.firstMutableClassDef
import app.revanced.patcher.firstMutableClassDefOrNull
import app.revanced.patcher.FingerprintBuilder
import app.revanced.patcher.extensions.*
import app.revanced.patcher.firstMutableClassDef
import app.revanced.patcher.firstMutableClassDefOrNull
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.shared.misc.mapping.ResourceType
@@ -91,7 +91,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
// This method is simple and does not follow branching.
throw IllegalArgumentException(
"Encountered a branch statement before " +
"a free register could be found from startIndex: $startIndex"
"a free register could be found from startIndex: $startIndex",
)
}
@@ -111,7 +111,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
// In practice this never occurs.
throw IllegalArgumentException(
"Could not find a free register from startIndex: " +
"$startIndex excluding: $registersToExclude"
"$startIndex excluding: $registersToExclude",
)
}
}
@@ -139,9 +139,13 @@ internal val Instruction.registersUsed: List<Int>
}
is ThreeRegisterInstruction -> listOf(registerA, registerB, registerC)
is TwoRegisterInstruction -> listOf(registerA, registerB)
is OneRegisterInstruction -> listOf(registerA)
is RegisterRangeInstruction -> (startRegister until (startRegister + registerCount)).toList()
else -> emptyList()
}
@@ -191,7 +195,7 @@ private fun Method.findInstructionIndexFromToString(fieldName: String): Int {
val stringUsageIndex = indexOfFirstInstruction(stringIndex) {
val reference = getReference<MethodReference>()
reference?.definingClass == "Ljava/lang/StringBuilder;" &&
(this as? FiveRegisterInstruction)?.registerD == stringRegister
(this as? FiveRegisterInstruction)?.registerD == stringRegister
}
if (stringUsageIndex < 0) {
throw IllegalArgumentException("Could not find StringBuilder usage in: $this")
@@ -249,11 +253,9 @@ internal fun Method.findFieldFromToString(fieldName: String): FieldReference {
/**
* Adds public [AccessFlags] and removes private and protected flags (if present).
*/
internal fun Int.toPublicAccessFlags(): Int {
return this.or(AccessFlags.PUBLIC.value)
.and(AccessFlags.PROTECTED.value.inv())
.and(AccessFlags.PRIVATE.value.inv())
}
internal fun Int.toPublicAccessFlags(): Int = this.or(AccessFlags.PUBLIC.value)
.and(AccessFlags.PROTECTED.value.inv())
.and(AccessFlags.PRIVATE.value.inv())
/**
* Find the [MutableMethod] from a given [Method] in a [MutableClass].
@@ -294,7 +296,6 @@ fun MutableMethod.injectHideViewCall(
"invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V",
)
/**
* Inserts instructions at a given index, using the existing control flow label at that index.
* Inserted instructions can have it's own control flow labels as well.
@@ -311,7 +312,7 @@ fun MutableMethod.injectHideViewCall(
// TODO: delete this on next major version bump.
fun MutableMethod.addInstructionsAtControlFlowLabel(
insertIndex: Int,
instructions: String
instructions: String,
) = addInstructionsAtControlFlowLabel(insertIndex, instructions, *arrayOf<ExternalLabel>())
/**
@@ -330,7 +331,7 @@ fun MutableMethod.addInstructionsAtControlFlowLabel(
fun MutableMethod.addInstructionsAtControlFlowLabel(
insertIndex: Int,
instructions: String,
vararg externalLabels: ExternalLabel
vararg externalLabels: ExternalLabel,
) {
// Duplicate original instruction and add to +1 index.
addInstruction(insertIndex + 1, getInstruction(insertIndex))
@@ -356,9 +357,7 @@ fun MutableMethod.addInstructionsAtControlFlowLabel(
* @throws PatchException if the resource cannot be found.
* @see [indexOfFirstResourceIdOrThrow], [indexOfFirstLiteralInstructionReversed]
*/
fun Method.indexOfFirstResourceId(resourceName: String): Int {
return indexOfFirstLiteralInstruction(ResourceType.ID[resourceName)]
}
fun Method.indexOfFirstResourceId(resourceName: String): Int = indexOfFirstLiteralInstruction(ResourceType.ID[resourceName])
/**
* Get the index of the first instruction with the id of the given resource name or throw a [PatchException].
@@ -407,8 +406,7 @@ fun Method.indexOfFirstLiteralInstructionOrThrow(literal: Long): Int {
* @return the first literal instruction with the value, or -1 if not found.
* @see indexOfFirstLiteralInstructionOrThrow
*/
fun Method.indexOfFirstLiteralInstruction(literal: Float) =
indexOfFirstLiteralInstruction(literal.toRawBits().toLong())
fun Method.indexOfFirstLiteralInstruction(literal: Float) = indexOfFirstLiteralInstruction(literal.toRawBits().toLong())
/**
* Find the index of the first literal instruction with the given float value,
@@ -428,8 +426,7 @@ fun Method.indexOfFirstLiteralInstructionOrThrow(literal: Float): Int {
* @return the first literal instruction with the value, or -1 if not found.
* @see indexOfFirstLiteralInstructionOrThrow
*/
fun Method.indexOfFirstLiteralInstruction(literal: Double) =
indexOfFirstLiteralInstruction(literal.toRawBits())
fun Method.indexOfFirstLiteralInstruction(literal: Double) = indexOfFirstLiteralInstruction(literal.toRawBits())
/**
* Find the index of the first literal instruction with the given double value,
@@ -473,8 +470,7 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Long): Int {
* @return the last literal instruction with the value, or -1 if not found.
* @see indexOfFirstLiteralInstructionOrThrow
*/
fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) =
indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong())
fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) = indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong())
/**
* Find the index of the last wide literal instruction with the given float value,
@@ -494,8 +490,7 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Float): Int {
* @return the last literal instruction with the value, or -1 if not found.
* @see indexOfFirstLiteralInstructionOrThrow
*/
fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) =
indexOfFirstLiteralInstructionReversed(literal.toRawBits())
fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) = indexOfFirstLiteralInstructionReversed(literal.toRawBits())
/**
* Find the index of the last wide literal instruction with the given double value,
@@ -567,10 +562,9 @@ fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int = indexOfFirstInst
* @return The index of the first opcode specified, or -1 if not found.
* @see indexOfFirstInstructionOrThrow
*/
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int =
indexOfFirstInstruction(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstruction(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
@@ -605,10 +599,9 @@ fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int = indexOfFi
* @throws PatchException
* @see indexOfFirstInstruction
*/
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int =
indexOfFirstInstructionOrThrow(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
@@ -634,10 +627,9 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, filter: Instructi
* @return -1 if the instruction is not found.
* @see indexOfFirstInstructionReversedOrThrow
*/
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int =
indexOfFirstInstructionReversed(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversed(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
@@ -674,10 +666,9 @@ fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int = indexOfF
* @return The index of the instruction.
* @see indexOfFirstInstructionReversed
*/
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int =
indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
@@ -734,8 +725,7 @@ fun Method.findInstructionIndicesReversedOrThrow(filter: Instruction.() -> Boole
* _Returns an empty list if no indices are found_
* @see findInstructionIndicesReversedOrThrow
*/
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> =
findInstructionIndicesReversed { this.opcode == opcode }
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> = findInstructionIndicesReversed { this.opcode == opcode }
/**
* @return An immutable list of indices of the opcode in reverse order.
@@ -773,7 +763,7 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, extensionMet
"""
$operation, $extensionMethodDescriptor
move-result v$register
"""
""",
)
}
@@ -795,7 +785,7 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Bo
addInstruction(
index + 1,
"const v$register, $overrideValue"
"const v$register, $overrideValue",
)
}
@@ -822,7 +812,7 @@ fun BytecodePatchContext.forEachInstructionAsSequence(
mutableClassDef,
mutableMethod,
instructions.size - 1 - index,
instruction
instruction,
)
} // Reverse indices again.
}
@@ -1230,7 +1220,7 @@ internal fun BytecodePatchContext.addStaticFieldToExtension(
methodName: String,
fieldName: String,
objectClass: String,
smaliInstructions: String
smaliInstructions: String,
) {
val mutableClass = firstMutableClassDef(type)
val objectCall = "$mutableClass->$fieldName:$objectClass"
@@ -1245,15 +1235,15 @@ internal fun BytecodePatchContext.addStaticFieldToExtension(
AccessFlags.PUBLIC.value or AccessFlags.STATIC.value,
null,
annotations,
null
).toMutable()
null,
).toMutable(),
)
addInstructionsWithLabels(
0,
"""
sget-object v0, $objectCall
""" + smaliInstructions
""" + smaliInstructions,
)
}
}
@@ -1277,12 +1267,16 @@ private class InstructionUtils {
GOTO, GOTO_16, GOTO_32,
IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE,
IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ,
PACKED_SWITCH_PAYLOAD, SPARSE_SWITCH_PAYLOAD
PACKED_SWITCH_PAYLOAD, SPARSE_SWITCH_PAYLOAD,
)
val returnOpcodes: EnumSet<Opcode> = EnumSet.of(
RETURN_VOID, RETURN, RETURN_WIDE, RETURN_OBJECT, RETURN_VOID_NO_BARRIER,
THROW
RETURN_VOID,
RETURN,
RETURN_WIDE,
RETURN_OBJECT,
RETURN_VOID_NO_BARRIER,
THROW,
)
val writeOpcodes: EnumSet<Opcode> = EnumSet.of(