From 2ddd9a5f807d452f24beab83a1dfdca6132bc1a9 Mon Sep 17 00:00:00 2001 From: Administrator Date: Tue, 8 Jul 2025 22:01:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=94=B9=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 3 - .idea/appInsightsSettings.xml | 26 -- .idea/codeStyles/Project.xml | 120 --------- .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/dbnavigator.xml | 140 +--------- .idea/deploymentTargetSelector.xml | 8 - .idea/git_toolbox_prj.xml | 15 -- .idea/google-java-format.xml | 6 - .idea/gradle.xml | 5 +- .idea/httpRequests/2025-06-21T105829.200.json | 6 - .idea/httpRequests/2025-06-21T115835.200.json | 5 - .idea/httpRequests/2025-06-21T122848.200.json | 3 - .idea/httpRequests/2025-06-21T124257.200.json | 1 - .idea/httpRequests/2025-06-21T132008.200.json | 4 - .../b3d893cf9de3a85a_bin.mt.plus.zip | Bin 22 -> 0 bytes .idea/httpRequests/http-client.cookies | 1 - .idea/httpRequests/http-requests-log.http | 108 -------- .idea/inspectionProfiles/Project_Default.xml | 6 - .idea/misc.xml | 10 +- app/build.gradle | 23 +- .../com/example/studyapp/MainActivity.java | 50 +++- .../java/com/example/studyapp/pad/DcInfo.kt | 14 + .../main/java/com/example/studyapp/pad/Pad.kt | 13 + .../java/com/example/studyapp/pad/PadTask.kt | 10 + .../java/com/example/studyapp/pad/PageData.kt | 17 ++ .../com/example/studyapp/pad/TaskDetail.kt | 14 + .../java/com/example/studyapp/update/Api.kt | 76 ++++++ .../example/studyapp/update/ApiResponse.kt | 23 ++ .../studyapp/update/ArmCloudSignatureV2.java | 30 +++ .../example/studyapp/update/ChangeCallBack.kt | 6 + .../com/example/studyapp/update/HttpUtil.kt | 226 +++++++++++++++++ .../com/example/studyapp/update/UpdateUtil.kt | 240 ++++++++++++++++++ app/src/main/jniLibs/arm64-v8a/libnative.so | Bin 81488 -> 78320 bytes build.gradle | 1 + gradle/libs.versions.toml | 4 + 35 files changed, 734 insertions(+), 485 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/appInsightsSettings.xml delete mode 100644 .idea/codeStyles/Project.xml delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/git_toolbox_prj.xml delete mode 100644 .idea/google-java-format.xml delete mode 100644 .idea/httpRequests/2025-06-21T105829.200.json delete mode 100644 .idea/httpRequests/2025-06-21T115835.200.json delete mode 100644 .idea/httpRequests/2025-06-21T122848.200.json delete mode 100644 .idea/httpRequests/2025-06-21T124257.200.json delete mode 100644 .idea/httpRequests/2025-06-21T132008.200.json delete mode 100644 .idea/httpRequests/b3d893cf9de3a85a_bin.mt.plus.zip delete mode 100644 .idea/httpRequests/http-client.cookies delete mode 100644 .idea/httpRequests/http-requests-log.http delete mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 app/src/main/java/com/example/studyapp/pad/DcInfo.kt create mode 100644 app/src/main/java/com/example/studyapp/pad/Pad.kt create mode 100644 app/src/main/java/com/example/studyapp/pad/PadTask.kt create mode 100644 app/src/main/java/com/example/studyapp/pad/PageData.kt create mode 100644 app/src/main/java/com/example/studyapp/pad/TaskDetail.kt create mode 100644 app/src/main/java/com/example/studyapp/update/Api.kt create mode 100644 app/src/main/java/com/example/studyapp/update/ApiResponse.kt create mode 100644 app/src/main/java/com/example/studyapp/update/ArmCloudSignatureV2.java create mode 100644 app/src/main/java/com/example/studyapp/update/ChangeCallBack.kt create mode 100644 app/src/main/java/com/example/studyapp/update/HttpUtil.kt create mode 100644 app/src/main/java/com/example/studyapp/update/UpdateUtil.kt 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 15cb0ecb3e219d1701294bfdf0fe3f5cb5d208e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22 NcmWIWW@Tf*000g10H*)| 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 967a4181429ae43d9831fb0df1b8bcbdfa361116..290c546bc928c7b9ff7bd8ae8943d807450e1bbf 100644 GIT binary patch delta 15084 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 delta 16005 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