Compare commits

...

10 Commits

7 changed files with 191 additions and 58 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Wed Feb 04 11:07:22 HKT 2026
stageCount=9
#Tue Mar 10 20:03:39 HKT 2026
stageCount=15
libraryProject=
baseVersion=15.15
publishVersion=15.15.8
publishVersion=15.15.14
buildCount=0
baseBetaVersion=15.15.9
baseBetaVersion=15.15.15

View File

@@ -25,7 +25,7 @@ import java.lang.reflect.Field;
* 适配 API30基于 Java7 开发
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2025年11月27日14时26分00秒
* @LastEditTime 2026年01月19日22时18分00秒
* @LastEditTime 2026-02-28
* @Describe 应用设置窗口(主开关联动子开关启用/禁用,主开关关闭则子开关禁用并取消勾选)
*/
public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivity {
@@ -39,6 +39,7 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
private CheckBox cbChargeTts; // 充电TTS主开关
private CheckBox cbUseageTtsBattary; // 用电TTS带电量提醒子开关
private CheckBox cbChargeTtsBattary; // 充电TTS带电量提醒子开关
private CheckBox cbTtsWhenNotifyBattery; // 👉 新增通知电量时同时播放TTS
// ======================== 接口实现区 =========================
@Override
@@ -96,6 +97,7 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
cbChargeTts = findViewById(R.id.activitysettingsCheckBox2);
cbUseageTtsBattary = findViewById(R.id.activitysettingsCheckBox3);
cbChargeTtsBattary = findViewById(R.id.activitysettingsCheckBox4);
cbTtsWhenNotifyBattery = findViewById(R.id.activitysettingsCheckBox5); // 👉 新增绑定
LogUtils.d(TAG, "initTtsCheckBoxes: TTS复选框绑定完成");
}
@@ -116,6 +118,7 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
cbChargeTts.setChecked(chargeMainOpen);
cbUseageTtsBattary.setChecked(bean.isEnableUseageTtsWithBattary());
cbChargeTtsBattary.setChecked(bean.isEnableChargeTtsWithBattary());
cbTtsWhenNotifyBattery.setChecked(bean.isEnableTtsWhenNotifyBattery()); // 👉 新增赋值
cbUseageTtsBattary.setEnabled(useMainOpen);
cbChargeTtsBattary.setEnabled(chargeMainOpen);
@@ -138,12 +141,8 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
public void onEnableUsePowerTts(View view) {
boolean isChecked = cbUsePowerTts.isChecked();
LogUtils.d(TAG, "onEnableUsePowerTts: 用电TTS主开关点击切换后状态=" + isChecked);
cbUsePowerTts.setChecked(isChecked);
// 主开关联动子开关
cbUseageTtsBattary.setEnabled(isChecked);
// if (!isChecked) {
// cbUseageTtsBattary.setChecked(false);
// }
// 保存配置
ThoughtfulServiceBean bean = getThoughtfulServiceBean();
bean.setIsEnableUsePowerTts(isChecked);
@@ -157,12 +156,8 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
public void onEnableChargeTts(View view) {
boolean isChecked = cbChargeTts.isChecked();
LogUtils.d(TAG, "onEnableChargeTts: 充电TTS主开关点击切换后状态=" + isChecked);
cbChargeTts.setChecked(isChecked);
// 主开关联动子开关
cbChargeTtsBattary.setEnabled(isChecked);
// if (!isChecked) {
// cbChargeTtsBattary.setChecked(false);
// }
// 保存配置
ThoughtfulServiceBean bean = getThoughtfulServiceBean();
bean.setIsEnableChargeTts(isChecked);
@@ -176,7 +171,6 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
public void onEnableUseageTtsWithBattary(View view) {
boolean isChecked = cbUseageTtsBattary.isChecked();
LogUtils.d(TAG, "onEnableUseageTtsWithBattary: 用电TTS电量提醒开关点击切换后状态=" + isChecked);
cbUseageTtsBattary.setChecked(isChecked);
ThoughtfulServiceBean bean = getThoughtfulServiceBean();
bean.setIsEnableUseageTtsWithBattary(isChecked);
ThoughtfulServiceBean.saveBean(this, bean);
@@ -189,13 +183,24 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
public void onEnableChargeTtsWithBattary(View view) {
boolean isChecked = cbChargeTtsBattary.isChecked();
LogUtils.d(TAG, "onEnableChargeTtsWithBattary: 充电TTS电量提醒开关点击切换后状态=" + isChecked);
cbChargeTtsBattary.setChecked(isChecked);
ThoughtfulServiceBean bean = getThoughtfulServiceBean();
bean.setIsEnableChargeTtsWithBattary(isChecked);
ThoughtfulServiceBean.saveBean(this, bean);
LogUtils.d(TAG, "onEnableChargeTtsWithBattary: 充电TTS电量提醒状态保存完成");
}
/**
* 👉 新增允许通知电量消息时同时播放TTS语音
*/
public void onEnableTtsWhenNotifyBattery(View view) {
boolean isChecked = cbTtsWhenNotifyBattery.isChecked();
LogUtils.d(TAG, "onEnableTtsWhenNotifyBattery: 通知电量时播TTS开关状态=" + isChecked);
ThoughtfulServiceBean bean = getThoughtfulServiceBean();
bean.setIsEnableTtsWhenNotifyBattery(isChecked);
ThoughtfulServiceBean.saveBean(this, bean);
LogUtils.d(TAG, "onEnableTtsWhenNotifyBattery: 保存完成");
}
// ======================== 工具方法区 =========================
/**
* 获取配置Bean实例避免重复代码

View File

@@ -4,7 +4,9 @@ import android.os.Handler;
import android.os.Message;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.models.ThoughtfulServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.threads.TTSRemindThread;
import java.lang.ref.WeakReference;
/**

View File

@@ -24,17 +24,19 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
// JSON序列化字段常量 杜绝硬编码
public static final String JSON_FIELD_IS_ENABLE_CHARGE_TTS = "isEnableChargeTts";
public static final String JSON_FIELD_IS_ENABLE_USE_POWER_TTS = "isEnableUsePowerTts";
// 新增字段JSON常量
public static final String JSON_FIELD_IS_ENABLE_USAGE_TTS_WITH_BATTERY = "isEnableUseageTtsWithBattary";
public static final String JSON_FIELD_IS_ENABLE_CHARGE_TTS_WITH_BATTERY = "isEnableChargeTtsWithBattary";
// 👉 新增通知电量消息时同时播放TTS
public static final String JSON_FIELD_IS_ENABLE_TTS_WHEN_NOTIFY_BATTERY = "isEnableTtsWhenNotifyBattery";
// ====================== 核心成员变量 - 私有封装 ======================
private boolean isEnableChargeTts = false; // 是否启用 充电TTS贴心语音服务
private boolean isEnableUsePowerTts = false; // 是否启用 用电TTS贴心语音服务
private boolean isEnableUseageTtsWithBattary = false; // 用电TTS加入电量提醒
private boolean isEnableChargeTtsWithBattary = false;// 充电TTS加入电量提醒
private boolean isEnableChargeTts = false; // 是否启用 充电TTS贴心语音服务
private boolean isEnableUsePowerTts = false; // 是否启用 用电TTS贴心语音服务
private boolean isEnableUseageTtsWithBattary = false; // 用电TTS加入电量提醒
private boolean isEnableChargeTtsWithBattary = false; // 充电TTS加入电量提醒
private boolean isEnableTtsWhenNotifyBattery = false; // 👉 允许通知电量消息时同时播放TTS语音
// ====================== Parcelable 静态创建器 (API30标准写法 必须public static final) ======================
// ====================== Parcelable 静态创建器 ======================
public static final Creator<ThoughtfulServiceBean> CREATOR = new Creator<ThoughtfulServiceBean>() {
@Override
public ThoughtfulServiceBean createFromParcel(Parcel source) {
@@ -48,45 +50,34 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
}
};
// ====================== 构造方法区 (无参+有参+Parcel构造 全覆盖) ======================
/**
* 无参构造 - JSON解析/反射实例化 必备
*/
// ====================== 构造方法区 ======================
public ThoughtfulServiceBean() {
LogUtils.d(TAG, "ThoughtfulServiceBean: 无参构造初始化默认禁用所有TTS服务");
}
/**
* 全参构造 - 手动配置所有服务状态
* @param isEnableChargeTts 充电TTS服务开关
* @param isEnableUsePowerTts 用电TTS服务开关
* @param isEnableUseageTtsWithBattary 用电TTS加电量提醒开关
* @param isEnableChargeTtsWithBattary 充电TTS加电量提醒开关
*/
public ThoughtfulServiceBean(boolean isEnableChargeTts, boolean isEnableUsePowerTts,
boolean isEnableUseageTtsWithBattary, boolean isEnableChargeTtsWithBattary) {
boolean isEnableUseageTtsWithBattary, boolean isEnableChargeTtsWithBattary,
boolean isEnableTtsWhenNotifyBattery) {
this.isEnableChargeTts = isEnableChargeTts;
this.isEnableUsePowerTts = isEnableUsePowerTts;
this.isEnableUseageTtsWithBattary = isEnableUseageTtsWithBattary;
this.isEnableChargeTtsWithBattary = isEnableChargeTtsWithBattary;
this.isEnableTtsWhenNotifyBattery = isEnableTtsWhenNotifyBattery;
LogUtils.d(TAG, "ThoughtfulServiceBean: 全参构造 | 充电TTS=" + isEnableChargeTts + " | 用电TTS=" + isEnableUsePowerTts
+ " | 用电TTS加电量=" + isEnableUseageTtsWithBattary + " | 充电TTS加电量=" + isEnableChargeTtsWithBattary);
+ " | 用电TTS加电量=" + isEnableUseageTtsWithBattary + " | 充电TTS加电量=" + isEnableChargeTtsWithBattary
+ " | 通知电量时播TTS=" + isEnableTtsWhenNotifyBattery);
}
/**
* Parcel反序列化构造 - Parcelable必备 私有私有化
*/
private ThoughtfulServiceBean(Parcel in) {
this.isEnableChargeTts = in.readByte() != 0;
this.isEnableUsePowerTts = in.readByte() != 0;
// 新增字段反序列化
this.isEnableUseageTtsWithBattary = in.readByte() != 0;
this.isEnableChargeTtsWithBattary = in.readByte() != 0;
LogUtils.d(TAG, "ThoughtfulServiceBean: Parcel构造解析完成 | 充电TTS=" + isEnableChargeTts + " | 用电TTS=" + isEnableUsePowerTts
+ " | 用电TTS加电量=" + isEnableUseageTtsWithBattary + " | 充电TTS加电量=" + isEnableChargeTtsWithBattary);
this.isEnableTtsWhenNotifyBattery = in.readByte() != 0; // 👉 新增反序列化
LogUtils.d(TAG, "ThoughtfulServiceBean: Parcel构造解析完成");
}
// ====================== Getter/Setter 方法区 (封装成员变量 统一访问) ======================
// ====================== Getter/Setter 方法区 ======================
public boolean isEnableChargeTts() {
return isEnableChargeTts;
}
@@ -105,7 +96,6 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
this.isEnableUsePowerTts = isEnableUsePowerTts;
}
// 新增 用电TTS加入电量提醒 Getter/Setter
public boolean isEnableUseageTtsWithBattary() {
return isEnableUseageTtsWithBattary;
}
@@ -115,7 +105,6 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
this.isEnableUseageTtsWithBattary = isEnableUseageTtsWithBattary;
}
// 新增 充电TTS加入电量提醒 Getter/Setter
public boolean isEnableChargeTtsWithBattary() {
return isEnableChargeTtsWithBattary;
}
@@ -125,7 +114,17 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
this.isEnableChargeTtsWithBattary = isEnableChargeTtsWithBattary;
}
// ====================== 重写父类 BaseBean 核心方法 (JSON序列化/反序列化 业务核心) ======================
// 👉 新增通知电量时播放TTS
public boolean isEnableTtsWhenNotifyBattery() {
return isEnableTtsWhenNotifyBattery;
}
public void setIsEnableTtsWhenNotifyBattery(boolean isEnableTtsWhenNotifyBattery) {
LogUtils.d(TAG, "setIsEnableTtsWhenNotifyBattery: 旧值=" + this.isEnableTtsWhenNotifyBattery + " 新值=" + isEnableTtsWhenNotifyBattery);
this.isEnableTtsWhenNotifyBattery = isEnableTtsWhenNotifyBattery;
}
// ====================== 重写父类 BaseBean 核心方法 ======================
@Override
public String getName() {
String className = ThoughtfulServiceBean.class.getName();
@@ -133,23 +132,17 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
return className;
}
/**
* JSON序列化 - 写入所有字段 适配持久化/网络传输
*/
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name(JSON_FIELD_IS_ENABLE_CHARGE_TTS).value(this.isEnableChargeTts);
jsonWriter.name(JSON_FIELD_IS_ENABLE_USE_POWER_TTS).value(this.isEnableUsePowerTts);
// 新增字段JSON序列化
jsonWriter.name(JSON_FIELD_IS_ENABLE_USAGE_TTS_WITH_BATTERY).value(this.isEnableUseageTtsWithBattary);
jsonWriter.name(JSON_FIELD_IS_ENABLE_CHARGE_TTS_WITH_BATTERY).value(this.isEnableChargeTtsWithBattary);
jsonWriter.name(JSON_FIELD_IS_ENABLE_TTS_WHEN_NOTIFY_BATTERY).value(this.isEnableTtsWhenNotifyBattery); // 👉 新增JSON写入
LogUtils.d(TAG, "writeThisToJsonWriter: JSON序列化完成所有TTS服务状态已写入");
}
/**
* JSON反序列化 - 读取字段生成实体 适配数据恢复
*/
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
ThoughtfulServiceBean bean = new ThoughtfulServiceBean();
@@ -163,13 +156,15 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
case JSON_FIELD_IS_ENABLE_USE_POWER_TTS:
bean.setIsEnableUsePowerTts(jsonReader.nextBoolean());
break;
// 新增字段反序列化
case JSON_FIELD_IS_ENABLE_USAGE_TTS_WITH_BATTERY:
bean.setIsEnableUseageTtsWithBattary(jsonReader.nextBoolean());
break;
case JSON_FIELD_IS_ENABLE_CHARGE_TTS_WITH_BATTERY:
bean.setIsEnableChargeTtsWithBattary(jsonReader.nextBoolean());
break;
case JSON_FIELD_IS_ENABLE_TTS_WHEN_NOTIFY_BATTERY:
bean.setIsEnableTtsWhenNotifyBattery(jsonReader.nextBoolean()); // 👉 新增JSON读取
break;
default:
jsonReader.skipValue();
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未知JSON字段 = " + fieldName);
@@ -181,22 +176,19 @@ public class ThoughtfulServiceBean extends BaseBean implements Parcelable, Seria
return bean;
}
// ====================== 实现 Parcelable 接口方法 (组件间Intent传递必备 API30/Java7完美适配) ======================
// ====================== Parcelable 接口方法 ======================
@Override
public int describeContents() {
return 0; // 无文件描述符等特殊内容固定返回0即可
return 0;
}
/**
* Parcel序列化 - boolean用byte存储(Java7/API30标准写法 避免兼容性问题)
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (isEnableChargeTts ? 1 : 0));
dest.writeByte((byte) (isEnableUsePowerTts ? 1 : 0));
// 新增字段Parcel序列化
dest.writeByte((byte) (isEnableUseageTtsWithBattary ? 1 : 0));
dest.writeByte((byte) (isEnableChargeTtsWithBattary ? 1 : 0));
dest.writeByte((byte) (isEnableTtsWhenNotifyBattery ? 1 : 0)); // 👉 新增Parcel写入
LogUtils.d(TAG, "writeToParcel: Parcel序列化完成所有TTS服务状态已写入");
}

View File

@@ -188,6 +188,9 @@ public class RemindThread extends Thread {
LogUtils.d(TAG, String.format("未有合适类型提醒,退出提醒线程 | threadId=%d", getId()));
break;
}
// 启动电量通知 TTS 语音提醒线程
TTSRemindThread.start(this.mContext, App.sQuantityOfElectricity, isCharging);
// 安全休眠,保留中断标记
safeSleepInternal(sleepTime);
@@ -280,6 +283,7 @@ public class RemindThread extends Thread {
*/
private void cleanThreadStateInternal() {
LogUtils.d(TAG, String.format("cleanThreadStateInternal() 调用 | threadId=%d", getId()));
TTSRemindThread.stopTTS();
isReminding = false;
isExist = true;
// 中断当前线程(如果存活)

View File

@@ -0,0 +1,122 @@
package cc.winboll.studio.powerbell.threads;
import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.models.ThoughtfulServiceBean;
import cc.winboll.studio.powerbell.services.TTSPlayService;
/**
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @Date 2026/02/28 20:41
* @Describe TTS 语音通知线程(单例 + 继承 Thread
*/
public class TTSRemindThread extends Thread {
public static final String TAG = "TTSRemindThread";
// 单例实例
private static TTSRemindThread sInstance;
// 运行标志
private volatile boolean mIsRunning = false;
private volatile int mBattery;
private volatile boolean mIsCharging;
private Context mContext;
/**
* 私有构造,单例禁用外部 new
*/
private TTSRemindThread(Context context) {
this.mContext = context.getApplicationContext();
}
/**
* 获取单例DCL 双重校验)
*/
public static TTSRemindThread getInstance(Context context) {
if (sInstance == null) {
synchronized (TTSRemindThread.class) {
if (sInstance == null) {
sInstance = new TTSRemindThread(context);
}
}
}
return sInstance;
}
/**
* 对外静态启动入口
*/
public static void start(Context context, int battery, boolean isCharging) {
TTSRemindThread instance = getInstance(context);
instance.mBattery = battery;
instance.mIsCharging = isCharging;
if (!instance.mIsRunning) {
LogUtils.d(TAG, "start() TTS 提醒线程启动");
instance.mIsRunning = true;
instance.start(); // 启动线程
}
}
/**
* 对外静态停止入口
*/
public static void stopTTS() {
if (sInstance != null) {
LogUtils.d(TAG, "stopTTS() TTS 提醒线程停止");
sInstance.mIsRunning = false;
sInstance = null;
}
}
/**
* 线程主逻辑
*/
@Override
public void run() {
super.run();
LogUtils.d(TAG, "run() TTS 线程已开始循环");
while (mIsRunning) {
try {
// ======================
// 在这里写你的循环 TTS 逻辑
// ======================
// TTS 语音通知模块
// 读取 TTS 语音通知配置
ThoughtfulServiceBean ttsBean = ThoughtfulServiceBean.loadBean(mContext, ThoughtfulServiceBean.class);
if (ttsBean == null) {
ttsBean = new ThoughtfulServiceBean();
}
if (ttsBean.isEnableTtsWhenNotifyBattery()) {
//ToastUtils.show("Test");
// 启动
//ToastUtils.show(String.format("mIsCharging %s, mBattery %d", mIsCharging, mBattery));
String text = mIsCharging ?"充电": "用电";
text += String.format("已达预定值,现在电量为百分之%d", mBattery);
TTSPlayService.startPlayTTS(mContext, text);
}
// 防止死循环疯狂跑,加一点休眠
sleep(6000);
} catch (InterruptedException e) {
LogUtils.e(TAG, "TTS 线程被中断", e);
break;
}
}
mIsRunning = false;
LogUtils.d(TAG, "run() TTS 线程已退出");
}
/**
* 是否正在运行
*/
public boolean isRunning() {
return mIsRunning;
}
}

View File

@@ -123,6 +123,14 @@
</LinearLayout>
<!-- 👉 你要的新选项允许通知电量消息时同时播放TTS语音 -->
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="允许通知电量消息时同时播放TTS语音"
android:onClick="onEnableTtsWhenNotifyBattery"
android:id="@+id/activitysettingsCheckBox5"/>
</LinearLayout>
<LinearLayout