接口改机

This commit is contained in:
Administrator 2025-07-08 22:01:28 +08:00
parent c63f13e54b
commit 2ddd9a5f80
35 changed files with 734 additions and 485 deletions

3
.idea/.gitignore vendored
View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="tabSettings">
<map>
<entry key="Firebase Crashlytics">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="PLACEHOLDER" />
<option name="mobileSdkAppId" value="" />
<option name="projectId" value="" />
<option name="projectNumber" value="" />
</ConnectionSetting>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="THIRTY_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@ -1,120 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="GoogleStyle" />
</state>
</component>

View File

@ -4,146 +4,14 @@
<mappings />
<preferences />
</component>
<component name="DBNavigator.Project.DataEditorManager">
<record-view-column-sorting-type value="BY_INDEX" />
<value-preview-text-wrapping value="true" />
<value-preview-pinned value="false" />
</component>
<component name="DBNavigator.Project.DatabaseAssistantManager">
<assistants>
<assistant-state connection-id="9e7d43d6-9c6a-47fa-b0b1-b14b18fadac4" default-profile-name="" selected-profile-name="" selected-model-name="" assistant-type="GENERIC" selected-action="SHOW_SQL" availability="UNAVAILABLE" acknowledgement="NONE">
<messages />
</assistant-state>
</assistants>
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="false" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseConsoleManager">
<connection id="9e7d43d6-9c6a-47fa-b0b1-b14b18fadac4">
<console name="Connection" type="STANDARD" schema="" session="Main" />
</connection>
</component>
<component name="DBNavigator.Project.DatabaseEditorStateManager">
<last-used-providers />
<assistants />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.DatabaseSessionManager">
<connection id="9e7d43d6-9c6a-47fa-b0b1-b14b18fadac4" />
</component>
<component name="DBNavigator.Project.ObjectQuickFilterManager">
<last-used-operator value="EQUAL" />
<filters />
</component>
<component name="DBNavigator.Project.Settings">
<connections>
<connection id="9e7d43d6-9c6a-47fa-b0b1-b14b18fadac4" active="true" signed="true">
<database>
<name value="Connection" />
<description value="" />
<database-type value="MYSQL" />
<config-type value="BASIC" />
<database-version value="9999.0" />
<driver-source value="BUNDLED" />
<driver-library value="" />
<driver value="" />
<url-type value="DATABASE" />
<host value="47.238.96.231" />
<port value="3306" />
<database value="gin_demo" />
<tns-folder value="" />
<tns-profile value="" />
<type value="USER_PASSWORD" />
<user value="root" />
<token-type value="" />
<token-config-file value="" />
<token-profile value="" />
<session-user value="" />
</database>
<properties>
<auto-commit value="false" />
</properties>
<ssh-settings>
<active value="false" />
<proxy-host value="" />
<proxy-port value="22" />
<proxy-user value="" />
<auth-type value="PASSWORD" />
<key-file value="" />
</ssh-settings>
<ssl-settings>
<active value="false" />
<certificate-authority-file value="" />
<client-certificate-file value="" />
<client-key-file value="" />
</ssl-settings>
<details>
<charset value="UTF-8" />
<session-management value="true" />
<ddl-file-binding value="true" />
<database-logging value="true" />
<connect-automatically value="true" />
<restore-workspace value="true" />
<restore-workspace-deep value="false" />
<environment-type value="default" />
<connectivity-timeout value="30" />
<idle-time-to-disconnect value="30" />
<idle-time-to-disconnect-pool value="5" />
<credential-expiry-time value="10" />
<max-connection-pool-size value="7" />
<alternative-statement-delimiter value="" />
</details>
<debugger>
<compile-dependencies value="true" />
<tcp-driver-tunneling value="false" />
<tcp-host-address value="" />
<tcp-port-from value="4000" />
<tcp-port-to value="4999" />
<debugger-type value="ASK" />
</debugger>
<object-filters hide-empty-schemas="false" hide-pseudo-columns="false" hide-audit-columns="false">
<object-filters />
<object-type-filter use-master-settings="true">
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="JAVA_CLASS" enabled="true" />
<object-type name="JAVA_INNER_CLASS" enabled="true" />
<object-type name="JAVA_FIELD" enabled="true" />
<object-type name="JAVA_METHOD" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
<object-type name="CREDENTIAL" enabled="true" />
<object-type name="AI_PROFILE" enabled="true" />
</object-type-filter>
</object-filters>
</connection>
</connections>
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
@ -558,8 +426,4 @@
</environment>
</general-settings>
</component>
<component name="DBNavigator.Project.StatementExecutionManager">
<execution-variables />
<execution-variable-types />
</component>
</project>

