重新建库,开源大部分代码,脱敏处理

This commit is contained in:
2026-06-03 19:09:28 +08:00
committed by Little1Yuan
commit 37f69aa244
145 changed files with 5800 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/build
+63
View File
@@ -0,0 +1,63 @@
plugins {
alias(libs.plugins.android.application)
}
android {
namespace = "cn.nahco3awa.naouc"
compileSdk = 36
defaultConfig {
applicationId = "cn.nahco3awa.naouc"
minSdk = 26
targetSdk = 36
versionCode = 1
versionName = "0.1.5"
ndk {
abiFilters.add("arm64-v8a")
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
viewBinding = true
}
sourceSets {
getByName("main") {
jniLibs.srcDirs("src/main/jniLibs")
}
}
}
dependencies {
implementation(libs.gson)
implementation(libs.okhttp)
implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.constraintlayout)
implementation(libs.lifecycle.livedata.ktx)
implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.navigation.fragment)
implementation(libs.navigation.ui)
implementation(libs.activity)
implementation(libs.zxing.android.embedded)
implementation(libs.recyclerview)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
}
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+45
View File
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.NaOUC">
<activity
android:name=".ui.ouc.activity.OucWaterActivity"
android:exported="false"
android:label="无卡取水" />
<activity
android:name=".ui.ouc.activity.OucNetActivity"
android:exported="false"
android:label="校园网账号管理" />
<activity
android:name=".ui.ouc.activity.OucBalanceActivity"
android:exported="false"
android:label="我的余额" />
<activity
android:name=".ui.ouc.activity.OucLoginMainActivity"
android:label="登录到 OUC" />
<activity
android:name=".MainActivity"
android:exported="true"
android:label="NaOUC">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,43 @@
package cn.nahco3awa.naouc;
import static android.widget.Toast.LENGTH_SHORT;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import cn.nahco3awa.naouc.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyCrashHandler crashHandler = MyCrashHandler.newInstance();
crashHandler.init(this);
Thread.setDefaultUncaughtExceptionHandler(crashHandler);
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
BottomNavigationView navView = findViewById(R.id.nav_view);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_ouc, R.id.navigation_weouc)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(binding.navView, navController);
}
private void sorryNo() {
Toast.makeText(this, "× 抱歉,不行。", LENGTH_SHORT).show();
finish();
}
}
@@ -0,0 +1,93 @@
package cn.nahco3awa.naouc;
import static android.widget.Toast.LENGTH_LONG;
import android.content.Context;
import android.os.Environment;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
public class MyCrashHandler implements Thread.UncaughtExceptionHandler {
private Thread.UncaughtExceptionHandler mDefaultHandler;
private Context mcontext;
private static MyCrashHandler myCrashHandler;
private MyCrashHandler() {}
public static synchronized MyCrashHandler newInstance() {
if (myCrashHandler == null)
myCrashHandler = new MyCrashHandler();
return myCrashHandler;
}
public void init(Context context) {
mcontext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(@NonNull Thread t, Throwable e) {
new AlertDialog.Builder(mcontext)
.setTitle("未捕获的异常!")
.setMessage(e.getMessage())
.show();
Toast.makeText(mcontext, e.getMessage(), LENGTH_LONG).show();
if (!handleExample(e) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(t, e);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(1);
}
}
private boolean handleExample(Throwable ex) {
if(ex == null)
return false;
saveCrashInfoToFile(ex);
return true;
}
private void saveCrashInfoToFile(Throwable ex) {
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable exCause = ex.getCause();
while (exCause != null) {
exCause.printStackTrace(printWriter);
exCause = exCause.getCause();
}
printWriter.close();
long timeMillis = System.currentTimeMillis();
String fileName = "crash-" + timeMillis + ".log";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String path = "/storage/emulated/0/crash_logInfo/";
File fl = new File(path);
if (!fl.exists()) {
boolean ignored = fl.mkdirs();
}
try {
FileOutputStream fileOutputStream = new FileOutputStream(path + fileName);
fileOutputStream.write(writer.toString().getBytes());
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,368 @@
package cn.nahco3awa.naouc.network.ouc;
import androidx.annotation.NonNull;
import java.io.IOException;
import cn.nahco3awa.naouc.network.ouc.request.AccountPayAliPayOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetBarCodePayOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetCardAccInfoOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetInfoByTokenOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetMyBillOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetPhotoBySnoOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetRsaOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetValidateCodeOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.LoginOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.NetGdcOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.OUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.TsmOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiAccUseHzWatchRequest;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiBookCodeCancelRequest;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiBookCodeRequest;
import cn.nahco3awa.naouc.network.ouc.response.AccountPayOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetBarCodePayOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetCardAccInfoOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetInfoByTokenOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetMyBillOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetPhotoBySnoOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetRsaKeyOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetValidateCodeOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.LoginOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.NetGdcOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.network.ouc.response.TsmOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiAccUseHzWatchResponse;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiBookCodeCancelResponse;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiBookCodeResponse;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OUCRequestSender {
public static OUCRequestSender INSTANCE = null;
private String sessionId;
private final String imeiTicket;
private String sourceTypeTicket;
private String jSessionId;
private final OkHttpClient httpClient;
private OUCRequestSender(String imeiTicket) {
this.imeiTicket = imeiTicket;
this.sourceTypeTicket = "0";
this.sessionId = "";
this.jSessionId = "";
httpClient = new OkHttpClient();
}
public static void init(String imeiTicket) {
INSTANCE = new OUCRequestSender(imeiTicket);
}
public static OUCRequestSender getInstance() {
return INSTANCE;
}
public String getImeiTicket() {
return imeiTicket;
}
public String getSessionId() {
return sessionId;
}
public String getSourceTypeTicket() {
return sourceTypeTicket;
}
public Request.Builder setAspHeaders(Request.Builder request) {
return request.header("Cookie", "JSESSIONID=" + jSessionId + "; ASP.NET_SessionId=" + getSessionId() + "; imeiticket=" + getImeiTicket() + "; sourcetypeticket=" + getSourceTypeTicket())
.header("X-Requested-With", "XMLHttpRequest")
.header("Origin", "https://vcard.ouc.edu.cn")
.header("Sec-Fetch-Site", "same-origin")
.header("Sec-Fetch-Mode", "cors")
.header("Sec-Fetch-Dest", "empty")
.header("Referer", "https://vcard.ouc.edu.cn//Phone/Login")
.header("User-Agent", "Mozilla/5.0 (Linux; Android 12; ALA-AN70 Build/HONORALA-AN70; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/99.0.4844.88 Mobile Safari/537.36");
}
public void waterApiBookCodeCancel(WaterApiBookCodeCancelRequest request, OUCCallback<WaterApiBookCodeCancelResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new WaterApiBookCodeCancelResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void waterApiBookCode(WaterApiBookCodeRequest request, OUCCallback<WaterApiBookCodeResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new WaterApiBookCodeResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void waterApiAccUseHzWatch(WaterApiAccUseHzWatchRequest request, OUCCallback<WaterApiAccUseHzWatchResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new WaterApiAccUseHzWatchResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void netGdc(NetGdcOUCRequest request, OUCCallback<NetGdcOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new NetGdcOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void tsm(TsmOUCRequest request, OUCCallback<TsmOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new TsmOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void getMyBill(GetMyBillOUCRequest request, OUCCallback<GetMyBillOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new GetMyBillOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void accountPayAlipay(AccountPayAliPayOUCRequest request, OUCCallback<AccountPayOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new AccountPayOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void getCardAccInfo(GetCardAccInfoOUCRequest request, OUCCallback<GetCardAccInfoOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
callback.onSuccess(new GetCardAccInfoOUCResponse(response));
}
});
}
public void getBarCodePay(GetBarCodePayOUCRequest request, OUCCallback<GetBarCodePayOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
GetBarCodePayOUCResponse response1;
try {
response1 = new GetBarCodePayOUCResponse(response);
callback.onSuccess(response1);
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void getPhotoBySno(GetPhotoBySnoOUCRequest request, OUCCallback<GetPhotoBySnoOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
callback.onSuccess(new GetPhotoBySnoOUCResponse(response));
}
});
}
public void getInfoByToken(GetInfoByTokenOUCRequest request, OUCCallback<GetInfoByTokenOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new GetInfoByTokenOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void getRsaKey(GetRsaOUCRequest request, OUCCallback<GetRsaKeyOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
callback.onSuccess(new GetRsaKeyOUCResponse(response));
}
});
}
public void login(LoginOUCRequest request, OUCCallback<LoginOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
try {
callback.onSuccess(new LoginOUCResponse(response));
} catch (Exception e) {
callback.onFailure(e);
}
}
});
}
public void getValidateCode(GetValidateCodeOUCRequest request, OUCCallback<GetValidateCodeOUCResponse> callback) {
sendRequest(request, new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
callback.onSuccess(new GetValidateCodeOUCResponse(response));
}
});
}
public void sendRequest(OUCRequest request, Callback callback) {
Request req = request.makeRequest(this);
Call call = httpClient.newCall(req);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
callback.onFailure(call, e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if (response.isSuccessful()) {
String setCookie = response.header("Set-Cookie");
if (setCookie != null) {
for (String cookie : setCookie.split(";")) {
String[] kv = cookie.split("=");
if (kv[0].equals("ASP.NET_SessionId")) {
OUCRequestSender.this.sessionId = kv[1];
}
if (kv[0].equals("JSESSIONID")) {
OUCRequestSender.this.jSessionId = kv[1];
}
}
}
}
callback.onResponse(call, response);
}
});
}
public String getjSessionId() {
return jSessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public void setSourceTypeTicket(String sourceTypeTicket) {
this.sourceTypeTicket = sourceTypeTicket;
}
}
@@ -0,0 +1,34 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class AccountPayAliPayOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/User/Account_Pay";
private final String account;
private final String tranamt;
public AccountPayAliPayOUCRequest(String account, String tranamt) {
this.account = account;
this.tranamt = tranamt;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder()
.url(URL)
.post(new FormBody.Builder()
.addEncoded("account", account)
.addEncoded("acctype", "001")
.addEncoded("tranamt", tranamt)
.addEncoded("objtype", "own")
.addEncoded("paytype", "alipay")
.addEncoded("client_type", "wap")
.addEncoded("paymethod", "4")
.addEncoded("iacctype", "acc")
.addEncoded("iswap", "0")
.addEncoded("json", "true")
.build())).build();
}
}
@@ -0,0 +1,118 @@
package cn.nahco3awa.naouc.network.ouc.request;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.util.QrCodeSign;
import cn.nahco3awa.naouc.util.RSASign;
import cn.nahco3awa.naouc.util.SignUtils;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetBarCodePayOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn:20085/PhonePay/MobilePayCommon";
private final String account;
private final String cardId;
private final String imei;
private final String sourceType;
public GetBarCodePayOUCRequest(String account, String cardId, String imei, String sourceType) {
this.account = account;
this.cardId = cardId;
this.imei = imei;
this.sourceType = sourceType;
}
/*
method
timestamp
v
registerid
request
sign
// md5string
clientType
versionName
versionCode
sourcetype
imei
MD5string
*/
public static final String UTF_8 = "UTF-8";
@Override
public Request makeRequest(OUCRequestSender sender) {
HashMap<String, String> map = new HashMap<>();
JsonObject jsonObject = new JsonObject();
JsonObject jsonObject2 = new JsonObject();
jsonObject.addProperty("account", account);
jsonObject.addProperty("acctype", "001");
jsonObject.addProperty("sourcetype", sourceType);
jsonObject.addProperty("flag", "00");
jsonObject.addProperty("cardid", cardId);
jsonObject2.add("synjones.pay.getbarcode", jsonObject);
JsonArray jsonArray = new JsonArray();
jsonArray.add(jsonObject2);
String request;
map.put("method", "synjones.pay.getbarcode");
String timestamp;
timestamp = URLEncoder.encode(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis())), StandardCharsets.UTF_8);
map.put("timestamp", timestamp);
map.put("v", "1.0");
map.put("registerid", "mobileby");
request = new SignUtils().sign(jsonArray.get(0).toString(), "qJzGEh6hESZDVJeCnFPGuxzaiB7NLQM5", "DESede");
String nr = URLEncoder.encode(request, StandardCharsets.UTF_8);
map.put("request", nr);
String sign = URLEncoder.encode(RSASign.sign(map), StandardCharsets.UTF_8);
map.put("sign", sign);
String signStatus = QrCodeSign.getSign(map);
if (signStatus != null) {
if (signStatus.equals("sign_error")) {
throw new RuntimeException("验证签名失败!");
}
map.put("clientType", "1");
map.put("versionName", "1.5.5");
map.put("versionCode", "10505");
map.put("sourcetype", sourceType);
map.put("imei", imei);
signStatus = QrCodeSign.getSign(map);
String md5 = QrCodeSign.getBase64(signStatus).toLowerCase();
FormBody formBody = new FormBody.Builder()
.add("method", "synjones.pay.getbarcode")
.add("timestamp", timestamp)
.add("v", "1.0")
.add("registerid", "mobileby")
.add("request", nr)
.add("sign", sign)
.add("md5string", md5)
.add("clientType", "1")
.add("versionName", "1.5.5")
.add("versionCode", "10505")
.add("sourcetype", sourceType)
.add("imei", imei)
.build();
return sender.setAspHeaders(new Request.Builder()
.url(URL)
.post(formBody)).build();
}
throw new RuntimeException("签名为空!");
}
}
@@ -0,0 +1,24 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetCardAccInfoOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/User/GetCardAccInfo";
private final String account;
public GetCardAccInfoOUCRequest(String account) {
this.account = account;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder()
.post(new FormBody.Builder()
.addEncoded("acc", account)
.addEncoded("json", "true")
.build())
.url(URL)).build();
}
}
@@ -0,0 +1,35 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetInfoByTokenOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/NoBase/GetInfoByToken";
private final String imei;
private final String sourceType;
private final String token;
public GetInfoByTokenOUCRequest(String imei, String sourceType, String token) {
this.imei = imei;
this.sourceType = sourceType;
this.token = token;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("clientType", "1")
.addEncoded("imei", imei)
.addEncoded("sourcetype", sourceType)
.addEncoded("versionName", "1.5.5")
.addEncoded("versionCode", "10505")
.addEncoded("token", token)
.build())
.build();
}
}
// 5760548
@@ -0,0 +1,28 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetMyBillOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/Report/GetMyBill";
private final String account;
private final int page;
public GetMyBillOUCRequest(String account, int page) {
this.account = account;
this.page = page;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("account", account)
.addEncoded("page", String.valueOf(page))
.addEncoded("json", "true")
.build())
.build();
}
}
@@ -0,0 +1,34 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetPhotoBySnoOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/NoBase/GetPhotoBySno";
private final String imei;
private final String sourceType;
private final String sno;
public GetPhotoBySnoOUCRequest(String imei, String sourceType, String sno) {
this.imei = imei;
this.sourceType = sourceType;
this.sno = sno;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("accesstype", sourceType)
.addEncoded("clientType", "1")
.addEncoded("sno", sno)
.addEncoded("imei", imei)
.addEncoded("sourcetype", sourceType)
.addEncoded("versionName", "1.5.5")
.addEncoded("versionCode", "10505")
.build())
.build();
}
}
@@ -0,0 +1,18 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class GetRsaOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/Common/GetRsaKey";
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("json", "true")
.build())
.build();
}
}
@@ -0,0 +1,28 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public class GetValidateCodeOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/Phone/GetValidateCode";
private long time;
public GetValidateCodeOUCRequest(long time) {
this.time = time;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder()
.url(URL + "?time=" + getTime())
.get())
.build();
}
}
@@ -0,0 +1,40 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class LoginOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn/Phone/Login";
private final String sno;
private final String pwd;
private final boolean remember;
private final String uclass;
private final String yzm;
private final String key;
public LoginOUCRequest(String sno, String pwd, boolean remember, String uClass, String yzm, String key) {
this.sno = sno;
this.pwd = pwd;
this.remember = remember;
this.uclass = uClass;
this.yzm = yzm;
this.key = key;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder()
.url(URL)
.post(new FormBody.Builder()
.addEncoded("sno", sno)
.addEncoded("pwd", pwd)
.addEncoded("remember", remember ? "1" : "0")
.addEncoded("uclass", uclass)
.addEncoded("yzm", yzm)
.addEncoded("key", key)
.addEncoded("json", "true")
.build()))
.build();
}
}
@@ -0,0 +1,15 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public class NetCheckOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn:8988/web/common/check.html?";
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL + "ticket=" + sender.getSourceTypeTicket())
.get()
.build();
}
}
@@ -0,0 +1,32 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class NetGdcOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn:8988/web/NetWork/NetGdc.html";
private final String account;
private final String netAccount;
private final int tran;
public NetGdcOUCRequest(String account, String netAccount, int tran) {
this.account = account;
this.netAccount = netAccount;
this.tran = tran;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("aid", "0030000000000301")
.addEncoded("account", account)
.addEncoded("tran", String.valueOf(tran))
.addEncoded("netacc", netAccount)
.addEncoded("acctype", "###")
.build())
.build();
}
}
@@ -0,0 +1,8 @@
package cn.nahco3awa.naouc.network.ouc.request;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public interface OUCRequest {
Request makeRequest(OUCRequestSender sender);
}
@@ -0,0 +1,36 @@
package cn.nahco3awa.naouc.network.ouc.request;
import com.google.gson.JsonObject;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class TsmOUCRequest implements OUCRequest {
public static final String URL = "https://vcard.ouc.edu.cn:8988/web/Common/Tsm.html";
private final String account;
private final String payAccount;
public TsmOUCRequest(String account, String payAccount) {
this.account = account;
this.payAccount = payAccount;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
JsonObject jsonObject = new JsonObject();
JsonObject queryInfo = new JsonObject();
queryInfo.addProperty("aid", "0030000000000301");
queryInfo.addProperty("account", account);
queryInfo.addProperty("payacc", payAccount);
jsonObject.add("query_net_info", queryInfo);
return sender.setAspHeaders(new Request.Builder())
.url(URL)
.post(new FormBody.Builder()
.addEncoded("jsondata", jsonObject.toString())
.addEncoded("funname", "synjones.onecard.query.net.info")
.addEncoded("json", "true")
.build())
.build();
}
}
@@ -0,0 +1,43 @@
package cn.nahco3awa.naouc.network.ouc.request;
import com.google.gson.JsonObject;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public class WaterApiAccUseHzWatchRequest implements OUCRequest {
public static final String URL = "http://222.195.158.17:5003/waterapi/api/AccUseHzWatch";
public static final byte[] PUBLIC_KEY = Base64.getDecoder().decode("3n4DdO47LWH2Co/WfpbdyA==");
public static final String AES_MODE = "AES/ECB/PKCS5Padding";
public static final String AES = "AES";
private final String account;
public WaterApiAccUseHzWatchRequest(String account) {
this.account = account;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("ano", account);
try {
byte[] raw = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(PUBLIC_KEY, AES);
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedInfo = cipher.doFinal(raw);
String info = Base64.getEncoder().encodeToString(encryptedInfo).replaceAll("=", "%3D");
return new Request.Builder()
.url(URL + "?info=" + info + "&token=" + sender.getSourceTypeTicket())
.get()
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,47 @@
package cn.nahco3awa.naouc.network.ouc.request;
import com.google.gson.JsonObject;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public class WaterApiBookCodeCancelRequest implements OUCRequest {
public static final String URL = "http://222.195.158.17:5003/waterapi/api/BookCodeReqCancel";
public static final byte[] PUBLIC_KEY = Base64.getDecoder().decode("3n4DdO47LWH2Co/WfpbdyA==");
public static final String AES_MODE = "AES/ECB/PKCS5Padding";
public static final String AES = "AES";
private final String account;
private final int classNo;
public WaterApiBookCodeCancelRequest(String account, int classNo) {
this.account = account;
this.classNo = classNo;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("ano", account);
jsonObject.addProperty("classno", classNo);
try {
byte[] raw = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(PUBLIC_KEY, AES);
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedInfo = cipher.doFinal(raw);
String info = Base64.getEncoder().encodeToString(encryptedInfo).replaceAll("=", "%3D");
return new Request.Builder()
.url(URL + "?info=" + info + "&token=" + sender.getSourceTypeTicket())
.get()
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,47 @@
package cn.nahco3awa.naouc.network.ouc.request;
import com.google.gson.JsonObject;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import okhttp3.Request;
public class WaterApiBookCodeRequest implements OUCRequest {
public static final String URL = "http://222.195.158.17:5003/waterapi/api/BookCodeReq";
public static final byte[] PUBLIC_KEY = Base64.getDecoder().decode("3n4DdO47LWH2Co/WfpbdyA==");
public static final String AES_MODE = "AES/ECB/PKCS5Padding";
public static final String AES = "AES";
private final String account;
private final int classNo;
public WaterApiBookCodeRequest(String account, int classNo) {
this.account = account;
this.classNo = classNo;
}
@Override
public Request makeRequest(OUCRequestSender sender) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("ano", account);
jsonObject.addProperty("classno", classNo);
try {
byte[] raw = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(PUBLIC_KEY, AES);
Cipher cipher = Cipher.getInstance(AES_MODE);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedInfo = cipher.doFinal(raw);
String info = Base64.getEncoder().encodeToString(encryptedInfo).replaceAll("=", "%3D");
return new Request.Builder()
.url(URL + "?info=" + info + "&token=" + sender.getSourceTypeTicket())
.get()
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,34 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class AccountPayOUCResponse extends OUCResponse {
private final String url;
private final String method;
private final String orderId;
public AccountPayOUCResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
if (!jsonObject.get("IsSucceed").getAsBoolean()) {
throw new RuntimeException(jsonObject.get("Msg").getAsString());
}
url = jsonObject.get("Msg").getAsString();
method = jsonObject.get("Obj").getAsString();
orderId = jsonObject.get("OrderID").getAsString();
}
public String getUrl() {
return url;
}
public String getMethod() {
return method;
}
public String getOrderId() {
return orderId;
}
}
@@ -0,0 +1,42 @@
package cn.nahco3awa.naouc.network.ouc.response;
import android.util.Log;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class GetBarCodePayOUCResponse extends OUCResponse {
private final int account;
private final long expires;
private final String[] barcode;
public GetBarCodePayOUCResponse(Response response) {
super(response);
JsonObject object = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
if (!object.get("retcode").getAsString().equals("0")) {
Log.e("GBCP", object.toString());
throw new RuntimeException(object.get("errmsg").getAsString());
}
JsonObject obj = object.getAsJsonObject("obj");
account = Integer.parseInt(obj.get("ACCOUNT").getAsString());
expires = Long.parseLong(obj.get("EXPIRES").getAsString());
barcode = new String[4];
var awa = obj.get("BARCODE").getAsJsonArray();
for (int i = 0; i < 4; i++) {
barcode[i] = awa.get(i).getAsString();
}
}
public int getAccount() {
return account;
}
public long getExpires() {
return expires;
}
public String[] getBarcode() {
return barcode;
}
}
@@ -0,0 +1,26 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import okhttp3.Response;
public class GetCardAccInfoOUCResponse extends OUCResponse {
private final int balance; // 我们假定海大没有富哥
public GetCardAccInfoOUCResponse(Response response) throws IOException {
super(response);
JsonObject jsonObject = JsonParser.parseString(response.body().string()).getAsJsonObject();
String msg = jsonObject.get("Msg").getAsString();
JsonObject queryObject = JsonParser.parseString(msg).getAsJsonObject().get("query_accinfo").getAsJsonObject();
if (!queryObject.get("retcode").getAsString().equals("0")) {
throw new RuntimeException(queryObject.get("errmsg").getAsString());
}
balance = Integer.parseInt(queryObject.get("accinfo").getAsJsonArray().get(0).getAsJsonObject().get("balance").getAsString());
}
public int getBalance() {
return balance;
}
}
@@ -0,0 +1,138 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class GetInfoByTokenOUCResponse extends OUCResponse {
private final String no;
private final String name;
private final String sex;
private final String sno;
private final String lastUpdate;
private final String account;
private final String cardId;
private final String password;
private final String bmmc;
private final String subjectCode;
private final String subjectName;
private final String gradeName;
private final String schoolName;
private final String pidName;
private final String pidCode;
private final String classCode;
private final String expDate;
private final String areaCode;
private final String deptCode;
private final String className;
public GetInfoByTokenOUCResponse(Response response) {
super(response);
JsonObject object = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
if (!object.get("IsSucceed").getAsBoolean()) {
throw new RuntimeException(object.get("Msg").getAsString());
}
JsonObject obj2 = object.getAsJsonObject("Obj");
no = obj2.get("NO").getAsString();
name = obj2.get("NAME").getAsString();
sex = obj2.get("SEX").getAsString();
sno = obj2.get("SNO").getAsString();
lastUpdate = obj2.get("LASTUPDATE").getAsString();
account = obj2.get("ACCOUNT").getAsString();
cardId = obj2.get("CARDID").getAsString();
subjectName = obj2.get("ZYMC").getAsString();
subjectCode = obj2.get("ZYDM").getAsString();
gradeName = obj2.get("NJMC").getAsString();
schoolName = obj2.get("XQMC").getAsString();
pidName = obj2.get("PIDNAME").getAsString();
pidCode = obj2.get("PIDCODE").getAsString();
classCode = obj2.get("BJDM").getAsString();
expDate = obj2.get("EXPDATE").getAsString();
areaCode = obj2.get("AREACODE").getAsString();
deptCode = obj2.get("DEPTCODE").getAsString();
className = obj2.get("BJMC").getAsString();
password = obj2.get("PASSWORD").getAsString();
bmmc = obj2.get("BMMC").getAsString();
}
public String getClassName() {
return className;
}
public String getDeptCode() {
return deptCode;
}
public String getAreaCode() {
return areaCode;
}
public String getExpDate() {
return expDate;
}
public String getClassCode() {
return classCode;
}
public String getPidCode() {
return pidCode;
}
public String getPidName() {
return pidName;
}
public String getSchoolName() {
return schoolName;
}
public String getGradeName() {
return gradeName;
}
public String getSubjectName() {
return subjectName;
}
public String getSubjectCode() {
return subjectCode;
}
public String getBmmc() {
return bmmc;
}
public String getPassword() {
return password;
}
public String getCardId() {
return cardId;
}
public String getAccount() {
return account;
}
public String getLastUpdate() {
return lastUpdate;
}
public String getSno() {
return sno;
}
public String getSex() {
return sex;
}
public String getName() {
return name;
}
public String getNo() {
return no;
}
}
@@ -0,0 +1,30 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.List;
import cn.nahco3awa.naouc.network.ouc.response.data.SingleBillData;
import okhttp3.Response;
public class GetMyBillOUCResponse extends OUCResponse {
private final List<SingleBillData> billData;
public GetMyBillOUCResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
var arr = jsonObject.get("rows").getAsJsonArray();
billData = new ArrayList<>(arr.size());
Gson gson = new Gson();
for (JsonElement jsonElement : arr) {
billData.add(gson.fromJson(jsonElement, SingleBillData.class));
}
}
public List<SingleBillData> getBillData() {
return billData;
}
}
@@ -0,0 +1,29 @@
package cn.nahco3awa.naouc.network.ouc.response;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.Base64;
import okhttp3.Response;
public class GetPhotoBySnoOUCResponse extends OUCResponse {
private final Bitmap image;
public GetPhotoBySnoOUCResponse(Response response) {
super(response);
JsonObject object = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
if (!object.get("IsSucceed").getAsBoolean()) {
throw new RuntimeException(object.get("Msg").getAsString());
}
String imageBase64 = object.get("Obj").getAsString();
byte[] bs = Base64.getDecoder().decode(imageBase64);
image = BitmapFactory.decodeByteArray(bs, 0, bs.length);
}
public Bitmap getImage() {
return image;
}
}
@@ -0,0 +1,32 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class GetRsaKeyOUCResponse extends OUCResponse {
private final String msg;
private final String e;
private final String mod;
public GetRsaKeyOUCResponse(Response response) {
super(response);
JsonObject object = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
msg = object.get("Msg").getAsString();
String[] keys = object.get("Obj").getAsString().split(",");
e = keys[0];
mod = keys[1];
}
public String getMod() {
return mod;
}
public String getMsg() {
return msg;
}
public String getE() {
return e;
}
}
@@ -0,0 +1,19 @@
package cn.nahco3awa.naouc.network.ouc.response;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import okhttp3.Response;
public class GetValidateCodeOUCResponse extends OUCResponse {
private final Bitmap image;
public GetValidateCodeOUCResponse(Response response) {
super(response);
image = BitmapFactory.decodeStream(response.body().byteStream());
}
public Bitmap getImage() {
return image;
}
}
@@ -0,0 +1,144 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class LoginOUCResponse extends OUCResponse {
private final String rescouseType;
private final String no;
private final String name;
private final String sex;
private final String sno;
private final String lastUpdate;
private final String account;
private final String cardId;
private final String tel;
private final String subjectName;
private final String subjectCode;
private final String gradeName;
private final String schoolName;
private final String pidName;
private final String pidCode;
private final String classCode;
private final String expDate;
private final String areaCode;
private final String deptCode;
private final String className;
private final String createdDate;
public LoginOUCResponse(Response response) {
super(response);
JsonObject object = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
if (!object.get("IsSucceed").getAsBoolean()) {
throw new RuntimeException(object.get("Msg").getAsString());
}
JsonObject obj2 = object.getAsJsonObject("Obj2");
rescouseType = obj2.get("RescouseType").getAsString();
no = obj2.get("NO").getAsString();
name = obj2.get("NAME").getAsString();
sex = obj2.get("SEX").getAsString();
sno = obj2.get("SNO").getAsString();
lastUpdate = obj2.get("LASTUPDATE").getAsString();
account = obj2.get("ACCOUNT").getAsString();
cardId = obj2.get("CARDID").getAsString();
tel = obj2.get("TEL").getAsString();
subjectName = obj2.get("ZYMC").getAsString();
subjectCode = obj2.get("ZYDM").getAsString();
gradeName = obj2.get("NJMC").getAsString();
schoolName = obj2.get("XQMC").getAsString();
pidName = obj2.get("PIDNAME").getAsString();
pidCode = obj2.get("PIDCODE").getAsString();
classCode = obj2.get("BJDM").getAsString();
expDate = obj2.get("EXPDATE").getAsString();
areaCode = obj2.get("AREACODE").getAsString();
deptCode = obj2.get("DEPTCODE").getAsString();
className = obj2.get("BJMC").getAsString();
createdDate = obj2.get("CREATEDATE").getAsString();
}
public String getCreatedDate() {
return createdDate;
}
public String getClassName() {
return className;
}
public String getDeptCode() {
return deptCode;
}
public String getAreaCode() {
return areaCode;
}
public String getExpDate() {
return expDate;
}
public String getClassCode() {
return classCode;
}
public String getPidCode() {
return pidCode;
}
public String getPidName() {
return pidName;
}
public String getSchoolName() {
return schoolName;
}
public String getGradeName() {
return gradeName;
}
public String getSubjectCode() {
return subjectCode;
}
public String getSubjectName() {
return subjectName;
}
public String getTel() {
return tel;
}
public String getCardId() {
return cardId;
}
public String getAccount() {
return account;
}
public String getLastUpdate() {
return lastUpdate;
}
public String getSno() {
return sno;
}
public String getSex() {
return sex;
}
public String getName() {
return name;
}
public String getNo() {
return no;
}
public String getRescouseType() {
return rescouseType;
}
}
@@ -0,0 +1,49 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class NetGdcOUCResponse extends OUCResponse {
private final int retCode;
private final String errMessage;
private final String aid;
private final String account;
private final String accountType;
private final int tranAmount;
public NetGdcOUCResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject().getAsJsonObject("pay_net_gdc");
retCode = Integer.parseInt(jsonObject.get("retcode").getAsString());
errMessage = jsonObject.get("errmsg").getAsString();
aid = jsonObject.get("aid").getAsString();
account = jsonObject.get("account").getAsString();
accountType = jsonObject.get("acctype").getAsString();
tranAmount = Integer.parseInt(jsonObject.get("tranamt").getAsString());
}
public int getRetCode() {
return retCode;
}
public int getTranAmount() {
return tranAmount;
}
public String getAccount() {
return account;
}
public String getAccountType() {
return accountType;
}
public String getAid() {
return aid;
}
public String getErrMessage() {
return errMessage;
}
}
@@ -0,0 +1,6 @@
package cn.nahco3awa.naouc.network.ouc.response;
public interface OUCCallback<R extends OUCResponse> {
void onSuccess(R response);
void onFailure(Throwable e);
}
@@ -0,0 +1,14 @@
package cn.nahco3awa.naouc.network.ouc.response;
import okhttp3.Response;
public abstract class OUCResponse {
private final Response response;
public OUCResponse(Response response) {
this.response = response;
}
public Response getResponse() {
return response;
}
}
@@ -0,0 +1,62 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class TsmOUCResponse extends OUCResponse {
private final String msg;
private final String aid;
private final String account;
private final String netAccount;
private final float balance;
private final boolean isFrozen;
private final boolean hasLost;
private final String retcode;
public TsmOUCResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject().getAsJsonObject("query_net_info");
if (!jsonObject.get("retcode").getAsString().equals("0")) {
throw new RuntimeException(jsonObject.get("errmsg").getAsString());
}
retcode = jsonObject.get("retcode").getAsString();
msg = jsonObject.get("errmsg").getAsString();
aid = jsonObject.get("aid").getAsString();
account = jsonObject.get("account").getAsString();
JsonObject netAccountObject = jsonObject.getAsJsonObject("netacc");
netAccount = netAccountObject.get("netacc").getAsString();
balance = Integer.parseInt(netAccountObject.get("bal").getAsString()) / 100.0f;
isFrozen = netAccountObject.get("freezeflag").getAsString().equals("1");
hasLost = netAccountObject.get("lostflag").getAsString().equals("1");
}
public String getMsg() {
return msg;
}
public String getAid() {
return aid;
}
public String getAccount() {
return account;
}
public String getNetAccount() {
return netAccount;
}
public float getBalance() {
return balance;
}
public boolean isFrozen() {
return isFrozen;
}
public boolean hasLost() {
return hasLost;
}
}
@@ -0,0 +1,52 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.List;
import cn.nahco3awa.naouc.network.ouc.response.data.SingleWaterHzWatchData;
import okhttp3.Response;
public class WaterApiAccUseHzWatchResponse extends OUCResponse {
private final int retNo;
private final String description;
private final List<SingleWaterHzWatchData> data;
public WaterApiAccUseHzWatchResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
retNo = jsonObject.get("RetNo").getAsInt();
description = jsonObject.get("RetDsp").getAsString();
if (retNo != 0) {
throw new RuntimeException(description);
}
data = new ArrayList<>();
for (JsonElement single : jsonObject.getAsJsonArray("List")) {
JsonObject singleData = single.getAsJsonObject();
data.add(new SingleWaterHzWatchData(
singleData.get("ClassNo").getAsInt(),
singleData.get("ClassName").getAsString(),
singleData.get("PosNum").getAsInt(),
singleData.get("WarnPosNum").getAsInt(),
singleData.get("UseFreeRate").getAsInt(),
singleData.get("BookRate").getAsInt(),
singleData.get("Actkind").getAsInt(),
singleData.get("BookCode").getAsString()
));
}
}
public List<SingleWaterHzWatchData> getData() {
return data;
}
public int getRetNo() {
return retNo;
}
public String getDescription() {
return description;
}
}
@@ -0,0 +1,31 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class WaterApiBookCodeCancelResponse extends OUCResponse {
private final int retNo;
private final String description;
private final String bookCode;
public WaterApiBookCodeCancelResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
retNo = jsonObject.get("RetNo").getAsInt();
description = jsonObject.get("RetDsp").getAsString();
bookCode = jsonObject.get("BookCode").getAsString();
}
public String getBookCode() {
return bookCode;
}
public int getRetNo() {
return retNo;
}
public String getDescription() {
return description;
}
}
@@ -0,0 +1,31 @@
package cn.nahco3awa.naouc.network.ouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.Response;
public class WaterApiBookCodeResponse extends OUCResponse {
private final int retNo;
private final String description;
private final String bookCode;
public WaterApiBookCodeResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
retNo = jsonObject.get("RetNo").getAsInt();
description = jsonObject.get("RetDsp").getAsString();
bookCode = jsonObject.get("BookCode").getAsString();
}
public String getBookCode() {
return bookCode;
}
public int getRetNo() {
return retNo;
}
public String getDescription() {
return description;
}
}
@@ -0,0 +1,19 @@
package cn.nahco3awa.naouc.network.ouc.response.data;
public class SingleBillData {
public int RO; // 行数
public String OCCTIME; // 支出事件
public String EFFECTDATE; // 生效时间
public String XQ; // 星期
public String MERCNAME; // 消费地点
public float TRANAMT; // 金额
public String TRANNAME; // 支付方式
public float CARDBAL; // 余额
public String JDESC; // 流水简介
public int JNUM;
public String MACCOUNT;
public String TRANCODE;
public String F1;
public String F2;
public String F3;
}
@@ -0,0 +1,107 @@
package cn.nahco3awa.naouc.network.ouc.response.data;
import java.util.Objects;
public final class SingleWaterHzWatchData {
private final int ClassNo;
private final String ClassName;
private final int PosNum;
private final int WarnPosNum;
private final int UseFreeRate;
private final int BookRate;
private int Actkind;
private String BookCode;
public SingleWaterHzWatchData(
int ClassNo, // 单位编号
String ClassName, // 单位名称
int PosNum, // 设备量
int WarnPosNum, // ???
int UseFreeRate, // 空闲率
int BookRate, // 预约比例(66为0.66%
int Actkind, // 0未预约 1已预约
String BookCode // 预约编号
) {
this.ClassNo = ClassNo;
this.ClassName = ClassName;
this.PosNum = PosNum;
this.WarnPosNum = WarnPosNum;
this.UseFreeRate = UseFreeRate;
this.BookRate = BookRate;
this.Actkind = Actkind;
this.BookCode = BookCode;
}
public int ClassNo() {
return ClassNo;
}
public String ClassName() {
return ClassName;
}
public int PosNum() {
return PosNum;
}
public int WarnPosNum() {
return WarnPosNum;
}
public int UseFreeRate() {
return UseFreeRate;
}
public int BookRate() {
return BookRate;
}
public int Actkind() {
return Actkind;
}
public String BookCode() {
return BookCode;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (SingleWaterHzWatchData) obj;
return this.ClassNo == that.ClassNo &&
Objects.equals(this.ClassName, that.ClassName) &&
this.PosNum == that.PosNum &&
this.WarnPosNum == that.WarnPosNum &&
this.UseFreeRate == that.UseFreeRate &&
this.BookRate == that.BookRate &&
this.Actkind == that.Actkind &&
Objects.equals(this.BookCode, that.BookCode);
}
@Override
public int hashCode() {
return Objects.hash(ClassNo, ClassName, PosNum, WarnPosNum, UseFreeRate, BookRate, Actkind, BookCode);
}
@Override
public String toString() {
return "SingleWaterHzWatchData[" +
"ClassNo=" + ClassNo + ", " +
"ClassName=" + ClassName + ", " +
"PosNum=" + PosNum + ", " +
"WarnPosNum=" + WarnPosNum + ", " +
"UseFreeRate=" + UseFreeRate + ", " +
"BookRate=" + BookRate + ", " +
"Actkind=" + Actkind + ", " +
"BookCode=" + BookCode + ']';
}
public void setActkind(int actkind) {
Actkind = actkind;
}
public void setBookCode(String bookCode) {
BookCode = bookCode;
}
}
@@ -0,0 +1,13 @@
package cn.nahco3awa.naouc.network.weouc;
public enum LoginType {
UNDERGRADUATE("undergraduate");
String name;
LoginType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@@ -0,0 +1,12 @@
package cn.nahco3awa.naouc.network.weouc;
import okhttp3.OkHttpClient;
public class WeOUCRequestSender {
private final OkHttpClient client;
private WeOUCRequestSender() {
client = new OkHttpClient();
}
}
@@ -0,0 +1,37 @@
package cn.nahco3awa.naouc.network.weouc.request;
import cn.nahco3awa.naouc.network.weouc.LoginType;
import cn.nahco3awa.naouc.network.weouc.WeOUCRequestSender;
import okhttp3.FormBody;
import okhttp3.Request;
public class KbWeOUCRequest implements WeOUCRequest {
public static final String URL = "https://api.weouc.com/api/jw/kb";
private final int xn;
private final int xq;
private final String sno;
private final LoginType loginType;
private final String password;
public KbWeOUCRequest(int xn, int xq, String sno, LoginType loginType, String password) {
this.xn = xn;
this.xq = xq;
this.sno = sno;
this.loginType = loginType;
this.password = password;
}
@Override
public Request makeRequest(WeOUCRequestSender sender) {
return new Request.Builder()
.url(URL)
.post(new FormBody.Builder()
.addEncoded("xn", String.valueOf(xn))
.addEncoded("xq", String.valueOf(xq))
.addEncoded("sno", sno)
.addEncoded("loginType", loginType.getName())
.addEncoded("password", password)
.build())
.build();
}
}
@@ -0,0 +1,8 @@
package cn.nahco3awa.naouc.network.weouc.request;
import cn.nahco3awa.naouc.network.weouc.WeOUCRequestSender;
import okhttp3.Request;
public interface WeOUCRequest {
Request makeRequest(WeOUCRequestSender sender);
}
@@ -0,0 +1,40 @@
package cn.nahco3awa.naouc.network.weouc.response;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.List;
import cn.nahco3awa.naouc.network.weouc.response.data.kb.ClassData;
import okhttp3.Response;
public class KbWeOUCResponse extends WeOUCResponse {
private final List<ClassData> classes;
private final boolean fromCache;
private final String message;
private final int status;
public KbWeOUCResponse(Response response) {
super(response);
JsonObject jsonObject = JsonParser.parseReader(response.body().charStream()).getAsJsonObject();
fromCache = jsonObject.get("from_cache").getAsBoolean();
message = jsonObject.get("message").getAsString();
status = jsonObject.get("status").getAsInt();
classes = ClassData.parseClassesData(jsonObject.get("data").getAsJsonArray());
}
public int getStatus() {
return status;
}
public List<ClassData> getClasses() {
return classes;
}
public String getMessage() {
return message;
}
public boolean isFromCache() {
return fromCache;
}
}
@@ -0,0 +1,6 @@
package cn.nahco3awa.naouc.network.weouc.response;
public interface WeOUCCallback<R extends WeOUCResponse> {
void onSuccess(R response);
void onFailure(Throwable e);
}
@@ -0,0 +1,14 @@
package cn.nahco3awa.naouc.network.weouc.response;
import okhttp3.Response;
public abstract class WeOUCResponse {
private final Response response;
public WeOUCResponse(Response response) {
this.response = response;
}
public Response getResponse() {
return response;
}
}
@@ -0,0 +1,134 @@
package cn.nahco3awa.naouc.network.weouc.response.data.kb;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ClassData {
private final String name;
private final String classRoom;
private final String credit;
private final String origin;
private final String status;
private final String teacher;
private final int begin;
private final int num;
private final int day;
private final List<String> weeks;
public static final Map<Integer, Integer> DAY_OF_WEEK_MAP = new HashMap<>();
public static final int[] CLASS_MINUTES = {
0,
8 * 60,
9 * 60,
10 * 60 + 10,
11 * 60 + 10,
// rest
13 * 60 + 30,
14 * 60 + 30,
15 * 60 + 30,
16 * 60 + 30,
17 * 60 + 30,
18 * 60 + 30,
19 * 60 + 30,
20 * 60 + 30
};
public ClassData(String name, String classRoom, String credit, String origin, String status, String teacher, int begin, int num, int day, List<String> weeks) {
this.name = name;
this.classRoom = classRoom;
this.credit = credit;
this.origin = origin;
this.status = status;
this.teacher = teacher;
this.begin = begin;
this.num = num;
this.day = day;
this.weeks = weeks;
}
public List<String> getWeeks() {
return weeks;
}
public int getDay() {
return day;
}
public int getNum() {
return num;
}
public int getBegin() {
return begin;
}
public String getTeacher() {
return teacher;
}
public String getStatus() {
return status;
}
public String getOrigin() {
return origin;
}
public String getCredit() {
return credit;
}
public String getClassRoom() {
return classRoom;
}
public String getName() {
return name;
}
public int getMinutesOfDay() {
return CLASS_MINUTES[getBegin()];
}
public static ClassData fromJson(JsonObject jsonObject) {
return new Gson().fromJson(jsonObject, ClassData.class);
}
public static List<ClassData> parseClassesData(JsonArray data) {
List<ClassData> ret = new ArrayList<>();
for (JsonElement datum : data) {
for (JsonElement classes : datum.getAsJsonObject().getAsJsonArray("classes")) {
if (classes.isJsonArray()) {
for (JsonElement classData : classes.getAsJsonArray()) {
if (classData.isJsonObject()) {
ret.add(fromJson(classData.getAsJsonObject()));
}
}
}
}
}
return ret;
}
public static int getClassDayByDayOfWeek(int dayOfWeek) {
return DAY_OF_WEEK_MAP.get(dayOfWeek);
}
static {
DAY_OF_WEEK_MAP.put(Calendar.SUNDAY, 6);
DAY_OF_WEEK_MAP.put(Calendar.MONDAY, 0);
DAY_OF_WEEK_MAP.put(Calendar.TUESDAY, 1);
DAY_OF_WEEK_MAP.put(Calendar.WEDNESDAY, 2);
DAY_OF_WEEK_MAP.put(Calendar.THURSDAY, 3);
DAY_OF_WEEK_MAP.put(Calendar.FRIDAY, 4);
DAY_OF_WEEK_MAP.put(Calendar.SATURDAY, 5);
}
}
@@ -0,0 +1,385 @@
package cn.nahco3awa.naouc.ui.ouc;
import static android.content.Context.MODE_PRIVATE;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.journeyapps.barcodescanner.BarcodeEncoder;
import java.io.IOException;
import java.util.Locale;
import java.util.Random;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.databinding.FragmentOucBinding;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.GetBarCodePayOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetCardAccInfoOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetInfoByTokenOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.NetCheckOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.TsmOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiAccUseHzWatchRequest;
import cn.nahco3awa.naouc.network.ouc.response.GetBarCodePayOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetCardAccInfoOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetInfoByTokenOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.network.ouc.response.TsmOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiAccUseHzWatchResponse;
import cn.nahco3awa.naouc.ui.ouc.activity.OucBalanceActivity;
import cn.nahco3awa.naouc.ui.ouc.activity.OucLoginMainActivity;
import cn.nahco3awa.naouc.ui.ouc.activity.OucNetActivity;
import cn.nahco3awa.naouc.ui.ouc.activity.OucWaterActivity;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
public class OUCFragment extends Fragment {
private SharedPreferences preferences;
private FragmentOucBinding binding;
private String sourceType = null;
private Button loginButton;
private TextView welcomeTextView;
private ActivityResultLauncher<Intent> loginLauncher;
private ImageView barcodeImageView;
private ImageView qrCodeImageView;
private TextView balanceTextView;
private TextView netBalanceTextView;
private TextView waterAvailableTextView;
private ImageView netBalanceImageView;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = FragmentOucBinding.inflate(inflater, container, false);
View root = binding.getRoot();
Context context = root.getContext();
preferences = context.getSharedPreferences("ouc", MODE_PRIVATE);
if (!preferences.contains("imei")) {
StringBuilder stringBuilder = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 32; i++) {
stringBuilder.append(random.nextInt(10));
}
preferences.edit()
.putString("imei", stringBuilder.toString())
.apply();
}
OUCRequestSender.init(preferences.getString("imei", "1145141919810deadbeef52013149922"));
loginLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
refreshLogonState();
}
});
loginButton = root.findViewById(R.id.oucMainLoginButton);
welcomeTextView = root.findViewById(R.id.oucMainWelcomeTextView);
barcodeImageView = root.findViewById(R.id.oucBarcodeImageView);
qrCodeImageView = root.findViewById(R.id.qrCodeImageView);
balanceTextView = root.findViewById(R.id.balanceTextView);
netBalanceTextView = root.findViewById(R.id.netBalanceTextView);
netBalanceImageView = root.findViewById(R.id.netImage);
waterAvailableTextView = root.findViewById(R.id.waterBalanceTextView);
loginButton.setOnClickListener(this::onClickLogin);
welcomeTextView.setOnClickListener(this::onClickWelcomeText);
barcodeImageView.setOnClickListener(this::onClickRefreshPayCode);
qrCodeImageView.setOnClickListener(this::onClickRefreshPayCode);
root.findViewById(R.id.cashButton).setOnClickListener(this::onClickBalance);
root.findViewById(R.id.netButton).setOnClickListener(this::onClickNet);
root.findViewById(R.id.waterButton).setOnClickListener(this::onClickWater);
refreshLogonState();
return root;
}
private GetInfoByTokenOUCResponse infoResponse = null;
public void refreshLogonState() {
if (isLogon()) {
loginButton.setText("登出");
sourceType = preferences.getString("source_ticket", "");
OUCRequestSender.getInstance().setSourceTypeTicket(sourceType);
OUCRequestSender.getInstance().getInfoByToken(new GetInfoByTokenOUCRequest(OUCRequestSender.getInstance().getImeiTicket(), sourceType, sourceType), new OUCCallback<>() {
@Override
public void onSuccess(GetInfoByTokenOUCResponse response) {
infoResponse = response;
requireActivity().runOnUiThread(() -> {
refreshWelcomeText();
refreshPayCode();
refreshBalance();
refreshNetBalance();
refreshAvailableWater();
});
}
@Override
public void onFailure(Throwable e) {
requireActivity().runOnUiThread(() -> {
Toast.makeText(getActivity(), "获取个人信息失败!", Toast.LENGTH_SHORT).show();
welcomeTextView.setText("可能需要重新登录?");
if (e.getMessage() != null && e.getMessage().equals("令牌失效")) {
preferences.edit()
.putBoolean("logon", false)
.apply();
refreshLogonState();
}
});
}
});
} else {
loginButton.setText("登录");
welcomeTextView.setText("尚未登录");
}
}
private void onClickRefreshPayCode(View view) {
if (isLogon() && infoResponse != null) {
refreshPayCode();
refreshBalance();
refreshNetBalance();
refreshAvailableWater();
}
}
@Override
public void onResume() {
super.onResume();
refreshLogonState();
}
private void refreshAvailableWater() {
waterAvailableTextView.setText("...");
OUCRequestSender.getInstance().waterApiAccUseHzWatch(new WaterApiAccUseHzWatchRequest(infoResponse.getAccount()), new OUCCallback<>() {
@Override
public void onSuccess(WaterApiAccUseHzWatchResponse response) {
requireActivity().runOnUiThread(() -> waterAvailableTextView.setText(response.getData().size() + " 可用"));
}
@Override
public void onFailure(Throwable e) {
requireActivity().runOnUiThread(() -> waterAvailableTextView.setText("获取失败"));
}
});
}
private void refreshNetBalance() {
netBalanceTextView.setText("...");
if (OUCRequestSender.getInstance().getjSessionId().isEmpty()) {
OUCRequestSender.getInstance().sendRequest(new NetCheckOUCRequest(), new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
requireActivity().runOnUiThread(() -> netBalanceTextView.setText("获取失败"));
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
refreshNetByTsm();
}
});
} else {
refreshNetByTsm();
}
}
private void refreshNetByTsm() {
String account = infoResponse.getAccount();
OUCRequestSender.getInstance().tsm(new TsmOUCRequest(account, infoResponse.getSno()), new OUCCallback<>() {
@Override
public void onSuccess(TsmOUCResponse response) {
requireActivity().runOnUiThread(() -> {
int redColor = 0xFFF44336;
if (response.isFrozen()) {
netBalanceTextView.setText("停机");
netBalanceImageView.setColorFilter(redColor, PorterDuff.Mode.MULTIPLY);
} else {
netBalanceTextView.setText(String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", response.getBalance()));
netBalanceImageView.setColorFilter(null);
}
});
}
@Override
public void onFailure(Throwable e) {
requireActivity().runOnUiThread(() -> {
netBalanceTextView.setText("获取失败");
new androidx.appcompat.app.AlertDialog.Builder(requireActivity())
.setTitle("网费详情获取失败")
.setMessage(e.getMessage())
.show();
});
}
});
}
private void refreshBalance() {
String account = infoResponse.getAccount();
balanceTextView.setText("...");
OUCRequestSender.getInstance().getCardAccInfo(new GetCardAccInfoOUCRequest(account), new OUCCallback<>() {
@Override
public void onSuccess(GetCardAccInfoOUCResponse response) {
requireActivity().runOnUiThread(() -> balanceTextView.setText(String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", response.getBalance() / 100.0)));
}
@Override
public void onFailure(Throwable e) {
requireActivity().runOnUiThread(() -> balanceTextView.setText("获取失败"));
}
});
}
private void refreshPayCode() {
String account = infoResponse.getAccount();
try {
GetBarCodePayOUCRequest getBarCodePayOUCRequest = new GetBarCodePayOUCRequest(account, "1", OUCRequestSender.getInstance().getImeiTicket(), OUCRequestSender.getInstance().getSourceTypeTicket());
OUCRequestSender.getInstance().getBarCodePay(getBarCodePayOUCRequest, new OUCCallback<>() {
@Override
public void onSuccess(GetBarCodePayOUCResponse response) {
try {
requireActivity().runOnUiThread(() -> {
try {
BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128;
BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
BitMatrix bitMatrix = barcodeEncoder.encode(response.getBarcode()[0], barcodeFormat, barcodeImageView.getWidth(), barcodeImageView.getHeight());
Bitmap barcodeBitmap = barcodeEncoder.createBitmap(bitMatrix);
barcodeImageView.setImageBitmap(barcodeBitmap);
bitMatrix = barcodeEncoder.encode(response.getBarcode()[0], BarcodeFormat.QR_CODE, qrCodeImageView.getWidth(), qrCodeImageView.getHeight());
Bitmap qrBitmap = barcodeEncoder.createBitmap(bitMatrix);
qrCodeImageView.setImageBitmap(qrBitmap);
} catch (WriterException e) {
requireActivity().runOnUiThread(() -> new AlertDialog.Builder(requireActivity())
.setTitle("显示支付码错误!")
.setMessage(e.getMessage())
.setNegativeButton("", null)
.show());
}
});
} catch (Exception e) {
requireActivity().runOnUiThread(() -> new AlertDialog.Builder(requireActivity())
.setTitle("显示支付码错误!")
.setMessage(e.getMessage())
.setNegativeButton("", null)
.show());
}
}
@Override
public void onFailure(Throwable e) {
requireActivity().runOnUiThread(() -> new AlertDialog.Builder(requireActivity())
.setTitle("获取支付码错误!")
.setMessage(e.getMessage())
.setNegativeButton("", null)
.show());
}
});
} catch (Exception e) {
requireActivity().runOnUiThread(() -> new AlertDialog.Builder(requireActivity())
.setTitle("获取支付码错误!")
.setMessage(e.getMessage())
.setNegativeButton("", null)
.show());
}
}
private void onClickWater(View view) {
if (isLogon() && infoResponse != null) {
Intent intent = new Intent(getActivity(), OucWaterActivity.class);
intent.putExtra("account", infoResponse.getAccount());
startActivity(intent);
}
}
private void onClickBalance(View view) {
if (isLogon() && infoResponse != null) {
Intent intent = new Intent(getActivity(), OucBalanceActivity.class);
intent.putExtra("account", infoResponse.getAccount());
startActivity(intent);
}
}
private void onClickNet(View view) {
if (isLogon() && infoResponse != null) {
Intent intent = new Intent(getActivity(), OucNetActivity.class);
intent.putExtra("account", infoResponse.getAccount());
intent.putExtra("sno", infoResponse.getSno());
startActivity(intent);
}
}
private void refreshWelcomeText() {
if (isLogon()) {
welcomeTextView.setText("欢迎回来," + getName() + "~");
} else {
welcomeTextView.setText("尚未登录");
}
}
private String getName() {
return preferences.getString("nickname", infoResponse == null ? "" : infoResponse.getName());
}
public boolean isLogon() {
return preferences.getBoolean("logon",false);
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
public void onClickLogin(View view) {
if (isLogon()) {
preferences.edit()
.putBoolean("logon", false)
.apply();
refreshLogonState();
} else {
loginLauncher.launch(new Intent(getActivity(), OucLoginMainActivity.class));
}
}
private void onClickWelcomeText(View view) {
EditText editText = new EditText(requireContext());
editText.setHint("输出昵称...");
String nick = preferences.getString("nickname", infoResponse == null ? "" : infoResponse.getName());
editText.setText(nick);
new androidx.appcompat.app.AlertDialog.Builder(requireActivity())
.setTitle("设置昵称:")
.setView(editText)
.setNegativeButton("取消", null)
.setPositiveButton("应用", (dialogInterface, i) -> {
preferences.edit()
.putString("nickname", editText.getText().toString())
.apply();
refreshWelcomeText();
})
.show();
}
}
@@ -0,0 +1,123 @@
package cn.nahco3awa.naouc.ui.ouc.activity;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.Locale;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.AccountPayAliPayOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetCardAccInfoOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetMyBillOUCRequest;
import cn.nahco3awa.naouc.network.ouc.response.AccountPayOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetCardAccInfoOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetMyBillOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.ui.ouc.view.ItemMyBillAdapter;
public class OucBalanceActivity extends AppCompatActivity {
private String account;
private TextView balanceTextView;
private RecyclerView myBillView;
private ItemMyBillAdapter adapt = new ItemMyBillAdapter(new ArrayList<>());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ouc_balance);
Intent intent = getIntent();
account = intent.getStringExtra("account");
balanceTextView = findViewById(R.id.balanceBigTextView);
myBillView = findViewById(R.id.myBillListView);
myBillView.setVisibility(INVISIBLE);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
myBillView.setLayoutManager(layoutManager);
myBillView.setAdapter(adapt);
refreshBalance();
refreshMyBill();
}
private void refreshMyBill() {
myBillView.setVisibility(INVISIBLE);
OUCRequestSender.getInstance().getMyBill(new GetMyBillOUCRequest(account, 1), new OUCCallback<>() {
@Override
public void onSuccess(GetMyBillOUCResponse response) {
runOnUiThread(() -> {
adapt = new ItemMyBillAdapter(response.getBillData());
myBillView.setAdapter(adapt);
myBillView.setVisibility(VISIBLE);
});
}
@Override
public void onFailure(Throwable e) {
myBillView.setVisibility(INVISIBLE);
}
});
}
private void refreshBalance() {
OUCRequestSender.getInstance().getCardAccInfo(new GetCardAccInfoOUCRequest(account), new OUCCallback<>() {
@Override
public void onSuccess(GetCardAccInfoOUCResponse response) {
runOnUiThread(() -> balanceTextView.setText(String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", response.getBalance() / 100.0)));
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> Toast.makeText(OucBalanceActivity.this, "获取余额失败!", Toast.LENGTH_SHORT).show());
}
});
}
public void onClickPay(View view) {
EditText editText = new EditText(this);
editText.setHint("请输入金额...");
editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
new AlertDialog.Builder(this)
.setTitle("充值")
.setView(editText)
.setNegativeButton("取消", null)
.setPositiveButton("充值", (dialogInterface, i) -> {
String amountString = editText.getText().toString();
double amount = Double.parseDouble(amountString) * 100;
String parsedAmount = String.valueOf((int)amount);
OUCRequestSender.getInstance().accountPayAlipay(new AccountPayAliPayOUCRequest(account, parsedAmount), new OUCCallback<>() {
@Override
public void onSuccess(AccountPayOUCResponse response) {
runOnUiThread(() -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(response.getUrl()));
startActivity(intent);
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> Toast.makeText(OucBalanceActivity.this, "下单失败!", Toast.LENGTH_SHORT).show());
}
});
})
.show();
}
}
@@ -0,0 +1,172 @@
package cn.nahco3awa.naouc.ui.ouc.activity;
import static android.widget.Toast.LENGTH_SHORT;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.GetRsaOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.GetValidateCodeOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.LoginOUCRequest;
import cn.nahco3awa.naouc.network.ouc.response.GetRsaKeyOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.GetValidateCodeOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.LoginOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
public class OucLoginMainActivity extends AppCompatActivity {
private SharedPreferences preferences;
private EditText snoEdit;
private EditText passwordEdit;
private EditText ysmEdit;
private CheckBox rememberCheck;
private ImageView ysmImageView;
private Button loginButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ouc_login_main);
snoEdit = findViewById(R.id.editTextOucSno);
passwordEdit = findViewById(R.id.editTextOucPassword);
ysmEdit = findViewById(R.id.editTextOucYsm);
rememberCheck = findViewById(R.id.checkBoxOucRemember);
ysmImageView = findViewById(R.id.oucYsmImageView);
loginButton = findViewById(R.id.buttonOucLogin);
preferences = getSharedPreferences("ouc", MODE_PRIVATE);
if (preferences.getBoolean("mem", false)) {
snoEdit.setText(preferences.getString("mem_sno", ""));
passwordEdit.setText(preferences.getString("mem_pwd", ""));
rememberCheck.setChecked(true);
}
getLoginNeeds();
}
private void getLoginNeeds() {
loginButton.setEnabled(false);
refreshYsmCode();
}
private void refreshYsmCode() {
OUCRequestSender.getInstance().getValidateCode(new GetValidateCodeOUCRequest(System.currentTimeMillis() + 1000 * 60 * 5), new OUCCallback<>() {
@Override
public void onSuccess(GetValidateCodeOUCResponse response) {
runOnUiThread(() -> {
ysmImageView.setImageBitmap(response.getImage());
loginButton.setEnabled(true);
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> {
Toast.makeText(OucLoginMainActivity.this, "网络连接有点问题,请重试", LENGTH_SHORT).show();
new AlertDialog.Builder(OucLoginMainActivity.this)
.setTitle("错误")
.setMessage("网络错误:\n" + e.getMessage())
.setNegativeButton("", null)
.show();
});
}
});
}
private void onLoginFailed(Throwable e) {
new AlertDialog.Builder(this)
.setTitle("登录失败……")
.setMessage("中国海洋大学门户登录失败,请稍后再试。\n" + e.getMessage())
.setNegativeButton("", null)
.show();
refreshYsmCode();
}
public void onClickLogin(View view) {
loginButton.setEnabled(false);
OUCRequestSender.getInstance().getRsaKey(new GetRsaOUCRequest(), new OUCCallback<>() {
@Override
public void onSuccess(GetRsaKeyOUCResponse response) {
try {
String pwd = passwordEdit.getText().toString();
BigInteger bigExpo = new BigInteger(response.getE(), 16);
BigInteger bigModulus = new BigInteger(response.getMod(), 16);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(bigModulus, bigExpo);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] light = pwd.getBytes(StandardCharsets.UTF_8);
byte[] encrypted = cipher.doFinal(light);
StringBuilder builder = new StringBuilder(encrypted.length * 2);
for (byte b : encrypted) {
String hexB = Integer.toHexString(b & 0xFF);
if (hexB.length() == 1) {
hexB = "0" + hexB;
}
builder.append(hexB);
}
String encryptedHex = builder.toString();
OUCRequestSender.getInstance().login(new LoginOUCRequest(snoEdit.getText().toString(), encryptedHex, rememberCheck.isChecked(), "8898", ysmEdit.getText().toString(), response.getMsg()), new OUCCallback<>() {
@Override
public void onSuccess(LoginOUCResponse loginResponse) {
runOnUiThread(() -> {
if (rememberCheck.isChecked()) {
preferences.edit()
.putString("mem_sno", loginResponse.getSno())
.putString("mem_pwd", pwd)
.apply();
}
preferences.edit()
.putString("source_ticket", loginResponse.getRescouseType())
.putBoolean("mem", rememberCheck.isChecked())
.putBoolean("logon", true)
.putString("sno", loginResponse.getSno())
.apply();
String name = preferences.getString("nickname", loginResponse.getName());
Toast.makeText(OucLoginMainActivity.this, name + ",欢迎回来~", LENGTH_SHORT).show();
setResult(Activity.RESULT_OK);
finish();
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> OucLoginMainActivity.this.onLoginFailed(e));
}
});
} catch (Exception e) {
runOnUiThread(() -> OucLoginMainActivity.this.onLoginFailed(e));
Log.e("OUCLogin", "Login failed", e);
}
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> OucLoginMainActivity.this.onLoginFailed(e));
}
});
}
}
@@ -0,0 +1,195 @@
package cn.nahco3awa.naouc.ui.ouc.activity;
import static android.widget.Toast.LENGTH_SHORT;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import java.util.Locale;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.NetGdcOUCRequest;
import cn.nahco3awa.naouc.network.ouc.request.TsmOUCRequest;
import cn.nahco3awa.naouc.network.ouc.response.NetGdcOUCResponse;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.network.ouc.response.TsmOUCResponse;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OucNetActivity extends AppCompatActivity {
private TextView netStatusTextView;
private TextView netBalanceTextView;
private String account;
private String sno;
private SharedPreferences preferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ouc_net);
Intent intent = getIntent();
account = intent.getStringExtra("account");
sno = intent.getStringExtra("sno");
netStatusTextView = findViewById(R.id.netStatusTextView);
netBalanceTextView = findViewById(R.id.netBalanceBigTextView);
refreshBalance();
preferences = getSharedPreferences("net", MODE_PRIVATE);
}
private void refreshBalance() {
OUCRequestSender.getInstance().tsm(new TsmOUCRequest(account, sno), new OUCCallback<>() {
@Override
public void onSuccess(TsmOUCResponse response) {
runOnUiThread(() -> {
netBalanceTextView.setText(String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", response.getBalance()));
netStatusTextView.setText(response.isFrozen() ? "校园网停机" : "校园网余额");
if (response.isFrozen()) netStatusTextView.setTextColor(0xFFF44336);
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> {
netStatusTextView.setText("查询失败");
netBalanceTextView.setText("");
});
}
});
}
public void onClickPay(View view) {
EditText editText = new EditText(this);
editText.setHint("请输入金额(元):");
editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
new AlertDialog.Builder(this)
.setTitle("网费缴纳")
.setView(editText)
.setNegativeButton("取消", null)
.setPositiveButton("缴纳", (dialog, which) -> {
String amountString = editText.getText().toString();
double amount = Double.parseDouble(amountString) * 100;
OUCRequestSender.getInstance().netGdc(new NetGdcOUCRequest(account, sno, (int) amount), new OUCCallback<>() {
@Override
public void onSuccess(NetGdcOUCResponse response) {
runOnUiThread(() -> {
if (response.getRetCode() == 0) {
Toast.makeText(OucNetActivity.this, "缴费成功~", LENGTH_SHORT).show();
refreshBalance();
} else {
Toast.makeText(OucNetActivity.this, "缴费失败:" + response.getErrMessage(), LENGTH_SHORT).show();
}
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> Toast.makeText(OucNetActivity.this, "缴费失败!", LENGTH_SHORT).show());
}
});
})
.show();
}
public void onClickLogin(View view) {
String password = preferences.getString("password", "");
if (password.isEmpty()) {
EditText editText = new EditText(this);
editText.setHint("请输入校园网密码...");
editText.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);
editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(this)
.setTitle("校园网认证")
.setView(editText)
.setNegativeButton("登录", (dialogInterface, i) -> {
preferences.edit()
.putString("password", editText.getText().toString())
.apply();
onClickLogin(null);
})
.show();
return;
}
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
int iip = wifiManager.getConnectionInfo().getIpAddress();
String ip = String.format(
Locale.SIMPLIFIED_CHINESE,
"%d.%d.%d.%d",
(iip & 0xff),
(iip >> 8 & 0xff),
(iip >> 16 & 0xff),
(iip >> 24 & 0xff)
);
OkHttpClient client = new OkHttpClient();
var request = new Request.Builder()
.url(String.format(
Locale.SIMPLIFIED_CHINESE,
"https://wxrz.ouc.edu.cn:802/eportal/portal/login?&callback=dr1003&login_method=1&user_account=%s&user_password=%s&wlan_user_ip=%s&wlan_user_ipv6=&wlan_user_mac=000000000000&wlan_ac_ip=&wlan_ac_name=&jsVersion=4.1&terminal_type=1&lang=zh-cn&v=3288&lang=zh",
sno, password, ip
))
.get()
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Toast.makeText(OucNetActivity.this, "登录失败,请检查校园网连接!", LENGTH_SHORT).show();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
var resp = response.body().string();
if (!resp.startsWith("dr1003(") || !resp.endsWith(");")) {
Toast.makeText(OucNetActivity.this, "登录失败,响应异常!", LENGTH_SHORT).show();
return;
}
resp = resp.substring(7, resp.length() - 2);
JsonObject jsonObject = JsonParser.parseString(resp).getAsJsonObject();
int result = jsonObject.get("result").getAsInt();
String msg = jsonObject.get("msg").getAsString();
if (result == 1) {
Toast.makeText(OucNetActivity.this, "校园网登录成功~", LENGTH_SHORT).show();
return;
}
int code = jsonObject.get("ret_code").getAsInt();
if (code == 2) {
Toast.makeText(OucNetActivity.this, "您已经在线啦~", LENGTH_SHORT).show();
return;
}
new AlertDialog.Builder(OucNetActivity.this)
.setTitle("校园网登录失败...")
.setMessage(msg)
.setNegativeButton("好吧", null)
.setPositiveButton("再试一次", (dialogInterface, i) -> onClickLogin(null))
.show();
}
});
}
public void onClickOfficial(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://222.195.158.36/Self/"));
startActivity(intent);
}
}
@@ -0,0 +1,74 @@
package cn.nahco3awa.naouc.ui.ouc.activity;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_SHORT;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiAccUseHzWatchRequest;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiAccUseHzWatchResponse;
import cn.nahco3awa.naouc.ui.ouc.view.ItemWaterAdapter;
public class OucWaterActivity extends AppCompatActivity {
private String account = null;
private RecyclerView waterListView;
private ItemWaterAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ouc_water);
Intent intent = getIntent();
account = intent.getStringExtra("account");
adapter = new ItemWaterAdapter(new ArrayList<>(), account, this);
waterListView = findViewById(R.id.waterListView);
waterListView.setVisibility(INVISIBLE);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
waterListView.setLayoutManager(layoutManager);
waterListView.setAdapter(adapter);
refreshWaterList();
}
private void refreshWaterList() {
waterListView.setVisibility(INVISIBLE);
OUCRequestSender.getInstance().waterApiAccUseHzWatch(new WaterApiAccUseHzWatchRequest(account), new OUCCallback<>() {
@Override
public void onSuccess(WaterApiAccUseHzWatchResponse response) {
runOnUiThread(() -> {
adapter = new ItemWaterAdapter(response.getData(), account, OucWaterActivity.this);
waterListView.setAdapter(adapter);
waterListView.setVisibility(VISIBLE);
});
}
@Override
public void onFailure(Throwable e) {
runOnUiThread(() -> {
waterListView.setVisibility(INVISIBLE);
Toast.makeText(OucWaterActivity.this, "刷新列表失败:" + e.getMessage(), LENGTH_SHORT).show();
});
}
});
}
@Override
protected void onResume() {
super.onResume();
refreshWaterList();
}
}
@@ -0,0 +1,96 @@
package cn.nahco3awa.naouc.ui.ouc.view;
import android.graphics.PorterDuff;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import java.util.Locale;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.response.data.SingleBillData;
public class ItemMyBillAdapter extends RecyclerView.Adapter<ItemMyBillAdapter.ViewHolder> {
private final List<SingleBillData> billData;
public ItemMyBillAdapter(List<SingleBillData> billData) {
this.billData = billData;
}
@NonNull @Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_my_bill, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
SingleBillData data = billData.get(position);
holder.setData(data);
}
public void addBillData(SingleBillData data) {
billData.add(data);
}
@Override
public int getItemCount() {
return billData.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final ImageView iconImageView;
private final TextView tranNameTextView;
private final TextView mercnNameTextView;
private final TextView amountTextView;
private final TextView balanceTextView;
private SingleBillData data = null;
public ViewHolder(@NonNull View itemView) {
super(itemView);
iconImageView = itemView.findViewById(R.id.cellMyBillImageView);
tranNameTextView = itemView.findViewById(R.id.cellMyBillTranNameTextView);
mercnNameTextView = itemView.findViewById(R.id.cellMyBillMercnNameTextView);
amountTextView = itemView.findViewById(R.id.cellMyBillAmountTextView);
balanceTextView = itemView.findViewById(R.id.cellMyBillBalanceTextView);
itemView.setOnClickListener(view -> {
if (data != null) {
new AlertDialog.Builder(view.getContext())
.setTitle("消费详情")
.setMessage("订单时间:" + data.OCCTIME +
"\n生效时间:" + data.EFFECTDATE +
"\n流水金额:" + getFormat(data.TRANAMT) +
"\n账户余额:" + getFormat(data.CARDBAL) +
"\n支付地点:" + data.MERCNAME +
"\n\n" + data.JDESC)
.setNegativeButton("",null)
.show();
}
});
}
private void setData(SingleBillData data) {
this.data = data;
float amt = data.TRANAMT;
int color = amt < 0 ? 0xFFF44336 : 0xFF8BC34A;
iconImageView.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
amountTextView.setTextColor(color);
amountTextView.setText(getFormat(amt));
tranNameTextView.setText(data.TRANNAME);
mercnNameTextView.setText(data.MERCNAME);
balanceTextView.setText("余额:" + getFormat(data.CARDBAL));
}
@NonNull
private static String getFormat(float amt) {
return String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", amt);
}
}
}
@@ -0,0 +1,124 @@
package cn.nahco3awa.naouc.ui.ouc.view;
import static android.widget.Toast.LENGTH_SHORT;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import java.util.Locale;
import cn.nahco3awa.naouc.R;
import cn.nahco3awa.naouc.network.ouc.OUCRequestSender;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiBookCodeCancelRequest;
import cn.nahco3awa.naouc.network.ouc.request.WaterApiBookCodeRequest;
import cn.nahco3awa.naouc.network.ouc.response.OUCCallback;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiBookCodeCancelResponse;
import cn.nahco3awa.naouc.network.ouc.response.WaterApiBookCodeResponse;
import cn.nahco3awa.naouc.network.ouc.response.data.SingleWaterHzWatchData;
public class ItemWaterAdapter extends RecyclerView.Adapter<ItemWaterAdapter.ViewHolder> {
private final List<SingleWaterHzWatchData> data;
private final String account;
private final Activity activity;
public ItemWaterAdapter(List<SingleWaterHzWatchData> data, String account, Activity activity) {
this.data = data;
this.account = account;
this.activity = activity;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_ouc_water, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
SingleWaterHzWatchData datum = data.get(position);
holder.setData(datum, account, activity);
}
@Override
public int getItemCount() {
return data.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView nameTextView;
private final TextView statusTextView;
private final TextView bookTextView;
private SingleWaterHzWatchData data = null;
private String account = null;
private boolean active;
private Activity activity;
public ViewHolder(@NonNull View itemView) {
super(itemView);
active = true;
nameTextView = itemView.findViewById(R.id.cellOucWaterNameTextView);
statusTextView = itemView.findViewById(R.id.cellOucWaterStatusTextView);
bookTextView = itemView.findViewById(R.id.cellOucWaterBookTextView);
itemView.setOnClickListener(view -> {
if (data != null && active) {
active = false;
if (data.Actkind() == 0) {
// 预约请求
OUCRequestSender.getInstance().waterApiBookCode(new WaterApiBookCodeRequest(account, data.ClassNo()), new OUCCallback<>() {
@Override
public void onSuccess(WaterApiBookCodeResponse response) {
activity.runOnUiThread(() -> {
data.setActkind(1);
data.setBookCode(response.getBookCode());
setData(data, account, activity);
});
}
@Override
public void onFailure(Throwable e) {
activity.runOnUiThread(() -> Toast.makeText(view.getContext(), "预约失败", LENGTH_SHORT).show());
}
});
} else {
// 取消预约
OUCRequestSender.getInstance().waterApiBookCodeCancel(new WaterApiBookCodeCancelRequest(account, data.ClassNo()), new OUCCallback<>() {
@Override
public void onSuccess(WaterApiBookCodeCancelResponse response) {
activity.runOnUiThread(() -> {
data.setActkind(0);
data.setBookCode("");
setData(data, account, activity);
});
}
@Override
public void onFailure(Throwable e) {
activity.runOnUiThread(() -> Toast.makeText(view.getContext(), "取消预约失败", LENGTH_SHORT).show());
}
});
}
}
});
}
private void setData(SingleWaterHzWatchData data, String account, Activity activity) {
this.account = account;
this.data = data;
this.activity = activity;
active = true;
int color = (data.Actkind() == 1 || data.UseFreeRate() <= 0) ? 0xFFF44336 : 0xFF8BC34A;
nameTextView.setText(data.ClassName());
statusTextView.setText(String.format(Locale.SIMPLIFIED_CHINESE, "%.2f", data.UseFreeRate() / 100.0f) + "% 可用");
bookTextView.setTextColor(color);
bookTextView.setText(data.Actkind() == 1 ? data.BookCode() : (data.UseFreeRate() > 0 ? "可预约" : "不可用"));
}
}
}
@@ -0,0 +1,41 @@
package cn.nahco3awa.naouc.ui.weouc;
import static android.content.Context.MODE_PRIVATE;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import cn.nahco3awa.naouc.databinding.FragmentWeoucBinding;
public class WeOUCFragment extends Fragment {
private FragmentWeoucBinding binding;
private Activity activity;
private Context context;
private View root;
private SharedPreferences preferences;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentWeoucBinding.inflate(inflater, container, true);
activity = requireActivity();
context = requireContext();
root = binding.getRoot();
preferences = context.getSharedPreferences("weouc", MODE_PRIVATE);
return root;
}
}
@@ -0,0 +1,24 @@
package cn.nahco3awa.naouc.util;
import android.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import synjones.commerce.utils.JniQrCodeSign;
public class QrCodeSign {
private static final JniQrCodeSign jniQrCodeSign = new JniQrCodeSign();
public static String getSign(Map<?, ?> map) {
return jniQrCodeSign.GetSign(map);
}
public static String getSign(String str) {
return jniQrCodeSign.GetOfflineQrCode(str);
}
public static String getBase64(String str) {
return new String(Base64.decode(str, 0), StandardCharsets.UTF_8);
}
}
@@ -0,0 +1,26 @@
package cn.nahco3awa.naouc.util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
public class RSASign {
private static final String f16254a = "SHA1withRSA";
private static final String f16256c = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDil3PZhXSwuPZZ9M4oRARVCyvNjV6Ogw2ndE+1uIzt4SAsI5SlWwp3EL37es++FWd73lLX74h5NYxrzUo+yLPc1E0eqIw6MANPtd+mAFY+SsA2FdjJN91iNorqL+HKzYGzMn3yQ8BbiNWtX3L692smTRcVsimeeNm2/EdOAddrpQIDAQAB";
private static final String f16257d = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOKXc9mFdLC49ln0zihEBFULK82NXo6DDad0T7W4jO3hICwjlKVbCncQvft6z74VZ3veUtfviHk1jGvNSj7Is9zUTR6ojDowA0+136YAVj5KwDYV2Mk33WI2iuov4crNgbMyffJDwFuI1a1fcvr3ayZNFxWyKZ542bb8R04B12ulAgMBAAECgYAwiEnq/DerJmK1j8acPz1CTds68p2fHpjNFg+Al5+vz7lJWvGanS5XpEFc3MgkKYd5s3vA/nAXrg1+hYDyg6BqM+lI6OHRZxPynaeQQeOiMDdTvR+pZ3b8uSx386riD1DM5d1oGRg9tMvJxQVCQU0bLrxViv2+KJf44dT3yqLJ3QJBAOwmsjpZi1BT+13IREjmdwEuTZRf7Ksffa1SvNyI+EoIpHZrM6V1w6vhRmJsENWe75qvJYy3hhem3i77O6z84oMCQQD1ow/fPTNxtM5qQKxMux3BEixp/j23ib+MIkoswmd+ARGtUEKqwnjXJWoXneXfWhMQTTJhBb5REwOEjOmv8IC3AkB09dlyMuVgHKgz07uWS6cHS7Ka2UOzoX4yePcXVzN6H3utNv02ZvRJzeJ5XsKbuwM7HqI/ZqogTsJejIoK7JkXAkAODxoudctG+8lArZju/1qxnT+rhWC0645qD+Bc9XeE77y6Rbi7G0xdTAfpeCEbCoXCzhhPE0wUSdlOsd4CMuq7AkBUD8WlEup0Ypa7oXTPGIdCOPZ+gxIWfEKBMAvi1paik+HIRfBdeaIPG1PyXrYDg8QWcZ3IrzMqLd9+jZ7XdYUF";
public static String sign(HashMap<String, String> map) {
String str = "";
Object[] array = map.keySet().toArray();
Arrays.sort(array);
for (Object obj : array) {
str = (obj.equals("request") || obj.equals("timestamp")) ? str + obj + URLDecoder.decode(map.get(obj), StandardCharsets.UTF_8) : str + obj + map.get(obj);
}
System.out.println("sourcestr=" + str);
String strB = new SignUtils().getPrivateKey(str, f16257d, f16254a);
System.out.println("sign=" + strB);
return strB;
}
}
@@ -0,0 +1,33 @@
package cn.nahco3awa.naouc.util;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class SignUtils {
public String getPrivateKey(String data, String key, String alg) {
try {
return new String(Base64.getEncoder().encode(SignatureUtil.getPrivateSign(data.getBytes(), Base64.getDecoder().decode(key), alg)));
} catch (GeneralSecurityException e) {
return "";
}
}
public String sign(String s, String key, String mode) {
Base64.Encoder encoder = Base64.getEncoder();
try {
return new String(encoder.encode(SymmetricCryptoUtil.encrypt(s.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(key), mode, Cipher.ENCRYPT_MODE)));
} catch (NoSuchPaddingException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | InvalidKeyException |
IllegalBlockSizeException | BadPaddingException e) {
return "";
}
}
}
@@ -0,0 +1,26 @@
package cn.nahco3awa.naouc.util;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
public class SignatureUtil {
public static byte[] getPrivateSign(byte[] bs, byte[] bs2, String alg) throws GeneralSecurityException {
PrivateKey privateKeyA = a(bs2, alg);
Signature signature = Signature.getInstance(alg);
signature.initSign(privateKeyA);
signature.update(bs);
return signature.sign();
}
public static PrivateKey a(byte[] bArr, String str) throws GeneralSecurityException {
return KeyFactory.getInstance(a(str, "with")).generatePrivate(new PKCS8EncodedKeySpec(bArr));
}
public static String a(String str, String str2) {
int iIndexOf;
return (str2 == null || (iIndexOf = str.indexOf(str2)) == -1) ? "" : str.substring(iIndexOf + str2.length());
}
}
@@ -0,0 +1,61 @@
package cn.nahco3awa.naouc.util;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class SymmetricCryptoUtil {
public static byte[] encrypt(byte[] data, byte[] key, String algorithm, int mode) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String finalAlgorithm = algorithm + "/CBC/PKCS5Padding";
byte[] iv = createZeroBlock(finalAlgorithm);
return encrypt(key, iv, finalAlgorithm, "CBC", mode).doFinal(data);
}
public static Cipher encrypt(byte[] key, byte[] iv, String transformation, String algorithm, int mode) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException {
Cipher cipher = Cipher.getInstance(transformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, a(transformation, "/"));
if (isEquals(algorithm, "CBC")) {
cipher.init(mode, secretKeySpec, new IvParameterSpec(iv));
} else {
cipher.init(mode, secretKeySpec);
}
return cipher;
}
public static byte[] createZeroBlock(String transformation) throws NoSuchPaddingException, NoSuchAlgorithmException {
int blockSize = Cipher.getInstance(transformation).getBlockSize();
return new byte[blockSize];
}
public static boolean isEquals(CharSequence charSequence, CharSequence charSequence2) {
if (charSequence == charSequence2) {
return true;
}
if (charSequence == null || charSequence2 == null) {
return false;
}
if ((charSequence instanceof String) && (charSequence2 instanceof String)) {
return charSequence.equals(charSequence2);
}
return charSequence.equals(charSequence2);
}
public static String a(String str, String str2) {
if (str == null || str2 == null) {
return str;
}
if (str2.isEmpty()) {
return "";
}
int iIndexOf = str.indexOf(str2);
return iIndexOf == -1 ? str : str.substring(0, iIndexOf);
}
}
@@ -0,0 +1,56 @@
package cn.nahco3awa.naouc.util.passwd;
public class BarrettMu {
public BigInt modulus;
public int k;
public BigInt mu;
public BigInt bkplus1;
public BarrettMu(BigInt m) {
modulus = m.biCopy();
k = modulus.biHighIndex() + 1;
BigInt b2k = new BigInt();
b2k.digits[2 * k] = 1;
mu = BigInt.biDivide(b2k, modulus);
bkplus1 = new BigInt();
bkplus1.digits[k + 1] = 1;
}
public BigInt modulo(BigInt x) {
var q1 = BigInt.biDivideByRadixPower(x, this.k - 1);
var q2 = BigInt.biMultiply(q1, this.mu);
var q3 = BigInt.biDivideByRadixPower(q2, this.k + 1);
var r1 = BigInt.biModuloByRadixPower(x, this.k + 1);
var r2term = BigInt.biMultiply(q3, this.modulus);
var r2 = BigInt.biModuloByRadixPower(r2term, this.k + 1);
var r = BigInt.biSubtract(r1, r2);
if (r.isNeg) {
r = BigInt.biAdd(r, this.bkplus1);
}
var rgtem = BigInt.biCompare(r, this.modulus) >= 0;
while (rgtem) {
r = BigInt.biSubtract(r, this.modulus);
rgtem = BigInt.biCompare(r, this.modulus) >= 0;
}
return r;
}
public BigInt multiplyMod(BigInt x, BigInt y) {
var xy = BigInt.biMultiply(x, y);
return this.modulo(xy);
}
public BigInt powMod(BigInt x, BigInt y) {
var result = new BigInt();
result.digits[0] = 1;
var a = x;
var k = y;
while (true) {
if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a);
k = k.biShiftRight(1);
if (k.digits[0] == 0 && k.biHighIndex() == 0) break;
a = this.multiplyMod(a, a);
}
return result;
}
}
@@ -0,0 +1,444 @@
package cn.nahco3awa.naouc.util.passwd;
public class BigInt {
public boolean isNeg;
public int[] digits;
public static int maxDigits;
public static int[] zeroArray;
public static BigInt bigZero;
public static BigInt bigOne;
public static final int BI_RADIX = 1 << 16;
public static final int BI_RADIX_BASE = 2;
public static final int BI_RADIX_BITS = 16;
public static final int BI_HALF_RADIX = BI_RADIX >>> 1;
public static final long BI_RADIX_SQUARED = (long) BI_RADIX * BI_RADIX;
public static final int MAX_DIGIT_VAL = BI_RADIX - 1;
public static final long MAX_INTEGER = 9_999_999_999_999_998L;
public static final int[] LOW_BIT_MASKS = new int[] {
0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
};
public static final int[] HIGH_BIT_MASKS = new int[] {
0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,
0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF
};
public static final char[] HEX_TO_CHAR = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'
};
public static final char[] hexatrigesimalToChar = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
};
public static void setMaxDigits(int value) {
maxDigits = value;
zeroArray = new int[maxDigits];
for (int i = 0; i < maxDigits; i++) {
zeroArray[i] = 0;
}
bigZero = new BigInt();
bigOne = new BigInt();
bigOne.digits[0] = 1;
}
public BigInt() {
digits = zeroArray.clone();
isNeg = false;
}
public BigInt(boolean flag) {
if (flag) {
digits = null;
} else {
digits = zeroArray.clone();
}
isNeg = false;
}
public static int charToHex(char c) {
int zero = 48;
int nine = zero + 9;
int lA = 97;
int lZ = lA + 25;
int bA = 65;
int bZ = bA + 25;
if (c >= zero && c <= nine) {
return c - zero;
} else if (c >= bA && c <= bZ) {
return 10 + c - bA;
} else if (c >= lA && c <= lZ) {
return 10 + c - lA;
} else {
return 0;
}
}
public static int hexToDigit(String s) {
int result = 0;
int sl = Math.min(s.length(), 4);
for (int i = 0; i < sl; i++) {
result <<= 4;
result |= charToHex(s.charAt(i));
}
return result;
}
public static BigInt biFromHex(String s) {
BigInt result = new BigInt();
int sl = s.length();
for (int i = sl, j = 0; i > 0; i -= 4, ++j) {
int ia = Math.max(i - 4, 0);
int ib = Math.min(i, 4);
result.digits[j] = hexToDigit(s.substring(Math.min(ia, ib), Math.max(ia, ib)));
}
return result;
}
public static BigInt biDivideByRadixPower(BigInt x, int n) {
var ret = new BigInt();
arrayCopy(x.digits, n, ret.digits, 0, ret.digits.length - n);
return ret;
}
public static BigInt biMultiply(BigInt x, BigInt y) {
var result = new BigInt();
int c;
var n = x.biHighIndex();
var t = y.biHighIndex();
int uv, k;
for (int i = 0; i <= t; ++i) {
c = 0;
k = i;
for (int j = 0; j <= n; ++j, ++k) {
uv = result.digits[k] + x.digits[j] * y.digits[i] + c;
result.digits[k] = uv & MAX_DIGIT_VAL;
c = uv >>> BI_RADIX_BITS;
//c = Math.floor(uv / biRadix);
}
result.digits[i + n + 1] = c;
}
// Someone give me a logical xor, please.
result.isNeg = x.isNeg != y.isNeg;
return result;
}
public static BigInt biModuloByRadixPower(BigInt x, int n) {
var result = new BigInt();
arrayCopy(x.digits, 0, result.digits, 0, n);
return result;
}
public static String biToHex(BigInt x) {
StringBuilder result = new StringBuilder();
for (var i = x.biHighIndex(); i > -1; --i) {
result.append(digitToHex(x.digits[i]));
}
return result.toString();
}
public static String reverseStr(String s)
{
StringBuilder result = new StringBuilder();
for (var i = s.length() - 1; i > -1; --i) {
result.append(s.charAt(i));
}
return result.toString();
}
private static String digitToHex(int n) {
var mask = 0xf;
StringBuilder result = new StringBuilder();
for (int i = 0; i < 4; ++i) {
result.append(HEX_TO_CHAR[n & mask]);
n >>>= 4;
}
return reverseStr(result.toString());
}
public static String biToString(BigInt x, int radix) {
var b = new BigInt();
b.digits[0] = radix;
var qr = biDivideModulo(x, b);
StringBuilder result = new StringBuilder(hexatrigesimalToChar[qr[1].digits[0]]);
while (biCompare(qr[0], bigZero) == 1) {
qr = biDivideModulo(qr[0], b);
// [???] digit = qr[1].digits[0];
result.append(hexatrigesimalToChar[qr[1].digits[0]]);
}
return (x.isNeg ? "-" : "") + reverseStr(result.toString());
}
public int biHighIndex() {
int result = digits.length - 1;
while (result > 0 && digits[result] == 0) -- result;
return result;
}
public BigInt biCopy() {
BigInt result = new BigInt(true);
result.digits = digits.clone();
result.isNeg = isNeg;
return result;
}
public static final int BITS_PER_DIGIT = 16;
public int biNumBits() {
int n = biHighIndex();
int d = digits[n];
int m = (n + 1) * BITS_PER_DIGIT;
int result;
for (result = m; result > m - BITS_PER_DIGIT; --result) {
if ((d & 0x8000) != 0) break;
d <<= 1;
}
return result;
}
public static BigInt biAdd(BigInt x, BigInt y) {
BigInt result;
if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = biSubtract(x, y);
y.isNeg = !y.isNeg;
}
else {
result = new BigInt();
var c = 0;
int n;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] + y.digits[i] + c;
result.digits[i] = n % BI_RADIX;
c = (n >= BI_RADIX) ? 1 : 0;
}
result.isNeg = x.isNeg;
}
return result;
}
public static BigInt biSubtract(BigInt x, BigInt y) {
BigInt result;
if (x.isNeg != y.isNeg) {
y.isNeg = !y.isNeg;
result = biAdd(x, y);
y.isNeg = !y.isNeg;
} else {
result = new BigInt();
int n, c;
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = x.digits[i] - y.digits[i] + c;
result.digits[i] = n % BI_RADIX;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += BI_RADIX;
c = -((n < 0) ? 1 : 0);
}
// Fix up the negative sign, if any.
if (c == -1) {
c = 0;
for (var i = 0; i < x.digits.length; ++i) {
n = -result.digits[i] + c;
result.digits[i] = n % BI_RADIX;
// Stupid non-conforming modulus operation.
if (result.digits[i] < 0) result.digits[i] += BI_RADIX;
c = -((n < 0) ? 1 : 0);
}
// Result is opposite sign of arguments.
result.isNeg = !x.isNeg;
} else {
// Result is same sign.
result.isNeg = x.isNeg;
}
}
return result;
}
public static void arrayCopy(int[] src, int srcStart, int[] dest, int destStart, int n)
{
var m = Math.min(srcStart + n, src.length);
for (int i = srcStart, j = destStart; i < m; ++i, ++j) {
dest[j] = src[i];
}
}
public BigInt biShiftLeft(int n) {
int digitCount = (int) Math.floor((double) n / BITS_PER_DIGIT);
var result = new BigInt();
arrayCopy(digits, 0, result.digits, digitCount,
result.digits.length - digitCount);
var bits = n % BITS_PER_DIGIT;
var rightBits = BITS_PER_DIGIT - bits;
int i, i1;
for (i = result.digits.length - 1, i1 = i - 1; i > 0; --i, --i1) {
result.digits[i] = ((result.digits[i] << bits) & MAX_DIGIT_VAL) |
((result.digits[i1] & HIGH_BIT_MASKS[bits]) >>>
(rightBits));
}
result.digits[0] = ((result.digits[i] << bits) & MAX_DIGIT_VAL);
result.isNeg = isNeg;
return result;
}
public static int biCompare(BigInt x, BigInt y)
{
if (x.isNeg != y.isNeg) {
return 1 - 2 * (x.isNeg ? 1 : 0);
}
for (var i = x.digits.length - 1; i >= 0; --i) {
if (x.digits[i] != y.digits[i]) {
if (x.isNeg) {
return 1 - 2 * (x.digits[i] > y.digits[i] ? 1 : 0);
} else {
return 1 - 2 * (x.digits[i] < y.digits[i] ? 1 : 0);
}
}
}
return 0;
}
public BigInt biShiftRight(int n)
{
int digitCount = (int) Math.floor((double) n / BITS_PER_DIGIT);
var result = new BigInt();
arrayCopy(digits, digitCount, result.digits, 0,
digits.length - digitCount);
var bits = n % BITS_PER_DIGIT;
var leftBits = BITS_PER_DIGIT - bits;
for (int i = 0, i1 = i + 1; i < result.digits.length - 1; ++i, ++i1) {
result.digits[i] = (result.digits[i] >>> bits) |
((result.digits[i1] & LOW_BIT_MASKS[bits]) << leftBits);
}
result.digits[result.digits.length - 1] >>>= bits;
result.isNeg = isNeg;
return result;
}
public static BigInt biMultiplyDigit(BigInt x, int y)
{
int n, c, uv;
BigInt result = new BigInt();
n = x.biHighIndex();
c = 0;
for (var j = 0; j <= n; ++j) {
uv = result.digits[j] + x.digits[j] * y + c;
result.digits[j] = uv & MAX_DIGIT_VAL;
c = uv >>> BI_RADIX_BITS;
//c = Math.floor(uv / biRadix);
}
result.digits[1 + n] = c;
return result;
}
public static BigInt biMultiplyByRadixPower(BigInt x, int n)
{
var result = new BigInt();
arrayCopy(x.digits, 0, result.digits, n, result.digits.length - n);
return result;
}
public static BigInt[] biDivideModulo(BigInt x, BigInt y) {
int nb = x.biNumBits();
int tb = y.biNumBits();
boolean origYIsNeg = y.isNeg;
BigInt q, r;
if (nb < tb) {
if (x.isNeg) {
q = bigOne.biCopy();
q.isNeg = !y.isNeg;
x.isNeg = false;
y.isNeg = false;
r = biSubtract(y, x);
// Restore signs, 'cause they're references.
x.isNeg = true;
y.isNeg = origYIsNeg;
} else {
q = new BigInt();
r = x.biCopy();
}
return new BigInt[]{q, r};
}
q = new BigInt();
r = x;
// Normalize Y.
int t = (int) (Math.ceil((double) tb / BITS_PER_DIGIT) - 1);
var lambda = 0;
while (y.digits[t] < BI_HALF_RADIX) {
y = y.biShiftLeft(1);
++lambda;
++tb;
t = (int) (Math.ceil((double) tb / BITS_PER_DIGIT) - 1);
}
// Shift r over to keep the quotient constant. We'll shift the
// remainder back at the end.
r = r.biShiftLeft(lambda);
nb += lambda; // Update the bit count for x.
int n = (int) (Math.ceil((double) nb / BITS_PER_DIGIT) - 1);
var b = biMultiplyByRadixPower(y, n - t);
while (biCompare(r, b) != -1) {
++q.digits[n - t];
r = biSubtract(r, b);
}
for (var i = n; i > t; --i) {
var ri = (i >= r.digits.length) ? 0 : r.digits[i];
var ri1 = (i - 1 >= r.digits.length) ? 0 : r.digits[i - 1];
var ri2 = (i - 2 >= r.digits.length) ? 0 : r.digits[i - 2];
var yt = (t >= y.digits.length) ? 0 : y.digits[t];
var yt1 = (t - 1 >= y.digits.length) ? 0 : y.digits[t - 1];
if (ri == yt) {
q.digits[i - t - 1] = MAX_DIGIT_VAL;
} else {
q.digits[i - t - 1] = (int) Math.floor((double) (ri * BI_RADIX + ri1) / yt);
}
var c1 = q.digits[i - t - 1] * ((yt * BI_RADIX) + yt1);
var c2 = (ri * BI_RADIX_SQUARED) + (((long) ri1 * BI_RADIX) + ri2);
while (c1 > c2) {
--q.digits[i - t - 1];
c1 = q.digits[i - t - 1] * ((yt * BI_RADIX) | yt1);
c2 = ((long) ri * BI_RADIX * BI_RADIX) + (((long) ri1 * BI_RADIX) + ri2);
}
b = biMultiplyByRadixPower(y, i - t - 1);
r = biSubtract(r, biMultiplyDigit(b, q.digits[i - t - 1]));
if (r.isNeg) {
r = biAdd(r, b);
--q.digits[i - t - 1];
}
}
r = r.biShiftRight(lambda);
// Fiddle with the signs and stuff to make sure that 0 <= r < y.
q.isNeg = x.isNeg != origYIsNeg;
if (x.isNeg) {
if (origYIsNeg) {
q = biAdd(q, bigOne);
} else {
q = biSubtract(q, bigOne);
}
y = y.biShiftRight(lambda);
r = biSubtract(y, r);
}
// Check for the unbelievably stupid degenerate case of r == -0.
if (r.digits[0] == 0 && r.biHighIndex() == 0) r.isNeg = false;
return new BigInt[]{q, r};
}
public static BigInt biDivide(BigInt x, BigInt y) {
return biDivideModulo(x, y)[0];
}
}
@@ -0,0 +1,94 @@
package cn.nahco3awa.naouc.util.passwd;
public class RSA {
public static class RSAKeyPair {
public BigInt e;
public BigInt d;
public BigInt m;
public int digitSize;
public int chunkSize;
public int radix;
public BarrettMu barrett;
public RSAKeyPair(String encryptionExponent, String decryptionExponent, String modulus) {
this.e = BigInt.biFromHex(encryptionExponent);
this.d = BigInt.biFromHex(decryptionExponent);
this.m = BigInt.biFromHex(modulus);
////////////////////////////////// TYF
this.digitSize = 2 * m.biHighIndex() + 2;
this.chunkSize = this.digitSize - 11;
////////////////////////////////// TYF
this.radix = 16;
this.barrett = new BarrettMu(this.m);
}
}
public static String encryptedString(RSAKeyPair key, String s) {
////////////////////////////////// TYF
if (key.chunkSize > key.digitSize - 11)
{
return "Error";
}
////////////////////////////////// TYF
var a = new int[s.length()];
var sl = s.length();
var i = 0;
while (i < sl) {
a[i] = s.charAt(i);
i++;
}
var al = a.length;
StringBuilder result = new StringBuilder();
int j, k;
BigInt block;
for (i = 0; i < al; i += key.chunkSize) {
block = new BigInt();
j = 0;
//for (k = i; k < i + key.chunkSize; ++j) {
// block.digits[j] = a[k++];
// block.digits[j] += a[k++] << 8;
//}
////////////////////////////////// TYF
// Add PKCS#1 v1.5 padding
// 0x00 || 0x02 || PseudoRandomNonZeroBytes || 0x00 || Message
// Variable a before padding must be of at most digitSize-11
// That is for 3 marker bytes plus at least 8 random non-zero bytes
int x;
var msgLength = (i+key.chunkSize)>al ? al%key.chunkSize : key.chunkSize;
var paddedSize = Math.max(8, key.digitSize - 3 - msgLength);
// Variable b with 0x00 || 0x02 at the highest index.
int[] b = new int[Math.max(msgLength+1+paddedSize, key.digitSize)];
for (x=0; x<msgLength; x++)
{
b[x] = a[i+msgLength-1-x];
}
b[msgLength] = 0; // marker
for (x=0; x<paddedSize; x++) {
b[msgLength+1+x] = (int) (Math.floor(Math.random()*254) + 1); // [1,255]
}
// It can be asserted that msgLength+paddedSize == key.digitSize-3
b[key.digitSize-2] = 2; // marker
b[key.digitSize-1] = 0; // marker
for (k = 0; k < key.digitSize; ++j)
{
block.digits[j] = b[k++];
block.digits[j] += b[k++] << 8;
}
////////////////////////////////// TYF
var crypt = key.barrett.powMod(block, key.e);
var text = key.radix == 16 ? BigInt.biToHex(crypt) : BigInt.biToString(crypt, key.radix);
result.append(text).append(" ");
}
return result.substring(0, Math.max(result.toString().length() - 1, 0)); // Remove last space.
}
}
@@ -0,0 +1,22 @@
package synjones.commerce.utils;
import java.util.Map;
public class JniQrCodeSign {
public native String GetOfflineQrCode(String str);
public native String GetOfflineQrCodeData(String str);
public native String GetRandomNum();
/** @noinspection rawtypes*/
public native String GetSign(Map map);
public native String SetKeyAndSha1(String str, String str2);
public native String SetKeyAndSha1(String str, String str2, int i);
static {
System.loadLibrary("JniQrCodeSign");
}
}
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13.41,18.09L13.41,20h-2.67v-1.93c-1.71,-0.36 -3.16,-1.46 -3.27,-3.4h1.96c0.1,1.05 0.82,1.87 2.65,1.87 1.96,0 2.4,-0.98 2.4,-1.59 0,-0.83 -0.44,-1.61 -2.67,-2.14 -2.48,-0.6 -4.18,-1.62 -4.18,-3.67 0,-1.72 1.39,-2.84 3.11,-3.21L10.74,4h2.67v1.95c1.86,0.45 2.79,1.86 2.85,3.39L14.3,9.34c-0.05,-1.11 -0.64,-1.87 -2.22,-1.87 -1.5,0 -2.4,0.68 -2.4,1.64 0,0.84 0.65,1.39 2.67,1.91s4.18,1.39 4.18,3.91c-0.01,1.83 -1.38,2.83 -3.12,3.16z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M5,13.18v4L12,21l7,-3.82v-4L12,17l-7,-3.82zM12,3L1,9l11,6 9,-4.91V17h2V9L12,3z"/>
</vector>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#333333"
android:alpha="0.6">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2c-5.33,4.55 -8,8.48 -8,11.8c0,4.98 3.8,8.2 8,8.2s8,-3.22 8,-8.2C20,10.48 17.33,6.55 12,2zM7.83,14c0.37,0 0.67,0.26 0.74,0.62c0.41,2.22 2.28,2.98 3.64,2.87c0.43,-0.02 0.79,0.32 0.79,0.75c0,0.4 -0.32,0.73 -0.72,0.75c-2.13,0.13 -4.62,-1.09 -5.19,-4.12C7.01,14.42 7.37,14 7.83,14z"/>
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z" />
</vector>

Some files were not shown because too many files have changed in this diff Show More