mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-28 13:11:03 +00:00
progress
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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="())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"())
|
||||
}
|
||||
|
||||
@@ -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\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
"""
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user