增加串口和定时开关机类
This commit is contained in:
@@ -51,4 +51,6 @@ dependencies {
|
|||||||
implementation libs.banner
|
implementation libs.banner
|
||||||
implementation libs.glide
|
implementation libs.glide
|
||||||
annotationProcessor libs.glidecompiler
|
annotationProcessor libs.glidecompiler
|
||||||
|
|
||||||
|
implementation 'io.github.xmaihh:serialport:2.1.1'
|
||||||
}
|
}
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package cn.ykbox.dashboard;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
|
||||||
import androidx.activity.result.ActivityResultCallback;
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import cn.ykbox.dashboard.databinding.ActivityBuildingDashboardBinding;
|
|
||||||
|
|
||||||
public class BuildingDashboardActivity extends FullscreenActivity {
|
|
||||||
private final static String TAG = "DashboardActivity";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the system UI should be auto-hidden after
|
|
||||||
* {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
|
|
||||||
*/
|
|
||||||
private static final boolean AUTO_HIDE = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
|
|
||||||
* user interaction before hiding the system UI.
|
|
||||||
*/
|
|
||||||
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Touch listener to use for in-layout UI controls to delay hiding the
|
|
||||||
* system UI. This is to prevent the jarring behavior of controls going away
|
|
||||||
* while interacting with activity UI.
|
|
||||||
*/
|
|
||||||
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
|
||||||
switch (motionEvent.getAction()) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
if (AUTO_HIDE) {
|
|
||||||
delayedHide(AUTO_HIDE_DELAY_MILLIS);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
view.performClick();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private ActivityBuildingDashboardBinding binding;
|
|
||||||
/// ActivityResultLauncher 用于处理设置页面的返回结果
|
|
||||||
private ActivityResultLauncher<Intent> settingsLauncher;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
binding = ActivityBuildingDashboardBinding.inflate(getLayoutInflater());
|
|
||||||
setContentView(binding.getRoot());
|
|
||||||
|
|
||||||
super.setViews(binding.webview, binding.fullscreenContentControls);
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
// 初始化 ActivityResultLauncher
|
|
||||||
initSettingsLauncher();
|
|
||||||
setupWebView();
|
|
||||||
|
|
||||||
// Upon interacting with UI controls, delay any scheduled hide()
|
|
||||||
// operations to prevent the jarring behavior of controls going away
|
|
||||||
// while interacting with the UI.
|
|
||||||
binding.settingsButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
// 打开设置界面
|
|
||||||
openSettingsActivity();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
SharedPreferences pre = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
String url = pre.getString("k_url", "http://10.1.58.176:8002");
|
|
||||||
binding.webview.loadUrl(url); // 加载网页
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化设置页面的 ActivityResultLauncher
|
|
||||||
*/
|
|
||||||
private void initSettingsLauncher() {
|
|
||||||
settingsLauncher = registerForActivityResult(
|
|
||||||
new ActivityResultContracts.StartActivityForResult(),
|
|
||||||
result -> {
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开设置页面
|
|
||||||
*/
|
|
||||||
private void openSettingsActivity() {
|
|
||||||
Intent intent = new Intent(this, SettingsActivity.class);
|
|
||||||
settingsLauncher.launch(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupWebView() {
|
|
||||||
binding.webview.getSettings().setJavaScriptEnabled(true); // 启用 JavaScript
|
|
||||||
binding.webview.setWebViewClient(new WebViewClient()); // 防止跳转到外部浏览器
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
129
app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java
Normal file
129
app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class ConfigReader {
|
||||||
|
private static final String TAG = "ConfigReader";
|
||||||
|
private static final String PREFS_NAME = "AppConfig";
|
||||||
|
private static final String POWER_OFF_TIME_KEY = "PowerOffTVTime";
|
||||||
|
|
||||||
|
private Context context;
|
||||||
|
private String configUrl;
|
||||||
|
private OkHttpClient httpClient;
|
||||||
|
private OnConfigLoadListener listener;
|
||||||
|
|
||||||
|
// 回调接口
|
||||||
|
public interface OnConfigLoadListener {
|
||||||
|
void onConfigLoaded(String powerOffTime);
|
||||||
|
void onConfigLoadFailed(String error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigReader(Context context, String configUrl) {
|
||||||
|
this.context = context;
|
||||||
|
this.configUrl = configUrl;
|
||||||
|
this.httpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnConfigLoadListener(OnConfigLoadListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步读取配置文件
|
||||||
|
public void loadConfig() {
|
||||||
|
new ConfigLoadTask().execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从本地获取保存的PowerOffTVTime
|
||||||
|
public String getSavedPowerOffTime() {
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
|
return prefs.getString(POWER_OFF_TIME_KEY, "23:00"); // 默认值
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存PowerOffTVTime到本地
|
||||||
|
private void savePowerOffTime(String powerOffTime) {
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = prefs.edit();
|
||||||
|
editor.putString(POWER_OFF_TIME_KEY, powerOffTime);
|
||||||
|
editor.apply();
|
||||||
|
Log.d(TAG, "PowerOffTVTime saved: " + powerOffTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步任务类
|
||||||
|
private class ConfigLoadTask extends AsyncTask<Void, Void, String> {
|
||||||
|
private String errorMessage = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doInBackground(Void... voids) {
|
||||||
|
try {
|
||||||
|
// 创建HTTP请求
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(configUrl)
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 执行请求
|
||||||
|
Response response = httpClient.newCall(request).execute();
|
||||||
|
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
String jsonString = response.body().string();
|
||||||
|
Log.d(TAG, "Received JSON: " + jsonString);
|
||||||
|
|
||||||
|
// 解析JSON
|
||||||
|
JSONObject jsonObject = new JSONObject(jsonString);
|
||||||
|
String powerOffTime = jsonObject.getString("PowerOffTVTime");
|
||||||
|
|
||||||
|
return powerOffTime;
|
||||||
|
} else {
|
||||||
|
errorMessage = "HTTP请求失败,状态码: " + response.code();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
errorMessage = "网络连接失败: " + e.getMessage();
|
||||||
|
Log.e(TAG, errorMessage, e);
|
||||||
|
return null;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
errorMessage = "JSON解析失败: " + e.getMessage();
|
||||||
|
Log.e(TAG, errorMessage, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(String powerOffTime) {
|
||||||
|
if (powerOffTime != null) {
|
||||||
|
// 保存到本地
|
||||||
|
savePowerOffTime(powerOffTime);
|
||||||
|
|
||||||
|
// 通知回调
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onConfigLoaded(powerOffTime);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 通知错误
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onConfigLoadFailed(errorMessage != null ? errorMessage : "未知错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放资源
|
||||||
|
public void release() {
|
||||||
|
if (httpClient != null) {
|
||||||
|
httpClient.dispatcher().executorService().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
public class ScheduledCommandTimer {
|
||||||
|
private static final String TAG = "ScheduledCommandTimer";
|
||||||
|
|
||||||
|
private Handler handler;
|
||||||
|
private Runnable timerRunnable;
|
||||||
|
private boolean isTimerRunning = false;
|
||||||
|
|
||||||
|
// 配置参数
|
||||||
|
private long checkInterval = 10 * 1000; // 10秒检查间隔
|
||||||
|
private int targetHour = 14; // 目标时间:小时
|
||||||
|
private int targetMinute = 30; // 目标时间:分钟
|
||||||
|
private long commandInterval = 10 * 1000; // 命令发送间隔10秒
|
||||||
|
private int maxCommandCount = 3; // 最多发送次数
|
||||||
|
|
||||||
|
// 状态变量
|
||||||
|
private int commandSentCount = 0;
|
||||||
|
private boolean hasReachedTargetTime = false;
|
||||||
|
private long firstCommandTime = 0;
|
||||||
|
|
||||||
|
// 回调接口
|
||||||
|
private CommandCallback commandCallback;
|
||||||
|
private TimerStatusCallback statusCallback;
|
||||||
|
|
||||||
|
// 回调接口定义
|
||||||
|
public interface CommandCallback {
|
||||||
|
void onCommandExecute(int currentCount, int totalCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TimerStatusCallback {
|
||||||
|
void onTimerStarted();
|
||||||
|
void onTimerStopped();
|
||||||
|
void onTargetTimeReached();
|
||||||
|
void onCommandSequenceCompleted();
|
||||||
|
void onTimeCheck(int currentHour, int currentMinute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造函数
|
||||||
|
public ScheduledCommandTimer() {
|
||||||
|
initTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledCommandTimer(int targetHour, int targetMinute) {
|
||||||
|
this.targetHour = targetHour;
|
||||||
|
this.targetMinute = targetMinute;
|
||||||
|
initTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建造者模式配置类
|
||||||
|
public static class Builder {
|
||||||
|
private ScheduledCommandTimer timer = new ScheduledCommandTimer();
|
||||||
|
|
||||||
|
public Builder setTargetTime(int hour, int minute) {
|
||||||
|
timer.targetHour = hour;
|
||||||
|
timer.targetMinute = minute;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCheckInterval(long intervalMs) {
|
||||||
|
timer.checkInterval = intervalMs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCommandInterval(long intervalMs) {
|
||||||
|
timer.commandInterval = intervalMs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setMaxCommandCount(int count) {
|
||||||
|
timer.maxCommandCount = count;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCommandCallback(CommandCallback callback) {
|
||||||
|
timer.commandCallback = callback;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setStatusCallback(TimerStatusCallback callback) {
|
||||||
|
timer.statusCallback = callback;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledCommandTimer build() {
|
||||||
|
timer.initTimer();
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTimer() {
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
timerRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
checkTimeAndSendCommand();
|
||||||
|
|
||||||
|
if (isTimerRunning) {
|
||||||
|
handler.postDelayed(this, checkInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动定时器
|
||||||
|
public void start() {
|
||||||
|
if (!isTimerRunning) {
|
||||||
|
isTimerRunning = true;
|
||||||
|
handler.post(timerRunnable);
|
||||||
|
Log.d(TAG, "定时器已启动");
|
||||||
|
|
||||||
|
if (statusCallback != null) {
|
||||||
|
statusCallback.onTimerStarted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止定时器
|
||||||
|
public void stop() {
|
||||||
|
if (isTimerRunning) {
|
||||||
|
isTimerRunning = false;
|
||||||
|
handler.removeCallbacks(timerRunnable);
|
||||||
|
Log.d(TAG, "定时器已停止");
|
||||||
|
|
||||||
|
if (statusCallback != null) {
|
||||||
|
statusCallback.onTimerStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重启定时器
|
||||||
|
public void restart() {
|
||||||
|
stop();
|
||||||
|
resetCommandState();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkTimeAndSendCommand() {
|
||||||
|
Calendar now = Calendar.getInstance();
|
||||||
|
int currentHour = now.get(Calendar.HOUR_OF_DAY);
|
||||||
|
int currentMinute = now.get(Calendar.MINUTE);
|
||||||
|
|
||||||
|
Log.d(TAG, String.format("时间检查: %02d:%02d, 目标: %02d:%02d",
|
||||||
|
currentHour, currentMinute, targetHour, targetMinute));
|
||||||
|
|
||||||
|
if (statusCallback != null) {
|
||||||
|
statusCallback.onTimeCheck(currentHour, currentMinute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否到达指定时间
|
||||||
|
if (currentHour == targetHour && currentMinute >= targetMinute) {
|
||||||
|
if (!hasReachedTargetTime) {
|
||||||
|
hasReachedTargetTime = true;
|
||||||
|
firstCommandTime = System.currentTimeMillis();
|
||||||
|
commandSentCount = 0;
|
||||||
|
Log.d(TAG, "到达目标时间,开始发送命令序列");
|
||||||
|
|
||||||
|
if (statusCallback != null) {
|
||||||
|
statusCallback.onTargetTimeReached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processCommandSequence();
|
||||||
|
} else {
|
||||||
|
if (hasReachedTargetTime) {
|
||||||
|
resetCommandState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processCommandSequence() {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long elapsedTime = currentTime - firstCommandTime;
|
||||||
|
|
||||||
|
// 检查是否在30秒窗口内且未超过最大发送次数
|
||||||
|
if (elapsedTime <= 30 * 1000 && commandSentCount < maxCommandCount) {
|
||||||
|
long expectedCommandTime = firstCommandTime + (commandSentCount * commandInterval);
|
||||||
|
|
||||||
|
if (currentTime >= expectedCommandTime) {
|
||||||
|
commandSentCount++;
|
||||||
|
Log.d(TAG, String.format("执行命令 %d/%d, 已用时: %d毫秒",
|
||||||
|
commandSentCount, maxCommandCount, elapsedTime));
|
||||||
|
|
||||||
|
if (commandCallback != null) {
|
||||||
|
commandCallback.onCommandExecute(commandSentCount, maxCommandCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否完成所有命令
|
||||||
|
if (commandSentCount >= maxCommandCount) {
|
||||||
|
Log.d(TAG, "命令序列执行完成");
|
||||||
|
if (statusCallback != null) {
|
||||||
|
statusCallback.onCommandSequenceCompleted();
|
||||||
|
}
|
||||||
|
resetCommandState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (elapsedTime > 30 * 1000) {
|
||||||
|
Log.d(TAG, "30秒窗口超时,重置状态");
|
||||||
|
resetCommandState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetCommandState() {
|
||||||
|
hasReachedTargetTime = false;
|
||||||
|
commandSentCount = 0;
|
||||||
|
firstCommandTime = 0;
|
||||||
|
Log.d(TAG, "命令发送状态已重置");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前状态
|
||||||
|
public boolean isRunning() {
|
||||||
|
return isTimerRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasReachedTarget() {
|
||||||
|
return hasReachedTargetTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCommandSentCount() {
|
||||||
|
return commandSentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRemainingTime() {
|
||||||
|
if (!hasReachedTargetTime) return -1;
|
||||||
|
long elapsedTime = System.currentTimeMillis() - firstCommandTime;
|
||||||
|
return Math.max(0, 30 * 1000 - elapsedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置方法
|
||||||
|
public void setTargetTime(int hour, int minute) {
|
||||||
|
this.targetHour = hour;
|
||||||
|
this.targetMinute = minute;
|
||||||
|
resetCommandState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommandCallback(CommandCallback callback) {
|
||||||
|
this.commandCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusCallback(TimerStatusCallback callback) {
|
||||||
|
this.statusCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放资源
|
||||||
|
public void destroy() {
|
||||||
|
stop();
|
||||||
|
commandCallback = null;
|
||||||
|
statusCallback = null;
|
||||||
|
handler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
package cn.ykbox.dashboard;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultCallback;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import cn.ykbox.dashboard.databinding.ActivityBuildingDashboardBinding;
|
||||||
|
|
||||||
|
public class BuildingDashboardActivity extends FullscreenActivity {
|
||||||
|
private final static String TAG = "DashboardActivity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the system UI should be auto-hidden after
|
||||||
|
* {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
|
||||||
|
*/
|
||||||
|
private static final boolean AUTO_HIDE = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
|
||||||
|
* user interaction before hiding the system UI.
|
||||||
|
*/
|
||||||
|
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
|
||||||
|
|
||||||
|
private ScheduledCommandTimer timer;
|
||||||
|
private ConfigReader configReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Touch listener to use for in-layout UI controls to delay hiding the
|
||||||
|
* system UI. This is to prevent the jarring behavior of controls going away
|
||||||
|
* while interacting with activity UI.
|
||||||
|
*/
|
||||||
|
private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||||
|
switch (motionEvent.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
if (AUTO_HIDE) {
|
||||||
|
delayedHide(AUTO_HIDE_DELAY_MILLIS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
view.performClick();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private ActivityBuildingDashboardBinding binding;
|
||||||
|
/// ActivityResultLauncher 用于处理设置页面的返回结果
|
||||||
|
private ActivityResultLauncher<Intent> settingsLauncher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
binding = ActivityBuildingDashboardBinding.inflate(getLayoutInflater());
|
||||||
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
|
super.setViews(binding.webview, binding.fullscreenContentControls);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// 初始化 ActivityResultLauncher
|
||||||
|
initSettingsLauncher();
|
||||||
|
setupConfig();
|
||||||
|
initWebView();
|
||||||
|
initTimer();
|
||||||
|
|
||||||
|
// Upon interacting with UI controls, delay any scheduled hide()
|
||||||
|
// operations to prevent the jarring behavior of controls going away
|
||||||
|
// while interacting with the UI.
|
||||||
|
binding.settingsButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
// 打开设置界面
|
||||||
|
openSettingsActivity();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (timer != null) {
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPreferences pre = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
String url = pre.getString("k_url", "http://10.1.58.176:8002");
|
||||||
|
binding.webview.loadUrl(url); // 加载网页
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (timer != null) {
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (timer != null) {
|
||||||
|
timer.destroy();
|
||||||
|
}
|
||||||
|
if (configReader != null) {
|
||||||
|
configReader.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化设置页面的 ActivityResultLauncher
|
||||||
|
*/
|
||||||
|
private void initSettingsLauncher() {
|
||||||
|
settingsLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开设置页面
|
||||||
|
*/
|
||||||
|
private void openSettingsActivity() {
|
||||||
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
|
settingsLauncher.launch(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupConfig(String configUrl) {
|
||||||
|
// 初始化配置读取器
|
||||||
|
configReader = new ConfigReader(this, configUrl);
|
||||||
|
configReader.setOnConfigLoadListener(new ConfigReader.OnConfigLoadListener() {
|
||||||
|
@Override
|
||||||
|
public void onConfigLoaded(String powerOffTime) {
|
||||||
|
// 配置加载成功
|
||||||
|
Log.i("MainActivity", "PowerOffTVTime加载成功: " + powerOffTime);
|
||||||
|
// 可以在这里更新UI或执行其他操作
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigLoadFailed(String error) {
|
||||||
|
// 配置加载失败
|
||||||
|
Log.e("MainActivity", "配置加载失败: " + error);
|
||||||
|
|
||||||
|
// 使用本地保存的配置
|
||||||
|
String savedTime = configReader.getSavedPowerOffTime();
|
||||||
|
Log.i("MainActivity", "使用本地保存的PowerOffTVTime: " + savedTime);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载配置
|
||||||
|
configReader.loadConfig();
|
||||||
|
|
||||||
|
// 或者直接获取本地保存的值
|
||||||
|
String localPowerOffTime = configReader.getSavedPowerOffTime();
|
||||||
|
Log.i("MainActivity", "本地PowerOffTVTime: " + localPowerOffTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initWebView() {
|
||||||
|
binding.webview.getSettings().setJavaScriptEnabled(true); // 启用 JavaScript
|
||||||
|
binding.webview.setWebViewClient(new WebViewClient()); // 防止跳转到外部浏览器
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTimer() {
|
||||||
|
// 方式1:使用建造者模式
|
||||||
|
timer = new ScheduledCommandTimer.Builder()
|
||||||
|
.setTargetTime(14, 30) // 设置目标时间为14:30
|
||||||
|
.setCheckInterval(10 * 1000) // 10秒检查一次
|
||||||
|
.setCommandInterval(10 * 1000) // 命令间隔10秒
|
||||||
|
.setMaxCommandCount(3) // 最多发送3次
|
||||||
|
.setCommandCallback(new ScheduledCommandTimer.CommandCallback() {
|
||||||
|
@Override
|
||||||
|
public void onCommandExecute(int currentCount, int totalCount) {
|
||||||
|
// 执行你的命令逻辑
|
||||||
|
executeCommand(currentCount, totalCount);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setStatusCallback(new ScheduledCommandTimer.TimerStatusCallback() {
|
||||||
|
@Override
|
||||||
|
public void onTimerStarted() {
|
||||||
|
Log.d("MainActivity", "定时器启动");
|
||||||
|
showToast("定时器已启动");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTimerStopped() {
|
||||||
|
Log.d("MainActivity", "定时器停止");
|
||||||
|
showToast("定时器已停止");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTargetTimeReached() {
|
||||||
|
Log.d("MainActivity", "到达目标时间");
|
||||||
|
showToast("到达目标时间,开始执行命令");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCommandSequenceCompleted() {
|
||||||
|
Log.d("MainActivity", "命令序列完成");
|
||||||
|
showToast("所有命令执行完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTimeCheck(int currentHour, int currentMinute) {
|
||||||
|
// 可选:更新UI显示当前时间
|
||||||
|
updateTimeDisplay(currentHour, currentMinute);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 方式2:直接构造
|
||||||
|
// timer = new ScheduledCommandTimer(14, 30);
|
||||||
|
// timer.setCommandCallback(commandCallback);
|
||||||
|
// timer.setStatusCallback(statusCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeCommand(int currentCount, int totalCount) {
|
||||||
|
// 在这里实现你的具体命令逻辑
|
||||||
|
Log.i("MainActivity", String.format("执行命令 %d/%d", currentCount, totalCount));
|
||||||
|
|
||||||
|
// 示例:发送网络请求
|
||||||
|
// sendNetworkRequest();
|
||||||
|
|
||||||
|
// 示例:调用系统服务
|
||||||
|
// callSystemService();
|
||||||
|
|
||||||
|
// 示例:发送广播
|
||||||
|
// sendBroadcast();
|
||||||
|
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
showToast(String.format("执行命令 %d/%d", currentCount, totalCount));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToast(String message) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* 版权所有 (C) 2024 宁波升维信息技术有限公司. 保留所有权利.
|
||||||
|
*
|
||||||
|
* 本软件是由 宁波升维信息技术有限公司 开发的。
|
||||||
|
* 未经版权所有者明确授权,任何人不得使用、复制、修改、分发本软件及其相关文档。
|
||||||
|
* 本软件包含机密和专有信息,未经授权不得向任何第三方披露。
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 通过串口设置班牌的功能
|
||||||
|
* @author: Hu Zhang <hu.zhang@live.com>
|
||||||
|
* @date: 2024/1/5
|
||||||
|
**/
|
||||||
|
|
||||||
|
package com.nb6868.classtv.serial;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import cn.ykbox.utils.Log;
|
||||||
|
|
||||||
|
import cn.ykbox.signageapi.utils.ByteArrayUtil;
|
||||||
|
import tp.xmaihh.serialport.SerialHelper;
|
||||||
|
import tp.xmaihh.serialport.bean.ComBean;
|
||||||
|
|
||||||
|
|
||||||
|
public class SerialControlDevices extends SerialHelper {
|
||||||
|
private static final String TAG = "SerialControlDevices";
|
||||||
|
|
||||||
|
|
||||||
|
private OnErrorListener mErrorListener = null;
|
||||||
|
|
||||||
|
public static synchronized SerialControlDevices getInstance() {
|
||||||
|
if (control == null) {
|
||||||
|
control = new SerialControlDevices();
|
||||||
|
}
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SerialControlDevices() {
|
||||||
|
super("/dev/ttyS3", 9600);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
super.open();
|
||||||
|
Log.i(TAG,"串口打开成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "串口打开失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorListener(OnErrorListener listener) {
|
||||||
|
this.mErrorListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDataReceived(ComBean ComRecData) {
|
||||||
|
Log.d(TAG,"onDataReceived: "+ ByteArrayUtil.toHexString(ComRecData.bRec));
|
||||||
|
|
||||||
|
String serialData = ByteArrayUtil.toHexString(ComRecData.bRec);
|
||||||
|
Message msg = workHandler.obtainMessage();
|
||||||
|
msg.what = SERIAL_MESSAGE;
|
||||||
|
msg.obj = serialData;
|
||||||
|
workHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void powerOffTV() {
|
||||||
|
sendHex("AABB0600000001060304");
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnErrorListener {
|
||||||
|
void onError(int error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<PreferenceCategory app:title="网页">
|
<PreferenceCategory app:title="网页地址">
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
app:key="k_url"
|
app:key="k_url"
|
||||||
app:title="网页地址"
|
app:title="URL 前缀"
|
||||||
app:defaultValue="http://10.1.58.176:8002"
|
app:defaultValue="http://10.1.58.176:8002"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,4 +1,4 @@
|
|||||||
#Thu Sep 11 13:33:07 CST 2025
|
#Thu Sep 11 21:34:47 CST 2025
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||||
|
|||||||
Reference in New Issue
Block a user