feat(kakaotalk): add layout handling for deleted and hidden messages in chat log
This is the fourth commit to make deleted, hidden messages visible.
This commit is contained in:
@ -3,10 +3,15 @@ package app.revanced.patches.kakaotalk.chatlog
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
|
import app.revanced.util.getReference
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||||
import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue
|
import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue
|
||||||
|
|
||||||
@ -23,6 +28,9 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch(
|
|||||||
val makeLayoutMethod = chatInfoViewClass.methods.firstOrNull {
|
val makeLayoutMethod = chatInfoViewClass.methods.firstOrNull {
|
||||||
it.name == "makeLayout"
|
it.name == "makeLayout"
|
||||||
} ?: error("makeLayout method not found in ChatInfoView class")
|
} ?: error("makeLayout method not found in ChatInfoView class")
|
||||||
|
val onDrawMethod = chatInfoViewClass.methods.firstOrNull {
|
||||||
|
it.name == "onDraw"
|
||||||
|
} ?: error("onDraw method not found in ChatInfoView class")
|
||||||
|
|
||||||
println("ChatInfoView class: $chatInfoViewClass")
|
println("ChatInfoView class: $chatInfoViewClass")
|
||||||
println("makeLayout method: $makeLayoutMethod")
|
println("makeLayout method: $makeLayoutMethod")
|
||||||
@ -172,22 +180,19 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch(
|
|||||||
).toMutable()
|
).toMutable()
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add logic to initialize these fields in the makeLayout method
|
val cls = chatInfoViewClass.type
|
||||||
|
|
||||||
makeLayoutMethod.addInstructionsWithLabels(
|
val deletedMakeLayoutBlock = """
|
||||||
0,
|
iget-boolean v0, p0, $cls->isDeleted:Z
|
||||||
"""
|
if-eqz v0, :skip_deleted
|
||||||
iget-boolean v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isDeleted:Z
|
|
||||||
if-eqz v0, :not_deleted
|
|
||||||
const-string v0, "[Deleted]"
|
const-string v0, "[Deleted]"
|
||||||
iget-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint;
|
iget-object v1, p0, $cls->deletedPaint:Landroid/text/TextPaint;
|
||||||
invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics;
|
invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics;
|
||||||
move-result-object v8
|
move-result-object v8
|
||||||
|
|
||||||
if-nez v8, :boring_deleted
|
if-nez v8, :boring_deleted
|
||||||
new-instance v1, Landroid/text/StaticLayout;
|
new-instance v1, Landroid/text/StaticLayout;
|
||||||
iget-object v4, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint;
|
iget-object v4, p0, $cls->deletedPaint:Landroid/text/TextPaint;
|
||||||
invoke-virtual { v4, v0 }, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
||||||
move-result v2
|
move-result v2
|
||||||
float-to-int v5, v2
|
float-to-int v5, v2
|
||||||
sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment;
|
sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment;
|
||||||
@ -197,9 +202,9 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch(
|
|||||||
move-object v2, v1
|
move-object v2, v1
|
||||||
move-object v3, v0
|
move-object v3, v0
|
||||||
invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V
|
invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V
|
||||||
goto :set_deleted_layout
|
goto :set_deleted
|
||||||
:boring_deleted
|
:boring_deleted
|
||||||
iget-object v3, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint;
|
iget-object v3, p0, $cls->deletedPaint:Landroid/text/TextPaint;
|
||||||
invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
||||||
move-result v1
|
move-result v1
|
||||||
float-to-int v4, v1
|
float-to-int v4, v1
|
||||||
@ -210,10 +215,125 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch(
|
|||||||
move-object v2, v0
|
move-object v2, v0
|
||||||
invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout;
|
invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout;
|
||||||
move-result-object v1
|
move-result-object v1
|
||||||
:set_deleted_layout
|
:set_deleted
|
||||||
iput-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedLayout:Landroid/text/Layout;
|
iput-object v1, p0, $cls->deletedLayout:Landroid/text/Layout;
|
||||||
""".trimIndent(),
|
:skip_deleted
|
||||||
ExternalLabel("not_deleted", makeLayoutMethod.getInstruction(0))
|
""".trimIndent()
|
||||||
|
|
||||||
|
val hiddenMakeLayoutBlock = """
|
||||||
|
iget-boolean v0, p0, $cls->isHidden:Z
|
||||||
|
if-eqz v0, :skip_hidden
|
||||||
|
const-string v0, "[Hidden]"
|
||||||
|
iget-object v1, p0, $cls->hiddenPaint:Landroid/text/TextPaint;
|
||||||
|
invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics;
|
||||||
|
move-result-object v8
|
||||||
|
if-nez v8, :boring_hidden
|
||||||
|
new-instance v1, Landroid/text/StaticLayout;
|
||||||
|
iget-object v4, p0, $cls->hiddenPaint:Landroid/text/TextPaint;
|
||||||
|
invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
||||||
|
move-result v2
|
||||||
|
float-to-int v5, v2
|
||||||
|
sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment;
|
||||||
|
const/4 v9, 0x1
|
||||||
|
const/high16 v7, 0x3f800000 # 1.0f
|
||||||
|
const/4 v8, 0x0
|
||||||
|
move-object v2, v1
|
||||||
|
move-object v3, v0
|
||||||
|
invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V
|
||||||
|
goto :set_hidden
|
||||||
|
:boring_hidden
|
||||||
|
iget-object v3, p0, $cls->hiddenPaint:Landroid/text/TextPaint;
|
||||||
|
invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F
|
||||||
|
move-result v1
|
||||||
|
float-to-int v4, v1
|
||||||
|
sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment;
|
||||||
|
const/4 v9, 0x0
|
||||||
|
const/high16 v6, 0x3f800000 # 1.0f
|
||||||
|
const/4 v7, 0x0
|
||||||
|
move-object v2, v0
|
||||||
|
invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout;
|
||||||
|
move-result-object v1
|
||||||
|
:set_hidden
|
||||||
|
iput-object v1, p0, $cls->hiddenLayout:Landroid/text/Layout;
|
||||||
|
:skip_hidden
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
makeLayoutMethod.addInstructions(
|
||||||
|
0,
|
||||||
|
deletedMakeLayoutBlock + "\n\n" + hiddenMakeLayoutBlock,
|
||||||
|
)
|
||||||
|
|
||||||
|
val superIndex = onDrawMethod.instructions.indexOfFirst {
|
||||||
|
it.opcode == Opcode.INVOKE_SUPER
|
||||||
|
}
|
||||||
|
|
||||||
|
val deletedOnDrawBlock = """
|
||||||
|
iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout;
|
||||||
|
if-eqz v0, :skip_deleted_draw
|
||||||
|
iget-boolean v0, p0, $cls->isDeleted:Z
|
||||||
|
if-eqz v0, :skip_deleted_draw
|
||||||
|
invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I
|
||||||
|
iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect;
|
||||||
|
invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z
|
||||||
|
iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect;
|
||||||
|
iget v0, v0, Landroid/graphics/Rect;->left:I
|
||||||
|
int-to-float v0, v0
|
||||||
|
iget-object v1, p0, $cls->deletedRect:Landroid/graphics/Rect;
|
||||||
|
iget v1, v1, Landroid/graphics/Rect;->top:I
|
||||||
|
int-to-float v1, v1
|
||||||
|
invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V
|
||||||
|
iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout;
|
||||||
|
.line 1
|
||||||
|
if-eqz v0, :fuck
|
||||||
|
.line 2
|
||||||
|
invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V
|
||||||
|
.line 3
|
||||||
|
:fuck
|
||||||
|
invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
val hiddenOnDrawBlock = """
|
||||||
|
iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout;
|
||||||
|
if-eqz v0, :skip_hidden_draw
|
||||||
|
iget-boolean v0, p0, $cls->isHidden:Z
|
||||||
|
if-eqz v0, :skip_hidden_draw
|
||||||
|
invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I
|
||||||
|
iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect;
|
||||||
|
invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z
|
||||||
|
iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect;
|
||||||
|
iget v0, v0, Landroid/graphics/Rect;->left:I
|
||||||
|
int-to-float v0, v0
|
||||||
|
iget-object v1, p0, $cls->hiddenRect:Landroid/graphics/Rect;
|
||||||
|
iget v1, v1, Landroid/graphics/Rect;->top:I
|
||||||
|
int-to-float v1, v1
|
||||||
|
invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V
|
||||||
|
iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout;
|
||||||
|
.line 4
|
||||||
|
if-eqz v0, :nullCheck_2
|
||||||
|
.line 5
|
||||||
|
invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V
|
||||||
|
.line 6
|
||||||
|
:nullCheck_2
|
||||||
|
invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
val instructionFollowingBothBlocks = onDrawMethod.getInstruction(superIndex + 1)
|
||||||
|
|
||||||
|
val skipHiddenLabel = ExternalLabel("skip_hidden_draw", instructionFollowingBothBlocks)
|
||||||
|
|
||||||
|
onDrawMethod.addInstructionsWithLabels(
|
||||||
|
superIndex + 1,
|
||||||
|
hiddenOnDrawBlock,
|
||||||
|
skipHiddenLabel
|
||||||
|
)
|
||||||
|
|
||||||
|
val firstInstructionOfHiddenBlock = onDrawMethod.getInstruction(superIndex + 1)
|
||||||
|
val skipDeletedLabel = ExternalLabel("skip_deleted_draw", firstInstructionOfHiddenBlock)
|
||||||
|
|
||||||
|
onDrawMethod.addInstructionsWithLabels(
|
||||||
|
superIndex + 1,
|
||||||
|
deletedOnDrawBlock,
|
||||||
|
skipDeletedLabel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user