refactor: code cleanup

This commit is contained in:
rhunk 2023-09-23 22:44:51 +02:00
parent fc838fed7a
commit 2c16f41fd6
34 changed files with 149 additions and 174 deletions

View File

@ -3,13 +3,14 @@ package me.rhunk.snapenhance.bridge
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.SharedContextHolder import me.rhunk.snapenhance.SharedContextHolder
class ForceStartActivity : Activity() { class ForceStartActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (intent.getBooleanExtra("streaks_notification_action", false)) { if (intent.getBooleanExtra("streaks_notification_action", false)) {
packageManager.getLaunchIntentForPackage("com.snapchat.android")?.apply { packageManager.getLaunchIntentForPackage(Constants.SNAPCHAT_PACKAGE_NAME)?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(this) startActivity(this)
} }

View File

@ -3,13 +3,8 @@ package me.rhunk.snapenhance
object Constants { object Constants {
const val SNAPCHAT_PACKAGE_NAME = "com.snapchat.android" const val SNAPCHAT_PACKAGE_NAME = "com.snapchat.android"
const val VIEW_INJECTED_CODE = 0x7FFFFF02
val ARROYO_MEDIA_CONTAINER_PROTO_PATH = intArrayOf(4, 4) val ARROYO_MEDIA_CONTAINER_PROTO_PATH = intArrayOf(4, 4)
val ARROYO_STRING_CHAT_MESSAGE_PROTO = ARROYO_MEDIA_CONTAINER_PROTO_PATH + intArrayOf(2, 1) val ARROYO_STRING_CHAT_MESSAGE_PROTO = ARROYO_MEDIA_CONTAINER_PROTO_PATH + intArrayOf(2, 1)
const val ENCRYPTION_PROTO_INDEX = 19
const val ENCRYPTION_PROTO_INDEX_V2 = 4
const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
} }

View File

@ -10,14 +10,14 @@ import android.os.Process
import android.widget.Toast import android.widget.Toast
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import kotlinx.coroutines.asCoroutineDispatcher
import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.Logger
import me.rhunk.snapenhance.core.bridge.BridgeClient import me.rhunk.snapenhance.core.bridge.BridgeClient
import me.rhunk.snapenhance.core.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.core.bridge.wrapper.LocaleWrapper
import me.rhunk.snapenhance.core.bridge.wrapper.MappingsWrapper import me.rhunk.snapenhance.core.bridge.wrapper.MappingsWrapper
import me.rhunk.snapenhance.core.config.ModConfig import me.rhunk.snapenhance.core.config.ModConfig
import me.rhunk.snapenhance.core.database.DatabaseAccess import me.rhunk.snapenhance.core.database.DatabaseAccess
import me.rhunk.snapenhance.core.eventbus.EventBus import me.rhunk.snapenhance.core.event.EventBus
import me.rhunk.snapenhance.core.event.EventDispatcher
import me.rhunk.snapenhance.core.util.download.HttpServer import me.rhunk.snapenhance.core.util.download.HttpServer
import me.rhunk.snapenhance.data.MessageSender import me.rhunk.snapenhance.data.MessageSender
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
@ -34,32 +34,28 @@ import kotlin.system.exitProcess
class ModContext { class ModContext {
private val executorService: ExecutorService = Executors.newCachedThreadPool() private val executorService: ExecutorService = Executors.newCachedThreadPool()
val coroutineDispatcher by lazy {
executorService.asCoroutineDispatcher()
}
lateinit var androidContext: Context lateinit var androidContext: Context
var mainActivity: Activity? = null
lateinit var bridgeClient: BridgeClient lateinit var bridgeClient: BridgeClient
var mainActivity: Activity? = null
val classCache get() = SnapEnhance.classCache
val resources: Resources get() = androidContext.resources
val gson: Gson = GsonBuilder().create() val gson: Gson = GsonBuilder().create()
private val modConfig = ModConfig() private val _config = ModConfig()
val config by modConfig val config by _config::root
val log by lazy { Logger(this.bridgeClient) } val log by lazy { Logger(this.bridgeClient) }
val event = EventBus(this)
val eventDispatcher = EventDispatcher(this)
val native = NativeLib()
val translation = LocaleWrapper() val translation = LocaleWrapper()
val httpServer = HttpServer()
val messageSender = MessageSender(this)
val features = FeatureManager(this) val features = FeatureManager(this)
val mappings = MappingsWrapper() val mappings = MappingsWrapper()
val actionManager = ActionManager(this) val actionManager = ActionManager(this)
val database = DatabaseAccess(this) val database = DatabaseAccess(this)
val httpServer = HttpServer() val event = EventBus(this)
val messageSender = MessageSender(this) val eventDispatcher = EventDispatcher(this)
val classCache get() = SnapEnhance.classCache val native = NativeLib()
val resources: Resources get() = androidContext.resources
val scriptRuntime by lazy { CoreScriptRuntime(log, androidContext.classLoader) } val scriptRuntime by lazy { CoreScriptRuntime(log, androidContext.classLoader) }
fun <T : Feature> feature(featureClass: KClass<T>): T { fun <T : Feature> feature(featureClass: KClass<T>): T {
@ -74,7 +70,7 @@ class ModContext {
} }
} }
fun executeAsync(runnable: () -> Unit) { fun executeAsync(runnable: ModContext.() -> Unit) {
executorService.submit { executorService.submit {
runCatching { runCatching {
runnable() runnable()
@ -99,7 +95,7 @@ class ModContext {
fun softRestartApp(saveSettings: Boolean = false) { fun softRestartApp(saveSettings: Boolean = false) {
if (saveSettings) { if (saveSettings) {
modConfig.writeConfig() _config.writeConfig()
} }
val intent: Intent? = androidContext.packageManager.getLaunchIntentForPackage( val intent: Intent? = androidContext.packageManager.getLaunchIntentForPackage(
Constants.SNAPCHAT_PACKAGE_NAME Constants.SNAPCHAT_PACKAGE_NAME
@ -117,7 +113,7 @@ class ModContext {
delayForceCloseApp(100) delayForceCloseApp(100)
} }
fun delayForceCloseApp(delay: Long) = Handler(Looper.getMainLooper()).postDelayed({ private fun delayForceCloseApp(delay: Long) = Handler(Looper.getMainLooper()).postDelayed({
forceCloseApp() forceCloseApp()
}, delay) }, delay)
@ -128,7 +124,7 @@ class ModContext {
fun reloadConfig() { fun reloadConfig() {
log.verbose("reloading config") log.verbose("reloading config")
modConfig.loadFromBridge(bridgeClient) _config.loadFromBridge(bridgeClient)
native.loadNativeConfig( native.loadNativeConfig(
NativeConfig( NativeConfig(
disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(), disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(),
@ -138,6 +134,6 @@ class ModContext {
} }
fun getConfigLocale(): String { fun getConfigLocale(): String {
return modConfig.locale return _config.locale
} }
} }

View File

@ -3,118 +3,102 @@ package me.rhunk.snapenhance
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import me.rhunk.snapenhance.bridge.SyncCallback import me.rhunk.snapenhance.bridge.SyncCallback
import me.rhunk.snapenhance.core.BuildConfig
import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.Logger
import me.rhunk.snapenhance.core.bridge.BridgeClient import me.rhunk.snapenhance.core.bridge.BridgeClient
import me.rhunk.snapenhance.core.eventbus.events.impl.SnapWidgetBroadcastReceiveEvent import me.rhunk.snapenhance.core.event.events.impl.SnapWidgetBroadcastReceiveEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.UnaryCallEvent import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo import me.rhunk.snapenhance.core.messaging.MessagingFriendInfo
import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo import me.rhunk.snapenhance.core.messaging.MessagingGroupInfo
import me.rhunk.snapenhance.core.util.ktx.getApplicationInfoCompat
import me.rhunk.snapenhance.data.SnapClassCache import me.rhunk.snapenhance.data.SnapClassCache
import me.rhunk.snapenhance.hook.HookAdapter
import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.HookStage
import me.rhunk.snapenhance.hook.Hooker
import me.rhunk.snapenhance.hook.hook import me.rhunk.snapenhance.hook.hook
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlin.time.measureTime import kotlin.time.measureTime
private fun useMainActivity(hookAdapter: HookAdapter, block: Activity.() -> Unit) {
val activity = hookAdapter.thisObject() as Activity
if (!activity.packageName.equals(Constants.SNAPCHAT_PACKAGE_NAME)) return
block(activity)
}
class SnapEnhance { class SnapEnhance {
companion object { companion object {
lateinit var classLoader: ClassLoader lateinit var classLoader: ClassLoader
val classCache: SnapClassCache by lazy { private set
val classCache by lazy {
SnapClassCache(classLoader) SnapClassCache(classLoader)
} }
} }
private val appContext = ModContext() private val appContext = ModContext()
private var isBridgeInitialized = false private var isBridgeInitialized = false
private fun hookMainActivity(methodName: String, stage: HookStage = HookStage.AFTER, block: Activity.() -> Unit) {
Activity::class.java.hook(methodName, stage, { isBridgeInitialized }) { param ->
val activity = param.thisObject() as Activity
if (!activity.packageName.equals(Constants.SNAPCHAT_PACKAGE_NAME)) return@hook
block(activity)
}
}
init { init {
Hooker.hook(Application::class.java, "attach", HookStage.BEFORE) { param -> Application::class.java.hook("attach", HookStage.BEFORE) { param ->
appContext.androidContext = param.arg<Context>(0).also { appContext.apply {
classLoader = it.classLoader androidContext = param.arg<Context>(0).also {
} classLoader = it.classLoader
appContext.bridgeClient = BridgeClient(appContext) }
bridgeClient = BridgeClient(appContext)
//for lspatch builds, we need to check if the service is correctly installed bridgeClient.apply {
runCatching { connect(
appContext.androidContext.packageManager.getApplicationInfoCompat(BuildConfig.APPLICATION_ID, PackageManager.GET_META_DATA) timeout = {
}.onFailure { crash("SnapEnhance bridge service is not responding. Please download stable version from https://github.com/rhunk/SnapEnhance/releases", it)
appContext.crash("SnapEnhance bridge service is not installed. Please download stable version from https://github.com/rhunk/SnapEnhance/releases") }
return@hook ) { bridgeResult ->
} if (!bridgeResult) {
Logger.xposedLog("Cannot connect to bridge service")
appContext.bridgeClient.apply { softRestartApp()
start { bridgeResult -> return@connect
if (!bridgeResult) { }
Logger.xposedLog("Cannot connect to bridge service") runCatching {
appContext.softRestartApp() init()
return@start }.onSuccess {
} isBridgeInitialized = true
runCatching { }.onFailure {
runBlocking { Logger.xposedLog("Failed to initialize", it)
init()
} }
}.onSuccess {
isBridgeInitialized = true
}.onFailure {
Logger.xposedLog("Failed to initialize", it)
} }
} }
} }
} }
Activity::class.java.hook( "onCreate", HookStage.AFTER, { isBridgeInitialized }) { hookMainActivity("onCreate") {
useMainActivity(it) { val isMainActivityNotNull = appContext.mainActivity != null
val isMainActivityNotNull = appContext.mainActivity != null appContext.mainActivity = this
appContext.mainActivity = this if (isMainActivityNotNull || !appContext.mappings.isMappingsLoaded()) return@hookMainActivity
if (isMainActivityNotNull || !appContext.mappings.isMappingsLoaded()) return@useMainActivity onActivityCreate()
onActivityCreate()
}
} }
Activity::class.java.hook( "onPause", HookStage.AFTER, { isBridgeInitialized }) { hookMainActivity("onPause") {
useMainActivity(it) { appContext.bridgeClient.closeSettingsOverlay()
appContext.bridgeClient.closeSettingsOverlay()
}
} }
var activityWasResumed = false var activityWasResumed = false
//we need to reload the config when the app is resumed //we need to reload the config when the app is resumed
//FIXME: called twice at first launch //FIXME: called twice at first launch
Activity::class.java.hook("onResume", HookStage.AFTER, { isBridgeInitialized }) { hookMainActivity("onResume") {
useMainActivity(it) { if (!activityWasResumed) {
if (!activityWasResumed) { activityWasResumed = true
activityWasResumed = true return@hookMainActivity
return@useMainActivity
}
appContext.actionManager.onNewIntent(this.intent)
appContext.reloadConfig()
syncRemote()
} }
appContext.actionManager.onNewIntent(this.intent)
appContext.reloadConfig()
syncRemote()
} }
} }
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
private suspend fun init() { private fun init() {
measureTime { measureTime {
with(appContext) { with(appContext) {
reloadConfig() reloadConfig()
initNative() initNative()
withContext(appContext.coroutineDispatcher) { executeAsync {
translation.userLocale = getConfigLocale() translation.userLocale = getConfigLocale()
translation.loadFromBridge(bridgeClient) translation.loadFromBridge(bridgeClient)
} }
@ -162,10 +146,8 @@ class SnapEnhance {
} }
private fun syncRemote() { private fun syncRemote() {
val database = appContext.database
appContext.executeAsync { appContext.executeAsync {
appContext.bridgeClient.sync(object : SyncCallback.Stub() { bridgeClient.sync(object : SyncCallback.Stub() {
override fun syncFriend(uuid: String): String? { override fun syncFriend(uuid: String): String? {
return database.getFriendInfo(uuid)?.toJson() return database.getFriendInfo(uuid)?.toJson()
} }
@ -181,7 +163,7 @@ class SnapEnhance {
} }
}) })
appContext.event.subscribe(SnapWidgetBroadcastReceiveEvent::class) { event -> event.subscribe(SnapWidgetBroadcastReceiveEvent::class) { event ->
if (event.action != BridgeClient.BRIDGE_SYNC_ACTION) return@subscribe if (event.action != BridgeClient.BRIDGE_SYNC_ACTION) return@subscribe
event.canceled = true event.canceled = true
val feedEntries = appContext.database.getFeedEntries(Int.MAX_VALUE) val feedEntries = appContext.database.getFeedEntries(Int.MAX_VALUE)
@ -204,7 +186,7 @@ class SnapEnhance {
) )
} }
appContext.bridgeClient.passGroupsAndFriends( bridgeClient.passGroupsAndFriends(
groups.map { it.toJson() }, groups.map { it.toJson() },
friends.map { it.toJson() } friends.map { it.toJson() }
) )

View File

@ -9,7 +9,7 @@ class OpenMap: AbstractAction() {
override fun run() { override fun run() {
context.runOnUiThread { context.runOnUiThread {
val mapActivityIntent = Intent() val mapActivityIntent = Intent()
mapActivityIntent.setClassName(BuildConfig.APPLICATION_ID, "me.rhunk.snapenhance.ui.MapActivity") mapActivityIntent.setClassName(BuildConfig.APPLICATION_ID, BuildConfig.APPLICATION_ID + ".ui.MapActivity")
mapActivityIntent.putExtra("location", Bundle().apply { mapActivityIntent.putExtra("location", Bundle().apply {
putDouble("latitude", context.config.experimental.spoof.location.latitude.get().toDouble()) putDouble("latitude", context.config.experimental.spoof.location.latitude.get().toDouble())
putDouble("longitude", context.config.experimental.spoof.location.longitude.get().toDouble()) putDouble("longitude", context.config.experimental.spoof.location.longitude.get().toDouble())

View File

@ -23,6 +23,7 @@ import me.rhunk.snapenhance.core.messaging.SocialScope
import me.rhunk.snapenhance.data.LocalePair import me.rhunk.snapenhance.data.LocalePair
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -33,22 +34,21 @@ class BridgeClient(
private lateinit var service: BridgeInterface private lateinit var service: BridgeInterface
companion object { companion object {
const val BRIDGE_SYNC_ACTION = "me.rhunk.snapenhance.core.bridge.SYNC" const val BRIDGE_SYNC_ACTION = BuildConfig.APPLICATION_ID + ".core.bridge.SYNC"
} }
fun start(callback: (Boolean) -> Unit) { fun connect(timeout: (Throwable) -> Unit, onResult: (Boolean) -> Unit) {
this.future = CompletableFuture() this.future = CompletableFuture()
//TODO: randomize package name
with(context.androidContext) { with(context.androidContext) {
//ensure the remote process is running //ensure the remote process is running
startActivity(Intent() startActivity(Intent()
.setClassName(BuildConfig.APPLICATION_ID, "me.rhunk.snapenhance.bridge.ForceStartActivity") .setClassName(BuildConfig.APPLICATION_ID, BuildConfig.APPLICATION_ID + ".bridge.ForceStartActivity")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
) )
val intent = Intent() val intent = Intent()
.setClassName(BuildConfig.APPLICATION_ID, "me.rhunk.snapenhance.bridge.BridgeService") .setClassName(BuildConfig.APPLICATION_ID, BuildConfig.APPLICATION_ID + ".bridge.BridgeService")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
bindService( bindService(
intent, intent,
@ -70,7 +70,11 @@ class BridgeClient(
) )
} }
} }
callback(future.get()) runCatching {
onResult(future.get(10, TimeUnit.SECONDS))
}.onFailure {
timeout(it)
}
} }

View File

@ -19,7 +19,6 @@ class ModConfig {
var wasPresent by Delegates.notNull<Boolean>() var wasPresent by Delegates.notNull<Boolean>()
lateinit var root: RootConfig lateinit var root: RootConfig
operator fun getValue(thisRef: Any?, property: Any?) = root
private fun load() { private fun load() {
root = RootConfig() root = RootConfig()

View File

@ -1,4 +1,4 @@
package me.rhunk.snapenhance.core.eventbus package me.rhunk.snapenhance.core.event
import me.rhunk.snapenhance.ModContext import me.rhunk.snapenhance.ModContext
import kotlin.reflect.KClass import kotlin.reflect.KClass

View File

@ -1,14 +1,15 @@
package me.rhunk.snapenhance package me.rhunk.snapenhance.core.event
import android.content.Intent import android.content.Intent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams import android.view.ViewGroup.LayoutParams
import me.rhunk.snapenhance.core.eventbus.events.impl.AddViewEvent import me.rhunk.snapenhance.ModContext
import me.rhunk.snapenhance.core.eventbus.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.OnSnapInteractionEvent import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent import me.rhunk.snapenhance.core.event.events.impl.OnSnapInteractionEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.SnapWidgetBroadcastReceiveEvent import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
import me.rhunk.snapenhance.core.event.events.impl.SnapWidgetBroadcastReceiveEvent
import me.rhunk.snapenhance.core.util.ktx.getObjectField import me.rhunk.snapenhance.core.util.ktx.getObjectField
import me.rhunk.snapenhance.core.util.ktx.setObjectField import me.rhunk.snapenhance.core.util.ktx.setObjectField
import me.rhunk.snapenhance.core.util.snap.SnapWidgetBroadcastReceiverHelper import me.rhunk.snapenhance.core.util.snap.SnapWidgetBroadcastReceiverHelper

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.core.eventbus.events package me.rhunk.snapenhance.core.event.events
import me.rhunk.snapenhance.core.eventbus.Event import me.rhunk.snapenhance.core.event.Event
import me.rhunk.snapenhance.hook.HookAdapter import me.rhunk.snapenhance.hook.HookAdapter
abstract class AbstractHookEvent : Event() { abstract class AbstractHookEvent : Event() {

View File

@ -1,8 +1,8 @@
package me.rhunk.snapenhance.core.eventbus.events.impl package me.rhunk.snapenhance.core.event.events.impl
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
class AddViewEvent( class AddViewEvent(
val parent: ViewGroup, val parent: ViewGroup,

View File

@ -0,0 +1,9 @@
package me.rhunk.snapenhance.core.event.events.impl
import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
class NetworkApiRequestEvent(
val request: Any,
val callback: Any,
var url: String,
) : AbstractHookEvent()

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.core.eventbus.events.impl package me.rhunk.snapenhance.core.event.events.impl
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
class OnSnapInteractionEvent( class OnSnapInteractionEvent(

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.core.eventbus.events.impl package me.rhunk.snapenhance.core.event.events.impl
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
import me.rhunk.snapenhance.data.wrapper.impl.MessageContent import me.rhunk.snapenhance.data.wrapper.impl.MessageContent
import me.rhunk.snapenhance.data.wrapper.impl.MessageDestinations import me.rhunk.snapenhance.data.wrapper.impl.MessageDestinations
import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.HookStage

View File

@ -1,8 +1,8 @@
package me.rhunk.snapenhance.core.eventbus.events.impl package me.rhunk.snapenhance.core.event.events.impl
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
class SnapWidgetBroadcastReceiveEvent( class SnapWidgetBroadcastReceiveEvent(
val androidContext: Context, val androidContext: Context,

View File

@ -0,0 +1,8 @@
package me.rhunk.snapenhance.core.event.events.impl
import me.rhunk.snapenhance.core.event.events.AbstractHookEvent
class UnaryCallEvent(
val uri: String,
var buffer: ByteArray
) : AbstractHookEvent()

View File

@ -1,9 +0,0 @@
package me.rhunk.snapenhance.core.eventbus.events.impl
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent
class NetworkApiRequestEvent(
val request: Any,
val callback: Any,
var url: String,
) : AbstractHookEvent()

View File

@ -1,8 +0,0 @@
package me.rhunk.snapenhance.core.eventbus.events.impl
import me.rhunk.snapenhance.core.eventbus.events.AbstractHookEvent
class UnaryCallEvent(
val uri: String,
var buffer: ByteArray
) : AbstractHookEvent()

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.features.impl package me.rhunk.snapenhance.features.impl
import me.rhunk.snapenhance.core.eventbus.events.impl.OnSnapInteractionEvent import me.rhunk.snapenhance.core.event.events.impl.OnSnapInteractionEvent
import me.rhunk.snapenhance.core.util.ktx.getObjectField import me.rhunk.snapenhance.core.util.ktx.getObjectField
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature

View File

@ -1,7 +1,7 @@
package me.rhunk.snapenhance.features.impl package me.rhunk.snapenhance.features.impl
import kotlinx.coroutines.* import kotlinx.coroutines.*
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
import me.rhunk.snapenhance.core.messaging.SocialScope import me.rhunk.snapenhance.core.messaging.SocialScope
import me.rhunk.snapenhance.data.ContentType import me.rhunk.snapenhance.data.ContentType
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature

View File

@ -470,11 +470,11 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
if (!canAutoDownload()) return@onOperaViewStateCallback if (!canAutoDownload()) return@onOperaViewStateCallback
context.executeAsync { context.executeAsync {
try { runCatching {
handleOperaMedia(mediaParamMap, mediaInfoMap, false) handleOperaMedia(mediaParamMap, mediaInfoMap, false)
} catch (e: Throwable) { }.onFailure {
context.log.error("Failed to handle opera media", e) context.log.error("Failed to handle opera media", it)
context.longToast(e.message) context.longToast(it.message)
} }
} }
} }

View File

@ -3,8 +3,8 @@ package me.rhunk.snapenhance.features.impl.downloader
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.widget.Button import android.widget.Button
import android.widget.RelativeLayout import android.widget.RelativeLayout
import me.rhunk.snapenhance.core.eventbus.events.impl.AddViewEvent import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
import me.rhunk.snapenhance.core.util.protobuf.ProtoReader import me.rhunk.snapenhance.core.util.protobuf.ProtoReader
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.features.impl.privacy package me.rhunk.snapenhance.features.impl.privacy
import me.rhunk.snapenhance.core.eventbus.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.HookStage

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.features.impl.privacy package me.rhunk.snapenhance.features.impl.privacy
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
import me.rhunk.snapenhance.data.NotificationType import me.rhunk.snapenhance.data.NotificationType
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams

View File

@ -1,7 +1,7 @@
package me.rhunk.snapenhance.features.impl.spying package me.rhunk.snapenhance.features.impl.spying
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import me.rhunk.snapenhance.core.eventbus.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
import me.rhunk.snapenhance.core.util.download.HttpServer import me.rhunk.snapenhance.core.util.download.HttpServer
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.features.impl.spying package me.rhunk.snapenhance.features.impl.spying
import me.rhunk.snapenhance.core.eventbus.events.impl.OnSnapInteractionEvent import me.rhunk.snapenhance.core.event.events.impl.OnSnapInteractionEvent
import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID import me.rhunk.snapenhance.data.wrapper.impl.SnapUUID
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams

View File

@ -3,7 +3,7 @@ package me.rhunk.snapenhance.features.impl.tweaks
import android.os.Build import android.os.Build
import android.os.FileObserver import android.os.FileObserver
import com.google.gson.JsonParser import com.google.gson.JsonParser
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.HookStage

View File

@ -14,7 +14,7 @@ import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
import me.rhunk.snapenhance.core.Logger import me.rhunk.snapenhance.core.Logger
import me.rhunk.snapenhance.core.download.data.SplitMediaAssetType import me.rhunk.snapenhance.core.download.data.SplitMediaAssetType
import me.rhunk.snapenhance.core.eventbus.events.impl.SnapWidgetBroadcastReceiveEvent import me.rhunk.snapenhance.core.event.events.impl.SnapWidgetBroadcastReceiveEvent
import me.rhunk.snapenhance.core.util.CallbackBuilder import me.rhunk.snapenhance.core.util.CallbackBuilder
import me.rhunk.snapenhance.core.util.download.RemoteMediaResolver import me.rhunk.snapenhance.core.util.download.RemoteMediaResolver
import me.rhunk.snapenhance.core.util.ktx.setObjectField import me.rhunk.snapenhance.core.util.ktx.setObjectField

View File

@ -1,6 +1,6 @@
package me.rhunk.snapenhance.features.impl.tweaks package me.rhunk.snapenhance.features.impl.tweaks
import me.rhunk.snapenhance.core.eventbus.events.impl.NetworkApiRequestEvent import me.rhunk.snapenhance.core.event.events.impl.NetworkApiRequestEvent
import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie import me.rhunk.snapenhance.core.util.snap.BitmojiSelfie
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams

View File

@ -1,8 +1,8 @@
package me.rhunk.snapenhance.features.impl.tweaks package me.rhunk.snapenhance.features.impl.tweaks
import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.core.eventbus.events.impl.SendMessageWithContentEvent import me.rhunk.snapenhance.core.event.events.impl.SendMessageWithContentEvent
import me.rhunk.snapenhance.core.eventbus.events.impl.UnaryCallEvent import me.rhunk.snapenhance.core.event.events.impl.UnaryCallEvent
import me.rhunk.snapenhance.core.util.protobuf.ProtoEditor import me.rhunk.snapenhance.core.util.protobuf.ProtoEditor
import me.rhunk.snapenhance.core.util.protobuf.ProtoReader import me.rhunk.snapenhance.core.util.protobuf.ProtoReader
import me.rhunk.snapenhance.data.ContentType import me.rhunk.snapenhance.data.ContentType

View File

@ -8,7 +8,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.core.eventbus.events.impl.AddViewEvent import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.hook.HookStage import me.rhunk.snapenhance.hook.HookStage

View File

@ -9,7 +9,6 @@ import android.view.ViewGroup.MarginLayoutParams
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.Constants.VIEW_INJECTED_CODE
import me.rhunk.snapenhance.features.impl.Messaging import me.rhunk.snapenhance.features.impl.Messaging
import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader import me.rhunk.snapenhance.features.impl.downloader.MediaDownloader
import me.rhunk.snapenhance.features.impl.spying.MessageLogger import me.rhunk.snapenhance.features.impl.spying.MessageLogger
@ -18,9 +17,11 @@ import me.rhunk.snapenhance.ui.menu.AbstractMenu
class ChatActionMenu : AbstractMenu() { class ChatActionMenu : AbstractMenu() {
private val viewInjectedTag = 0x7FFFFF02
private fun wasInjectedView(view: View): Boolean { private fun wasInjectedView(view: View): Boolean {
if (view.getTag(VIEW_INJECTED_CODE) != null) return true if (view.getTag(viewInjectedTag) != null) return true
view.setTag(VIEW_INJECTED_CODE, true) view.setTag(viewInjectedTag, true)
return false return false
} }
@ -108,7 +109,7 @@ class ChatActionMenu : AbstractMenu() {
text = this@ChatActionMenu.context.translation["chat_action_menu.preview_button"] text = this@ChatActionMenu.context.translation["chat_action_menu.preview_button"]
setOnClickListener { setOnClickListener {
closeActionMenu() closeActionMenu()
this@ChatActionMenu.context.executeAsync { this@ChatActionMenu.context.feature(MediaDownloader::class).onMessageActionMenu(true) } this@ChatActionMenu.context.executeAsync { feature(MediaDownloader::class).onMessageActionMenu(true) }
} }
}) })
@ -117,9 +118,7 @@ class ChatActionMenu : AbstractMenu() {
setOnClickListener { setOnClickListener {
closeActionMenu() closeActionMenu()
this@ChatActionMenu.context.executeAsync { this@ChatActionMenu.context.executeAsync {
this@ChatActionMenu.context.feature( feature(MediaDownloader::class).onMessageActionMenu(false)
MediaDownloader::class
).onMessageActionMenu(false)
} }
} }
}) })
@ -132,8 +131,8 @@ class ChatActionMenu : AbstractMenu() {
setOnClickListener { setOnClickListener {
closeActionMenu() closeActionMenu()
this@ChatActionMenu.context.executeAsync { this@ChatActionMenu.context.executeAsync {
with(this@ChatActionMenu.context.feature(Messaging::class)) { feature(Messaging::class).apply {
context.feature(MessageLogger::class).deleteMessage(openedConversationUUID.toString(), lastFocusedMessageId) feature(MessageLogger::class).deleteMessage(openedConversationUUID.toString(), lastFocusedMessageId)
} }
} }
} }

View File

@ -164,9 +164,7 @@ class FriendFeedInfoMenu : AbstractMenu() {
) { dialog: DialogInterface, _: Int -> dialog.dismiss() } ) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
targetPerson?.let { targetPerson?.let {
builder.setNegativeButton(context.translation["modal_option.profile_info"]) { _, _ -> builder.setNegativeButton(context.translation["modal_option.profile_info"]) { _, _ ->
context.executeAsync { context.executeAsync { showProfileInfo(it) }
showProfileInfo(it)
}
} }
} }
builder.show() builder.show()

View File

@ -7,7 +7,7 @@ import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.LinearLayout import android.widget.LinearLayout
import me.rhunk.snapenhance.Constants import me.rhunk.snapenhance.Constants
import me.rhunk.snapenhance.core.eventbus.events.impl.AddViewEvent import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
import me.rhunk.snapenhance.features.Feature import me.rhunk.snapenhance.features.Feature
import me.rhunk.snapenhance.features.FeatureLoadParams import me.rhunk.snapenhance.features.FeatureLoadParams
import me.rhunk.snapenhance.features.impl.Messaging import me.rhunk.snapenhance.features.impl.Messaging