diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml deleted file mode 100644 index 371f2e2..0000000 --- a/.idea/appInsightsSettings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 57b2461..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index b9d18bf..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml index b838193..64f9316 100644 --- a/.idea/dbnavigator.xml +++ b/.idea/dbnavigator.xml @@ -4,146 +4,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
+ @@ -558,8 +426,4 @@
- - - - \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 2ec1778..b268ef3 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,14 +4,6 @@ diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml deleted file mode 100644 index 02b915b..0000000 --- a/.idea/git_toolbox_prj.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/google-java-format.xml b/.idea/google-java-format.xml deleted file mode 100644 index 2aa056d..0000000 --- a/.idea/google-java-format.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 2a72309..97f0a8e 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,20 +1,17 @@ - diff --git a/.idea/httpRequests/2025-06-21T105829.200.json b/.idea/httpRequests/2025-06-21T105829.200.json deleted file mode 100644 index 0b03c72..0000000 --- a/.idea/httpRequests/2025-06-21T105829.200.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "b3d893cf9de3a85a": [ - "b3d893cf9de3a85a_bin.mt.plus.zip", - "dd597ef6-70c8-4765-94c3-a3262817b94c_b3d893cf9de3a85a_bin.mt.plus.zip" - ] -} diff --git a/.idea/httpRequests/2025-06-21T115835.200.json b/.idea/httpRequests/2025-06-21T115835.200.json deleted file mode 100644 index eb83fe1..0000000 --- a/.idea/httpRequests/2025-06-21T115835.200.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "b3d893cf9de3a85a": [ - "b3d893cf9de3a85a_bin.mt.plus.zip" - ] -} diff --git a/.idea/httpRequests/2025-06-21T122848.200.json b/.idea/httpRequests/2025-06-21T122848.200.json deleted file mode 100644 index 3d9dec4..0000000 --- a/.idea/httpRequests/2025-06-21T122848.200.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "bin.mt.plus": "b3d893cf9de3a85a_bin.mt.plus.zip" -} diff --git a/.idea/httpRequests/2025-06-21T124257.200.json b/.idea/httpRequests/2025-06-21T124257.200.json deleted file mode 100644 index 0967ef4..0000000 --- a/.idea/httpRequests/2025-06-21T124257.200.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/.idea/httpRequests/2025-06-21T132008.200.json b/.idea/httpRequests/2025-06-21T132008.200.json deleted file mode 100644 index 28fe5f1..0000000 --- a/.idea/httpRequests/2025-06-21T132008.200.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "bin.mt.plus": "b3d893cf9de3a85a_bin.mt.plus.zip", - "com.android.chrome": "b3d893cf9de3a85a_com.android.chrome.zip" -} diff --git a/.idea/httpRequests/b3d893cf9de3a85a_bin.mt.plus.zip b/.idea/httpRequests/b3d893cf9de3a85a_bin.mt.plus.zip deleted file mode 100644 index 15cb0ec..0000000 Binary files a/.idea/httpRequests/b3d893cf9de3a85a_bin.mt.plus.zip and /dev/null differ diff --git a/.idea/httpRequests/http-client.cookies b/.idea/httpRequests/http-client.cookies deleted file mode 100644 index edfe326..0000000 --- a/.idea/httpRequests/http-client.cookies +++ /dev/null @@ -1 +0,0 @@ -# domain path name value date diff --git a/.idea/httpRequests/http-requests-log.http b/.idea/httpRequests/http-requests-log.http deleted file mode 100644 index 6e133cf..0000000 --- a/.idea/httpRequests/http-requests-log.http +++ /dev/null @@ -1,108 +0,0 @@ -POST http://47.238.96.231:8112/device_info_upload?id=FyZqWrStUvOpKlMn&taskId=d2fc8ffb-63a7-4c03-ae10-2eeb9ce8c989&deviceIp={"timezone":"America\/Los_Angeles","ip":"74.82.228.84","organization":"AS25764 NWF-IFIBER-ASN-2","asn":25764,"area_code":"0","organization_name":"NWF-IFIBER-ASN-2","country_code":"US","country_code3":"USA","continent_code":"NA","accuracy":50,"region":"Washington","latitude":"47.1285","longitude":"-119.2883","city":"Moses Lake","country":"United States"} - -Content-Type: application/json; charset=utf-8 -Content-Length: 114 -User-Agent: IntelliJ HTTP Client/Android Studio Narwhal | 2025.1.1 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -{ - "bigoDeviceObject": BIGO_DEVICE_OBJECT, - "afDeviceObject": AF_DEVICE_OBJECT, - "other": DEVICE_INFO - } - -<> 2025-07-07T182436.200.json - -### - -POST http://47.238.96.231:8112/device_info_upload?id=FyZqWrStUvOpKlMn&taskId=d2fc8ffb-63a7-4c03-ae10-2eeb9ce8c989&deviceIp={"timezone":"America\/Los_Angeles","ip":"74.82.228.84","organization":"AS25764 NWF-IFIBER-ASN-2","asn":25764,"area_code":"0","organization_name":"NWF-IFIBER-ASN-2","country_code":"US","country_code3":"USA","continent_code":"NA","accuracy":50,"region":"Washington","latitude":"47.1285","longitude":"-119.2883","city":"Moses Lake","country":"United States"} - -Content-Type: application/json; charset=utf-8 -Content-Length: 114 -User-Agent: IntelliJ HTTP Client/Android Studio Narwhal | 2025.1.1 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -{ - "bigoDeviceObject": BIGO_DEVICE_OBJECT, - "afDeviceObject": AF_DEVICE_OBJECT, - "other": DEVICE_INFO - } - -<> 2025-07-07T181724.200.json - -### - -POST http://47.238.96.231:8112/device_info_upload?id=FyZqWrStUvOpKlMn&taskId=d2fc8ffb-63a7-4c03-ae10-2eeb9ce8c989&deviceIp={"timezone":"America\/Los_Angeles","ip":"74.82.228.84","organization":"AS25764 NWF-IFIBER-ASN-2","asn":25764,"area_code":"0","organization_name":"NWF-IFIBER-ASN-2","country_code":"US","country_code3":"USA","continent_code":"NA","accuracy":50,"region":"Washington","latitude":"47.1285","longitude":"-119.2883","city":"Moses Lake","country":"United States"} - -Content-Type: application/json; charset=utf-8 -Content-Length: 114 -User-Agent: IntelliJ HTTP Client/Android Studio Narwhal | 2025.1.1 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -{ - "bigoDeviceObject": BIGO_DEVICE_OBJECT, - "afDeviceObject": AF_DEVICE_OBJECT, - "other": DEVICE_INFO - } - -<> 2025-07-07T181305.200.json - -### - -GET http://47.238.96.231:8112/get_package_info?androidId=b3d893cf9de3a85a -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> 2025-06-21T132008.200.json - -### - -GET http://47.238.96.231:8112/download_code_file?file_name=b3d893cf9de3a85a_bin.mt.plus.zip -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> b3d893cf9de3a85a_bin.mt.plus.zip - -### - -GET http://47.238.96.231:8112/download_code_file?file_name="b3d893cf9de3a85a_bin.mt.plus.zip" -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> 2025-06-21T124257.200.json - -### - -GET http://47.238.96.231:8112/get_package_info?androidId=b3d893cf9de3a85a -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> 2025-06-21T122848.200.json - -### - -GET http://47.238.96.231:8112/get_package_info?androidId=b3d893cf9de3a85a -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> 2025-06-21T115835.200.json - -### - -GET http://47.238.96.231:8112/get_package_info?androidId=b3d893cf9de3a85a -User-Agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.1.2 -Accept-Encoding: br, deflate, gzip, x-gzip -Accept: */* - -<> 2025-06-21T105829.200.json - -### - diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index cf247ce..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 8562ed5..74dd639 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,16 +1,10 @@ + - + - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 2762f2f..7c3c4bc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) } android { @@ -62,6 +63,9 @@ android { path file("src/main/cpp/CMakeLists.txt") } } + kotlinOptions { + jvmTarget = '11' + } applicationVariants.all { variant -> variant.outputs.all { output -> @@ -78,19 +82,20 @@ dependencies { implementation libs.activity implementation libs.constraintlayout implementation libs.play.services.ads.identifier + implementation libs.core.ktx testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core implementation 'androidx.work:work-runtime:2.9.0' // Retrofit 核心库 - implementation 'com.squareup.retrofit2:retrofit:2.9.0' - - // 如果需要用 Gson 作为 JSON 序列化/反序列化工具,还需添加以下依赖 - implementation 'com.squareup.retrofit2:converter-gson:2.9.0' - - // 如果需要 RxJava 支持(可选) - implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' +// implementation 'com.squareup.retrofit2:retrofit:2.9.0' +// +// // 如果需要用 Gson 作为 JSON 序列化/反序列化工具,还需添加以下依赖 +// implementation 'com.squareup.retrofit2:converter-gson:2.9.0' +// +// // 如果需要 RxJava 支持(可选) +// implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' implementation 'org.nanohttpd:nanohttpd:2.3.1' @@ -102,5 +107,9 @@ dependencies { testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-inline:4.8.0' + implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0")) + implementation("com.squareup.okhttp3:okhttp") + implementation("com.squareup.okhttp3:logging-interceptor") + implementation ("com.google.code.gson:gson:2.10.1") } diff --git a/app/src/main/java/com/example/studyapp/MainActivity.java b/app/src/main/java/com/example/studyapp/MainActivity.java index c41c271..6a3354d 100644 --- a/app/src/main/java/com/example/studyapp/MainActivity.java +++ b/app/src/main/java/com/example/studyapp/MainActivity.java @@ -39,8 +39,11 @@ import com.example.studyapp.device.ChangeDeviceInfoUtil; import com.example.studyapp.proxy.ClashUtil; import com.example.studyapp.service.MyAccessibilityService; import com.example.studyapp.task.TaskUtil; +import com.example.studyapp.update.ChangeCallBack; +import com.example.studyapp.update.UpdateUtil; import com.example.studyapp.utils.IpUtil; import com.example.studyapp.utils.LogFileUtil; +import com.example.studyapp.utils.ShellUtils; import com.example.studyapp.worker.CheckAccessibilityWorker; import java.io.IOException; @@ -277,20 +280,35 @@ public class MainActivity extends AppCompatActivity { private void processMainTask(String androidId, String taskId) { try { + ShellUtils.execRootCmdAndGetResult("pm grant com.example.studyapp android.permission.INTERACT_ACROSS_USERS"); + ShellUtils.execRootCmdAndGetResult("pm grant com.example.studyapp android.permission.WRITE_SECURE_SETTINGS"); + ShellUtils.execRootCmdAndGetResult("pm setenforce 0"); initializeDeviceAndRunScript(); processScriptResults(androidId, taskId); } catch (Exception e) { LogFileUtil.logAndWrite(Log.ERROR, TAG, "Unexpected task error", e); } + } private void initializeDeviceAndRunScript() { ChangeDeviceInfoUtil.getAddDeviceInfo(currentCountry.toUpperCase(), DEVICE_TYPE, (bigoDevice, afDevice) -> { startProxyVpn(this); - ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this, - bigoDevice, afDevice); - AutoJsUtil.runAutojsScript(this); + UpdateUtil.INSTANCE.changeDevice(getPackageName(), bigoDevice, afDevice, new ChangeCallBack() { + @Override + public void changeSuccess() { + AutoJsUtil.runAutojsScript(MainActivity.this); + } + + @Override + public void changeFailed() { + LogFileUtil.logAndWrite(Log.ERROR, TAG, "Change device failed", null); + } + }); +// ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this, +// bigoDevice, afDevice); +// AutoJsUtil.runAutojsScript(this); }); AutoJsUtil.registerScriptResultReceiver(this); } @@ -332,15 +350,25 @@ public class MainActivity extends AppCompatActivity { private void updateDeviceAndExecuteTask(String androidId, String taskId, String result, JSONObject bigoDevice, JSONObject afDevice) { startProxyVpn(this); - ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this, bigoDevice, afDevice); - AutoJsUtil.runAutojsScript(this); + UpdateUtil.INSTANCE.changeDevice(result, bigoDevice, afDevice,new ChangeCallBack() { + @Override + public void changeSuccess() { + AutoJsUtil.runAutojsScript(MainActivity.this); + + TaskUtil.execSaveTask(MainActivity.this, androidId, taskId, result, IpUtil.fetchGeoInfo()); + try { + infoUpload(MainActivity.this, androidId, result); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override + public void changeFailed() { + LogFileUtil.logAndWrite(Log.ERROR, TAG, "Change device failed", null); + } + }); +// ChangeDeviceInfoUtil.changeDeviceInfo(result, this, bigoDevice, afDevice); - TaskUtil.execSaveTask(this, androidId, taskId, result, IpUtil.fetchGeoInfo()); - try { - infoUpload(this, androidId, result); - } catch (IOException e) { - throw new RuntimeException(e); - } } diff --git a/app/src/main/java/com/example/studyapp/pad/DcInfo.kt b/app/src/main/java/com/example/studyapp/pad/DcInfo.kt new file mode 100644 index 0000000..83c9c52 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/pad/DcInfo.kt @@ -0,0 +1,14 @@ +package com.android.grape.pad + + +import com.google.gson.annotations.SerializedName + +data class DcInfo( + var area: String = "", + var dcCode: String = "", + var dcName: String = "", + var ossEndpoint: String = "", + var ossEndpointInternal: String = "", + var ossFileEndpoint: String = "", + var ossScreenshotEndpoint: String = "" +) \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/pad/Pad.kt b/app/src/main/java/com/example/studyapp/pad/Pad.kt new file mode 100644 index 0000000..d89c811 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/pad/Pad.kt @@ -0,0 +1,13 @@ +package com.android.grape.pad + + +import com.google.gson.annotations.SerializedName + +data class Pad( + var page: Int = 0, + var pageData: List = listOf(), + var rows: Int = 0, + var size: Int = 0, + var total: Int = 0, + var totalPage: Int = 0 +) \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/pad/PadTask.kt b/app/src/main/java/com/example/studyapp/pad/PadTask.kt new file mode 100644 index 0000000..2c20f61 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/pad/PadTask.kt @@ -0,0 +1,10 @@ +package com.android.grape.pad + + +import com.google.gson.annotations.SerializedName + +data class PadTask( + var padCode: String = "", + var taskId: Int = 0, + var vmStatus: Int = 0 +) \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/pad/PageData.kt b/app/src/main/java/com/example/studyapp/pad/PageData.kt new file mode 100644 index 0000000..21d1fac --- /dev/null +++ b/app/src/main/java/com/example/studyapp/pad/PageData.kt @@ -0,0 +1,17 @@ +package com.android.grape.pad + + +import com.google.gson.annotations.SerializedName + +data class PageData( + var dataSize: Long = 0, + var dataSizeUsed: Long = 0, + var dcInfo: DcInfo = DcInfo(), + var deviceLevel: String = "", + var deviceStatus: Int = 0, + var imageId: String = "", + var online: Int = 0, + var padCode: String = "", + var padStatus: Int = 0, + var streamStatus: Int = 0 +) \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/pad/TaskDetail.kt b/app/src/main/java/com/example/studyapp/pad/TaskDetail.kt new file mode 100644 index 0000000..7a62ce6 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/pad/TaskDetail.kt @@ -0,0 +1,14 @@ +package com.android.grape.pad + + +import com.google.gson.annotations.SerializedName + +data class TaskDetail( + var endTime: Long = 0, + var errorMsg: String = "", + var padCode: String = "", + var taskContent: Any? = Any(), + var taskId: Int = 0, + var taskResult: Any? = Any(), + var taskStatus: Int = 0 +) \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/update/Api.kt b/app/src/main/java/com/example/studyapp/update/Api.kt new file mode 100644 index 0000000..ecaa92c --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/Api.kt @@ -0,0 +1,76 @@ +package com.example.studyapp.update + +import android.util.Log +import com.android.grape.pad.Pad +import com.android.grape.pad.PadTask +import com.android.grape.pad.TaskDetail +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import org.json.JSONArray +import org.json.JSONObject +import kotlin.apply +import kotlin.collections.isNotEmpty +import kotlin.to +import kotlin.toString + +object Api { + private const val TAG = "Api" + const val UPDATE_PAD: String = "/openapi/open/pad/updatePadProperties" + const val PAD_DETAIL: String = "/openapi/open/pad/padDetails" + const val PAD_TASK: String = "/task-center/open/task/padTaskDetail" + + + fun padDetail(): ApiResponse{ + val param = Gson().toJson( + mapOf( + "page" to 1, + "rows" to 10, + "padCode" to listOf("ACP250702PWJCTLF") + ) + ) + val (response, code) = HttpUtils.postSync(PAD_DETAIL, param) + if (code == 200) { + Log.d("padDetail", response.toString()) + var apiResponse: ApiResponse = Gson().fromJson(response, object : TypeToken>() {}.type) + return apiResponse + } else { + Log.d("padDetail", "error: $code") + return ApiResponse(code, "error", 0, null) + } + } + + fun updatePad(params: String): ApiResponseList{ + val (response, code) = HttpUtils.postSync(UPDATE_PAD, params) + if (code == 200) { + Log.d("updatePad", response.toString()) + var apiResponse: ApiResponseList = Gson().fromJson(response, object : TypeToken>() {}.type) + return apiResponse + } else { + Log.d("updatePad", "error: $code") + return ApiResponseList(code, "error", 0, emptyList()) + } + } + + fun padTaskDetail(taskId: Int): Int{ + val jsonString = JSONObject().apply { + put("taskIds", JSONArray().apply { + put(taskId) + }) + }.toString() + Log.d(TAG, "padTaskDetail: $jsonString") + val (response, code) = HttpUtils.postSync(PAD_TASK, jsonString) + if (code == 200) { + Log.d("padTaskDetail", response.toString()) + var apiResponse: ApiResponseList = Gson().fromJson(response, object : TypeToken>() {}.type) + val taskList = apiResponse.data + if (apiResponse.isSuccess() && taskList!= null && taskList.isNotEmpty()){ + val task = taskList[0] + return task.taskStatus + } + return -1 + }else { + Log.d("padTaskDetail", "error: $code") + return -1 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/update/ApiResponse.kt b/app/src/main/java/com/example/studyapp/update/ApiResponse.kt new file mode 100644 index 0000000..de94d43 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/ApiResponse.kt @@ -0,0 +1,23 @@ +package com.example.studyapp.update + +data class ApiResponse( + val code: Int, + val message: String, + val ts: Long, + var data: T? = null +){ + fun isSuccess(): Boolean { + return code == 200 + } +} + +data class ApiResponseList( + val code: Int, + val message: String, + val ts: Long, + var data: List? = null +){ + fun isSuccess(): Boolean { + return code == 200 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/update/ArmCloudSignatureV2.java b/app/src/main/java/com/example/studyapp/update/ArmCloudSignatureV2.java new file mode 100644 index 0000000..9f82bcc --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/ArmCloudSignatureV2.java @@ -0,0 +1,30 @@ +package com.example.studyapp.update; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; + +public class ArmCloudSignatureV2 { + public static final String ALGORITHM = "HmacSHA256"; + public static final String SECRET_KEY = "gz8f1u0t63byzdu6ozbx8r5qs3e5lipt"; + public static final String SECRET_ID = "3yc8c8bg1dym0zaiwjh867al"; + + public static String calculateSignature(String timestamp, String path, String body) throws Exception { + String stringToSign = timestamp + path + (body != null ? body : ""); + Mac hmacSha256 = Mac.getInstance(ALGORITHM); + SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_ID.getBytes(StandardCharsets.UTF_8), ALGORITHM); + hmacSha256.init(secretKeySpec); + byte[] hash = hmacSha256.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(hash); + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/app/src/main/java/com/example/studyapp/update/ChangeCallBack.kt b/app/src/main/java/com/example/studyapp/update/ChangeCallBack.kt new file mode 100644 index 0000000..d0593b3 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/ChangeCallBack.kt @@ -0,0 +1,6 @@ +package com.example.studyapp.update + +interface ChangeCallBack { + fun changeSuccess() + fun changeFailed() +} \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/update/HttpUtil.kt b/app/src/main/java/com/example/studyapp/update/HttpUtil.kt new file mode 100644 index 0000000..9c64bb2 --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/HttpUtil.kt @@ -0,0 +1,226 @@ +package com.example.studyapp.update + +import android.util.Log +import com.google.gson.Gson +import okhttp3.* +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody.Companion.toRequestBody +import java.io.IOException +import java.util.concurrent.TimeUnit + +object HttpUtils { + const val HOST: String = "https://openapi-hk.armcloud.net" + // OkHttp客户端配置 + private val client: OkHttpClient by lazy { + OkHttpClient.Builder() + .connectTimeout(15, TimeUnit.SECONDS) + .readTimeout(15, TimeUnit.SECONDS) + .writeTimeout(15, TimeUnit.SECONDS) + .build() + } + + // JSON媒体类型 + private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull() + + // 回调接口 + interface HttpCallback { + fun onSuccess(response: String, code: Int) + fun onFailure(error: String, code: Int?) + } + + /** + * GET 请求(异步) + * + * @param url 请求URL + * @param params 查询参数(可选) + * @param headers 请求头(可选) + * @param callback 回调接口 + */ + fun getAsync( + url: String, + params: Map? = null, + callback: HttpCallback + ) { + val request = buildGetRequest(url, params) + executeRequestAsync(request, callback) + } + + /** + * POST 请求(异步) + * + * @param url 请求URL + * @param body 请求体(JSON格式) + * @param headers 请求头(可选) + * @param callback 回调接口 + */ + fun postAsync( + url: String, + body: String? = null, + callback: HttpCallback + ) { + val request = buildPostRequest(url, body) + executeRequestAsync(request, callback) + } + + /** + * GET 请求(同步) + * + * @param url 请求URL + * @param params 查询参数(可选) + * @param headers 请求头(可选) + * @return Pair<响应内容, 状态码> + */ + fun getSync( + url: String, + params: Map? = null, + ): Pair { + val request = buildGetRequest(url, params) + return executeRequestSync(request) + } + + /** + * POST 请求(同步) + * + * @param url 请求URL + * @param body 请求体(JSON格式) + * @param headers 请求头(可选) + * @return Pair<响应内容, 状态码> + */ + fun postSync( + url: String, + body: String? = null + ): Pair { + val request = buildPostRequest(url, body) + return executeRequestSync(request) + } + + /** + * 取消所有请求 + */ + fun cancelAllRequests() { + client.dispatcher.cancelAll() + } + + // 内部方法 -------------------------------- + + private fun buildGetRequest( + path: String , + params: Map?, + ): Request { + val url = "$HOST$path" + val httpUrlBuilder = url.toHttpUrlOrNull()?.newBuilder() + ?: throw IllegalArgumentException("Invalid URL: $url") + + var param = "" + params?.forEach { (key, value) -> + httpUrlBuilder.addQueryParameter(key, value) + param += "&${key}=${value}" + } + if (param.isNotEmpty()){ + param = param.substring(1) + } + + val requestBuilder = Request.Builder().url(httpUrlBuilder.build()) + + val authver = "2.0" + val timestamp = System.currentTimeMillis() + val sign = + ArmCloudSignatureV2.calculateSignature(timestamp.toString(), path, param) + addHeaders( + requestBuilder, + mapOf( + "authver" to authver, + "x-ak" to ArmCloudSignatureV2.SECRET_KEY, + "x-timestamp" to timestamp.toString(), + "x-sign" to sign + ) + ) + + return requestBuilder.build() + } + + private fun buildPostRequest( + path: String, + body: String? = null + ): Request { + val url = "$HOST$path" + val bodyString = body?:"" + val requestBuilder = Request.Builder() + .url(url) + .post(bodyString.toRequestBody(JSON_MEDIA_TYPE)) + val authver = "2.0" + val timestamp = System.currentTimeMillis() + val sign = + ArmCloudSignatureV2.calculateSignature(timestamp.toString(), path, body) + addHeaders( + requestBuilder, + mapOf( + "authver" to authver, + "x-ak" to ArmCloudSignatureV2.SECRET_KEY, + "x-timestamp" to timestamp.toString(), + "x-sign" to sign + ) + ) + + return requestBuilder.build() + } + + private fun addHeaders( + builder: Request.Builder, + headers: Map + ) { + headers.forEach { (key, value) -> + builder.addHeader(key, value) + } + } + + private fun buildFormBody(formData: Map): RequestBody { + val formBodyBuilder = FormBody.Builder() + formData.forEach { (key, value) -> + formBodyBuilder.add(key, value) + } + return formBodyBuilder.build() + } + + private fun executeRequestAsync( + request: Request, + callback: HttpCallback + ) { + client.newCall(request).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + val responseBody = response.body?.string() + val code = response.code + + if (response.isSuccessful && responseBody != null) { + callback.onSuccess(responseBody, code) + } else { + callback.onFailure( + responseBody ?: "Empty response", + code + ) + } + } + + override fun onFailure(call: Call, e: IOException) { + callback.onFailure(e.message ?: "Unknown network error", null) + } + }) + } + + private fun executeRequestSync(request: Request): Pair { + return try { + val response = client.newCall(request).execute() + val responseBody = response.peekBody(Long.MAX_VALUE).string() + val code = response.code + Log.d("TAG", "executeRequestSync: $responseBody") + if (response.isSuccessful && responseBody.isNotEmpty()) { + Pair(responseBody, code) + } else { + Pair(null, -1) + } + } catch (e: IOException) { + Pair(null, -1) // 网络错误状态码 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/studyapp/update/UpdateUtil.kt b/app/src/main/java/com/example/studyapp/update/UpdateUtil.kt new file mode 100644 index 0000000..02bc38e --- /dev/null +++ b/app/src/main/java/com/example/studyapp/update/UpdateUtil.kt @@ -0,0 +1,240 @@ +package com.example.studyapp.update + +import android.util.Log +import com.example.studyapp.utils.ShellUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject + +object UpdateUtil { + val scope = CoroutineScope(Dispatchers.IO) + fun changeDevice(recordPackageName: String, bigoDeviceObject:JSONObject?, afDeviceObject:JSONObject?, callback: ChangeCallBack){ + try { + val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code") + Log.d("TAG", "changeDevice: $padCode") + val jsonObject = JSONObject().apply { + put("padCodes", JSONArray().apply { + put(padCode) + }) + } + var timeZone: String = "" + bigoDeviceObject?.apply { + val cpuClockSpeed: String = bigoDeviceObject.optString("cpu_clock_speed") + val gaid: String = bigoDeviceObject.optString("gaid") + val userAgent: String = bigoDeviceObject.optString("User-Agent") + val osLang: String = bigoDeviceObject.optString("os_lang") + val osVer: String = bigoDeviceObject.optString("os_ver") + timeZone = bigoDeviceObject.optString("tz") + val systemCountry: String = bigoDeviceObject.optString("system_country") + val simCountry: String = bigoDeviceObject.optString("sim_country") + val romFreeIn: Long = bigoDeviceObject.optLong("rom_free_in") + val resolution: String = bigoDeviceObject.optString("resolution") + val vendor: String = bigoDeviceObject.optString("vendor") + val batteryScale: Int = bigoDeviceObject.optInt("bat_scale") + + val net: String = bigoDeviceObject.optString("net") + val dpi: Int = bigoDeviceObject.optInt("dpi") + val romFreeExt: Long = bigoDeviceObject.optLong("rom_free_ext") + val dpiF: String = bigoDeviceObject.optString("dpi_f") + val cpuCoreNum: Int = bigoDeviceObject.optInt("cpu_core_num") + } + afDeviceObject?.apply { + 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().getStackTrace()[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.optInt(".deviceData.dim.ydp") + 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", "") + + jsonObject.apply { + put("modemPropertiesList", JSONArray().apply { + put(JSONObject().apply { + put("propertiesName", "MCCMNC") + put("propertiesValue", "${cell_mcc},${cell_mnc}") + }) + }) + put("systemPropertiesList", JSONArray().apply { + put(JSONObject().apply { + put("propertiesName", "ro.product.manufacturer") + put("propertiesValue", ro_product_manufacturer) + }) + put(JSONObject().apply { + put("propertiesName", "ro.product.brand") + put("propertiesValue", ro_product_brand) + }) + put(JSONObject().apply { + put("propertiesName", "ro.product.model") + put("propertiesValue", ro_product_model) + }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.display.id") +// put("propertiesValue", ) +// }) + put(JSONObject().apply { + put("propertiesName", "ro.product.name") + put("propertiesValue", ro_product_name) + }) + put(JSONObject().apply { + put("propertiesName", "ro.product.device") + put("propertiesValue", ro_product_device) + }) +// put(JSONObject().apply { +// put("propertiesName", "ro.product.board") +// put("propertiesValue", bo) +// }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.tags") +// put("propertiesValue", ) +// }) + put(JSONObject().apply { + put("propertiesName", "ro.build.fingerprint") + put("propertiesValue", ro_build_fingerprint) + }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.date.utc") +// put("propertiesValue", da) +// }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.user") +// put("propertiesValue", user) +// }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.host") +// put("propertiesValue", device.expand.) +// }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.description") +// put("propertiesValue", des) +// }) + put(JSONObject().apply { + put("propertiesName", "ro.build.version.incremental") + put("propertiesValue", ro_build_version_incremental) + }) +// put(JSONObject().apply { +// put("propertiesName", "ro.build.version.codename") +// put("propertiesValue", device.cod) +// }) + }) + put("settingPropertiesList", JSONArray().apply { + put(JSONObject().apply { + put("propertiesName", "ssaid/${recordPackageName}") + put("propertiesValue", androidId) + }) +// put(JSONObject().apply { +// put("propertiesName", "bt/mac") +// put("propertiesValue", mac) +// }) + put(JSONObject().apply { + put("propertiesName", "language") + put("propertiesValue", langCode) + }) + put(JSONObject().apply { + put("propertiesName", "timezone") + put("propertiesValue", timeZone) + }) +// put(JSONObject().apply { +// put("propertiesName", "systemvolume") +// put("propertiesValue", device.expand.) +// }) + }) + put("oaidPropertiesList", JSONArray().apply { + put(JSONObject().apply { + put("propertiesName", "AAID") + put("propertiesValue", advertiserId) + }) + }) + } + } + + val jsonString = jsonObject.toString() + val response = Api.updatePad(jsonString) + val dataList = response.data + if (response.isSuccess() && dataList!= null && dataList.isNotEmpty()){ + val padTask = dataList[0] + scope.launch { + Log.d("TAG", "changeDevice: $padTask") + var loop = true + while (loop) { + delay(5000) + val result = Api.padTaskDetail(padTask.taskId) + if (result == 3) { + Log.d("ChangeDeviceInfoUtil", "changeDeviceInfo changeDeviceInfo success") + loop = false + callback.changeSuccess() + } else if (result == -1) { + Log.d("ChangeDeviceInfoUtil", "changeDeviceInfo changeDeviceInfo fail") + loop = false + callback.changeFailed() + } + } + } + } + } catch (e: JSONException) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/app/src/main/jniLibs/arm64-v8a/libnative.so b/app/src/main/jniLibs/arm64-v8a/libnative.so index 967a418..290c546 100644 Binary files a/app/src/main/jniLibs/arm64-v8a/libnative.so and b/app/src/main/jniLibs/arm64-v8a/libnative.so differ diff --git a/build.gradle b/build.gradle index ac77d27..c4ae509 100644 --- a/build.gradle +++ b/build.gradle @@ -7,4 +7,5 @@ buildscript { } plugins { alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 82a3b7e..8ce6ab6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,8 @@ material = "1.12.0" activity = "1.10.1" constraintlayout = "2.2.1" playServicesAdsIdentifier = "18.2.0" +kotlin = "2.0.21" +coreKtx = "1.16.0" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -18,6 +20,8 @@ material = { group = "com.google.android.material", name = "material", version.r activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } play-services-ads-identifier = { group = "com.google.android.gms", name = "play-services-ads-identifier", version.ref = "playServicesAdsIdentifier" } +core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }