diff --git a/app/src/main/kotlin/ShiggyXposed/xposed/xposed/Module.kt b/app/src/main/kotlin/ShiggyXposed/xposed/xposed/Module.kt index 41f878f..fb4fcc8 100644 --- a/app/src/main/kotlin/ShiggyXposed/xposed/xposed/Module.kt +++ b/app/src/main/kotlin/ShiggyXposed/xposed/xposed/Module.kt @@ -2,182 +2,75 @@ package GoonXposed.xposed import android.app.Activity import android.content.Context -import android.os.Build -import de.robv.android.xposed.IXposedHookZygoteInit -import de.robv.android.xposed.XC_MethodHook +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.callbacks.XC_LoadPackage -import kotlinx.serialization.json.JsonObjectBuilder -import java.io.File -import java.lang.reflect.Method +import GoonXposed.xposed.modules.appearance.FontsModule -data class AppInfo( - val name: String, - val packageName: String, - val version: String, - val versionCode: Long, -) +class MainModule : IXposedHookLoadPackage { + private var lastShakeTime: Long = 0 + private val SHAKE_THRESHOLD = 15f + private val SHAKE_INTERVAL_MS = 500L -abstract class Module { - /** - * Builds a JSON payload to be injected into the JavaScript context. - */ - @Deprecated("This will be removed in future versions. Payloads can be replaced via synchronous bridge methods.") - open fun buildPayload(builder: JsonObjectBuilder) { - } + override fun handleLoadPackage(lparam: XC_LoadPackage.LoadPackageParam) { + // Load the fonts module + FontsModule.onLoad(lparam) + + XposedBridge.log("GoonXposed: FontsModule loaded for ${lparam.packageName}") - /** - * Called during Zygote initialization. - */ - open fun onInit(startupParam: IXposedHookZygoteInit.StartupParam) {} - - /** - * Called when a package is loaded. - * - * Hooks should typically be set up here. - * - * Bridge methods that do not require [Context] can also be registered here. - */ - open fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) {} - - /** - * Called after [Context] has been attached to a [android.content.ContextWrapper] - * via [android.content.ContextWrapper.attachBaseContext]. - * - * This may be called multiple times for different [Context]s, e.g. when the app is killed by the system. - * - * For bridge methods that require access to [Context], register them here. - */ - open fun onContext(context: Context) {} - - /** - * Called after an [Activity.onCreate] method is executed. - * - * UI code that requires an [Activity] context can be placed here. - * - * Bridge methods must not be registered here, as it can be too late and cause crashes. - * - * If you need to register bridge methods that require an [Activity], do it in [onContext] and make it async. - * - * Once an [Activity] is available, execute the queued calls. Then from JS, call the method asynchronously. - */ - open fun onActivity(activity: Activity) {} - - protected fun Context.getAppInfo(): AppInfo { - val pInfo = packageManager.getPackageInfo(packageName, 0) - val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) pInfo.longVersionCode - else @Suppress("DEPRECATION") pInfo.versionCode.toLong() - - return AppInfo( - packageManager.getApplicationLabel(applicationInfo).toString(), - packageName, - pInfo.versionName ?: versionCode.toString(), - versionCode, - ) - } - - protected fun File.asDir() { - if (!this.isDirectory) this.delete() - this.mkdirs() - } - - protected fun File.asFile() { - if (!this.isFile) this.deleteRecursively() - } - - protected fun Class<*>.method( - name: String, vararg params: Class<*>? - ): Method = getDeclaredMethod(name, *params).apply { - isAccessible = true - } - - protected fun ClassLoader.safeLoadClass(name: String): Class<*>? = runCatching { loadClass(name) }.getOrNull() - - protected fun Method.hook(hook: XC_MethodHook): XC_MethodHook.Unhook = XposedBridge.hookMethod(this, hook) - - protected fun Method.hook(block: MethodHookBuilder.() -> Unit): XC_MethodHook.Unhook = - hook(MethodHookBuilder().apply(block).build()) - - protected fun Class<*>.hookMethod( - name: String, vararg params: Class<*>?, block: MethodHookBuilder.() -> Unit - ): XC_MethodHook.Unhook = method(name, *params).hook(MethodHookBuilder().apply(block).build()) - - protected class MethodHookBuilder { - private var beforeBlock: (HookScope.() -> Unit)? = null - private var afterBlock: (HookScope.() -> Unit)? = null - - fun before(block: HookScope.() -> Unit) { - beforeBlock = block - } - - fun after(block: HookScope.() -> Unit) { - afterBlock = block - } - - fun build(): XC_MethodHook = object : XC_MethodHook() { - override fun beforeHookedMethod(param: MethodHookParam) { - val b = beforeBlock - if (b != null) { - val scope = HookScope( - param = param, proceed = { p -> - super.beforeHookedMethod(p) - }) - scope.b() - } else { - super.beforeHookedMethod(param) + // Hook into the main activity to detect shakes + try { + val activityClass = Class.forName("android.app.Activity") + val method = activityClass.getDeclaredMethod("onCreate", Bundle::class.java) + + XposedBridge.hookMethod(method, object : XC_MethodHook() { + override fun afterHookedMethod(param: MethodHookParam) { + val activity = param.thisObject as Activity + setupShakeDetection(activity) } - } - - override fun afterHookedMethod(param: MethodHookParam) { - val a = afterBlock - if (a != null) { - val scope = HookScope( - param = param, proceed = { p -> - super.afterHookedMethod(p) - }) - scope.a() - } else { - super.afterHookedMethod(param) - } - } + }) + } catch (e: Throwable) { + XposedBridge.log("GoonXposed: Failed to hook activity: ${e.message}") } } - /** - * Scope object passed to before/after hook blocks. - * - * Provides: - * - Access to the [param] object - * - [proceed] to call the original XC_MethodHook super method - * - Accessors for `thisObject`, `args`, `result`, and `throwable` - * - * @property param The [XC_MethodHook.MethodHookParam] for the current hook. - * @property proceed Function that calls the super method. - */ - protected class HookScope internal constructor( - val param: XC_MethodHook.MethodHookParam, private val proceed: (XC_MethodHook.MethodHookParam) -> Unit - ) { - /** - * Continues with the default XC_MethodHook super behavior. - * Equivalent to calling `super.beforeHookedMethod(param)` or - * `super.afterHookedMethod(param)` depending on the phase. - */ - fun proceed() = proceed(param) + private fun setupShakeDetection(activity: Activity) { + try { + val sensorManager = activity.getSystemService(Context.SENSOR_SERVICE) as SensorManager + val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) - val thisObject: Any? get() = param.thisObject + if (accelerometer != null) { + sensorManager.registerListener(object : SensorEventListener { + override fun onSensorChanged(event: SensorEvent) { + val x = event.values[0] + val y = event.values[1] + val z = event.values[2] - val args: Array get() = param.args + val acceleration = Math.sqrt((x * x + y * y + z * z).toDouble()).toFloat() + val currentTime = System.currentTimeMillis() - var result: Any? - get() = param.result - set(value) { - param.result = value + if (acceleration > SHAKE_THRESHOLD && + currentTime - lastShakeTime > SHAKE_INTERVAL_MS) { + lastShakeTime = currentTime + onShakeDetected(activity) + } + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} + }, accelerometer, SensorManager.SENSOR_DELAY_UI) } + } catch (e: Throwable) { + XposedBridge.log("GoonXposed: Failed to setup shake detection: ${e.message}") + } + } - var throwable: Throwable? - get() = param.throwable - set(value) { - param.throwable = value - } + private fun onShakeDetected(activity: Activity) { + XposedBridge.log("GoonXposed: Shake detected!") + // You can show a toast or dialog here + // Or launch your UI } }