├── .gitignore
├── .project
├── .settings
└── org.eclipse.buildship.core.prefs
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── autorun
│ │ ├── CheckAllowTest.java
│ │ ├── ExampleInstrumentedTest.java
│ │ └── NoSSLv3SocketFactory.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ ├── com
│ │ │ └── example
│ │ │ │ └── autorun
│ │ │ │ ├── data
│ │ │ │ ├── LoginDataSource.java
│ │ │ │ ├── LoginRepository.java
│ │ │ │ ├── Result.java
│ │ │ │ └── model
│ │ │ │ │ └── LoggedInUser.java
│ │ │ │ ├── helper
│ │ │ │ ├── AESUtil.java
│ │ │ │ ├── App.java
│ │ │ │ ├── CheckAllow.java
│ │ │ │ └── SystemUtil.java
│ │ │ │ └── ui
│ │ │ │ └── login
│ │ │ │ ├── LoggedInUserView.java
│ │ │ │ ├── LoginActivity.java
│ │ │ │ ├── LoginFormState.java
│ │ │ │ ├── LoginResult.java
│ │ │ │ ├── LoginViewModel.java
│ │ │ │ └── LoginViewModelFactory.java
│ │ └── org
│ │ │ └── runrun
│ │ │ ├── App.java
│ │ │ ├── UniRunMain.java
│ │ │ ├── entity
│ │ │ ├── AppConfig.java
│ │ │ ├── Location.java
│ │ │ ├── NewRecordBody.java
│ │ │ ├── Response.java
│ │ │ ├── ResponseType
│ │ │ │ ├── ClubInfo.java
│ │ │ │ ├── JoinClubResult.java
│ │ │ │ ├── MyActivityItem.java
│ │ │ │ ├── NewRecordResult.java
│ │ │ │ ├── RunStandard.java
│ │ │ │ ├── SchoolBound.java
│ │ │ │ ├── SignInTf.java
│ │ │ │ ├── SportsClassStudentLearnClockingV0.java
│ │ │ │ └── UserInfo.java
│ │ │ └── SignInOrSignBackBody.java
│ │ │ ├── run
│ │ │ └── Request.java
│ │ │ └── utils
│ │ │ ├── FileUtil.java
│ │ │ ├── HTTP
│ │ │ ├── CustomCookieStore.java
│ │ │ ├── HttpUtil.java
│ │ │ ├── HttpUtil2.java
│ │ │ └── HttpUtilEntity.java
│ │ │ ├── JsonUtils.java
│ │ │ ├── MD5Utils.java
│ │ │ ├── SignUtils.java
│ │ │ └── TrackUtils.java
│ ├── res
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ │ └── activity_login.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ │ └── themes.xml
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ └── xml
│ │ │ └── network_security_config.xml
│ └── resources
│ │ ├── map.json
│ │ └── map2.json
│ └── test
│ ├── java
│ └── com
│ │ └── example
│ │ └── autorun
│ │ ├── CheckAllowTest.java
│ │ └── ExampleUnitTest.java
│ └── resources
│ ├── map.json
│ ├── template.json
│ ├── test.js
│ └── 路径标记点图.png
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /app/release/
17 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AutoRun1
4 | Project AutoRun1 created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
19 | 1636629667783
20 |
21 | 30
22 |
23 | org.eclipse.core.resources.regexFilterMatcher
24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5 | connection.project.dir=
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=D\:/Program Files (x86)/AdoptOpenJDK/jdk-11.0.11.9-hotspot
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoRun
2 | fuck unirun
3 |
4 | ## 坐标拾取
5 |
6 | 使用高德的坐标拾取:[高德坐标拾取1](https://lbs.gaode.com/console/show/picker) or [高德坐标拾取2](https://lbs.amap.com/tools/picker)
7 |
8 |
9 | ## 分析过程
10 |
11 | https://www.jysafe.cn/4707.air
12 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release/
3 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdkVersion 30
7 | buildToolsVersion "30.0.3"
8 |
9 | defaultConfig {
10 | applicationId "com.example.autorun"
11 | minSdkVersion 22
12 | targetSdkVersion 31
13 | versionCode 1
14 | versionName "1.3.0"
15 | multiDexEnabled true
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | buildFeatures {
31 | viewBinding true
32 | }
33 | packagingOptions {
34 | resources {
35 | excludes += ['META-INF/DEPENDENCIES', 'androidsupportmultidexversion.txt']
36 | }
37 | }
38 | namespace 'com.example.autorun'
39 |
40 | }
41 |
42 | dependencies {
43 |
44 | implementation 'androidx.appcompat:appcompat:1.3.0'
45 | implementation 'com.google.android.material:material:1.3.0'
46 | implementation 'androidx.annotation:annotation:1.2.0'
47 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
48 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
49 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
50 | testImplementation 'junit:junit:4.13.2'
51 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
52 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
53 | compileOnly 'org.projectlombok:lombok:1.18.24'
54 | annotationProcessor 'org.projectlombok:lombok:1.18.24'
55 | api 'com.github.ok2c.hc5.android:httpclient-android:0.1.1'
56 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3'
57 | implementation 'com.android.support:multidex:1.0.3'
58 | // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
59 | implementation 'org.apache.commons:commons-lang3:3.12.0'
60 | // https://mvnrepository.com/artifact/org.gavaghan/geodesy
61 | implementation 'org.gavaghan:geodesy:1.1.3'
62 | // implementation 'ch.qos.logback:logback-classic:1.2.3'
63 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/autorun/CheckAllowTest.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun;
2 |
3 | import com.example.autorun.helper.CheckAllow;
4 |
5 | import org.junit.Test;
6 |
7 | public class CheckAllowTest {
8 | @Test
9 | public void test(){
10 | System.out.println("==============");
11 | new CheckAllow().run();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/autorun/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 |
5 | import org.junit.runner.RunWith;
6 |
7 |
8 | /**
9 | * Instrumented test, which will execute on an Android device.
10 | *
11 | * @see Testing documentation
12 | */
13 | @RunWith(AndroidJUnit4.class)
14 | public class ExampleInstrumentedTest {
15 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/autorun/NoSSLv3SocketFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun;
2 |
3 | import java.io.IOException;
4 | import java.net.InetAddress;
5 | import java.net.Socket;
6 |
7 | import javax.net.ssl.HttpsURLConnection;
8 | import javax.net.ssl.SSLSocket;
9 | import javax.net.ssl.SSLSocketFactory;
10 |
11 | public class NoSSLv3SocketFactory extends SSLSocketFactory {
12 | private final SSLSocketFactory delegate;
13 |
14 | public NoSSLv3SocketFactory() {
15 | this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
16 | }
17 |
18 | public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
19 | this.delegate = delegate;
20 | }
21 |
22 | @Override
23 | public String[] getDefaultCipherSuites() {
24 | // return delegate.getDefaultCipherSuites();
25 | return new String[]{
26 | "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
27 | };
28 | }
29 |
30 | @Override
31 | public String[] getSupportedCipherSuites() {
32 | // return delegate.getSupportedCipherSuites();
33 |
34 | return new String[]{
35 | "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
36 | };
37 | }
38 |
39 | private Socket makeSocketSafe(Socket socket) {
40 | if (socket instanceof SSLSocket) {
41 | String[] protocols = {
42 | "TLSv1.1",
43 | "TLSv1.2"
44 | };
45 | ((SSLSocket) socket).setEnabledProtocols(protocols);
46 | }
47 | return socket;
48 | }
49 |
50 | @Override
51 | public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
52 | return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
53 | }
54 |
55 | @Override
56 | public Socket createSocket(String host, int port) throws IOException {
57 | return makeSocketSafe(delegate.createSocket(host, port));
58 | }
59 |
60 | @Override
61 | public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
62 | return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
63 | }
64 |
65 | @Override
66 | public Socket createSocket(InetAddress host, int port) throws IOException {
67 | return makeSocketSafe(delegate.createSocket(host, port));
68 | }
69 |
70 | @Override
71 | public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
72 | return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/data/LoginDataSource.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.data;
2 |
3 | import com.example.autorun.data.model.LoggedInUser;
4 |
5 | import java.io.IOException;
6 |
7 | /**
8 | * Class that handles authentication w/ login credentials and retrieves user information.
9 | */
10 | public class LoginDataSource {
11 |
12 | public Result login(String username, String password) {
13 |
14 | try {
15 | // TODO: handle loggedInUser authentication
16 | LoggedInUser fakeUser =
17 | new LoggedInUser(
18 | java.util.UUID.randomUUID().toString(),
19 | "Jane Doe");
20 | return new Result.Success<>(fakeUser);
21 | } catch (Exception e) {
22 | return new Result.Error(new IOException("Error logging in", e));
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/data/LoginRepository.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.data;
2 |
3 | import com.example.autorun.data.model.LoggedInUser;
4 |
5 | /**
6 | * Class that requests authentication and user information from the remote data source and
7 | * maintains an in-memory cache of login status and user credentials information.
8 | */
9 | public class LoginRepository {
10 |
11 | private static volatile LoginRepository instance;
12 |
13 | private LoginDataSource dataSource;
14 |
15 | // If user credentials will be cached in local storage, it is recommended it be encrypted
16 | // @see https://developer.android.com/training/articles/keystore
17 | private LoggedInUser user = null;
18 |
19 | // private constructor : singleton access
20 | private LoginRepository(LoginDataSource dataSource) {
21 | this.dataSource = dataSource;
22 | }
23 |
24 | public static LoginRepository getInstance(LoginDataSource dataSource) {
25 | if (instance == null) {
26 | instance = new LoginRepository(dataSource);
27 | }
28 | return instance;
29 | }
30 |
31 |
32 | private void setLoggedInUser(LoggedInUser user) {
33 | this.user = user;
34 | // If user credentials will be cached in local storage, it is recommended it be encrypted
35 | // @see https://developer.android.com/training/articles/keystore
36 | }
37 |
38 | public Result login(String username, String password) {
39 | // handle login
40 | Result result = dataSource.login(username, password);
41 | if (result instanceof Result.Success) {
42 | setLoggedInUser(((Result.Success) result).getData());
43 | }
44 | return result;
45 | }
46 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/data/Result.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.data;
2 |
3 | /**
4 | * A generic class that holds a result success w/ data or an error exception.
5 | */
6 | public class Result {
7 | // hide the private constructor to limit subclass types (Success, Error)
8 | private Result() {
9 | }
10 |
11 | @Override
12 | public String toString() {
13 | if (this instanceof Result.Success) {
14 | Result.Success success = (Result.Success) this;
15 | return "Success[data=" + success.getData().toString() + "]";
16 | } else if (this instanceof Result.Error) {
17 | Result.Error error = (Result.Error) this;
18 | return "Error[exception=" + error.getError().toString() + "]";
19 | }
20 | return "";
21 | }
22 |
23 | // Success sub-class
24 | public final static class Success extends Result {
25 | private T data;
26 |
27 | public Success(T data) {
28 | this.data = data;
29 | }
30 |
31 | public T getData() {
32 | return this.data;
33 | }
34 | }
35 |
36 | // Error sub-class
37 | public final static class Error extends Result {
38 | private Exception error;
39 |
40 | public Error(Exception error) {
41 | this.error = error;
42 | }
43 |
44 | public Exception getError() {
45 | return this.error;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/data/model/LoggedInUser.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.data.model;
2 |
3 | /**
4 | * Data class that captures user information for logged in users retrieved from LoginRepository
5 | */
6 | public class LoggedInUser {
7 |
8 | private String userId;
9 | private String displayName;
10 |
11 | public LoggedInUser(String userId, String displayName) {
12 | this.userId = userId;
13 | this.displayName = displayName;
14 | }
15 |
16 | public String getDisplayName() {
17 | return displayName;
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/helper/AESUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.helper;
2 |
3 |
4 | import android.util.Base64;
5 |
6 | import java.nio.charset.StandardCharsets;
7 |
8 | import javax.crypto.Cipher;
9 | import javax.crypto.spec.SecretKeySpec;
10 |
11 |
12 | /**
13 | * @Author jiyec
14 | * @Date 2021/9/5 10:18
15 | * @Version 1.0
16 | **/
17 | public class AESUtil {
18 |
19 | // 加密
20 | public static String Encrypt(String sSrc, String sKey) throws Exception {
21 | if (sKey == null) {
22 | System.out.print("Key为空null");
23 | return null;
24 | }
25 | // 判断Key是否为16位
26 | if (sKey.length() != 16) {
27 | System.out.print("Key长度不是16位");
28 | return null;
29 | }
30 | byte[] raw = sKey.getBytes("utf-8");
31 | SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
32 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
33 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
34 | byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
35 | return Base64.encodeToString(encrypted, 1);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
36 | }
37 |
38 | // 解密
39 | public static String Decrypt(String sSrc, String sKey) throws Exception {
40 | try {
41 | // 判断Key是否正确
42 | if (sKey == null) {
43 | System.out.print("Key为空null");
44 | return null;
45 | }
46 | // 判断Key是否为16位
47 | if (sKey.length() != 16) {
48 | System.out.print("Key长度不是16位");
49 | return null;
50 | }
51 | byte[] raw = sKey.getBytes(StandardCharsets.UTF_8);
52 | SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
53 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
54 | cipher.init(Cipher.DECRYPT_MODE, skeySpec);
55 | byte[] encrypted1 = Base64.decode(sSrc, 1);//先用base64解密
56 | try {
57 | byte[] original = cipher.doFinal(encrypted1);
58 | String originalString = new String(original, StandardCharsets.UTF_8);
59 | return originalString;
60 | } catch (Exception e) {
61 | System.out.println(e.toString());
62 | return null;
63 | }
64 | } catch (Exception ex) {
65 | System.out.println(ex.toString());
66 | return null;
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/helper/App.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.helper;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.view.View;
7 | import android.widget.ProgressBar;
8 | import android.widget.TextView;
9 |
10 | import androidx.appcompat.widget.TintContextWrapper;
11 |
12 | import com.example.autorun.ui.login.LoginActivity;
13 | import com.fasterxml.jackson.core.type.TypeReference;
14 |
15 | import org.apache.hc.core5.http.ParseException;
16 | import org.runrun.entity.AppConfig;
17 | import org.runrun.entity.Location;
18 | import org.runrun.entity.NewRecordBody;
19 | import org.runrun.entity.Response;
20 | import org.runrun.entity.ResponseType.NewRecordResult;
21 | import org.runrun.entity.ResponseType.RunStandard;
22 | import org.runrun.entity.ResponseType.SchoolBound;
23 | import org.runrun.entity.ResponseType.SignInTf;
24 | import org.runrun.entity.ResponseType.UserInfo;
25 | import org.runrun.entity.SignInOrSignBackBody;
26 | import org.runrun.run.Request;
27 | import org.runrun.utils.FileUtil;
28 | import org.runrun.utils.JsonUtils;
29 | import org.runrun.utils.TrackUtils;
30 |
31 | import java.io.IOException;
32 | import java.io.InputStream;
33 | import java.text.SimpleDateFormat;
34 | import java.util.*;
35 |
36 | import lombok.Setter;
37 |
38 | /**
39 | * Hello world!
40 | *
41 | */
42 | public class App extends Thread
43 | {
44 | AppConfig config;
45 | @Setter
46 | private InputStream mapInput;
47 |
48 | @Setter
49 | private TextView resultArea;
50 | @Setter
51 | ProgressBar loadingProgressBar;
52 | public static String ERROR;
53 | @Setter
54 | private String type;
55 | private final StringBuffer token;
56 |
57 | public App(AppConfig config) {
58 | this.config = config;
59 | token = config.getToken();
60 | }
61 |
62 | // 跑步
63 | @SuppressLint("DefaultLocale")
64 | public void runRun() throws IOException, ParseException {
65 |
66 | appendMsg("开始");
67 | // ==========配置 START==============
68 | String phone = config.getPhone();
69 | String password = config.getPassword();
70 | int schoolSite = 0; // 0航空港,1龙泉暂不支持
71 | long runDistance = config.getDistance(); // 路程米
72 | int runTime = config.getRunTime(); // 时间分钟
73 |
74 | // 型号仓库: https://github.com/KHwang9883/MobileModels
75 | // ==========配置 END==============
76 |
77 | if (config.getBrand().length() == 0) {
78 | appendMsg("请配置手机型号信息");
79 | return;
80 | }
81 | // 计算平均配速,防止跑太快
82 | double average = 1.0 * runTime / runDistance * 1000;
83 |
84 | if(Double.isNaN(average)){
85 | appendMsg("输入不正确");
86 | return;
87 | }
88 | if (average < 6) {
89 | String[] notice = {
90 | "我认为这种事情是不可能的",
91 | "太快了",
92 | "要死了",
93 | "你正在自毁",
94 | "你正在自残",
95 | "你得锻炼正造成身体上的损伤",
96 | "六分是养身",
97 | "七分是自娱",
98 | "八分是治愈"
99 | };
100 | appendMsg("八分是治愈,七分是自娱,六分是养身,五分是自伤,四分是自残,三分是自毁。");
101 | appendMsg(String.format("你的配速是:%.2f 分钟/公里, %s", average, notice[(int) average]));
102 | return;
103 | }
104 | appendMsg(String.format("平均配速:%.2f\n", average));
105 |
106 | // if(config.getRunTime() > 0)return;
107 |
108 | Request request = new Request(token.toString(), config);
109 | appendMsg("开始登录");
110 | Response userInfoResponse = request.login(phone, password);
111 | UserInfo userInfo = userInfoResponse.getResponse();
112 | if(userInfo == null ) {
113 | appendMsg("登录失败");
114 | return;
115 | }
116 | long userId = userInfo.getUserId();
117 | if (userId != -1) {
118 | token.delete(0, token.length());
119 | token.append(request.getToken());
120 |
121 | appendMsg("获取跑步标准");
122 | RunStandard runStandard = request.getRunStandard(userInfo.getSchoolId());
123 | appendMsg("获取学校经纬度区域信息");
124 | SchoolBound[] schoolBounds = request.getSchoolBound(userInfo.getSchoolId());
125 |
126 | appendMsg("生成跑步数据");
127 | // 新增跑步数据
128 | NewRecordBody recordBody = new NewRecordBody();
129 | recordBody.setUserId(userId);
130 | recordBody.setAppVersions(config.getAppVersion());
131 | recordBody.setBrand(config.getBrand());
132 | recordBody.setMobileType(config.getMobileType());
133 | recordBody.setSysVersions(config.getSysVersion());
134 | recordBody.setRunDistance(runDistance);
135 | recordBody.setRunTime(runTime);
136 | recordBody.setYearSemester(runStandard.getSemesterYear());
137 | recordBody.setRealityTrackPoints(schoolBounds[schoolSite].getSiteBound() + "--");
138 |
139 | // 今天日期 年-月-日
140 | @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat();
141 | sdf.applyPattern("yyyy-MM-dd");
142 | Date date = new Date();
143 | String formatTime = sdf.format(date);
144 | recordBody.setRecordDate(formatTime);
145 |
146 | // 生成跑步数据
147 | String tack = genTack(runDistance);
148 | recordBody.setTrackPoints(tack);
149 |
150 | //发送数据
151 | appendMsg("提交跑步数据");
152 | String result = request.recordNew(recordBody);
153 | Response response = JsonUtils.string2Obj(result, new TypeReference>() {
154 | });
155 | appendMsg("");
156 | appendMsg("返回原始数据:" + result);
157 | appendMsg("解析数据:");
158 | appendMsg("跑步结果:" + response.getCode() + " - " + response.getMsg());
159 | NewRecordResult response1 = response.getResponse();
160 | appendMsg("生成的跑步ID:" + response1.getRecordId());
161 | appendMsg("结果状态:" + response1.getResultStatus());
162 | appendMsg("结果描述:" + response1.getResultDesc());
163 | appendMsg("超速警告次数:" + response1.getOverSpeedWarn());
164 | appendMsg("警告内容:" + response1.getWarnContent());
165 | } else {
166 | appendMsg("用户Id获取失败");
167 | }
168 | }
169 |
170 | // 签到/签退
171 | public void runSignInOrBack() throws IOException {
172 | String phone = config.getPhone();
173 | String password = config.getPassword();
174 | Request request = new Request(token.toString(), config);
175 | Response userInfoResponse = request.getUserInfo();
176 | //更新token
177 | if(userInfoResponse.getCode() != 10000) {
178 | appendMsg("token无效,更新");
179 | userInfoResponse = request.login(phone, password);
180 | token.delete(0, token.length());
181 | token.append(request.getToken());
182 | }
183 | UserInfo userInfo = userInfoResponse.getResponse();
184 |
185 | if (userInfo != null) {
186 | Long studentId = userInfo.getStudentId();
187 | SignInTf signInTf = request.getSignInTf(String.valueOf(studentId));
188 | appendMsg("待签到俱乐部:{}" + signInTf.toString());
189 | String signStatus = signInTf.getSignStatus();
190 | String signInStatus = signInTf.getSignInStatus();
191 | String signBackStatus = signInTf.getSignBackStatus();
192 |
193 | if ("1".equals(signInStatus) && "1".equals(signBackStatus)) {
194 | appendMsg("未知状态");
195 | return ;
196 | }
197 |
198 | String signType;
199 | if ("1".equals(signStatus)) {
200 | // 可签到
201 | signType = "1";
202 | } else if ("1".equals(signInStatus) && "2".equals(signStatus)) {
203 | // 可签退
204 | signType = "2";
205 | } else {
206 | appendMsg("非可签到签退状态,或没有可签到项目");
207 | return ;
208 | }
209 |
210 | SignInOrSignBackBody signInOrSignBackBody = new SignInOrSignBackBody(
211 | signInTf.getActivityId(),
212 | signInTf.getLatitude(),
213 | signInTf.getLongitude(),
214 | signType,
215 | studentId);
216 |
217 | Response signInOrSignBack = request.signInOrSignBack(signInOrSignBackBody);
218 | appendMsg("签到结果:");
219 | appendMsg(signInOrSignBack.getMsg());
220 | } else {
221 | appendMsg("用户信息获取失败");
222 | }
223 | }
224 | public void run(){
225 | try{
226 | if("run".equals(type)) {
227 | runRun();
228 | }else if("signInOrBack".equals(type)){
229 | runSignInOrBack();
230 | }else{
231 | appendMsg("未知操作");
232 | }
233 | }catch (Exception e){
234 | e.printStackTrace();
235 | String msg;
236 | if(e instanceof RuntimeException) {
237 | StackTraceElement traceElement = e.getStackTrace()[0];
238 | msg = e.getMessage() + "\n异常来源:" +traceElement.getClassName() + " - line:" + traceElement.getLineNumber();
239 | }else{
240 | msg = e.getMessage();
241 | }
242 | appendMsg(msg);
243 | }finally {
244 | stopLoading();
245 | }
246 | }
247 |
248 | public void appendMsg(String msg){
249 | Context context = resultArea.getContext();
250 |
251 | Activity activity = null;
252 | if(context instanceof LoginActivity) {
253 | activity = (Activity) context;
254 | }else if(context instanceof TintContextWrapper){
255 | activity = (Activity)((TintContextWrapper) context).getBaseContext();
256 | }
257 | if(activity != null)
258 | activity.runOnUiThread(new Runnable() {
259 | @Override
260 | public void run() {
261 | resultArea.append("\n" + msg);
262 | }
263 | });
264 | }
265 |
266 | public String genTack(long distance) {
267 | if(mapInput == null)
268 | mapInput = org.runrun.App.class.getResourceAsStream("/map.json");
269 | String json = FileUtil.ReadFile(mapInput);
270 | try {
271 | mapInput.close();
272 | } catch (IOException e) {
273 | e.printStackTrace();
274 | }
275 | if (json.length() == 0) {
276 | System.out.println("配置读取失败");
277 | return null;
278 | }
279 | Location[] locations = JsonUtils.string2Obj(json, Location[].class);
280 | return TrackUtils.gen(distance, locations);
281 | }
282 |
283 | public void stopLoading(){
284 | Context context = resultArea.getContext();
285 | // 4.4 TintContextWrapper
286 | // 5.1 LoginActivity
287 |
288 | Activity activity = null;
289 | if(context instanceof LoginActivity) {
290 | activity = (Activity) context;
291 | }else if(context instanceof TintContextWrapper){
292 | activity = (Activity)((TintContextWrapper) context).getBaseContext();
293 | }
294 |
295 | if(activity != null)
296 | activity.runOnUiThread(new Runnable() {
297 | @Override
298 | public void run() {
299 | loadingProgressBar.setVisibility(View.INVISIBLE);
300 | }
301 | });
302 | }
303 | }
304 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/autorun/helper/CheckAllow.java:
--------------------------------------------------------------------------------
1 | package com.example.autorun.helper;
2 |
3 | import android.os.Build;
4 | import android.os.Looper;
5 | import android.util.Base64;
6 | import android.util.Log;
7 | import android.widget.TextView;
8 |
9 | import org.runrun.utils.HTTP.HttpUtil2;
10 | import org.runrun.utils.JsonUtils;
11 |
12 | import java.nio.charset.StandardCharsets;
13 | import java.util.Date;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 | import java.util.function.Consumer;
17 |
18 | import lombok.AllArgsConstructor;
19 | import lombok.Data;
20 | import lombok.EqualsAndHashCode;
21 | import lombok.NoArgsConstructor;
22 | import lombok.extern.slf4j.Slf4j;
23 |
24 | @Slf4j
25 | @Data
26 | @EqualsAndHashCode(callSuper=false)
27 | @AllArgsConstructor
28 | @NoArgsConstructor
29 | public class CheckAllow extends Thread{
30 | private static String TAG = CheckAllow.class.getSimpleName();
31 | private String androidId = null;
32 | private String uuid = null;
33 | private String apkVersion = null;
34 | private TextView resultArea;
35 | private Consumer