View File

@ -4,14 +4,6 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-06-23T04:03:54.535123700Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=LMV500N03f5c1fc" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoogleJavaFormatSettings">
<option name="enabled" value="false" />
</component>
</project>

View File

@ -1,20 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$PROJECT_DIR$/../../../../Program Files/gradle-8.14" />
<option name="gradleJvm" value="#JAVA_HOME" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>

View File

@ -1,6 +0,0 @@
{
"b3d893cf9de3a85a": [
"b3d893cf9de3a85a_bin.mt.plus.zip",
"dd597ef6-70c8-4765-94c3-a3262817b94c_b3d893cf9de3a85a_bin.mt.plus.zip"
]
}

View File

@ -1,5 +0,0 @@
{
"b3d893cf9de3a85a": [
"b3d893cf9de3a85a_bin.mt.plus.zip"
]
}

View File

@ -1,3 +0,0 @@
{
"bin.mt.plus": "b3d893cf9de3a85a_bin.mt.plus.zip"
}

View File

@ -1 +0,0 @@
{}

View File

@ -1,4 +0,0 @@
{
"bin.mt.plus": "b3d893cf9de3a85a_bin.mt.plus.zip",
"com.android.chrome": "b3d893cf9de3a85a_com.android.chrome.zip"
}

View File

@ -1 +0,0 @@
# domain path name value date

View File

@ -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
###

View File

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UsePropertyAccessSyntax" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@ -1,16 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.72" />
</ProjectState>
</option>
</component>
</project>

View File

@ -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")
}

View File

@ -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);
}
}

View File

@ -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 = ""
)

View File

@ -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<PageData> = listOf(),
var rows: Int = 0,
var size: Int = 0,
var total: Int = 0,
var totalPage: Int = 0
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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<Pad>{
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<Pad> = Gson().fromJson(response, object : TypeToken<ApiResponse<Pad>>() {}.type)
return apiResponse
} else {
Log.d("padDetail", "error: $code")
return ApiResponse(code, "error", 0, null)
}
}
fun updatePad(params: String): ApiResponseList<PadTask>{
val (response, code) = HttpUtils.postSync(UPDATE_PAD, params)
if (code == 200) {
Log.d("updatePad", response.toString())
var apiResponse: ApiResponseList<PadTask> = Gson().fromJson(response, object : TypeToken<ApiResponseList<PadTask>>() {}.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<TaskDetail> = Gson().fromJson(response, object : TypeToken<ApiResponseList<TaskDetail>>() {}.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
}
}
}

View File

@ -0,0 +1,23 @@
package com.example.studyapp.update
data class ApiResponse<T>(
val code: Int,
val message: String,
val ts: Long,
var data: T? = null
){
fun isSuccess(): Boolean {
return code == 200
}
}
data class ApiResponseList<T>(
val code: Int,
val message: String,
val ts: Long,
var data: List<T>? = null
){
fun isSuccess(): Boolean {
return code == 200
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,6 @@
package com.example.studyapp.update
interface ChangeCallBack {
fun changeSuccess()
fun changeFailed()
}

View File

@ -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<String, String>? = 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<String, String>? = null,
): Pair<String?, Int> {
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<String?, Int> {
val request = buildPostRequest(url, body)
return executeRequestSync(request)
}
/**
* 取消所有请求
*/
fun cancelAllRequests() {
client.dispatcher.cancelAll()
}
// 内部方法 --------------------------------
private fun buildGetRequest(
path: String ,
params: Map<String, String>?,
): 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<String, String>
) {
headers.forEach { (key, value) ->
builder.addHeader(key, value)
}
}
private fun buildFormBody(formData: Map<String, String>): 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<String?, Int> {
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) // 网络错误状态码
}
}
}

View File

@ -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()
}
}
}

View File

@ -7,4 +7,5 @@ buildscript {
}
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
}

View File

@ -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" }