|
@@ -0,0 +1,369 @@
|
|
|
+package xn.huaxue.update;
|
|
|
+
|
|
|
+import android.content.Intent;
|
|
|
+import android.content.IntentFilter;
|
|
|
+import android.os.AsyncTask;
|
|
|
+import android.os.Bundle;
|
|
|
+import android.os.CountDownTimer;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+import android.widget.EditText;
|
|
|
+import android.widget.TextView;
|
|
|
+
|
|
|
+import androidx.annotation.Nullable;
|
|
|
+import androidx.appcompat.app.AppCompatActivity;
|
|
|
+import androidx.core.util.Pair;
|
|
|
+
|
|
|
+import com.blankj.utilcode.util.ActivityUtils;
|
|
|
+import com.blankj.utilcode.util.AppUtils;
|
|
|
+import com.blankj.utilcode.util.FileUtils;
|
|
|
+import com.blankj.utilcode.util.GsonUtils;
|
|
|
+import com.blankj.utilcode.util.LogUtils;
|
|
|
+import com.blankj.utilcode.util.NetworkUtils;
|
|
|
+import com.blankj.utilcode.util.SPUtils;
|
|
|
+import com.blankj.utilcode.util.ShellUtils;
|
|
|
+import com.blankj.utilcode.util.ThreadUtils;
|
|
|
+import com.blankj.utilcode.util.TimeUtils;
|
|
|
+import com.blankj.utilcode.util.ToastUtils;
|
|
|
+import com.hjq.permissions.Permission;
|
|
|
+import com.hjq.permissions.XXPermissions;
|
|
|
+import com.lxj.xpopup.XPopup;
|
|
|
+import com.lxj.xpopup.impl.InputConfirmPopupView;
|
|
|
+
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.concurrent.ThreadLocalRandom;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+import okhttp3.Response;
|
|
|
+import xn.huaxue.update.constant.AppConstant;
|
|
|
+import xn.huaxue.update.databinding.ActivityMainBinding;
|
|
|
+import xn.huaxue.update.http.HttpTool;
|
|
|
+import xn.huaxue.update.http.bean.response.UpdateTask;
|
|
|
+import xn.huaxue.update.receiver.TimeTickReceiver;
|
|
|
+
|
|
|
+public class MainActivity extends AppCompatActivity {
|
|
|
+ private ActivityMainBinding binding;
|
|
|
+ private CountDownTimer initCdTimer;
|
|
|
+ private InputConfirmPopupView inputConfirmPopupView;
|
|
|
+ private CountDownTimer requestPermissionCdTimer;
|
|
|
+ private CountDownTimer timeCdTimer;
|
|
|
+ private TimeTickReceiver timeTickReceiver;
|
|
|
+ private CountDownTimer updateCdTimer;
|
|
|
+ private final AtomicBoolean isUploading = new AtomicBoolean(false);
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
|
|
|
+ super.onCreate(savedInstanceState);
|
|
|
+ binding = ActivityMainBinding.inflate(getLayoutInflater());
|
|
|
+ setContentView(binding.getRoot());
|
|
|
+ timeCdTimer = new CountDownTimer(1000, 1000) {
|
|
|
+ @Override
|
|
|
+ public void onTick(long millisUntilFinished) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFinish() {
|
|
|
+ if (isFinishing() || isDestroyed()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!new SimpleDateFormat("HH:mm", Locale.getDefault()).format(new Date()).equals("06:01")) {
|
|
|
+ MainActivity.this.binding.time.setText(TimeUtils.getNowString());
|
|
|
+ MainActivity.this.timeCdTimer.start();
|
|
|
+ } else {
|
|
|
+ LogUtils.d("定时重启");
|
|
|
+ ShellUtils.execCmd("reboot", true);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ };
|
|
|
+ timeCdTimer.start();
|
|
|
+ requestPermissionCdTimer = new CountDownTimer(1000, 1000) {
|
|
|
+ @Override
|
|
|
+ public void onTick(long millisUntilFinished) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFinish() {
|
|
|
+ requestPermission();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ binding.main.postDelayed(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ if (!isFinishing() && !isDestroyed()) {
|
|
|
+ if (!isUploading.get()) {
|
|
|
+ LogUtils.d("初始化失败");
|
|
|
+ ShellUtils.execCmd("reboot", true);
|
|
|
+ } else {
|
|
|
+ LogUtils.d("初始化成功");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 60 * 1000);
|
|
|
+
|
|
|
+ initCdTimer = new CountDownTimer(5 * 1000, 100) {
|
|
|
+ @Override
|
|
|
+ public void onTick(long millisUntilFinished) {
|
|
|
+ binding.tipsTV.setText((millisUntilFinished / 1000) + "秒后开始初始化!");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFinish() {
|
|
|
+ MainActivity.this.binding.tipsTV.setText("开始初始化...");
|
|
|
+ AsyncTask.execute(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ Tool.INSTANCE.showBar(false);
|
|
|
+ MainActivity.this.requestPermissionCdTimer.start();
|
|
|
+ MainActivity.this.isUploading.set(true);
|
|
|
+ } catch (Exception e) {
|
|
|
+ LogUtils.e("重启", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ });
|
|
|
+ MainActivity.this.initCdTimer.cancel();
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ };
|
|
|
+ initCdTimer.start();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void requestPermission() {
|
|
|
+ if (!XXPermissions.isGrantedPermissions(this, Permission.READ_EXTERNAL_STORAGE)
|
|
|
+ || !XXPermissions.isGrantedPermissions(this, Permission.WRITE_EXTERNAL_STORAGE)
|
|
|
+ || !XXPermissions.isGrantedPermissions(this, Permission.NOTIFICATION_SERVICE)) {
|
|
|
+ Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.READ_EXTERNAL_STORAGE");
|
|
|
+ Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.WRITE_EXTERNAL_STORAGE");
|
|
|
+ Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.NOTIFICATION_SERVICE");
|
|
|
+ this.requestPermissionCdTimer.start();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.requestPermissionCdTimer.cancel();
|
|
|
+ terminalAuth();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ ThreadUtils.SimpleTask<Boolean> simpleTask = new ThreadUtils.SimpleTask<Boolean>() {
|
|
|
+ @Override
|
|
|
+ public Boolean doInBackground() throws Throwable {
|
|
|
+ ShellUtils.CommandResult result = ShellUtils.execCmd(String.format("ping -c 5 %s", Tool.INSTANCE.getBaseUrl().host()), false);
|
|
|
+ if (result.result == 0) {
|
|
|
+ PingResult pingResult = parsePingOutput(result.successMsg);
|
|
|
+ return pingResult.getAvgRtt() < 100;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSuccess(Boolean result) {
|
|
|
+ if (result) {
|
|
|
+ MainActivity.this.binding.tipsTV.setText("鉴权中...");
|
|
|
+ ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Pair<Boolean, String>>() {
|
|
|
+ @Override
|
|
|
+ public Pair<Boolean, String> doInBackground() throws Throwable {
|
|
|
+ try {
|
|
|
+ SPUtils.getInstance().put("TerminalAuth", "");
|
|
|
+ Response responseTerminalAuth = HttpTool.INSTANCE.terminalAuth();
|
|
|
+ if (responseTerminalAuth.isSuccessful()) {
|
|
|
+ JSONObject jSONObject = new JSONObject(responseTerminalAuth.body().string());
|
|
|
+ if (200 == jSONObject.getInt("code")) {
|
|
|
+ String string = jSONObject.getString("data");
|
|
|
+ SPUtils sPUtils = SPUtils.getInstance();
|
|
|
+ if (TextUtils.isEmpty(string)) {
|
|
|
+ string = "";
|
|
|
+ }
|
|
|
+ sPUtils.put("TerminalAuth", string);
|
|
|
+ return Pair.create(true, "");
|
|
|
+ }
|
|
|
+ return Pair.create(false, jSONObject.getString("message"));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ LogUtils.e(Log.getStackTraceString(e));
|
|
|
+ }
|
|
|
+ return Pair.create(false, "鉴权异常,请联系管理员!");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSuccess(Pair<Boolean, String> result) {
|
|
|
+ if (result.first) {
|
|
|
+ ThreadUtils.cancel(MainActivity.this.simpleTask);
|
|
|
+ MainActivity.this.timeTickReceiver = new TimeTickReceiver();
|
|
|
+ MainActivity.this.registerReceiver(MainActivity.this.timeTickReceiver, new IntentFilter("android.intent.action.TIME_TICK"));
|
|
|
+ MainActivity.this.updateCdTimer = new CountDownTimer(20000L, 1000L) { // from class: xn.huaxue.update.MainActivity.5.1.1
|
|
|
+ @Override // android.os.CountDownTimer
|
|
|
+ public void onTick(long j) {
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override // android.os.CountDownTimer
|
|
|
+ public void onFinish() {
|
|
|
+ UpdateTool.INSTANCE.checkUpdate(MainActivity.this);
|
|
|
+ AsyncTask.execute(new Runnable() { // from class: xn.huaxue.update.MainActivity.5.1.1.1
|
|
|
+ @Override // java.lang.Runnable
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ HttpTool.INSTANCE.heartbeat();
|
|
|
+ } catch (Exception e) {
|
|
|
+ LogUtils.e(Log.getStackTraceString(e));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ MainActivity.this.updateCdTimer.start();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ MainActivity.this.updateCdTimer.start();
|
|
|
+ Tool.INSTANCE.stopApp("xn.hxp");
|
|
|
+ Tool.INSTANCE.openApp("xn.hxp");
|
|
|
+ AsyncTask.execute(() -> {
|
|
|
+ if (SPUtils.getInstance().getBoolean("isSelfUpdate", false)) {
|
|
|
+ try {
|
|
|
+ UpdateTask.Task task = (UpdateTask.Task) GsonUtils.fromJson(SPUtils.getInstance().getString("SelfUpdate", ""), UpdateTask.Task.class);
|
|
|
+ if (task != null) {
|
|
|
+ HttpTool.INSTANCE.updateCallBack(task.getTaskId(), task.getDeviceCode(), true, true);
|
|
|
+ SPUtils.getInstance().put("isSelfUpdate", false, true);
|
|
|
+ Tool.INSTANCE.reboot();
|
|
|
+ }
|
|
|
+ } catch (IOException | JSONException e) {
|
|
|
+ LogUtils.e(Log.getStackTraceString(e));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ MainActivity.this.binding.tipsTV.setText("运行中");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ThreadUtils.cancel(MainActivity.this.simpleTask);
|
|
|
+ } else {
|
|
|
+ MainActivity.this.binding.tipsTV.setText("无法连接到服务器,正在重试...");
|
|
|
+ }
|
|
|
+ String iPAddress = NetworkUtils.getIPAddress(true);
|
|
|
+ TextView textView = MainActivity.this.binding.ipTV;
|
|
|
+ if (TextUtils.isEmpty(iPAddress)) {
|
|
|
+ iPAddress = "NULL";
|
|
|
+ }
|
|
|
+ textView.setText(iPAddress);
|
|
|
+ String serialNumber = Tool.INSTANCE.getSerialNumber();
|
|
|
+ MainActivity.this.binding.snTV.setText(TextUtils.isEmpty(serialNumber) ? "NULL" : serialNumber);
|
|
|
+
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ private void terminalAuth() {
|
|
|
+ ThreadUtils.executeByCachedAtFixRate(simpleTask, ThreadLocalRandom.current().nextInt(10, 20), TimeUnit.SECONDS);
|
|
|
+ // 清理一个月前的log
|
|
|
+ AsyncTask.execute(() -> {
|
|
|
+ List<File> fileList = FileUtils.listFilesInDir("/sdcard/logs/");
|
|
|
+ List<File> crashList = FileUtils.listFilesInDir("/sdcard/logs/crash");
|
|
|
+ for (int i = 0; i < fileList.size(); i++) {
|
|
|
+ File file = fileList.get(i);
|
|
|
+ long oneMonth = 30 * 86400 * 1000L;
|
|
|
+ if ((System.currentTimeMillis() - file.lastModified()) > oneMonth) {
|
|
|
+ LogUtils.d("删除日志文件", file);
|
|
|
+ FileUtils.delete(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int i = 0; i < crashList.size(); i++) {
|
|
|
+ File file = crashList.get(i);
|
|
|
+ long oneMonth = 30 * 86400 * 1000L;
|
|
|
+ if ((System.currentTimeMillis() - file.lastModified()) > oneMonth) {
|
|
|
+ LogUtils.d("删除crash文件", file);
|
|
|
+ FileUtils.delete(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onPostCreate(@Nullable Bundle savedInstanceState) {
|
|
|
+ super.onPostCreate(savedInstanceState);
|
|
|
+ binding.versionNameTV.setText(AppUtils.getAppVersionName());
|
|
|
+
|
|
|
+ inputConfirmPopupView = new XPopup.Builder(this).autoDismiss(false).asInputConfirm("Tips", "请输入管理员密码",
|
|
|
+ text -> {
|
|
|
+ if (text.equals(SPUtils.getInstance().getString(AppConstant.ADMIN_PASSWORD, "admin@098&"))) {
|
|
|
+ ActivityUtils.startActivity(SettingActivity.class);
|
|
|
+ inputConfirmPopupView.dismiss();
|
|
|
+ } else {
|
|
|
+ ToastUtils.showLong("密码不正确,请重新输入!");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ binding.logoIV.setOnLongClickListener(v -> {
|
|
|
+ if (AppUtils.isAppDebug()) {
|
|
|
+ ActivityUtils.startActivity(SettingActivity.class);
|
|
|
+ } else {
|
|
|
+ EditText editText = inputConfirmPopupView.getEditText();
|
|
|
+ if (null != editText) {
|
|
|
+ editText.setText("");
|
|
|
+ }
|
|
|
+ inputConfirmPopupView.show();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onDestroy() {
|
|
|
+ super.onDestroy();
|
|
|
+ TimeTickReceiver timeTickReceiver = this.timeTickReceiver;
|
|
|
+ if (timeTickReceiver != null) {
|
|
|
+ unregisterReceiver(timeTickReceiver);
|
|
|
+ this.timeTickReceiver = null;
|
|
|
+ }
|
|
|
+ Tool.INSTANCE.exitApp();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public PingResult parsePingOutput(String pingOutput) {
|
|
|
+ PingResult result = new PingResult();
|
|
|
+ // 解析目标IP
|
|
|
+ Pattern ipPattern = Pattern.compile("PING (\\d+\\.\\d+\\.\\d+\\.\\d+)");
|
|
|
+ Matcher ipMatcher = ipPattern.matcher(pingOutput);
|
|
|
+ if (ipMatcher.find()) {
|
|
|
+ result.setTargetIP(ipMatcher.group(1));
|
|
|
+ }
|
|
|
+ // 解析统计信息
|
|
|
+ Pattern statsPattern = Pattern.compile(
|
|
|
+ "(\\d+) packets transmitted, (\\d+) received, (\\d+)% packet loss, time (\\d+)ms"
|
|
|
+ );
|
|
|
+ Matcher statsMatcher = statsPattern.matcher(pingOutput);
|
|
|
+ if (statsMatcher.find()) {
|
|
|
+ result.setPacketsTransmitted(Integer.parseInt(statsMatcher.group(1)));
|
|
|
+ result.setPacketsReceived(Integer.parseInt(statsMatcher.group(2)));
|
|
|
+ result.setPacketLossPercentage(Double.parseDouble(statsMatcher.group(3)));
|
|
|
+ }
|
|
|
+ // 解析RTT信息
|
|
|
+ Pattern rttPattern = Pattern.compile(
|
|
|
+ "rtt min/avg/max/mdev = (\\d+\\.\\d+)/(\\d+\\.\\d+)/(\\d+\\.\\d+)/(\\d+\\.\\d+) ms"
|
|
|
+ );
|
|
|
+ Matcher rttMatcher = rttPattern.matcher(pingOutput);
|
|
|
+ if (rttMatcher.find()) {
|
|
|
+ result.setMinRtt(Double.parseDouble(rttMatcher.group(1)));
|
|
|
+ result.setAvgRtt(Double.parseDouble(rttMatcher.group(2)));
|
|
|
+ result.setMaxRtt(Double.parseDouble(rttMatcher.group(3)));
|
|
|
+ result.setMdevRtt(Double.parseDouble(rttMatcher.group(4)));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+}
|