From 6ae1ab126ecbb63a5576d1037cedfa8715d84164 Mon Sep 17 00:00:00 2001 From: Zhanghu Date: Fri, 12 Sep 2025 08:45:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=B2=E5=8F=A3=E5=92=8C?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E5=BC=80=E5=85=B3=E6=9C=BA=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app_dashboard/build.gradle | 2 + .../dashboard/BuildingDashboardActivity.java | 119 --------- .../java/cn/ykbox/dashboard/ConfigReader.java | 129 +++++++++ .../dashboard/ScheduledCommandTimer .java | 249 +++++++++++++++++ .../{ => activity}/BaseActivity.java | 0 .../activity/BuildingDashboardActivity.java | 252 ++++++++++++++++++ .../{ => activity}/FullscreenActivity.java | 0 .../{ => activity}/GalleryActivity.java | 0 .../{ => activity}/SettingsActivity.java | 0 .../{ => activity}/StartActivity.java | 0 .../serial/SerialControlDevices.java | 72 +++++ .../src/main/res/xml/root_preferences.xml | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 13 files changed, 707 insertions(+), 122 deletions(-) delete mode 100644 app_dashboard/src/main/java/cn/ykbox/dashboard/BuildingDashboardActivity.java create mode 100644 app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java create mode 100644 app_dashboard/src/main/java/cn/ykbox/dashboard/ScheduledCommandTimer .java rename app_dashboard/src/main/java/cn/ykbox/dashboard/{ => activity}/BaseActivity.java (100%) create mode 100644 app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java rename app_dashboard/src/main/java/cn/ykbox/dashboard/{ => activity}/FullscreenActivity.java (100%) rename app_dashboard/src/main/java/cn/ykbox/dashboard/{ => activity}/GalleryActivity.java (100%) rename app_dashboard/src/main/java/cn/ykbox/dashboard/{ => activity}/SettingsActivity.java (100%) rename app_dashboard/src/main/java/cn/ykbox/dashboard/{ => activity}/StartActivity.java (100%) create mode 100644 app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java diff --git a/app_dashboard/build.gradle b/app_dashboard/build.gradle index 723710b..542961e 100644 --- a/app_dashboard/build.gradle +++ b/app_dashboard/build.gradle @@ -51,4 +51,6 @@ dependencies { implementation libs.banner implementation libs.glide annotationProcessor libs.glidecompiler + + implementation 'io.github.xmaihh:serialport:2.1.1' } \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/BuildingDashboardActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/BuildingDashboardActivity.java deleted file mode 100644 index b805e8a..0000000 --- a/app_dashboard/src/main/java/cn/ykbox/dashboard/BuildingDashboardActivity.java +++ /dev/null @@ -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 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()); // 防止跳转到外部浏览器 - - } -} \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java new file mode 100644 index 0000000..8abbed4 --- /dev/null +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/ConfigReader.java @@ -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 { + 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(); + } + } +} \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/ScheduledCommandTimer .java b/app_dashboard/src/main/java/cn/ykbox/dashboard/ScheduledCommandTimer .java new file mode 100644 index 0000000..0dfab48 --- /dev/null +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/ScheduledCommandTimer .java @@ -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; + } +} \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/BaseActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BaseActivity.java similarity index 100% rename from app_dashboard/src/main/java/cn/ykbox/dashboard/BaseActivity.java rename to app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BaseActivity.java diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java new file mode 100644 index 0000000..68f5d6f --- /dev/null +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/BuildingDashboardActivity.java @@ -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 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(); + } + +} \ No newline at end of file diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/FullscreenActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/FullscreenActivity.java similarity index 100% rename from app_dashboard/src/main/java/cn/ykbox/dashboard/FullscreenActivity.java rename to app_dashboard/src/main/java/cn/ykbox/dashboard/activity/FullscreenActivity.java diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/GalleryActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/GalleryActivity.java similarity index 100% rename from app_dashboard/src/main/java/cn/ykbox/dashboard/GalleryActivity.java rename to app_dashboard/src/main/java/cn/ykbox/dashboard/activity/GalleryActivity.java diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/SettingsActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java similarity index 100% rename from app_dashboard/src/main/java/cn/ykbox/dashboard/SettingsActivity.java rename to app_dashboard/src/main/java/cn/ykbox/dashboard/activity/SettingsActivity.java diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/StartActivity.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java similarity index 100% rename from app_dashboard/src/main/java/cn/ykbox/dashboard/StartActivity.java rename to app_dashboard/src/main/java/cn/ykbox/dashboard/activity/StartActivity.java diff --git a/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java b/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java new file mode 100644 index 0000000..be346c6 --- /dev/null +++ b/app_dashboard/src/main/java/cn/ykbox/dashboard/serial/SerialControlDevices.java @@ -0,0 +1,72 @@ +/************************************************************************* + * 版权所有 (C) 2024 宁波升维信息技术有限公司. 保留所有权利. + * + * 本软件是由 宁波升维信息技术有限公司 开发的。 + * 未经版权所有者明确授权,任何人不得使用、复制、修改、分发本软件及其相关文档。 + * 本软件包含机密和专有信息,未经授权不得向任何第三方披露。 + *************************************************************************/ + +/** + * @description: 通过串口设置班牌的功能 + * @author: Hu Zhang + * @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); + } +} diff --git a/app_dashboard/src/main/res/xml/root_preferences.xml b/app_dashboard/src/main/res/xml/root_preferences.xml index d0df2ed..80e840d 100644 --- a/app_dashboard/src/main/res/xml/root_preferences.xml +++ b/app_dashboard/src/main/res/xml/root_preferences.xml @@ -1,8 +1,8 @@ - + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e7c01c9..c790175 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Thu Sep 11 13:33:07 CST 2025 +#Thu Sep 11 21:34:47 CST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip