改机参数新增
This commit is contained in:
parent
0239820321
commit
e2800ffe8e
|
@ -48,6 +48,11 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AndroidGrape"
|
||||
tools:targetApi="31">
|
||||
<provider
|
||||
android:name=".provider.DeviceInfoProvider"
|
||||
android:authorities="com.android.grape.deviceinfo.provider"
|
||||
android:exported="true">
|
||||
</provider>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
|
|
|
@ -13,6 +13,8 @@ import androidx.core.view.ViewCompat
|
|||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.android.grape.databinding.ActivityMainBinding
|
||||
import com.android.grape.job.MonitorService
|
||||
import com.android.grape.provider.DeviceDataAccessor
|
||||
import com.android.grape.provider.DeviceInfoHelper
|
||||
import com.android.grape.util.ClashUtil
|
||||
import com.android.grape.util.MockTools
|
||||
import com.android.grape.util.NotificationPermissionHandler
|
||||
|
@ -22,6 +24,7 @@ import com.android.grape.util.StoragePermissionHelper
|
|||
import com.android.grape.util.Util
|
||||
import com.android.grape.util.Util.AUTO_JSPACKAGENAME
|
||||
import com.android.grape.util.Util.killRecordProcess
|
||||
import com.google.gson.Gson
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
|
@ -42,9 +45,13 @@ class MainActivity : AppCompatActivity() {
|
|||
ScriptUtil.registerScriptResultReceiver()
|
||||
viewBinding.start.setOnClickListener {
|
||||
MonitorService.onEvent(MainApplication.instance)
|
||||
// DeviceDataAccessor.saveDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
|
||||
}
|
||||
viewBinding.stop.setOnClickListener {
|
||||
killRecordProcess(this, packageName)
|
||||
// DeviceDataAccessor.deleteDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
|
||||
// val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
|
||||
// Log.d("TAG", "onCreate: ${Gson().toJson(deviceInfo?:"")}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.android.grape.data
|
|||
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
data class Device(
|
||||
var advertiserId: String = "",
|
||||
|
@ -110,4 +112,32 @@ data class Device(
|
|||
var vendingVersionName: String = "",
|
||||
@SerializedName("web_ua")
|
||||
var webUa: String = ""
|
||||
)
|
||||
){
|
||||
fun toJson(): String {
|
||||
return JSONObject().apply {
|
||||
put("sensors", JSONArray(sensor))
|
||||
put("arch", arch)
|
||||
put("cpu_abi", cpuAbi)
|
||||
put("cpu_abi2", cpuAbi2)
|
||||
put("size", dim.size)
|
||||
put("xdp", dim.xdp)
|
||||
put("ydp", dim.ydp)
|
||||
put("y_px", dim.yPx)
|
||||
put("x_px", dim.xPx)
|
||||
put("d_dpi", dim.dDpi)
|
||||
put("btch", btch)
|
||||
put("btl", batteryLevel)
|
||||
put("disk", disk)
|
||||
put("sdk", sdk)
|
||||
put("network", network)
|
||||
put("api_ver", vendingVersionCode)
|
||||
put("api_ver_name", vendingVersionName)
|
||||
put("carrier", carrier)
|
||||
put("product", product)
|
||||
put("last_boot_time", lastBootTime)
|
||||
put("install_source_info", installerPackage)
|
||||
put("advertiserId", advertiserId)
|
||||
}.toString()
|
||||
}
|
||||
|
||||
}
|
|
@ -9,4 +9,6 @@ data class Sensor(
|
|||
var sV: String = "",
|
||||
var sVE: List<Double> = listOf(),
|
||||
var sVS: List<Double> = listOf()
|
||||
)
|
||||
) {
|
||||
companion object
|
||||
}
|
|
@ -15,7 +15,7 @@ class AutoJobService : JobIntentService() {
|
|||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
ScriptUtil.execScript(
|
||||
this@AutoJobService,
|
||||
"/sdcard/autojs/main.js"
|
||||
"/sdcard/script/main.js"
|
||||
)
|
||||
}, 2000L)
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package com.android.grape.provider
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.android.grape.data.Device
|
||||
|
||||
// DeviceDataAccessor.kt
|
||||
object DeviceDataAccessor {
|
||||
|
||||
// 保存设备信息到提供方
|
||||
fun saveDeviceInfo(context: Context, device: Device): Uri? {
|
||||
val resolver = context.contentResolver
|
||||
val actualDeviceId = DeviceInfoHelper.getDeviceId()
|
||||
|
||||
val values = ContentValues().apply {
|
||||
put(DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID, actualDeviceId)
|
||||
put(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA, device.toJson())
|
||||
}
|
||||
|
||||
// 尝试更新现有记录
|
||||
val updateCount = resolver.update(
|
||||
getDeviceUri(actualDeviceId),
|
||||
values,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
// 如果没有更新记录,则插入新记录
|
||||
return if (updateCount == 0) {
|
||||
resolver.insert(DeviceInfoContract.CONTENT_URI, values)
|
||||
} else {
|
||||
getDeviceUri(actualDeviceId)
|
||||
}
|
||||
}
|
||||
|
||||
// 读取设备信息
|
||||
fun getDeviceInfo(context: Context, deviceId: String? = null): String? {
|
||||
val resolver = context.contentResolver
|
||||
val actualDeviceId = deviceId ?: DeviceInfoHelper.getDeviceId()
|
||||
|
||||
val cursor = resolver.query(
|
||||
getDeviceUri(actualDeviceId),
|
||||
arrayOf(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
return cursor?.use {
|
||||
if (it.moveToFirst()) {
|
||||
val json =
|
||||
it.getString(it.run { it.getColumnIndex(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA) })
|
||||
json
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有设备信息
|
||||
fun getAllDeviceInfo(context: Context): List<String> {
|
||||
val resolver = context.contentResolver
|
||||
val deviceList = mutableListOf<String>()
|
||||
|
||||
resolver.query(
|
||||
DeviceInfoContract.CONTENT_URI,
|
||||
arrayOf(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA),
|
||||
null,
|
||||
null,
|
||||
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP} DESC"
|
||||
)?.use { cursor ->
|
||||
val dataIndex = cursor.getColumnIndex(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA)
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
val json = cursor.getString(dataIndex)
|
||||
deviceList.add(json)
|
||||
}
|
||||
}
|
||||
|
||||
return deviceList
|
||||
}
|
||||
|
||||
// 删除设备信息
|
||||
fun deleteDeviceInfo(context: Context, deviceId: String? = null): Int {
|
||||
val actualDeviceId = deviceId ?: DeviceInfoHelper.getDeviceId()
|
||||
return context.contentResolver.delete(
|
||||
getDeviceUri(actualDeviceId),
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun getDeviceUri(deviceId: String): Uri {
|
||||
return Uri.withAppendedPath(
|
||||
DeviceInfoContract.CONTENT_URI,
|
||||
"device/$deviceId"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.android.grape.provider
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
|
||||
object DeviceInfoContract {
|
||||
const val AUTHORITY = "com.android.grape.deviceinfo.provider"
|
||||
val CONTENT_URI: Uri = "content://$AUTHORITY/device_info".toUri()
|
||||
|
||||
object DeviceInfoEntry {
|
||||
const val TABLE_NAME = "device_info"
|
||||
const val COLUMN_DEVICE_ID = "device_id"
|
||||
const val COLUMN_DATA = "data"
|
||||
const val COLUMN_TIMESTAMP = "timestamp"
|
||||
|
||||
// JSON 键名
|
||||
const val KEY_CPU_ABI = "cpu_abi"
|
||||
const val KEY_DIM = "dim"
|
||||
const val KEY_BTCH = "btch"
|
||||
const val KEY_ARCH = "arch"
|
||||
const val KEY_BTL = "btl"
|
||||
const val KEY_CPU_ABI2 = "cpu_abi2"
|
||||
const val KEY_DISK = "disk"
|
||||
const val KEY_SDK = "sdk"
|
||||
const val KEY_NETWORK = "network"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.android.grape.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import android.provider.BaseColumns
|
||||
|
||||
class DeviceInfoDbHelper(context: Context) : SQLiteOpenHelper(
|
||||
context, DATABASE_NAME, null, DATABASE_VERSION
|
||||
) {
|
||||
companion object {
|
||||
const val DATABASE_NAME = "device_info.db"
|
||||
const val DATABASE_VERSION = 1
|
||||
|
||||
const val SQL_CREATE_ENTRIES = """
|
||||
CREATE TABLE ${DeviceInfoContract.DeviceInfoEntry.TABLE_NAME} (
|
||||
${BaseColumns._ID} INTEGER PRIMARY KEY,
|
||||
${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} TEXT UNIQUE,
|
||||
${DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA} TEXT NOT NULL,
|
||||
${DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP} INTEGER NOT NULL DEFAULT (strftime('%s','now'))
|
||||
)
|
||||
"""
|
||||
}
|
||||
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.execSQL(SQL_CREATE_ENTRIES)
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("DROP TABLE IF EXISTS ${DeviceInfoContract.DeviceInfoEntry.TABLE_NAME}")
|
||||
onCreate(db)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.android.grape.provider
|
||||
|
||||
object DeviceInfoHelper {
|
||||
// 获取设备唯一ID
|
||||
fun getDeviceId(): String {
|
||||
return "d1b3e7f8c9a04b8e9f2c1d5e6f7a8b9c"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package com.android.grape.provider
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.content.UriMatcher
|
||||
import android.database.Cursor
|
||||
import android.database.sqlite.SQLiteQueryBuilder
|
||||
import android.net.Uri
|
||||
import android.provider.BaseColumns
|
||||
import java.sql.SQLException
|
||||
|
||||
// DeviceInfoProvider.kt
|
||||
class DeviceInfoProvider : ContentProvider() {
|
||||
private lateinit var dbHelper: DeviceInfoDbHelper
|
||||
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
|
||||
addURI(DeviceInfoContract.AUTHORITY, "device_info", 1)
|
||||
addURI(DeviceInfoContract.AUTHORITY, "device_info/#", 2)
|
||||
addURI(DeviceInfoContract.AUTHORITY, "device_info/device/*", 3)
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean {
|
||||
dbHelper = DeviceInfoDbHelper(context!!)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? {
|
||||
val db = dbHelper.readableDatabase
|
||||
val qb = SQLiteQueryBuilder().apply {
|
||||
tables = DeviceInfoContract.DeviceInfoEntry.TABLE_NAME
|
||||
}
|
||||
|
||||
when (uriMatcher.match(uri)) {
|
||||
1 -> {} // 查询所有
|
||||
2 -> qb.appendWhere("${BaseColumns._ID} = ${uri.lastPathSegment}")
|
||||
3 -> qb.appendWhere("${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = '${uri.lastPathSegment}'")
|
||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||
}
|
||||
|
||||
return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder).apply {
|
||||
setNotificationUri(context!!.contentResolver, uri)
|
||||
}
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? {
|
||||
val db = dbHelper.writableDatabase
|
||||
val now = System.currentTimeMillis() / 1000
|
||||
|
||||
// 添加时间戳
|
||||
values?.put(DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP, now)
|
||||
|
||||
val rowId = db.insert(DeviceInfoContract.DeviceInfoEntry.TABLE_NAME, null, values)
|
||||
|
||||
if (rowId > 0) {
|
||||
val newUri = ContentUris.withAppendedId(DeviceInfoContract.CONTENT_URI, rowId)
|
||||
context?.contentResolver?.notifyChange(newUri, null)
|
||||
return newUri
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?
|
||||
): Int {
|
||||
val db = dbHelper.writableDatabase
|
||||
val now = System.currentTimeMillis() / 1000
|
||||
|
||||
// 更新时间戳
|
||||
values?.put(DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP, now)
|
||||
|
||||
val count = when (uriMatcher.match(uri)) {
|
||||
1 -> db.update(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
values, selection, selectionArgs
|
||||
)
|
||||
2 -> {
|
||||
val id = uri.lastPathSegment
|
||||
db.update(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
values,
|
||||
"${BaseColumns._ID} = ?",
|
||||
arrayOf(id)
|
||||
)
|
||||
}
|
||||
3 -> {
|
||||
val deviceId = uri.lastPathSegment
|
||||
db.update(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
values,
|
||||
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = ?",
|
||||
arrayOf(deviceId)
|
||||
)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||
}
|
||||
|
||||
context?.contentResolver?.notifyChange(uri, null)
|
||||
return count
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
|
||||
val db = dbHelper.writableDatabase
|
||||
|
||||
val count = when (uriMatcher.match(uri)) {
|
||||
1 -> db.delete(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
selection, selectionArgs
|
||||
)
|
||||
2 -> {
|
||||
val id = uri.lastPathSegment
|
||||
db.delete(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
"${BaseColumns._ID} = ?",
|
||||
arrayOf(id)
|
||||
)
|
||||
}
|
||||
3 -> {
|
||||
val deviceId = uri.lastPathSegment
|
||||
db.delete(
|
||||
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
|
||||
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = ?",
|
||||
arrayOf(deviceId)
|
||||
)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||
}
|
||||
|
||||
context?.contentResolver?.notifyChange(uri, null)
|
||||
return count
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
return when (uriMatcher.match(uri)) {
|
||||
1 -> "${DeviceInfoContract.AUTHORITY}/device_info"
|
||||
2, 3 -> "vnd.android.cursor.item/vnd.example.deviceinfo"
|
||||
else -> throw IllegalArgumentException("Unknown URI: $uri")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import com.android.grape.MainApplication
|
|||
import com.android.grape.data.Device
|
||||
import com.android.grape.net.Api
|
||||
import com.android.grape.net.ChangeCallBack
|
||||
import com.android.grape.provider.DeviceDataAccessor
|
||||
import com.android.grape.util.Util.paramsJson
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -28,6 +29,7 @@ object ChangeDeviceInfoUtil {
|
|||
return
|
||||
}
|
||||
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
|
||||
DeviceDataAccessor.saveDeviceInfo(MainApplication.instance, device)
|
||||
val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code")
|
||||
Log.d("TAG", "changeDevice: $padCode")
|
||||
val jsonString = JSONObject().apply {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.android.grape.util
|
||||
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.BufferedReader
|
||||
|
@ -16,6 +18,7 @@ import java.io.InputStreamReader
|
|||
import java.io.OutputStream
|
||||
import java.io.RandomAccessFile
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.Enumeration
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
@ -387,4 +390,31 @@ object FileUtils {
|
|||
output.close()
|
||||
input.close()
|
||||
}
|
||||
|
||||
fun writePackageName(packageName: String) {
|
||||
val file = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
"script/packagesname.txt"
|
||||
)
|
||||
val parentDir = file.getParentFile()
|
||||
if (parentDir != null && !parentDir.exists()) {
|
||||
val dirsCreated = parentDir.mkdirs()
|
||||
if (!dirsCreated) {
|
||||
Log.e("FileWrite", "Failed to create directories: $parentDir")
|
||||
return
|
||||
}
|
||||
}
|
||||
LogUtils.d("TAG", "writePackageName: $packageName", null)
|
||||
try {
|
||||
BufferedOutputStream(
|
||||
FileOutputStream(file)
|
||||
).use { bos ->
|
||||
bos.write(packageName.toByteArray(StandardCharsets.UTF_8))
|
||||
bos.flush() // 确保数据写入磁盘
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("FileWrite", "Failed to write package name: $packageName", e)
|
||||
// 6. 可以考虑添加重试机制或通知用户
|
||||
}
|
||||
}
|
||||
}
|
|
@ -185,9 +185,9 @@ public class ShellUtils {
|
|||
|
||||
public static void execRootCmd(String cmd) {
|
||||
// 校验命令是否安全
|
||||
if (!isCommandSafe(cmd)) {
|
||||
return;
|
||||
}
|
||||
// if (!isCommandSafe(cmd)) {
|
||||
// return;
|
||||
// }
|
||||
List<String> cmds = new ArrayList<>();
|
||||
cmds.add(cmd);
|
||||
|
||||
|
|
|
@ -1140,7 +1140,7 @@ object Util {
|
|||
return false
|
||||
}
|
||||
|
||||
unzipAPkSh(script_path, "/sdcard/autojs/")
|
||||
unzipAPkSh(script_path, "/sdcard/script/")
|
||||
delFileSh(script_path)
|
||||
}
|
||||
return isDownload
|
||||
|
@ -2571,9 +2571,9 @@ object Util {
|
|||
*/
|
||||
//当本应用位于后台时,则将它切换到最前端
|
||||
fun setTopApp(context: Context) {
|
||||
// Log.i(TAG, "start to setTopApp");
|
||||
Log.i(TAG, "start to setTopApp");
|
||||
if (isRunningForeground(context)) {
|
||||
// Log.i(TAG, "app isRunningForeground");
|
||||
Log.i(TAG, "app isRunningForeground");
|
||||
return;
|
||||
}
|
||||
//获取ActivityManager
|
||||
|
|
Loading…
Reference in New Issue