refactor: location spoofer

This commit is contained in:
rhunk 2023-10-11 16:53:53 +02:00
parent 1a7755e45c
commit 32a458a690
15 changed files with 238 additions and 257 deletions

View File

@ -52,10 +52,6 @@
android:exported="true" android:exported="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:excludeFromRecents="true" /> android:excludeFromRecents="true" />
<activity
android:name=".ui.MapActivity"
android:exported="true"
android:excludeFromRecents="true" />
<activity android:name=".bridge.ForceStartActivity" <activity android:name=".bridge.ForceStartActivity"
android:theme="@android:style/Theme.NoDisplay" android:theme="@android:style/Theme.NoDisplay"
android:excludeFromRecents="true" android:excludeFromRecents="true"

View File

@ -1,98 +0,0 @@
package me.rhunk.snapenhance.ui
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.os.Bundle
import android.view.MotionEvent
import android.widget.Button
import android.widget.EditText
import me.rhunk.snapenhance.R
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.views.Projection
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Overlay
class MapActivity : Activity() {
private lateinit var mapView: MapView
@SuppressLint("MissingInflatedId", "ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val contextBundle = intent.extras?.getBundle("location") ?: return
val locationLatitude = contextBundle.getDouble("latitude")
val locationLongitude = contextBundle.getDouble("longitude")
Configuration.getInstance().load(applicationContext, getSharedPreferences("osmdroid", Context.MODE_PRIVATE))
setContentView(R.layout.map)
mapView = findViewById(R.id.mapView)
mapView.setMultiTouchControls(true);
mapView.setTileSource(TileSourceFactory.MAPNIK)
val startPoint = GeoPoint(locationLatitude, locationLongitude)
mapView.controller.setZoom(10.0)
mapView.controller.setCenter(startPoint)
val marker = Marker(mapView)
marker.isDraggable = true
marker.position = startPoint
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
mapView.overlays.add(object: Overlay() {
override fun onSingleTapConfirmed(e: MotionEvent?, mapView: MapView?): Boolean {
val proj: Projection = mapView!!.projection
val loc = proj.fromPixels(e!!.x.toInt(), e.y.toInt()) as GeoPoint
marker.position = loc
mapView.invalidate()
return true
}
})
mapView.overlays.add(marker)
val applyButton = findViewById<Button>(R.id.apply_location_button)
applyButton.setOnClickListener {
val bundle = Bundle()
bundle.putFloat("latitude", marker.position.latitude.toFloat())
bundle.putFloat("longitude", marker.position.longitude.toFloat())
setResult(RESULT_OK, intent.putExtra("location", bundle))
finish()
}
val setPreciseLocationButton = findViewById<Button>(R.id.set_precise_location_button)
setPreciseLocationButton.setOnClickListener {
val locationDialog = layoutInflater.inflate(R.layout.precise_location_dialog, null)
val dialogLatitude = locationDialog.findViewById<EditText>(R.id.dialog_latitude).also { it.setText(marker.position.latitude.toString()) }
val dialogLongitude = locationDialog.findViewById<EditText>(R.id.dialog_longitude).also { it.setText(marker.position.longitude.toString()) }
AlertDialog.Builder(this)
.setView(locationDialog)
.setTitle("Set a precise location")
.setPositiveButton("Set") { _, _ ->
val latitude = dialogLatitude.text.toString().toDoubleOrNull()
val longitude = dialogLongitude.text.toString().toDoubleOrNull()
if (latitude != null && longitude != null) {
val preciseLocation = GeoPoint(latitude, longitude)
mapView.controller.setCenter(preciseLocation)
marker.position = preciseLocation
mapView.invalidate()
}
}.setNegativeButton("Cancel") { _, _ -> }.show()
}
}
override fun onDestroy() {
super.onDestroy()
mapView.onDetach()
}
}

View File

