diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6481955..5699688 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,8 @@
+
@@ -41,6 +43,7 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
@@ -117,8 +120,6 @@
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
-
-
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/MainActivity.kt b/app/src/main/java/com/android/grape/MainActivity.kt
index ad4fc42..7d25c15 100644
--- a/app/src/main/java/com/android/grape/MainActivity.kt
+++ b/app/src/main/java/com/android/grape/MainActivity.kt
@@ -13,18 +13,24 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import androidx.lifecycle.lifecycleScope
import com.android.grape.databinding.ActivityMainBinding
import com.android.grape.job.MonitorService
import com.android.grape.receiver.ScriptReceiver
import com.android.grape.util.ClashUtil
+import com.android.grape.util.HttpUtil
+import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.StoragePermissionHelper
import com.blankj.utilcode.util.LogUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels()
private lateinit var viewBinding: ActivityMainBinding
private var intentFilter: IntentFilter? = null
private var scriptReceiver: ScriptReceiver? = null
+ private lateinit var permissionHandler: NotificationPermissionHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
@@ -39,15 +45,14 @@ class MainActivity : AppCompatActivity() {
registerReceiver()
viewBinding.start.setOnClickListener {
try {
- ClashUtil.startProxy(this) // 在主线程中调用
- ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170")
- } catch (e: Exception) {
- LogUtils.log(
- Log.ERROR,
- "MainActivity",
- "startProxyVpn: Failed to start VPN",
- e
+ ClashUtil.startProxy(this)
+ ClashUtil.switchProxyGroup(
+ "GLOBAL",
+ ClashUtil.getRandomLocale(),
+ "http://127.0.0.1:6170"
)
+ } catch (e: Exception) {
+ LogUtils.e("startProxyVpn: Failed to start VPN", e)
Toast.makeText(
this,
"Failed to start VPN: " + (if (e.message != null) e.message else "Unknown error"),
@@ -77,7 +82,11 @@ class MainActivity : AppCompatActivity() {
}
private fun checkPermission() {
- viewModel.checkAccessibilityService()
+ permissionHandler = NotificationPermissionHandler(this) { result ->
+ handlePermissionResult(result)
+ }
+ checkNotificationPermission()
+
StoragePermissionHelper.requestFullStoragePermission(
activity = this,
onGranted = { performFileOperation() },
@@ -85,10 +94,56 @@ class MainActivity : AppCompatActivity() {
)
}
+ private fun checkNotificationPermission() {
+ when (val result = NotificationPermissionHandler.checkPermissionState(this)) {
+ NotificationPermissionHandler.PermissionResult.GRANTED,
+ NotificationPermissionHandler.PermissionResult.NOT_NEEDED -> {
+ showNotification()
+ }
+
+ NotificationPermissionHandler.PermissionResult.DENIED,
+ NotificationPermissionHandler.PermissionResult.NEEDS_SETTINGS -> {
+ // 请求权限
+ permissionHandler.requestNotificationPermission()
+ }
+ }
+ }
+
+ /**
+ * 处理权限结果回调
+ */
+ private fun handlePermissionResult(result: NotificationPermissionHandler.PermissionResult) {
+ when (result) {
+ NotificationPermissionHandler.PermissionResult.GRANTED -> {
+ // 权限已授予,显示通知
+ showNotification()
+ Toast.makeText(this, "通知权限已开启", Toast.LENGTH_SHORT).show()
+ }
+
+ NotificationPermissionHandler.PermissionResult.DENIED -> {
+ // 权限被拒绝
+ Toast.makeText(this, "通知权限被拒绝", Toast.LENGTH_SHORT).show()
+ }
+
+ NotificationPermissionHandler.PermissionResult.NEEDS_SETTINGS -> {
+ Toast.makeText(this, "通知权限被拒绝", Toast.LENGTH_SHORT).show()
+ }
+
+ NotificationPermissionHandler.PermissionResult.NOT_NEEDED -> {
+ // 不需要特殊权限(旧设备)
+ showNotification()
+ }
+ }
+ }
+
+ private fun showNotification() {
+ viewModel.checkAccessibilityService()
+ }
+
private fun performFileOperation() {
// 执行文件读写操作
// Toast.makeText(this, "文件访问权限已授予", Toast.LENGTH_SHORT).show()
- MonitorService.onEvent(this)
+// MonitorService.onEvent(this)
}
private fun showPermissionDeniedDialog() {
diff --git a/app/src/main/java/com/android/grape/data/As.kt b/app/src/main/java/com/android/grape/data/As.kt
new file mode 100644
index 0000000..2df87f4
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/As.kt
@@ -0,0 +1,8 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class As(
+ var nameValuePairs: NameValuePairs = NameValuePairs()
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/DdlInfo.kt b/app/src/main/java/com/android/grape/data/DdlInfo.kt
new file mode 100644
index 0000000..33bbb73
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/DdlInfo.kt
@@ -0,0 +1,11 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class DdlInfo(
+ var fromfg: Int = 0,
+ var net0: Int = 0,
+ var rfrwait: Int = 0,
+ var status: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Device.kt b/app/src/main/java/com/android/grape/data/Device.kt
new file mode 100644
index 0000000..0609d6a
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Device.kt
@@ -0,0 +1,113 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Device(
+ var advertiserId: String = "",
+ @SerializedName("af_preinstalled")
+ var afPreinstalled: Boolean = false,
+ var androidId: String = "",
+ var arch: String = "",
+ @SerializedName("as")
+ var asX: As = As(),
+ var battery: Int = 0,
+ var battery1: Int = 0,
+ var batteryLevel: Int = 0,
+ var batteryType: Int = 0,
+ var bn: String = "",
+ var brand: String = "",
+ var btch: String = "",
+ @SerializedName("build_display_id")
+ var buildDisplayId: String = "",
+ var carrier: String = "",
+ @SerializedName("click_ts")
+ var clickTs: Int = 0,
+ var clk: String = "",
+ var country: String = "",
+ @SerializedName("cpu_abi")
+ var cpuAbi: String = "",
+ @SerializedName("cpu_abi2")
+ var cpuAbi2: String = "",
+ var ddlInfo: DdlInfo = DdlInfo(),
+ var debug: Boolean = false,
+ var device: String = "",
+ var deviceCity: String = "",
+ var deviceType: String = "",
+ var dim: Dim = Dim(),
+ var dimId: Int = 0,
+ var dimReset: Int = 0,
+ var dimType: Int = 0,
+ var disk: String = "",
+ var diskRate: Double = 0.0,
+ var expand: Expand = Expand(),
+ var fetchAdIdLatency: Int = 0,
+ @SerializedName("from_fg")
+ var fromFg: Int = 0,
+ @SerializedName("google_custom")
+ var googleCustom: GoogleCustom = GoogleCustom(),
+ var hook: String = "",
+ @SerializedName("init_to_fg")
+ var initToFg: Int = 0,
+ var install: String = "",
+ @SerializedName("install_begin_ts")
+ var installBeginTs: Int = 0,
+ @SerializedName("installer_package")
+ var installerPackage: String = "",
+ var instant: Boolean = false,
+ var ip: String = "",
+ var ivc: Boolean = false,
+ var lang: String = "",
+ @SerializedName("lang_code")
+ var langCode: String = "",
+ @SerializedName("last_boot_time")
+ var lastBootTime: Long = 0,
+ var lastBootTimeOff: Int = 0,
+ var latency: Int = 0,
+ var locale: Locale = Locale(),
+ var manufactor: String = "",
+ var mcc: Int = 0,
+ var mnc: Int = 0,
+ var model: String = "",
+ @SerializedName("native_dir")
+ var nativeDir: Boolean = false,
+ var network: String = "",
+ var noRcLatency: Boolean = false,
+ @SerializedName("open_referrer")
+ var openReferrer: String = "",
+ @SerializedName("open_referrerReset")
+ var openReferrerReset: Int = 0,
+ var opener: String = "",
+ var `operator`: String = "",
+ var platformextension: String = "",
+ var pr: Pr = Pr(),
+ var product: String = "",
+ var rawDevice: String = "",
+ var rawProduct: String = "",
+ @SerializedName("rc.delay")
+ var rcDelay: Int = 0,
+ @SerializedName("rc.latency")
+ var rcLatency: Int = 0,
+ var referrer: String = "",
+ @SerializedName("sc_o")
+ var scO: String = "",
+ var sdk: String = "",
+ var sdkVer: String = "",
+ var sensor: List = listOf(),
+ var sensorReset: Int = 0,
+ @SerializedName("sensor_size")
+ var sensorSize: Int = 0,
+ @SerializedName("sig_n")
+ var sigN: String = "",
+ @SerializedName("sys_ua")
+ var sysUa: String = "",
+ var timepassedsincelastlaunch: Int = 0,
+ var tzDisplayName: String = "",
+ var tzOffTime: Int = 0,
+ @SerializedName("val")
+ var valX: String = "",
+ var vendingVersionCode: String = "",
+ var vendingVersionName: String = "",
+ @SerializedName("web_ua")
+ var webUa: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Dim.kt b/app/src/main/java/com/android/grape/data/Dim.kt
new file mode 100644
index 0000000..a9ee4bc
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Dim.kt
@@ -0,0 +1,16 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Dim(
+ @SerializedName("d_dpi")
+ var dDpi: String = "",
+ var size: String = "",
+ @SerializedName("x_px")
+ var xPx: String = "",
+ var xdp: String = "",
+ @SerializedName("y_px")
+ var yPx: String = "",
+ var ydp: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Expand.kt b/app/src/main/java/com/android/grape/data/Expand.kt
new file mode 100644
index 0000000..9514251
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Expand.kt
@@ -0,0 +1,87 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Expand(
+ @SerializedName("ABI")
+ var aBI: String = "",
+ @SerializedName("API")
+ var aPI: String = "",
+ var amGetConfig: String = "",
+ @SerializedName("AndroidID")
+ var androidID: String = "",
+ @SerializedName("AndroidVer")
+ var androidVer: String = "",
+ @SerializedName("BSSID")
+ var bSSID: String = "",
+ var baseband: String = "",
+ var batteryLevel: Int = 0,
+ var board: String = "",
+ var bootLoader: String = "",
+ var brand: String = "",
+ var country: String = "",
+ @SerializedName("CountryCode")
+ var countryCode: String = "",
+ var cpuinfobuf: String = "",
+ var cpuinfostr: String = "",
+ @SerializedName("DPI")
+ var dPI: Int = 0,
+ var dataStatfs: Long = 0,
+ var device: String = "",
+ var display: String = "",
+ var displayLang: String = "",
+ var downloadCacheStatfs: Long = 0,
+ var fingerprint: String = "",
+ var firstInstallTime: Int = 0,
+ var gaid: String = "",
+ var glExtensions: String = "",
+ var glRenderer: String = "",
+ var glVendor: String = "",
+ var glVersion: String = "",
+ var height: Int = 0,
+ @SerializedName("ID")
+ var iD: String = "",
+ var incremental: String = "",
+ var lang: String = "",
+ var lastUpdateTime: Int = 0,
+ var latitude: Double = 0.0,
+ var localip: String = "",
+ var longtitude: Double = 0.0,
+ var lyMAC: String = "",
+ @SerializedName("Manufacture")
+ var manufacture: String = "",
+ var model: String = "",
+ var network: String = "",
+ var phoneBootTime: Int = 0,
+ var phoneUsedTime: Int = 0,
+ var pmfea: String = "",
+ var pmlib: String = "",
+ var procStat: String = "",
+ var procVersion: String = "",
+ var ratioVersion: String = "",
+ var referrerClickTime: Long = 0,
+ var referrerFromGP: String = "",
+ var regionid: String = "",
+ var roBoardPlatform: String = "",
+ var roBootimageBuildFingerprint: String = "",
+ var roBuildDateUtc: Int = 0,
+ var roBuildDescription: String = "",
+ var roHardware: String = "",
+ var roProductCpuAbilist: String = "",
+ var roProductName: String = "",
+ var rootStatfs: Int = 0,
+ var screenBrightness: Int = 0,
+ var sdStatfs: Long = 0,
+ var sdcardCreateTime: Int = 0,
+ var soRomRam: String = "",
+ var timerawoff: Int = 0,
+ var tmdisplayname: String = "",
+ var uname: String = "",
+ var width: Int = 0,
+ @SerializedName("WifiMAC")
+ var wifiMAC: String = "",
+ @SerializedName("WifiName")
+ var wifiName: String = "",
+ var wvua: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/GoogleCustom.kt b/app/src/main/java/com/android/grape/data/GoogleCustom.kt
new file mode 100644
index 0000000..52b0eb6
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/GoogleCustom.kt
@@ -0,0 +1,14 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class GoogleCustom(
+ @SerializedName("click_server_ts")
+ var clickServerTs: Int = 0,
+ @SerializedName("install_begin_server_ts")
+ var installBeginServerTs: Int = 0,
+ @SerializedName("install_version")
+ var installVersion: String = "",
+ var instant: Boolean = false
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Locale.kt b/app/src/main/java/com/android/grape/data/Locale.kt
new file mode 100644
index 0000000..cd8a682
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Locale.kt
@@ -0,0 +1,10 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Locale(
+ var country: String = "",
+ var displayLang: String = "",
+ var lang: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/NameValuePairs.kt b/app/src/main/java/com/android/grape/data/NameValuePairs.kt
new file mode 100644
index 0000000..4325e89
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/NameValuePairs.kt
@@ -0,0 +1,11 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class NameValuePairs(
+ var cav: Int = 0,
+ @SerializedName("null")
+ var nullX: Int = 0,
+ var other: Int = 0
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/NameValuePairsX.kt b/app/src/main/java/com/android/grape/data/NameValuePairsX.kt
new file mode 100644
index 0000000..3b52f3b
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/NameValuePairsX.kt
@@ -0,0 +1,22 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class NameValuePairsX(
+ var ac: String = "",
+ var ah: String = "",
+ var ai: String = "",
+ var ak: String = "",
+ var al: String = "",
+ var am: String = "",
+ var an: String = "",
+ var ap: String = "",
+ var aq: String = "",
+ var ar: String = "",
+ @SerializedName("as")
+ var asX: String = "",
+ var at: String = "",
+ var au: String = "",
+ var av: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Pr.kt b/app/src/main/java/com/android/grape/data/Pr.kt
new file mode 100644
index 0000000..cc45e0f
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Pr.kt
@@ -0,0 +1,8 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Pr(
+ var nameValuePairs: NameValuePairsX = NameValuePairsX()
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/data/Sensor.kt b/app/src/main/java/com/android/grape/data/Sensor.kt
new file mode 100644
index 0000000..ae1b569
--- /dev/null
+++ b/app/src/main/java/com/android/grape/data/Sensor.kt
@@ -0,0 +1,12 @@
+package com.android.grape.data
+
+
+import com.google.gson.annotations.SerializedName
+
+data class Sensor(
+ var sN: String = "",
+ var sT: Int = 0,
+ var sV: String = "",
+ var sVE: List = listOf(),
+ var sVS: List = listOf()
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/job/OpenAppService.kt b/app/src/main/java/com/android/grape/job/OpenAppService.kt
index 04ddaa3..8e7e6aa 100644
--- a/app/src/main/java/com/android/grape/job/OpenAppService.kt
+++ b/app/src/main/java/com/android/grape/job/OpenAppService.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.app.JobIntentService
+import com.android.grape.util.ChangeDeviceInfoUtil
import com.android.grape.util.MockTools
import com.android.grape.util.ServiceUtils
import com.android.grape.util.Util
@@ -28,13 +29,15 @@ class OpenAppService : JobIntentService() {
Util.doScript(this, Util.AUTO_JSPACKAGENAME) //autojs
}
try {
- if (Util.isNeedRestored) {
- Log.d("IOSTQ:", "执行留存任务")
- Util.setRrInfo(this)
- } else {
- Log.d("IOSTQ:", "执行新装任务")
- Util.setInfo(this)
- }
+ //todo fix 改机流程
+// if (Util.isNeedRestored) {
+// Log.d("IOSTQ:", "执行留存任务")
+// Util.setRrInfo(this)
+// } else {
+// Log.d("IOSTQ:", "执行新装任务")
+// Util.setInfo(this)
+// }
+ ChangeDeviceInfoUtil.changeDeviceInfo()
} catch (e: IOException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/com/android/grape/util/ChangeDeviceInfoUtil.kt b/app/src/main/java/com/android/grape/util/ChangeDeviceInfoUtil.kt
index 7df6551..1e82f97 100644
--- a/app/src/main/java/com/android/grape/util/ChangeDeviceInfoUtil.kt
+++ b/app/src/main/java/com/android/grape/util/ChangeDeviceInfoUtil.kt
@@ -3,329 +3,150 @@ package com.android.grape.util
import android.content.ContentResolver
import android.content.Context
import android.util.Log
-import com.android.grape.data.AfInfo
-import com.android.grape.data.BigoInfo
-import com.android.grape.data.DeviceInfo
+import com.android.grape.MainApplication
+import com.android.grape.data.Device
+import com.android.grape.util.Util.paramsJson
import com.blankj.utilcode.util.LogUtils
import org.json.JSONObject
import java.lang.reflect.InvocationTargetException
object ChangeDeviceInfoUtil {
fun changeDeviceInfo(
- current_pkg_name: String,
- context: Context?,
- bigoDeviceObject: JSONObject?,
- afDeviceObject: JSONObject?
) {
- var bigoDeviceObject = bigoDeviceObject
- var afDeviceObject = afDeviceObject
try {
- val bigoDevice: BigoInfo
- if (bigoDeviceObject != null) {
- // BIGO
- val cpuClockSpeed = bigoDeviceObject.optString("cpu_clock_speed")
- val gaid = bigoDeviceObject.optString("gaid")
- val userAgent = bigoDeviceObject.optString("User-Agent")
- val osLang = bigoDeviceObject.optString("os_lang")
- val osVer = bigoDeviceObject.optString("os_ver")
- val tz = bigoDeviceObject.optString("tz")
- val systemCountry = bigoDeviceObject.optString("system_country")
- val simCountry = bigoDeviceObject.optString("sim_country")
- val romFreeIn = bigoDeviceObject.optLong("rom_free_in")
- val resolution = bigoDeviceObject.optString("resolution")
- val vendor = bigoDeviceObject.optString("vendor")
- val batteryScale = bigoDeviceObject.optInt("bat_scale")
- // String model = deviceObject.optString("model");
- val net = bigoDeviceObject.optString("net")
- val dpi = bigoDeviceObject.optLong("dpi")
- val romFreeExt = bigoDeviceObject.optLong("rom_free_ext")
- val dpiF = bigoDeviceObject.optString("dpi_f")
- val cpuCoreNum = bigoDeviceObject.optLong("cpu_core_num")
-
- bigoDevice = BigoInfo()
- bigoDevice.cpuClockSpeed = cpuClockSpeed
- bigoDevice.gaid = gaid
- bigoDevice.userAgent = userAgent
- bigoDevice.osLang = osLang
- bigoDevice.osVer = osVer
- bigoDevice.tz = tz
- bigoDevice.systemCountry = systemCountry
- bigoDevice.simCountry = simCountry
- bigoDevice.romFreeIn = romFreeIn
- bigoDevice.resolution = resolution
- bigoDevice.vendor = vendor
- bigoDevice.batteryScale = batteryScale
- bigoDevice.net = net
- bigoDevice.dpi = dpi
- bigoDevice.romFreeExt = romFreeExt
- bigoDevice.dpiF = dpiF
- bigoDevice.cpuCoreNum = cpuCoreNum
-// TaskUtil.setBigoDevice(bigoDevice)
- try {
- callVCloudSettings_put(
- "$current_pkg_name.system_country",
- systemCountry,
- context
- )
- callVCloudSettings_put("$current_pkg_name.sim_country", simCountry, context)
- callVCloudSettings_put(
- "$current_pkg_name.rom_free_in",
- romFreeIn.toString(),
- context
- )
- callVCloudSettings_put("$current_pkg_name.resolution", resolution, context)
- callVCloudSettings_put("$current_pkg_name.vendor", vendor, context)
- callVCloudSettings_put(
- "$current_pkg_name.battery_scale",
- batteryScale.toString(),
- context
- )
- callVCloudSettings_put("$current_pkg_name.os_lang", osLang, context)
- // callVCloudSettings_put(current_pkg_name + ".model", model, context);
- callVCloudSettings_put("$current_pkg_name.net", net, context)
- callVCloudSettings_put("$current_pkg_name.dpi", dpi.toString(), context)
- callVCloudSettings_put(
- "$current_pkg_name.rom_free_ext",
- romFreeExt.toString(),
- context
- )
- callVCloudSettings_put("$current_pkg_name.dpi_f", dpiF, context)
- callVCloudSettings_put(
- "$current_pkg_name.cpu_core_num",
- cpuCoreNum.toString(),
- context
- )
- callVCloudSettings_put(
- "$current_pkg_name.cpu_clock_speed",
- cpuClockSpeed,
- context
- )
- callVCloudSettings_put(current_pkg_name + "_gaid", gaid, context)
- // **User-Agent**
- callVCloudSettings_put(current_pkg_name + "_user_agent", userAgent, context)
- // **os_lang**系统语言
- callVCloudSettings_put(current_pkg_name + "_os_lang", osLang, context)
- // **os_ver**
- callVCloudSettings_put(current_pkg_name + "_os_ver", osVer, context)
- // **tz** (时区)
- callVCloudSettings_put(current_pkg_name + "_tz", tz, context)
- } catch (e: Throwable) {
- LogUtils.e(
- Log.ERROR,
- "ChangeDeviceInfoUtil",
- "Error occurred while changing device info",
- e
- )
- throw RuntimeException("Error occurred in changeDeviceInfo", e)
- }
- bigoDeviceObject = null
+ val deviceObject = paramsJson?.getJSONObject("device")
+ if (deviceObject == null) {
+ LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
+ return
}
+ val context = MainApplication.instance
+ val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
+ val currentPkgName = MainApplication.instance.packageName
+ vcloudsettingsPut(
+ "$currentPkgName.system_country",
+ device.country,
+ context
+ )
+ vcloudsettingsPut("$currentPkgName.sim_country", device.country, context)
+// callVCloudSettings_put(
+// "$currentPkgName.rom_free_in",
+// romFreeIn.toString(),
+// context
+// )
+ vcloudsettingsPut(
+ "$currentPkgName.resolution",
+ "${device.expand.width}x${device.expand.height}}",
+ context
+ )
+ vcloudsettingsPut("$currentPkgName.vendor", device.expand.glVendor, context)
+// callVCloudSettings_put("$currentPkgName.battery_scale", batteryScale.toString(), context)
+ vcloudsettingsPut("$currentPkgName.os_lang", device.lang, context)
+ vcloudsettingsPut("$currentPkgName.model", device.model, context);
+ vcloudsettingsPut("$currentPkgName.net", device.network, context)
+ vcloudsettingsPut("$currentPkgName.dpi", device.expand.dPI.toString(), context)
+// callVCloudSettings_put(
+// "$currentPkgName.rom_free_ext",
+// romFreeExt.toString(),
+// context
+// )
+// callVCloudSettings_put("$currentPkgName.dpi_f", dpiF, context)
+// callVCloudSettings_put("$currentPkgName.cpu_core_num", cpuCoreNum.toString(), context)
+// callVCloudSettings_put("$currentPkgName.cpu_clock_speed", cpuClockSpeed, context)
+ vcloudsettingsPut(currentPkgName + "_gaid", device.expand.gaid, context)
+ // **User-Agent**
+// callVCloudSettings_put(currentPkgName + "_user_agent", userAgent, context)
+ // **os_lang**系统语言
+ vcloudsettingsPut(currentPkgName + "_os_lang", device.lang, context)
+ // **os_ver**
+ vcloudsettingsPut(currentPkgName + "_os_ver", device.sdkVer, context)
+ // **tz** (时区)
+ vcloudsettingsPut(currentPkgName + "_tz", device.tzOffTime.toString(), context)
- val deviceInfo: DeviceInfo
- val afDevice: AfInfo
- if (afDeviceObject != null) {
- val advertiserId = afDeviceObject.optString(".advertiserId")
- val model = afDeviceObject.optString(".model")
- val brand = afDeviceObject.optString(".brand")
- val androidId = afDeviceObject.optString(".android_id")
- val xPixels = afDeviceObject.optInt(".deviceData.dim.x_px")
- val yPixels = afDeviceObject.optInt(".deviceData.dim.y_px")
- val densityDpi = afDeviceObject.optInt(".deviceData.dim.d_dpi")
- val country = afDeviceObject.optString(".country")
- val batteryLevel = afDeviceObject.optString(".batteryLevel")
- val stackInfo = Thread.currentThread().stackTrace[2].toString()
- val product = afDeviceObject.optString(".product")
- val network = afDeviceObject.optString(".network")
- val langCode = afDeviceObject.optString(".lang_code")
- val cpuAbi = afDeviceObject.optString(".deviceData.cpu_abi")
- val yDp = afDeviceObject.optLong(".deviceData.dim.ydp")
+ vcloudsettingsPut("$currentPkgName.advertiserId", device.advertiserId, context)
+ vcloudsettingsPut("$currentPkgName.brand", device.brand, context)
+ vcloudsettingsPut("$currentPkgName.android_id", device.androidId, context)
+ vcloudsettingsPut("$currentPkgName.lang", device.lang, context)
+ vcloudsettingsPut("$currentPkgName.country", device.country, context)
+ vcloudsettingsPut(
+ "$currentPkgName.batteryLevel",
+ device.batteryLevel.toString(), context
+ )
+// callVCloudSettings_put(
+// currentPkgName + "_screen.optMetrics.stack",
+// stackInfo,
+// context
+// )
+ vcloudsettingsPut("$currentPkgName.product", device.product, context)
+ vcloudsettingsPut("$currentPkgName.network", device.network, context)
+ vcloudsettingsPut("$currentPkgName.cpu_abi", device.cpuAbi, context)
+ vcloudsettingsPut("$currentPkgName.lang_code", device.langCode, context)
+ // **广告标识符 (advertiserId)** 及 **启用状态**
+ val isAdIdEnabled = true // 默认启用广告 ID
+ vcloudsettingsPut(
+ "$currentPkgName.advertiserIdEnabled",
+ isAdIdEnabled.toString(),
+ context
+ )
- afDevice = AfInfo()
- afDevice.advertiserId = advertiserId
- afDevice.model = model
- afDevice.brand = brand
- afDevice.androidId = androidId
- afDevice.xPixels = xPixels
- afDevice.yPixels = yPixels
- afDevice.densityDpi = densityDpi
- afDevice.country = country
- afDevice.batteryLevel = batteryLevel
- afDevice.stackInfo = stackInfo
- afDevice.product = product
- afDevice.network = network
- afDevice.langCode = langCode
- afDevice.cpuAbi = cpuAbi
- afDevice.yDp = yDp
-// TaskUtil.setAfDevice(afDevice)
+ val displayMetrics = JSONObject()
- val lang = afDeviceObject.optString(".lang")
- val ro_product_brand = afDeviceObject.optString("ro.product.brand", "")
- val ro_product_model = afDeviceObject.optString("ro.product.model", "")
- val ro_product_manufacturer =
- afDeviceObject.optString("ro.product.manufacturer", "")
- val ro_product_device = afDeviceObject.optString("ro.product.device", "")
- val ro_product_name = afDeviceObject.optString("ro.product.name", "")
- val ro_build_version_incremental =
- afDeviceObject.optString("ro.build.version.incremental", "")
- val ro_build_fingerprint = afDeviceObject.optString("ro.build.fingerprint", "")
- val ro_odm_build_fingerprint =
- afDeviceObject.optString("ro.odm.build.fingerprint", "")
- val ro_product_build_fingerprint =
- afDeviceObject.optString("ro.product.build.fingerprint", "")
- val ro_system_build_fingerprint =
- afDeviceObject.optString("ro.system.build.fingerprint", "")
- val ro_system_ext_build_fingerprint =
- afDeviceObject.optString("ro.system_ext.build.fingerprint", "")
- val ro_vendor_build_fingerprint =
- afDeviceObject.optString("ro.vendor.build.fingerprint", "")
- val ro_build_platform = afDeviceObject.optString("ro.board.platform", "")
- val persist_sys_cloud_drm_id =
- afDeviceObject.optString("persist.sys.cloud.drm.id", "")
- val persist_sys_cloud_battery_capacity =
- afDeviceObject.optInt("persist.sys.cloud.battery.capacity", -1)
- val persist_sys_cloud_gpu_gl_vendor =
- afDeviceObject.optString("persist.sys.cloud.gpu.gl_vendor", "")
- val persist_sys_cloud_gpu_gl_renderer =
- afDeviceObject.optString("persist.sys.cloud.gpu.gl_renderer", "")
- val persist_sys_cloud_gpu_gl_version =
- afDeviceObject.optString("persist.sys.cloud.gpu.gl_version", "")
- val persist_sys_cloud_gpu_egl_vendor =
- afDeviceObject.optString("persist.sys.cloud.gpu.egl_vendor", "")
- val persist_sys_cloud_gpu_egl_version =
- afDeviceObject.optString("persist.sys.cloud.gpu.egl_version", "")
- val global_android_id = afDeviceObject.optString(".android_id", "")
- val anticheck_pkgs = afDeviceObject.optString(".anticheck_pkgs", "")
- val pm_list_features = afDeviceObject.optString(".pm_list_features", "")
- val pm_list_libraries = afDeviceObject.optString(".pm_list_libraries", "")
- val system_http_agent = afDeviceObject.optString("system.http.agent", "")
- val webkit_http_agent = afDeviceObject.optString("webkit.http.agent", "")
- val com_fk_tools_pkgInfo = afDeviceObject.optString(".pkg_info", "")
- val appsflyerKey = afDeviceObject.optString(".appsflyerKey", "")
- val appUserId = afDeviceObject.optString(".appUserId", "")
- val disk = afDeviceObject.optString(".disk", "")
- val operator = afDeviceObject.optString(".operator", "")
- val cell_mcc = afDeviceObject.optString(".cell.mcc", "")
- val cell_mnc = afDeviceObject.optString(".cell.mnc", "")
- val date1 = afDeviceObject.optString(".date1", "")
- val date2 = afDeviceObject.optString(".date2", "")
- val bootId = afDeviceObject.optString("BootId", "")
+ displayMetrics.put("widthPixels", device.expand.width)
- deviceInfo = DeviceInfo()
- deviceInfo.lang = lang
- deviceInfo.roProductBrand = ro_product_brand
- deviceInfo.roProductModel = ro_product_model
- deviceInfo.roProductManufacturer = ro_product_manufacturer
- deviceInfo.roProductDevice = ro_product_device
- deviceInfo.roProductName = ro_product_name
- deviceInfo.roBuildVersionIncremental = ro_build_version_incremental
- deviceInfo.roBuildFingerprint = ro_build_fingerprint
- deviceInfo.roOdmBuildFingerprint = ro_odm_build_fingerprint
- deviceInfo.roProductBuildFingerprint = ro_product_build_fingerprint
- deviceInfo.roSystemBuildFingerprint = ro_system_build_fingerprint
- deviceInfo.roSystemExtBuildFingerprint = ro_system_ext_build_fingerprint
- deviceInfo.roVendorBuildFingerprint = ro_vendor_build_fingerprint
- deviceInfo.roBuildPlatform = ro_build_platform
- deviceInfo.persistSysCloudDrmId = persist_sys_cloud_drm_id
- deviceInfo.persistSysCloudBatteryCapacity = persist_sys_cloud_battery_capacity
- deviceInfo.persistSysCloudGpuGlVendor = persist_sys_cloud_gpu_gl_vendor
- deviceInfo.persistSysCloudGpuGlRenderer = persist_sys_cloud_gpu_gl_renderer
- deviceInfo.persistSysCloudGpuGlVersion = persist_sys_cloud_gpu_gl_version
- deviceInfo.persistSysCloudGpuEglVendor = persist_sys_cloud_gpu_egl_vendor
- deviceInfo.persistSysCloudGpuEglVersion = persist_sys_cloud_gpu_egl_version
-// TaskUtil.setDeviceInfo(deviceInfo)
- try {
- callVCloudSettings_put("$current_pkg_name.advertiserId", advertiserId, context)
- callVCloudSettings_put("$current_pkg_name.model", model, context)
- callVCloudSettings_put("$current_pkg_name.brand", brand, context)
- callVCloudSettings_put("$current_pkg_name.android_id", androidId, context)
- callVCloudSettings_put("$current_pkg_name.lang", lang, context)
- callVCloudSettings_put("$current_pkg_name.country", country, context)
- callVCloudSettings_put("$current_pkg_name.batteryLevel", batteryLevel, context)
- callVCloudSettings_put(
- current_pkg_name + "_screen.optMetrics.stack",
- stackInfo,
- context
- )
- callVCloudSettings_put("$current_pkg_name.product", product, context)
- callVCloudSettings_put("$current_pkg_name.network", network, context)
- callVCloudSettings_put("$current_pkg_name.cpu_abi", cpuAbi, context)
- callVCloudSettings_put("$current_pkg_name.lang_code", langCode, context)
- // **广告标识符 (advertiserId)** 及 **启用状态**
- val isAdIdEnabled = true // 默认启用广告 ID
- callVCloudSettings_put(
- "$current_pkg_name.advertiserIdEnabled",
- isAdIdEnabled.toString(),
- context
- )
+ displayMetrics.put("heightPixels", device.expand.height)
+ displayMetrics.put("densityDpi", device.expand.dPI)
+ displayMetrics.put("yDp", device.dim.ydp)
+ vcloudsettingsPut(
+ "screen.device.displayMetrics",
+ displayMetrics.toString(),
+ context
+ )
- val displayMetrics = JSONObject()
-
- displayMetrics.put("widthPixels", xPixels)
-
- displayMetrics.put("heightPixels", yPixels)
- displayMetrics.put("densityDpi", densityDpi)
- displayMetrics.put("yDp", yDp)
- callVCloudSettings_put(
- "screen.device.displayMetrics",
- displayMetrics.toString(),
- context
- )
-
- if (!ShellUtils.hasRootAccess()) {
- LogUtils.d(
- "ERROR",
- "ChangeDeviceInfoUtil",
- "Root access is required to execute system property changes"
- )
- }
- // 设置机型, 直接设置属性
- ShellUtils.execRootCmd("setprop ro.product.brand $ro_product_brand")
- ShellUtils.execRootCmd("setprop ro.product.model $ro_product_model")
- ShellUtils.execRootCmd("setprop ro.product.manufacturer $ro_product_manufacturer")
- ShellUtils.execRootCmd("setprop ro.product.device $ro_product_device")
- ShellUtils.execRootCmd("setprop ro.product.name $ro_product_name")
- ShellUtils.execRootCmd("setprop ro.build.version.incremental $ro_build_version_incremental")
- ShellUtils.execRootCmd("setprop ro.build.fingerprint $ro_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint $ro_odm_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.product.build.fingerprint $ro_product_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.system.build.fingerprint $ro_system_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint $ro_system_ext_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint $ro_vendor_build_fingerprint")
- ShellUtils.execRootCmd("setprop ro.board.platform $ro_build_platform")
-
- // Native.setBootId(bootId);
- // 修改drm id
- ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id $persist_sys_cloud_drm_id")
- // 电量模拟需要大于1000
- ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity $persist_sys_cloud_battery_capacity")
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor $persist_sys_cloud_gpu_gl_vendor")
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer $persist_sys_cloud_gpu_gl_renderer")
- // 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version $persist_sys_cloud_gpu_gl_version")
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor $persist_sys_cloud_gpu_egl_vendor")
- ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version $persist_sys_cloud_gpu_egl_version")
- } catch (e: Throwable) {
- LogUtils.e(
- Log.ERROR,
- "ChangeDeviceInfoUtil",
- "Error occurred in changeDeviceInfo",
- e
- )
- throw RuntimeException("Error occurred in changeDeviceInfo", e)
- }
- afDeviceObject = null
+ if (!ShellUtils.hasRootAccess()) {
+ LogUtils.d(
+ "ERROR",
+ "ChangeDeviceInfoUtil",
+ "Root access is required to execute system property changes"
+ )
}
- } catch (e: Exception) {
- e.printStackTrace()
+ // 设置机型, 直接设置属性
+ ShellUtils.execRootCmd("setprop ro.product.brand ${device.brand}")
+ ShellUtils.execRootCmd("setprop ro.product.model ${device.model}")
+ ShellUtils.execRootCmd("setprop ro.product.manufacturer ${device.manufactor}")
+ ShellUtils.execRootCmd("setprop ro.product.device ${device.device}")
+ ShellUtils.execRootCmd("setprop ro.product.name ${device.expand.roProductName}")
+ ShellUtils.execRootCmd("setprop ro.build.version.incremental ${device.expand.incremental}")
+ ShellUtils.execRootCmd("setprop ro.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.product.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.system.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
+ ShellUtils.execRootCmd("setprop ro.board.platform ${device.expand.roBoardPlatform}")
+
+ // 修改drm id
+// ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id $persist_sys_cloud_drm_id")
+ // 电量模拟需要大于1000
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity ${device.battery}")
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor ${device.expand.glVendor}")
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer ${device.expand.glRenderer}")
+ // 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
+ ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version ${device.expand.glVersion}")
+// ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor $persist_sys_cloud_gpu_egl_vendor")
+// ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version $persist_sys_cloud_gpu_egl_version")
+ } catch (e: Throwable) {
+ LogUtils.e(
+ Log.ERROR,
+ "ChangeDeviceInfoUtil",
+ "Error occurred while changing device info",
+ e
+ )
+ throw RuntimeException("Error occurred in changeDeviceInfo", e)
}
+
}
- private fun callVCloudSettings_put(key: String?, value: String?, context: Context?) {
- if (context == null) {
- LogUtils.e(Log.ERROR, "ChangeDeviceInfoUtil", "Context cannot be null", null)
- throw IllegalArgumentException("Context cannot be null")
- }
- if (key == null || key.isEmpty()) {
+ private fun vcloudsettingsPut(key: String?, value: String?, context: Context) {
+ if (key.isNullOrEmpty()) {
LogUtils.e(Log.ERROR, "ChangeDeviceInfoUtil", "Key cannot be null or empty", null)
throw IllegalArgumentException("Key cannot be null or empty")
}
@@ -350,15 +171,11 @@ object ChangeDeviceInfoUtil {
Log.d("Debug", "putString executed successfully.")
} catch (e: ClassNotFoundException) {
LogUtils.e(
- Log.WARN,
- "ChangeDeviceInfoUtil",
"Class not found: android.provider.VCloudSettings\$Global. This may not be supported on this device.",
e
)
} catch (e: NoSuchMethodException) {
LogUtils.e(
- Log.WARN,
- "ChangeDeviceInfoUtil",
"Method not found: android.provider.VCloudSettings\$Global.putString. This may not be supported on this",
e
)
@@ -366,23 +183,17 @@ object ChangeDeviceInfoUtil {
val cause = e.targetException
if (cause is SecurityException) {
LogUtils.e(
- Log.ERROR,
- "ChangeDeviceInfoUtil",
"Error occurred in changeDeviceInfo",
cause
)
} else {
LogUtils.e(
- Log.ERROR,
- "ChangeDeviceInfoUtil",
"Error occurred in changeDeviceInfo",
cause
)
}
} catch (e: Exception) {
LogUtils.e(
- Log.ERROR,
- "ChangeDeviceInfoUtil",
"Unexpected error during putString invocation",
e
)
diff --git a/app/src/main/java/com/android/grape/util/ClashUtil.kt b/app/src/main/java/com/android/grape/util/ClashUtil.kt
index c0bc5f1..72c3bfd 100644
--- a/app/src/main/java/com/android/grape/util/ClashUtil.kt
+++ b/app/src/main/java/com/android/grape/util/ClashUtil.kt
@@ -77,9 +77,19 @@ object ClashUtil {
}
fun unregisterReceiver(context: Context) {
- context.unregisterReceiver(clashStatusReceiver)
+ try {
+ context.unregisterReceiver(clashStatusReceiver)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
}
+ fun getRandomLocale(): String {
+ val locales = listOf("ru", "us")
+ return locales.random()
+ }
+
+
fun switchProxyGroup(groupName: String?, proxyName: String?, controllerUrl: String) {
if (groupName == null || groupName.trim { it <= ' ' }
.isEmpty() || proxyName == null || proxyName.trim { it <= ' ' }.isEmpty()) {
diff --git a/app/src/main/java/com/android/grape/util/GsonUtils.kt b/app/src/main/java/com/android/grape/util/GsonUtils.kt
new file mode 100644
index 0000000..e094dee
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/GsonUtils.kt
@@ -0,0 +1,72 @@
+package com.android.grape.util
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonObject
+import com.google.gson.reflect.TypeToken
+import java.lang.reflect.Type
+import java.util.*
+
+object GsonUtils {
+ // 可配置的Gson实例
+ private val gson: Gson by lazy {
+ GsonBuilder()
+// .setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+ .create()
+ }
+
+ // 自定义Gson实例
+ private val customGson = mutableMapOf()
+
+ /**
+ * 通用转换函数
+ * @param json JsonObject
+ * @param clazz 目标类型
+ */
+ fun fromJsonObject(json: String, clazz: Class): T {
+ return gson.fromJson(json, clazz)
+ }
+
+ /**
+ * 通用转换函数(带泛型)
+ * @param json JsonObject
+ * @param typeToken 类型Token
+ */
+ fun fromJsonObject(json: JsonObject, typeToken: TypeToken): T {
+ return gson.fromJson(json, typeToken.type)
+ }
+
+ /**
+ * 使用自定义适配器转换
+ * @param json JsonObject
+ * @param clazz 目标类型
+ * @param adapters 适配器列表
+ */
+ @RequiresApi(Build.VERSION_CODES.P)
+ fun fromJsonObject(
+ json: JsonObject,
+ clazz: Class,
+ vararg adapters: Pair
+ ): T {
+ val gsonKey = clazz.name + adapters.joinToString { it.first.typeName }
+ val customGsonInstance = customGson[gsonKey] ?: buildCustomGson(adapters).also {
+ customGson[gsonKey] = it
+ }
+
+ return customGsonInstance.fromJson(json, clazz)
+ }
+
+ private fun buildCustomGson(adapters: Array>): Gson {
+ val builder = GsonBuilder()
+ adapters.forEach { (type, adapter) ->
+ when (adapter) {
+ is JsonDeserializer<*> -> builder.registerTypeAdapter(type, adapter)
+ else -> throw IllegalArgumentException("Unsupported adapter type")
+ }
+ }
+ return builder.create()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/util/HttpUtil.java b/app/src/main/java/com/android/grape/util/HttpUtil.java
new file mode 100644
index 0000000..97a420a
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/HttpUtil.java
@@ -0,0 +1,49 @@
+package com.android.grape.util;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.blankj.utilcode.util.LogUtils;
+
+import org.json.JSONObject;
+
+import java.nio.charset.StandardCharsets;
+
+public class HttpUtil {
+
+ public static void execReloginTask(Context context) {
+ String url = "http://39.103.73.250/tt/ddj/preRequest!requestRelogin.do";
+ String ANDROID_ID = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
+ String params = "platform=Android&tag=" + "119" + "&uuid=" + ANDROID_ID;
+ System.out.println("IOSTQ:execReloginTask->url:" + url + "?" + params);
+ try {
+
+ String result = new MyPost().PostData(context, " ".getBytes(StandardCharsets.UTF_8), url + "?" + params);
+
+ LogUtils.e("request result : " + result);
+
+ } catch (Exception e) {
+ Log.i("TAG", "execTask error:" + e.getMessage());
+ }
+ }
+
+ public static void execInstallTask(Context context) {
+ String url = "http://39.103.73.250/tt/ddj/preRequest!requestInstall.do";
+
+ String ANDROID_ID = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
+
+ String params = "platform=Android&tag=" + "119" + "&uuid=" + ANDROID_ID;
+ LogUtils.e("IOSTQ:request result : " + url + "?" + params);
+ try {
+
+ String result = new MyPost().PostData(context, " ".getBytes("utf-8"), url + "?" + params);
+
+ LogUtils.e("request result : " + result);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ LogUtils.i("TAG", "execTask error:" + e.getMessage());
+ }
+ }
+}
diff --git a/app/src/main/java/com/android/grape/util/MyPost.java b/app/src/main/java/com/android/grape/util/MyPost.java
new file mode 100644
index 0000000..fb058be
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/MyPost.java
@@ -0,0 +1,168 @@
+package com.android.grape.util;
+
+import android.content.Context;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class MyPost {
+
+ private static final String TAG = "MyPost";
+// private static final String TAG = TT.dd("4B7HyaIsVcs=");
+
+ private static okhttp3.OkHttpClient oklient = new okhttp3.OkHttpClient();
+
+ public String PostData(Context context, byte[] byt, String url_) {
+
+ byte[] bytes = postDataBytes(context, byt, url_);
+
+ if (bytes != null && bytes.length > 0) {
+
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ return null;
+ }
+
+ public String PostDataCommon(Context context, byte[] byt, String url_) {
+ byte[] bytes = postDataBytes(context, byt, url_);
+
+ if (bytes != null && bytes.length >= 0) {
+ if (bytes.length == 0) {
+ return "";
+ } else {
+ try {
+ return new String(bytes, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+
+ public String httpGet(String url) throws Exception {
+
+ URL obj = new URL(url);
+ HttpURLConnection con = (HttpURLConnection) obj.openConnection();
+
+ //默认值我GET
+ con.setRequestMethod("GET");
+
+ int responseCode = con.getResponseCode();
+ System.out.println("\nSending 'GET' request to URL : " + url);
+ System.out.println("Response Code : " + responseCode);
+
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(con.getInputStream()));
+ String inputLine;
+ StringBuffer response = new StringBuffer();
+
+ while ((inputLine = in.readLine()) != null) {
+ response.append(inputLine);
+ }
+ in.close();
+
+ //打印结果
+ System.out.println(response.toString());
+ return response.toString();
+
+ }
+
+ public byte[] postDataBytes(Context context, byte[] byt, String url_) {
+ String result = null;
+ HttpURLConnection httpUrlConnection = null;
+ InputStream inStrm = null;
+ ByteArrayOutputStream baos = null;
+ BufferedInputStream bis = null;
+
+ try {
+ httpUrlConnection = NetWorkUtils.getHttpURLConnection(context, url_);
+
+ httpUrlConnection.setAllowUserInteraction(true);
+ httpUrlConnection.setDoOutput(true);
+ httpUrlConnection.setDoInput(true);
+ httpUrlConnection.setUseCaches(false);
+ httpUrlConnection.setRequestProperty("Connection", "close");//add 20200428
+ httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
+// httpUrlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ httpUrlConnection.setRequestMethod("POST");
+ httpUrlConnection.setConnectTimeout(20000);
+ OutputStream outStrm = null;
+
+
+ outStrm = httpUrlConnection.getOutputStream();
+
+
+ outStrm.write(byt);
+ outStrm.flush();
+ outStrm.close();
+
+ inStrm = httpUrlConnection.getInputStream();
+
+ baos = new ByteArrayOutputStream();
+
+ bis = new BufferedInputStream(inStrm);
+ byte[] buf = new byte[1024];
+ int readSize = -1;
+
+ while ((readSize = bis.read(buf)) != -1) {
+ baos.write(buf, 0, readSize);
+ }
+
+ byte[] data = baos.toByteArray();
+
+ return data;
+ } catch (Exception e) {
+ e.printStackTrace();
+ result = null;
+ } finally {
+
+ if (baos != null) {
+ try {
+ baos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (bis != null) {
+ try {
+ bis.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (inStrm != null) {
+ try {
+ inStrm.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (httpUrlConnection != null) {
+ httpUrlConnection.disconnect();
+ httpUrlConnection = null;
+ }
+
+ System.gc();
+ }
+
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/android/grape/util/NetWorkUtils.java b/app/src/main/java/com/android/grape/util/NetWorkUtils.java
new file mode 100644
index 0000000..27a82d4
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/NetWorkUtils.java
@@ -0,0 +1,27 @@
+package com.android.grape.util;
+
+import android.content.Context;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class NetWorkUtils {
+
+ public static HttpURLConnection getHttpURLConnection(Context context,
+ String _url) throws IOException {
+ return getHttpURLConnection(context, _url, false);
+ }
+
+ private static int dynamicPort0 = 20380;
+
+ public static HttpURLConnection getHttpURLConnection(Context context, String _url, boolean isProxy) throws IOException {
+ URL url = new URL(_url);
+
+ HttpURLConnection httpUrlConnection = null;
+
+ httpUrlConnection = (HttpURLConnection)url.openConnection();
+ return httpUrlConnection;
+ }
+
+}
diff --git a/app/src/main/java/com/android/grape/util/NotificationPermissionHelper.kt b/app/src/main/java/com/android/grape/util/NotificationPermissionHelper.kt
new file mode 100644
index 0000000..233c1d9
--- /dev/null
+++ b/app/src/main/java/com/android/grape/util/NotificationPermissionHelper.kt
@@ -0,0 +1,309 @@
+package com.android.grape.util
+
+import android.Manifest
+import android.app.NotificationManager
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.RequiresApi
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.ContextCompat
+
+/**
+ * 通知权限管理工具
+ *
+ * 使用示例:
+ *
+ * class MainActivity : AppCompatActivity() {
+ * private lateinit var permissionHandler: NotificationPermissionHandler
+ *
+ * override fun onCreate(savedInstanceState: Bundle?) {
+ * super.onCreate(savedInstanceState)
+ *
+ * // 初始化权限处理器
+ * permissionHandler = NotificationPermissionHandler(this, ::onPermissionResult)
+ *
+ * // 检查通知权限
+ * if (permissionHandler.shouldRequestNotificationPermission()) {
+ * permissionHandler.requestNotificationPermission()
+ * }
+ * }
+ *
+ * override fun onResume() {
+ * super.onResume()
+ * // 处理从设置返回的情况
+ * permissionHandler.handleReturnFromSettings()
+ * }
+ *
+ * // 权限回调处理
+ * private fun onPermissionResult(result: PermissionResult) {
+ * when(result) {
+ * PermissionResult.GRANTED -> showNotification()
+ * PermissionResult.DENIED -> showRationale()
+ * PermissionResult.NEEDS_SETTINGS -> showSettingsGuide()
+ * PermissionResult.NOT_NEEDED -> showNotification()
+ * }
+ * }
+ * }
+ */
+class NotificationPermissionHandler(
+ private val context: Context,
+ private val callback: (PermissionResult) -> Unit
+) {
+ // Android 13+ 通知权限请求启动器
+ private var permissionLauncher: ActivityResultLauncher? = null
+
+ // 请求状态跟踪
+ private var permissionRequestPending = false
+ private var lastPermissionState = false
+
+ // 用于跟踪从设置页面返回的状态
+ private var returnFromSettings = false
+
+ init {
+ registerPermissionLauncherIfNeeded()
+ }
+
+ /**
+ * 检查是否需要请求通知权限
+ */
+ fun shouldRequestNotificationPermission(): Boolean {
+ return !areNotificationsEnabled()
+ }
+
+ /**
+ * 检查通知权限是否已授予
+ */
+ fun areNotificationsEnabled(): Boolean {
+ return when {
+ // Android 13+ (TIRAMISU) 需要运行时权限
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
+ ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+ // Android 8.0+ (Oreo) 检查通知设置
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
+ NotificationManagerCompat.from(context).areNotificationsEnabled()
+ }
+ // Android 7.1 及以下不需要特别权限
+ else -> true
+ }
+ }
+
+ /**
+ * 请求通知权限
+ */
+ fun requestNotificationPermission() {
+ // 保存当前权限状态,用于比较设置后是否发生变化
+ lastPermissionState = areNotificationsEnabled()
+
+ when {
+ // Android 13+ - 使用运行时权限请求
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
+ requestPermissionApi33()
+ }
+ // Android 8.0-12 - 跳转到应用通知设置
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
+ openNotificationSettings()
+ permissionRequestPending = true
+ }
+ // Android 7.1 及以下 - 默认启用
+ else -> {
+ callback(PermissionResult.NOT_NEEDED)
+ }
+ }
+ }
+
+ /**
+ * 处理从设置页面返回的情况
+ * 应在Activity的onResume中调用
+ */
+ fun handleReturnFromSettings() {
+ if (returnFromSettings) {
+ returnFromSettings = false
+ checkSettingsChanged()
+ }
+ }
+
+ /**
+ * 打开应用的通知设置页面
+ */
+ fun openNotificationSettings() {
+ val intent = when {
+ // Android 8.0及以上
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
+ Intent().apply {
+ action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
+ putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
+
+ // 处理特定设备需要额外设置的情况
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ putExtra(Settings.EXTRA_CHANNEL_ID, context.applicationInfo.uid)
+ }
+ }
+ }
+ // Android 7.1及以下
+ else -> {
+ Intent().apply {
+ action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+ addCategory(Intent.CATEGORY_DEFAULT)
+ data = Uri.parse("package:${context.packageName}")
+ }
+ }
+ }
+
+ if (context is AppCompatActivity) {
+ returnFromSettings = true
+ context.startActivity(intent)
+ }
+ }
+
+ /**
+ * 显示权限解释对话框
+ */
+ fun showPermissionRationaleDialog() {
+ if (context !is AppCompatActivity) return
+
+ val activity = context as AppCompatActivity
+
+ AlertDialog.Builder(activity)
+ .setTitle("需要通知权限")
+ .setMessage("我们需要通知权限来向你发送重要信息、更新提醒等内容。请允许通知权限以使用完整功能。")
+ .setPositiveButton("确定") { _, _ ->
+ requestNotificationPermission()
+ }
+ .setNegativeButton("取消", null)
+ .show()
+ }
+
+ // 私有方法 --------------------------------------------
+
+ /**
+ * Android 13+ 权限请求处理
+ */
+ @RequiresApi(33)
+ private fun requestPermissionApi33() {
+ if (permissionLauncher == null) {
+ throw IllegalStateException("Permission launcher not registered. Call registerPermissionLauncherIfNeeded() first.")
+ }
+
+ val activity = context as? AppCompatActivity ?: return
+
+ when {
+ // 已经拥有权限
+ areNotificationsEnabled() -> {
+ callback(PermissionResult.GRANTED)
+ }
+ // 需要显示权限解释
+ ActivityCompat.shouldShowRequestPermissionRationale(
+ activity,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) -> {
+ showPermissionRationaleDialog()
+ }
+ // 请求权限
+ else -> {
+ permissionRequestPending = true
+ permissionLauncher?.launch(Manifest.permission.POST_NOTIFICATIONS)
+ }
+ }
+ }
+
+ /**
+ * 注册权限启动器(仅Android 13+需要)
+ */
+ private fun registerPermissionLauncherIfNeeded() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
+ if (context !is AppCompatActivity) return
+
+ val activity = context as AppCompatActivity
+
+ permissionLauncher = activity.registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted ->
+ if (isGranted) {
+ callback(PermissionResult.GRANTED)
+ } else {
+ // 如果用户勾选了"不再询问"
+ if (!ActivityCompat.shouldShowRequestPermissionRationale(
+ activity,
+ Manifest.permission.POST_NOTIFICATIONS
+ )) {
+ callback(PermissionResult.NEEDS_SETTINGS)
+ } else {
+ callback(PermissionResult.DENIED)
+ }
+ }
+ permissionRequestPending = false
+ }
+ }
+
+ /**
+ * 检查设置页面返回后的权限变化
+ */
+ private fun checkSettingsChanged() {
+ if (!permissionRequestPending) return
+
+ permissionRequestPending = false
+
+ val currentState = areNotificationsEnabled()
+ when {
+ currentState -> callback(PermissionResult.GRANTED)
+ currentState != lastPermissionState -> callback(PermissionResult.DENIED)
+ // 状态未改变
+ else -> Unit // 无操作
+ }
+ }
+
+ /**
+ * 权限请求结果枚举
+ */
+ enum class PermissionResult {
+ GRANTED, // 权限已授予
+ DENIED, // 权限被拒绝
+ NEEDS_SETTINGS, // 需要跳转到设置
+ NOT_NEEDED // 不需要权限(Android 7.1及以下)
+ }
+
+ companion object {
+ /**
+ * 快速检查当前设备的通知权限状态
+ */
+ @JvmStatic
+ fun checkPermissionState(context: Context): PermissionResult {
+ return when {
+ // Android 13+ 需要运行时权限
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
+ if (ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED) {
+ PermissionResult.GRANTED
+ } else {
+ PermissionResult.DENIED
+ }
+ }
+ // Android 8.0+ 检查通知设置
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
+ if (NotificationManagerCompat.from(context).areNotificationsEnabled()) {
+ PermissionResult.GRANTED
+ } else {
+ PermissionResult.NEEDS_SETTINGS
+ }
+ }
+ // Android 7.1 及以下默认启用通知
+ else -> PermissionResult.NOT_NEEDED
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/android/grape/util/Util.kt b/app/src/main/java/com/android/grape/util/Util.kt
index e9b0787..647498c 100644
--- a/app/src/main/java/com/android/grape/util/Util.kt
+++ b/app/src/main/java/com/android/grape/util/Util.kt
@@ -696,7 +696,7 @@ object Util {
val valid = false
println("IOSTQ:execReloginTask->url:$url?$params")
try {
- val result: String? = MyPost.postData(" ".toByteArray(charset("utf-8")),
+ val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
"$url?$params"
)
@@ -748,7 +748,7 @@ object Util {
// boolean valid = false;
printStr("IOSTQ:request result : $url?$params")
try {
- val result: String? = MyPost.postData(" ".toByteArray(charset("utf-8")),
+ val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
"$url?$params"
)
@@ -2394,7 +2394,7 @@ object Util {
// Log.i(TAG, "setFinish");
MonitorService.setRunning(false)
- killRecordProcess(context, "com.tunnelworkshop.postern")
+// killRecordProcess(context, "com.tunnelworkshop.postern")
killRecordProcess(context, AUTO_JSPACKAGENAME)
Handler(Looper.getMainLooper()).postDelayed(Runnable {
MonitorService.onEvent(
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..d092877
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+ 127.0.0.1
+
+
\ No newline at end of file