feat: Enhance Blackbox core virtualization, system service proxies, and hook mechanisms for improved compatibility.

This commit is contained in:
alex5402
2026-01-30 22:13:05 +05:30
parent 64d0421685
commit 9572ccefa9
147 changed files with 488 additions and 299 deletions
@@ -7,15 +7,11 @@ import top.niunaijun.blackboxa.view.main.BlackBoxLoader
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
*/
object AppManager {
private const val TAG = "AppManager"
@JvmStatic
val mBlackBoxLoader by lazy {
try {
@@ -9,55 +9,56 @@ import android.widget.FrameLayout
import android.widget.RelativeLayout
import com.imuxuan.floatingview.FloatingMagnetView
import com.imuxuan.floatingview.FloatingView
import kotlin.math.cos
import kotlin.math.sin
import top.niunaijun.blackbox.entity.location.BLocation
import top.niunaijun.blackbox.fake.frameworks.BLocationManager
import top.niunaijun.blackboxa.app.App
import top.niunaijun.blackboxa.widget.EnFloatView
import kotlin.math.cos
import kotlin.math.sin
/**
* RockerManager - Advanced GPS Location Spoofing with Floating Joystick Control
*
*
* @Description: Provides a floating joystick/rocker control for real-time GPS location manipulation
* ```
* in virtual apps. Allows users to move their fake GPS location by dragging a joystick.
*
* @Features:
*
* @Features
* ```
* :
* - Floating joystick that appears on screen
* - Real-time GPS coordinate updates
* - Precise distance and angle control
* - App-specific location spoofing
* - Automatic activity lifecycle management
*
*
* @Usage:
* 1. RockerManager automatically initializes when virtual apps start
* 2. A floating joystick appears on the left side of the screen
* 3. Drag the joystick to change GPS location:
* ```
* - Distance: How far to move (in meters)
* - Angle: Direction to move (0-360 degrees)
* ```
* 4. Location updates happen in real-time as you move the joystick
*
*
* @Permissions Required:
* - SYSTEM_ALERT_WINDOW: To show floating view over other apps
* - ACCESS_FINE_LOCATION: To access GPS location services
* - ACCESS_COARSE_LOCATION: For approximate location access
*
*
* @Requirements:
* - Fake location must be enabled in BlackBox
* - User must grant overlay and location permissions
* - Virtual app must be running
*
*
* @Author: kotlinMiku
* @CreateDate: 2022/3/19 19:37
* @LastModified: 2024 - Enhanced with better error handling and permissions
*/
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
*/
object RockerManager {
@@ -65,8 +66,8 @@ object RockerManager {
private var isInitialized = false
// Earth radius constants for coordinate calculations
private const val Ea = 6378137.0 // Equator radius (meters)
private const val Eb = 6356725.0 // Polar radius (meters)
private const val Ea = 6378137.0 // Equator radius (meters)
private const val Eb = 6356725.0 // Polar radius (meters)
fun init(application: Application?, userId: Int) {
try {
@@ -93,7 +94,7 @@ object RockerManager {
}
Log.d(TAG, "Initializing RockerManager for userId: $userId")
val enFloatView = initFloatView()
if (enFloatView is EnFloatView) {
enFloatView.setListener { angle: Float, distance: Float ->
@@ -106,31 +107,47 @@ object RockerManager {
}
// Register activity lifecycle callbacks for floating view management
application.registerActivityLifecycleCallbacks(object : BaseActivityLifecycleCallback {
override fun onActivityStarted(activity: Activity) {
super.onActivityStarted(activity)
try {
FloatingView.get().attach(activity)
Log.d(TAG, "Floating view attached to activity: ${activity.javaClass.simpleName}")
} catch (e: Exception) {
Log.e(TAG, "Error attaching floating view to activity: ${e.message}")
}
}
application.registerActivityLifecycleCallbacks(
object : BaseActivityLifecycleCallback {
override fun onActivityStarted(activity: Activity) {
super.onActivityStarted(activity)
try {
FloatingView.get().attach(activity)
Log.d(
TAG,
"Floating view attached to activity: ${activity.javaClass.simpleName}"
)
} catch (e: Exception) {
Log.e(
TAG,
"Error attaching floating view to activity: ${e.message}"
)
}
}
override fun onActivityStopped(activity: Activity) {
super.onActivityStopped(activity)
try {
FloatingView.get().detach(activity)
Log.d(TAG, "Floating view detached from activity: ${activity.javaClass.simpleName}")
} catch (e: Exception) {
Log.e(TAG, "Error detaching floating view from activity: ${e.message}")
override fun onActivityStopped(activity: Activity) {
super.onActivityStopped(activity)
try {
FloatingView.get().detach(activity)
Log.d(
TAG,
"Floating view detached from activity: ${activity.javaClass.simpleName}"
)
} catch (e: Exception) {
Log.e(
TAG,
"Error detaching floating view from activity: ${e.message}"
)
}
}
}
}
})
)
isInitialized = true
Log.d(TAG, "RockerManager initialized successfully - Floating GPS joystick is now active!")
Log.d(
TAG,
"RockerManager initialized successfully - Floating GPS joystick is now active!"
)
} catch (e: Exception) {
Log.e(TAG, "Error initializing RockerManager: ${e.message}")
Log.e(TAG, "Stack trace: ", e)
@@ -139,10 +156,11 @@ object RockerManager {
private fun initFloatView(): FloatingMagnetView? {
return try {
val params = FrameLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
)
val params =
FrameLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
)
params.gravity = Gravity.START or Gravity.CENTER
val view = EnFloatView(App.getContext())
@@ -166,7 +184,10 @@ object RockerManager {
return
}
Log.d(TAG, "Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}")
Log.d(
TAG,
"Changing location - Distance: ${distance}m, Angle: ${angle}°, Current: ${location.latitude}, ${location.longitude}"
)
// Calculate new coordinates based on joystick input
val dx = distance * sin(angle * Math.PI / 180.0)
@@ -178,41 +199,41 @@ object RockerManager {
val newLng = (dx / ed + location.longitude * Math.PI / 180.0) * 180.0 / Math.PI
val newLat = (dy / ec + location.latitude * Math.PI / 180.0) * 180.0 / Math.PI
val newLocation = BLocation(newLat, newLng)
// Update the location
BLocationManager.get().setLocation(userId, packageName, newLocation)
Log.d(TAG, "Location updated - New: ${newLat}, ${newLng}")
} catch (e: Exception) {
Log.e(TAG, "Error changing location: ${e.message}")
Log.e(TAG, "Stack trace: ", e)
}
}
/**
* Check if RockerManager is currently initialized and active
*/
/** Check if RockerManager is currently initialized and active */
fun isActive(): Boolean {
return isInitialized
}
/**
* Check if required permissions are granted for RockerManager to work
*/
/** Check if required permissions are granted for RockerManager to work */
fun checkPermissions(context: Context): Boolean {
return try {
// Check if overlay permission is granted (required for floating view)
val hasOverlayPermission = android.provider.Settings.canDrawOverlays(context)
if (!hasOverlayPermission) {
Log.w(TAG, "Overlay permission not granted - RockerManager cannot show floating view")
Log.w(
TAG,
"Overlay permission not granted - RockerManager cannot show floating view"
)
return false
}
// Check if location permissions are granted
val hasLocationPermission = context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED
val hasLocationPermission =
context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) ==
android.content.pm.PackageManager.PERMISSION_GRANTED
if (!hasLocationPermission) {
Log.w(TAG, "Location permission not granted - RockerManager cannot access location")
return false
@@ -226,20 +247,16 @@ object RockerManager {
}
}
/**
* Get a list of required permissions for RockerManager
*/
/** Get a list of required permissions for RockerManager */
fun getRequiredPermissions(): List<String> {
return listOf(
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION
)
}
/**
* Clean up resources (useful for testing or when disabling the feature)
*/
/** Clean up resources (useful for testing or when disabling the feature) */
fun cleanup() {
try {
isInitialized = false
@@ -248,4 +265,4 @@ object RockerManager {
Log.e(TAG, "Error during cleanup: ${e.message}")
}
}
}
}
@@ -8,20 +8,21 @@ import kotlin.reflect.KProperty
/**
* updated by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
*/
open class AppSharedPreferenceDelegate<Data>(context: Context, private val default: Data, spName: String? = null) : ReadWriteProperty<Any, Data?> {
open class AppSharedPreferenceDelegate<Data>(
context: Context,
private val default: Data,
spName: String? = null
) : ReadWriteProperty<Any, Data?> {
private val mSharedPreferences by lazy {
val tmpCacheName = if (TextUtils.isEmpty(spName)) {
AppSharedPreferenceDelegate::class.java.simpleName
} else {
spName
}
val tmpCacheName =
if (TextUtils.isEmpty(spName)) {
AppSharedPreferenceDelegate::class.java.simpleName
} else {
spName
}
return@lazy context.getSharedPreferences(tmpCacheName, Context.MODE_PRIVATE)
}
@@ -35,14 +36,18 @@ open class AppSharedPreferenceDelegate<Data>(context: Context, private val defau
protected fun findData(key: String, default: Data): Data {
with(mSharedPreferences) {
val result: Any = when (default) {
is Int -> getInt(key, default)
is Long -> getLong(key, default)
is Float -> getFloat(key, default)
is String -> getString(key, default)!!
is Boolean -> getBoolean(key, default)
else -> throw IllegalArgumentException("This type $default can not be saved into sharedPreferences")
}
val result: Any =
when (default) {
is Int -> getInt(key, default)
is Long -> getLong(key, default)
is Float -> getFloat(key, default)
is String -> getString(key, default)!!
is Boolean -> getBoolean(key, default)
else ->
throw IllegalArgumentException(
"This type $default can not be saved into sharedPreferences"
)
}
return result as? Data ?: default
}
}
@@ -58,9 +63,12 @@ open class AppSharedPreferenceDelegate<Data>(context: Context, private val defau
is Float -> putFloat(key, value)
is String -> putString(key, value)
is Boolean -> putBoolean(key, value)
else -> throw IllegalArgumentException("This type $default can not be saved into Preferences")
else ->
throw IllegalArgumentException(
"This type $default can not be saved into Preferences"
)
}
}
}
}
}
}
@@ -1,85 +1,72 @@
package top.niunaijun.blackboxa.util
import android.app.ActivityManager
import android.content.Context
import android.util.Log
import java.lang.Runtime
/**
* Memory management utility to prevent crashes during memory-intensive operations
*/
/** Memory management utility to prevent crashes during memory-intensive operations */
/**
* created by alex5402 on 4/9/21.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
* TFNQw5HgWUS33Ke1eNmSFTwoQySGU7XNsK (USDT TRC20)
* * ∧_∧ (`・ω・∥ 丶 つ0 しーJ
*/
object MemoryManager {
private const val TAG = "MemoryManager"
private const val MEMORY_THRESHOLD = 0.8 // 80% memory usage threshold
private const val CRITICAL_MEMORY_THRESHOLD = 0.9 // 90% memory usage threshold
/**
* Check if memory usage is within safe limits
*/
/** Check if memory usage is within safe limits */
fun isMemorySafe(): Boolean {
return try {
val runtime = Runtime.getRuntime()
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
val maxMemory = runtime.maxMemory()
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
memoryUsage < MEMORY_THRESHOLD
} catch (e: Exception) {
Log.e(TAG, "Error checking memory: ${e.message}")
true // Assume safe if we can't check
}
}
/**
* Check if memory usage is critical
*/
/** Check if memory usage is critical */
fun isMemoryCritical(): Boolean {
return try {
val runtime = Runtime.getRuntime()
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
val maxMemory = runtime.maxMemory()
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
memoryUsage > CRITICAL_MEMORY_THRESHOLD
} catch (e: Exception) {
Log.e(TAG, "Error checking critical memory: ${e.message}")
false // Assume not critical if we can't check
}
}
/**
* Get current memory usage percentage
*/
/** Get current memory usage percentage */
fun getMemoryUsagePercentage(): Int {
return try {
val runtime = Runtime.getRuntime()
val usedMemory = runtime.totalMemory() - runtime.freeMemory()
val maxMemory = runtime.maxMemory()
val memoryUsage = usedMemory.toDouble() / maxMemory.toDouble()
(memoryUsage * 100).toInt()
} catch (e: Exception) {
Log.e(TAG, "Error getting memory usage: ${e.message}")
0
}
}
/**
* Force garbage collection if memory usage is high
*/
/** Force garbage collection if memory usage is high */
fun forceGarbageCollectionIfNeeded(): Boolean {
return try {
if (isMemoryCritical()) {
Log.w(TAG, "Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection")
Log.w(
TAG,
"Memory usage critical (${getMemoryUsagePercentage()}%), forcing garbage collection"
)
System.gc()
Thread.sleep(100) // Give GC time to work
true
@@ -91,20 +78,18 @@ object MemoryManager {
false
}
}
/**
* Optimize memory for RecyclerView operations
*/
/** Optimize memory for RecyclerView operations */
fun optimizeMemoryForRecyclerView() {
try {
val memoryUsage = getMemoryUsagePercentage()
if (memoryUsage > 70) {
Log.d(TAG, "Memory usage high (${memoryUsage}%), optimizing for RecyclerView")
// Force garbage collection
System.gc()
// Clear any caches if possible
try {
val runtime = Runtime.getRuntime()
@@ -117,10 +102,8 @@ object MemoryManager {
Log.e(TAG, "Error optimizing memory: ${e.message}")
}
}
/**
* Check if we should skip icon loading to save memory
*/
/** Check if we should skip icon loading to save memory */
fun shouldSkipIconLoading(): Boolean {
return try {
val memoryUsage = getMemoryUsagePercentage()
@@ -130,10 +113,8 @@ object MemoryManager {
false
}
}
/**
* Get memory info for debugging
*/
/** Get memory info for debugging */
fun getMemoryInfo(): String {
return try {
val runtime = Runtime.getRuntime()
@@ -141,7 +122,7 @@ object MemoryManager {
val freeMemory = runtime.freeMemory()
val usedMemory = totalMemory - freeMemory
val maxMemory = runtime.maxMemory()
"Memory: ${usedMemory / 1024 / 1024}MB used / ${maxMemory / 1024 / 1024}MB max (${getMemoryUsagePercentage()}%)"
} catch (e: Exception) {
"Memory: Unknown (${e.message})"