@ -149,7 +149,10 @@ class FeaturesSection : Section() {
if (showDialog) { if (showDialog) {
Dialog( Dialog(
onDismissRequest = { showDialog = false } properties = DialogProperties(
usePlatformDefaultWidth = false
),
onDismissRequest = { showDialog = false },
) { ) {
dialogComposable() dialogComposable()
} }
@ -182,6 +185,24 @@ class FeaturesSection : Section() {
) )
} }
DataProcessors.Type.MAP_COORDINATES -> {
registerDialogOnClickCallback()
dialogComposable = {
alertDialogs.ChooseLocationDialog(property) {
showDialog = false
}
}
Text(
overflow = TextOverflow.Ellipsis,
maxLines = 1,
modifier = Modifier.widthIn(0.dp, 120.dp),
text = (propertyValue.get() as Pair<*, *>).let {
"${it.first.toString().toFloatOrNull() ?: 0F}, ${it.second.toString().toFloatOrNull() ?: 0F}"
}
)
}
DataProcessors.Type.STRING_UNIQUE_SELECTION -> { DataProcessors.Type.STRING_UNIQUE_SELECTION -> {
registerDialogOnClickCallback() registerDialogOnClickCallback()

View File

@ -1,41 +1,52 @@
package me.rhunk.snapenhance.ui.util package me.rhunk.snapenhance.ui.util
import android.content.Context
import android.view.MotionEvent
import androidx.compose.foundation.ScrollState import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper import me.rhunk.snapenhance.common.bridge.wrapper.LocaleWrapper
import me.rhunk.snapenhance.common.config.DataProcessors import me.rhunk.snapenhance.common.config.DataProcessors
import me.rhunk.snapenhance.common.config.PropertyPair import me.rhunk.snapenhance.common.config.PropertyPair
import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Overlay
class AlertDialogs( class AlertDialogs(
private val translation: LocaleWrapper, private val translation: LocaleWrapper,
){ ){
@Composable @Composable
fun DefaultDialogCard(content: @Composable ColumnScope.() -> Unit) { fun DefaultDialogCard(modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) {
Card( Card(
shape = MaterialTheme.shapes.medium, shape = MaterialTheme.shapes.medium,
modifier = Modifier modifier = Modifier
.padding(10.dp, 5.dp, 10.dp, 10.dp), .padding(10.dp, 5.dp, 10.dp, 10.dp)
.then(modifier),
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@ -195,7 +206,9 @@ class AlertDialogs(
) )
Row( Row(
modifier = Modifier.padding(top = 10.dp).fillMaxWidth(), modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly, horizontalArrangement = Arrangement.SpaceEvenly,
) { ) {
Button(onClick = { dismiss() }) { Button(onClick = { dismiss() }) {
@ -252,7 +265,9 @@ class AlertDialogs(
) )
Row( Row(
modifier = Modifier.padding(top = 10.dp).fillMaxWidth(), modifier = Modifier
.padding(top = 10.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly, horizontalArrangement = Arrangement.SpaceEvenly,
) { ) {
Button(onClick = { onDismiss() }) { Button(onClick = { onDismiss() }) {
@ -305,4 +320,145 @@ class AlertDialogs(
} }
} }
} }
@Composable
fun ChooseLocationDialog(property: PropertyPair<*>, dismiss: () -> Unit = {}) {
val coordinates = remember {
(property.value.get() as Pair<*, *>).let {
it.first.toString().toDouble() to it.second.toString().toDouble()
}
}
val context = LocalContext.current
LaunchedEffect(Unit) {
Configuration.getInstance().load(context, context.getSharedPreferences("osmdroid", Context.MODE_PRIVATE))
}
var marker by remember { mutableStateOf<Marker?>(null) }
val mapView = remember {
MapView(context).apply {
setMultiTouchControls(true)
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
setTileSource(TileSourceFactory.MAPNIK)
val startPoint = GeoPoint(coordinates.first, coordinates.second)
controller.setZoom(10.0)
controller.setCenter(startPoint)
marker = Marker(this).apply {
isDraggable = true
position = startPoint
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
}
overlays.add(object: Overlay() {
override fun onSingleTapConfirmed(e: MotionEvent, mapView: MapView): Boolean {
marker?.position = mapView.projection.fromPixels(e.x.toInt(), e.y.toInt()) as GeoPoint
mapView.invalidate()
return true
}
})
overlays.add(marker)
}
}
DisposableEffect(Unit) {
onDispose {
mapView.onDetach()
}
}
var customCoordinatesDialog by remember { mutableStateOf(false) }
Box(
modifier = Modifier.fillMaxWidth().fillMaxHeight(fraction = 0.9f),
) {
AndroidView(
factory = { mapView }
)
Row(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(10.dp),
horizontalArrangement = Arrangement.spacedBy(10.dp),
) {
FilledIconButton(
onClick = {
val lat = marker?.position?.latitude ?: coordinates.first
val lon = marker?.position?.longitude ?: coordinates.second
property.value.setAny(lat to lon)
dismiss()
}) {
Icon(
modifier = Modifier
.size(60.dp)
.padding(5.dp),
imageVector = Icons.Filled.Check,
contentDescription = null
)
}
FilledIconButton(
onClick = {
customCoordinatesDialog = true
}) {
Icon(
modifier = Modifier
.size(60.dp)
.padding(5.dp),
imageVector = Icons.Filled.Edit,
contentDescription = null
)
}
}
if (customCoordinatesDialog) {
val lat = remember { mutableStateOf(coordinates.first.toString()) }
val lon = remember { mutableStateOf(coordinates.second.toString()) }
DefaultDialogCard(
modifier = Modifier.align(Alignment.Center)
) {
TextField(
modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp),
value = lat.value,
onValueChange = { lat.value = it },
label = { Text(text = "Latitude") },
singleLine = true
)
TextField(
modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp),
value = lon.value,
onValueChange = { lon.value = it },
label = { Text(text = "Longitude") },
singleLine = true
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
) {
Button(onClick = {
customCoordinatesDialog = false
}) {
Text(text = translation["button.cancel"])
}
Button(onClick = {
marker?.position = GeoPoint(lat.value.toDouble(), lon.value.toDouble())
mapView.controller.setCenter(marker?.position)
mapView.invalidate()
customCoordinatesDialog = false
}) {
Text(text = translation["button.ok"])
}
}
}
}
}
}
} }

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.osmdroid.views.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</org.osmdroid.views.MapView>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/set_precise_location_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:padding="10dp"
android:background="@android:color/white"
android:text="Set Precise Location"
android:textSize="20sp"
tools:ignore="HardcodedText,RtlHardcoded" />
<Button
android:id="@+id/apply_location_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/white"
android:text="Apply"
android:textSize="20sp"
tools:ignore="HardcodedText,RtlHardcoded" />
</FrameLayout>
</FrameLayout>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
android:orientation="vertical"
tools:ignore="HardcodedText">
<EditText
android:id="@+id/dialog_latitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:ems="10"
android:hint="Latitude"
android:inputType="number|numberDecimal|numberSigned" />
<EditText
android:id="@+id/dialog_longitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:ems="10"
android:hint="Longitude"
android:inputType="number|numberDecimal|numberSigned" />
</LinearLayout>

View File

@ -356,6 +356,16 @@
"name": "Global", "name": "Global",
"description": "Tweak Global Snapchat Settings", "description": "Tweak Global Snapchat Settings",
"properties": { "properties": {
"spoofLocation": {
"name": "Location",
"description": "Spoof your location",
"properties": {
"coordinates": {
"name": "Coordinates",
"description": "Set the coordinates"
}
}
},
"snapchat_plus": { "snapchat_plus": {
"name": "Snapchat Plus", "name": "Snapchat Plus",
"description": "Enables Snapchat Plus features\nSome Server-sided features may not work" "description": "Enables Snapchat Plus features\nSome Server-sided features may not work"
@ -464,20 +474,6 @@
"name": "Spoof", "name": "Spoof",
"description": "Spoof various information about you", "description": "Spoof various information about you",
"properties": { "properties": {
"location": {
"name": "Location",
"description": "Spoof your location",
"properties": {
"location_latitude": {
"name": "Latitude",
"description": "The latitude of the location"
},
"location_longitude": {
"name": "Longitude",
"description": "The longitude of the location"
}
}
},
"device": { "device": {
"name": "Device", "name": "Device",
"description": "Spoof your device information", "description": "Spoof your device information",

View File

@ -8,8 +8,7 @@ enum class EnumAction(
val isCritical: Boolean = false, val isCritical: Boolean = false,
) { ) {
CLEAN_CACHE("clean_snapchat_cache", exitOnFinish = true), CLEAN_CACHE("clean_snapchat_cache", exitOnFinish = true),
EXPORT_CHAT_MESSAGES("export_chat_messages"), EXPORT_CHAT_MESSAGES("export_chat_messages");
OPEN_MAP("open_map");
companion object { companion object {
const val ACTION_PARAMETER = "se_action" const val ACTION_PARAMETER = "se_action"

View File

@ -60,6 +60,12 @@ open class ConfigContainer(
container.parentContainerKey = it container.parentContainerKey = it
}.get() }.get()
protected fun mapCoordinates(
key: String,
defaultValue: Pair<Double, Double> = 0.0 to 0.0,
params: ConfigParamsBuilder = {}
) = registerProperty(key, DataProcessors.MAP_COORDINATES, PropertyValue(defaultValue), params)
fun toJson(): JsonObject { fun toJson(): JsonObject {
val json = JsonObject() val json = JsonObject()
properties.forEach { (propertyKey, propertyValue) -> properties.forEach { (propertyKey, propertyValue) ->

View File

@ -14,6 +14,7 @@ object DataProcessors {
FLOAT, FLOAT,
STRING_MULTIPLE_SELECTION, STRING_MULTIPLE_SELECTION,
STRING_UNIQUE_SELECTION, STRING_UNIQUE_SELECTION,
MAP_COORDINATES,
CONTAINER, CONTAINER,
} }
@ -75,6 +76,20 @@ object DataProcessors {
deserialize = { obj -> obj.takeIf { !it.isJsonNull }?.asString } deserialize = { obj -> obj.takeIf { !it.isJsonNull }?.asString }
) )
val MAP_COORDINATES = PropertyDataProcessor(
type = Type.MAP_COORDINATES,
serialize = {
JsonObject().apply {
addProperty("lat", it.first)
addProperty("lng", it.second)
}
},
deserialize = { obj ->
val jsonObject = obj.asJsonObject
jsonObject["lat"].asDouble to jsonObject["lng"].asDouble
},
)
fun <T : ConfigContainer> container(container: T) = PropertyDataProcessor( fun <T : ConfigContainer> container(container: T) = PropertyDataProcessor(
type = Type.CONTAINER, type = Type.CONTAINER,
serialize = { serialize = {

View File

@ -4,6 +4,10 @@ import me.rhunk.snapenhance.common.config.ConfigContainer
import me.rhunk.snapenhance.common.config.FeatureNotice import me.rhunk.snapenhance.common.config.FeatureNotice
class Global : ConfigContainer() { class Global : ConfigContainer() {
inner class SpoofLocation : ConfigContainer(hasGlobalState = true) {
val coordinates = mapCoordinates("coordinates", 0.0 to 0.0) { requireRestart()} // lat, long
}
val spoofLocation = container("spoofLocation", SpoofLocation())
val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.BAN_RISK); requireRestart() } val snapchatPlus = boolean("snapchat_plus") { addNotices(FeatureNotice.BAN_RISK); requireRestart() }
val disableMetrics = boolean("disable_metrics") val disableMetrics = boolean("disable_metrics")
val blockAds = boolean("block_ads") val blockAds = boolean("block_ads")

View File

@ -4,12 +4,6 @@ import me.rhunk.snapenhance.common.config.ConfigContainer
import me.rhunk.snapenhance.common.config.FeatureNotice import me.rhunk.snapenhance.common.config.FeatureNotice
class Spoof : ConfigContainer() { class Spoof : ConfigContainer() {
inner class Location : ConfigContainer(hasGlobalState = true) {
val latitude = float("location_latitude")
val longitude = float("location_longitude")
}
val location = container("location", Location())
inner class Device : ConfigContainer(hasGlobalState = true) { inner class Device : ConfigContainer(hasGlobalState = true) {
val fingerprint = string("fingerprint") val fingerprint = string("fingerprint")
val androidId = string("android_id") val androidId = string("android_id")

View File

@ -1,21 +0,0 @@
package me.rhunk.snapenhance.core.action.impl
import android.content.Intent
import android.os.Bundle
import me.rhunk.snapenhance.common.BuildConfig
import me.rhunk.snapenhance.core.action.AbstractAction
class OpenMap: AbstractAction() {
override fun run() {
context.runOnUiThread {
val mapActivityIntent = Intent()
mapActivityIntent.setClassName(BuildConfig.APPLICATION_ID, BuildConfig.APPLICATION_ID + ".ui.MapActivity")
mapActivityIntent.putExtra("location", Bundle().apply {
putDouble("latitude", context.config.experimental.spoof.location.latitude.get().toDouble())
putDouble("longitude", context.config.experimental.spoof.location.longitude.get().toDouble())
})
context.mainActivity!!.startActivityForResult(mapActivityIntent, 0x1337)
}
}
}

View File

@ -1,41 +1,28 @@
package me.rhunk.snapenhance.core.features.impl.global package me.rhunk.snapenhance.core.features.impl.global
import android.content.Intent import android.location.Location
import android.location.LocationManager
import me.rhunk.snapenhance.core.features.Feature import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.features.FeatureLoadParams import me.rhunk.snapenhance.core.features.FeatureLoadParams
import me.rhunk.snapenhance.core.util.hook.HookStage import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.Hooker
import me.rhunk.snapenhance.core.util.hook.hook import me.rhunk.snapenhance.core.util.hook.hook
class LocationSpoofer: Feature("LocationSpoof", loadParams = FeatureLoadParams.ACTIVITY_CREATE_ASYNC) { class LocationSpoofer: Feature("LocationSpoof", loadParams = FeatureLoadParams.ACTIVITY_CREATE_SYNC) {
override fun asyncOnActivityCreate() { override fun onActivityCreate() {
Hooker.hook(context.mainActivity!!.javaClass, "onActivityResult", HookStage.BEFORE) { param -> if (context.config.global.spoofLocation.globalState != true) return
val intent = param.argNullable<Intent>(2) ?: return@hook
val bundle = intent.getBundleExtra("location") ?: return@hook
param.setResult(null)
with(context.config.experimental.spoof.location) { val coordinates by context.config.global.spoofLocation.coordinates
latitude.set(bundle.getFloat("latitude"))
longitude.set(bundle.getFloat("longitude"))
context.longToast("Location set to $latitude, $longitude") Location::class.java.apply {
} hook("getLatitude", HookStage.BEFORE) { it.setResult(coordinates.first) }
hook("getLongitude", HookStage.BEFORE) { it.setResult(coordinates.second) }
hook("getAccuracy", HookStage.BEFORE) { it.setResult(0.0F) }
} }
if (context.config.experimental.spoof.location.globalState != true) return LocationManager::class.java.apply {
//Might be redundant because it calls isProviderEnabledForUser which we also hook, meaning if isProviderEnabledForUser returns true this will also return true
val latitude by context.config.experimental.spoof.location.latitude hook("isProviderEnabled", HookStage.BEFORE) { it.setResult(true) }
val longitude by context.config.experimental.spoof.location.longitude hook("isProviderEnabledForUser", HookStage.BEFORE) { it.setResult(true) }
}
val locationClass = android.location.Location::class.java
val locationManagerClass = android.location.LocationManager::class.java
locationClass.hook("getLatitude", HookStage.BEFORE) { it.setResult(latitude.toDouble()) }
locationClass.hook("getLongitude", HookStage.BEFORE) { it.setResult(longitude.toDouble()) }
locationClass.hook("getAccuracy", HookStage.BEFORE) { it.setResult(0.0F) }
//Might be redundant because it calls isProviderEnabledForUser which we also hook, meaning if isProviderEnabledForUser returns true this will also return true
locationManagerClass.hook("isProviderEnabled", HookStage.BEFORE) { it.setResult(true) }
locationManagerClass.hook("isProviderEnabledForUser", HookStage.BEFORE) { it.setResult(true) }
} }
} }

View File

@ -5,7 +5,6 @@ import me.rhunk.snapenhance.common.action.EnumAction
import me.rhunk.snapenhance.core.ModContext import me.rhunk.snapenhance.core.ModContext
import me.rhunk.snapenhance.core.action.impl.CleanCache import me.rhunk.snapenhance.core.action.impl.CleanCache
import me.rhunk.snapenhance.core.action.impl.ExportChatMessages import me.rhunk.snapenhance.core.action.impl.ExportChatMessages
import me.rhunk.snapenhance.core.action.impl.OpenMap
import me.rhunk.snapenhance.core.manager.Manager import me.rhunk.snapenhance.core.manager.Manager
class ActionManager( class ActionManager(
@ -16,7 +15,6 @@ class ActionManager(
mapOf( mapOf(
EnumAction.CLEAN_CACHE to CleanCache::class, EnumAction.CLEAN_CACHE to CleanCache::class,
EnumAction.EXPORT_CHAT_MESSAGES to ExportChatMessages::class, EnumAction.EXPORT_CHAT_MESSAGES to ExportChatMessages::class,
EnumAction.OPEN_MAP to OpenMap::class,
).map { ).map {
it.key to it.value.java.getConstructor().newInstance().apply { it.key to it.value.java.getConstructor().newInstance().apply {
this.context = modContext this.context = modContext