Compare commits
21 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e1d72a02b | |||
| a21a2ba4a5 | |||
| f4c16dd332 | |||
| feae9f4e14 | |||
| c4f5f18089 | |||
| c030de64b8 | |||
| 59094217da | |||
| 6a17d3d7f9 | |||
| bc730dffc8 | |||
| 4b196acfce | |||
| cf857c1359 | |||
| 81b758ddc5 | |||
| 64a53058cc | |||
| aae17b6cd2 | |||
| d6637e1c17 | |||
| 6d425cab5c | |||
| ab566f76ff | |||
| cd04458c62 | |||
| 6b46180da7 | |||
| af8b57b735 | |||
| 21c02db577 |
@@ -81,7 +81,7 @@ dependencies {
|
||||
|
||||
// WinBoLL库 nexus.winboll.cc 地址
|
||||
api 'cc.winboll.studio:libaes:15.15.2'
|
||||
api 'cc.winboll.studio:libappbase:15.15.4'
|
||||
api 'cc.winboll.studio:libappbase:15.15.11'
|
||||
|
||||
// WinBoLL备用库 jitpack.io 地址
|
||||
//api 'com.github.ZhanGSKen:AES:aes-v15.15.2'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Mon Jan 19 20:40:18 HKT 2026
|
||||
stageCount=3
|
||||
#Tue Mar 10 20:02:12 HKT 2026
|
||||
stageCount=14
|
||||
libraryProject=
|
||||
baseVersion=15.15
|
||||
publishVersion=15.15.2
|
||||
publishVersion=15.15.13
|
||||
buildCount=0
|
||||
baseBetaVersion=15.15.3
|
||||
baseBetaVersion=15.15.14
|
||||
|
||||
@@ -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实例,避免重复代码
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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服务状态已写入");
|
||||
}
|
||||
|
||||
|
||||
@@ -24,56 +24,55 @@ import cc.winboll.studio.powerbell.services.ThoughtfulService;
|
||||
* @Describe 统一处理系统与应用内广播,同步电池状态与配置,保障多线程数据一致性
|
||||
*/
|
||||
public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// ====================== 静态常量区(置顶归类,消除魔法值) ======================
|
||||
// ====================== 静态常量区 ======================
|
||||
public static final String TAG = "ControlCenterServiceReceiver";
|
||||
|
||||
// 广播Action常量(带包名前缀防冲突)
|
||||
public static final String ACTION_UPDATE_FOREGROUND_NOTIFICATION = "cc.winboll.studio.powerbell.action.ACTION_UPDATE_FOREGROUND_NOTIFICATION";
|
||||
public static final String ACTION_APPCONFIG_CHANGED = "cc.winboll.studio.powerbell.action.ACTION_APPCONFIG_CHANGED";
|
||||
public static final String EXTRA_APP_CONFIG_BEAN = "extra_app_config_bean";
|
||||
|
||||
// 广播优先级与电量范围常量
|
||||
private static final int BROADCAST_PRIORITY = IntentFilter.SYSTEM_HIGH_PRIORITY - 10;
|
||||
private static final int BATTERY_LEVEL_MIN = 0;
|
||||
private static final int BATTERY_LEVEL_MAX = 100;
|
||||
private static final int INVALID_BATTERY = -1; // 无效电量标识
|
||||
private static final int INVALID_BATTERY = -1;
|
||||
|
||||
// ====================== 静态状态标记(volatile保证多线程可见性) ======================
|
||||
private static volatile int sLastBatteryLevel = INVALID_BATTERY; // 上次电量(多线程可见)
|
||||
private static volatile boolean sIsCharging = false; // 上次充电状态(多线程可见)
|
||||
// ====================== 静态状态(防抖动 + 防重复播报) ======================
|
||||
private static volatile int sLastBatteryLevel = INVALID_BATTERY;
|
||||
private static volatile boolean sIsCharging = false;
|
||||
|
||||
// ====================== 成员变量区(弱引用防泄漏,按功能分层) ======================
|
||||
// 【新增】防重复触发:3秒内只允许一次播报(关键修复)
|
||||
private static final long MIN_TRIGGER_INTERVAL = 3000;
|
||||
private static long sLastTriggerTime = 0;
|
||||
|
||||
// ====================== 成员变量 ======================
|
||||
private WeakReference<ControlCenterService> mwrControlCenterService;
|
||||
private boolean isRegistered = false; // 标记广播注册状态,避免冗余操作
|
||||
private boolean isRegistered = false;
|
||||
|
||||
// ====================== 构造方法(初始化弱引用,避免服务强引用泄漏) ======================
|
||||
// ====================== 构造 ======================
|
||||
public ControlCenterServiceReceiver(ControlCenterService service) {
|
||||
LogUtils.d(TAG, String.format("ControlCenterServiceReceiver() 构造 | 服务实例:%s",
|
||||
LogUtils.d(TAG, String.format("ControlCenterServiceReceiver() 构造 | 服务:%s",
|
||||
service != null ? service.getClass().getSimpleName() : "null"));
|
||||
this.mwrControlCenterService = new WeakReference<ControlCenterService>(service);
|
||||
this.mwrControlCenterService = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
// ====================== 广播核心接收逻辑(入口方法,分Action分发处理) ======================
|
||||
// ====================== 广播入口 ======================
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent != null ? intent.getAction() : "null";
|
||||
LogUtils.d(TAG, String.format("onReceive() 执行 | 接收广播 Action:%s", action));
|
||||
LogUtils.d(TAG, String.format("onReceive() | Action=%s", action));
|
||||
|
||||
// 基础参数校验
|
||||
if (context == null || intent == null || action == null) {
|
||||
LogUtils.e(TAG, "onReceive() 终止 | 参数无效(context=" + context + " | intent=" + intent + ")");
|
||||
LogUtils.e(TAG, "onReceive() 终止:参数无效");
|
||||
return;
|
||||
}
|
||||
|
||||
// 弱引用获取服务,双重校验服务有效性
|
||||
ControlCenterService service = mwrControlCenterService != null ? mwrControlCenterService.get() : null;
|
||||
if (service == null || service.isDestroyed()) {
|
||||
LogUtils.e(TAG, "onReceive() 终止 | 服务已销毁或为空,执行注销");
|
||||
LogUtils.e(TAG, "onReceive() 终止:服务已销毁");
|
||||
unregisterAction(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// 分Action处理业务逻辑
|
||||
switch (action) {
|
||||
case Intent.ACTION_BATTERY_CHANGED:
|
||||
handleBatteryStateChanged(service, intent);
|
||||
@@ -82,192 +81,145 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
handleUpdateForegroundNotification(service);
|
||||
break;
|
||||
case ACTION_APPCONFIG_CHANGED:
|
||||
LogUtils.d(TAG, "onReceive() 分发 | 处理配置更新广播");
|
||||
handleNotifyAppConfigUpdate(service);
|
||||
break;
|
||||
default:
|
||||
LogUtils.w(TAG, String.format("onReceive() 警告 | 未知Action=%s", action));
|
||||
LogUtils.w(TAG, "未知Action:" + action);
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "onReceive() 完成 | 广播处理结束");
|
||||
}
|
||||
|
||||
// ====================== 业务处理方法(按功能拆分,强化容错与日志) ======================
|
||||
/**
|
||||
* 处理电池状态变化广播
|
||||
* @param service 控制中心服务实例
|
||||
* @param intent 电池状态广播意图
|
||||
*/
|
||||
// ====================== 电池状态(核心修复区) ======================
|
||||
private void handleBatteryStateChanged(ControlCenterService service, Intent intent) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged() 执行 | 解析电池状态");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged() 解析电池状态");
|
||||
try {
|
||||
// 1. 解析并校验当前电池状态
|
||||
boolean currentCharging = BatteryUtils.isCharging(intent);
|
||||
int currentBatteryLevel = BatteryUtils.getCurrentBatteryLevel(intent);
|
||||
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged() 解析 | 充电=%b | 电量=%d%%", currentCharging, currentBatteryLevel));
|
||||
|
||||
// 2. 状态无变化则跳过,减少无效运算
|
||||
LogUtils.d(TAG, String.format("当前:充电=%b | 电量=%d%%", currentCharging, currentBatteryLevel));
|
||||
|
||||
// ================ 【关键修复1】状态没变直接跳过 ================
|
||||
if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged() 跳过 | 电池状态无变化");
|
||||
LogUtils.d(TAG, "状态无变化,跳过");
|
||||
return;
|
||||
}
|
||||
|
||||
// 在插拔充电线时,执行贴心服务
|
||||
if(currentCharging != sIsCharging && sLastBatteryLevel != INVALID_BATTERY) {
|
||||
//App.notifyMessage(TAG, String.format("sLastBatteryLevel %d", sLastBatteryLevel));
|
||||
if(currentCharging) {
|
||||
ThoughtfulService.startServiceWithType(service, ThoughtfulService.ServiceType.CHARGE_STATE);
|
||||
} else {
|
||||
ThoughtfulService.startServiceWithType(service, ThoughtfulService.ServiceType.DISCHARGE_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 更新静态缓存状态,保证多线程可见
|
||||
// ================ 【关键修复2】只有 真正插拔充电 才播报 ================
|
||||
boolean isRealPlugSwitch = (currentCharging != sIsCharging);
|
||||
boolean isBatteryValid = (sLastBatteryLevel != INVALID_BATTERY);
|
||||
|
||||
// ================ 【关键修复3】防抖动:3秒内不重复触发 ================
|
||||
long now = System.currentTimeMillis();
|
||||
boolean canTrigger = (now - sLastTriggerTime >= MIN_TRIGGER_INTERVAL);
|
||||
|
||||
if (isRealPlugSwitch && isBatteryValid && canTrigger) {
|
||||
LogUtils.d(TAG, "检测到充电状态切换 → 执行TTS提醒");
|
||||
|
||||
// 更新触发时间
|
||||
sLastTriggerTime = now;
|
||||
|
||||
// 执行播报
|
||||
if (currentCharging) {
|
||||
ThoughtfulService.startServiceWithType(service, ThoughtfulService.ServiceType.CHARGE_STATE);
|
||||
} else {
|
||||
ThoughtfulService.startServiceWithType(service, ThoughtfulService.ServiceType.DISCHARGE_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
sIsCharging = currentCharging;
|
||||
sLastBatteryLevel = currentBatteryLevel;
|
||||
|
||||
// 4. 同步缓存状态到配置
|
||||
// 同步配置
|
||||
handleNotifyAppConfigUpdate(service);
|
||||
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged() 完成 | 缓存电量=%d%% | 缓存充电状态=%b",
|
||||
sLastBatteryLevel, sIsCharging));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged() 失败", e);
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理配置变更通知,同步缓存状态到配置
|
||||
* @param service 控制中心服务实例
|
||||
*/
|
||||
// ====================== 配置同步 ======================
|
||||
private void handleNotifyAppConfigUpdate(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate() 执行 | 同步缓存状态到配置");
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate() 同步配置");
|
||||
try {
|
||||
// 加载最新配置
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(service).loadAppConfig();
|
||||
if (latestConfig == null) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 终止 | 最新配置为空");
|
||||
LogUtils.e(TAG, "配置为空,终止");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate() 加载 | 充电阈值=%d | 耗电阈值=%d",
|
||||
latestConfig.getChargeReminderValue(), latestConfig.getUsageReminderValue()));
|
||||
|
||||
// 同步缓存的电池状态到配置
|
||||
App.sQuantityOfElectricity = sLastBatteryLevel;
|
||||
latestConfig.setIsCharging(sIsCharging);
|
||||
service.notifyAppConfigUpdate(latestConfig);
|
||||
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate() 完成 | 缓存电量=%d%% | 充电状态=%b",
|
||||
sLastBatteryLevel, sIsCharging));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 失败", e);
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理前台服务通知更新
|
||||
* @param service 控制中心服务实例
|
||||
*/
|
||||
// ====================== 通知更新 ======================
|
||||
private void handleUpdateForegroundNotification(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification() 执行 | 更新前台通知");
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification() 更新通知");
|
||||
try {
|
||||
NotificationManagerUtils notifyUtils = service.getNotificationManager();
|
||||
NotificationMessage notifyMsg = service.getForegroundNotifyMsg();
|
||||
|
||||
// 非空校验,避免空指针
|
||||
if (notifyUtils == null || notifyMsg == null) {
|
||||
LogUtils.e(TAG, String.format("handleUpdateForegroundNotification() 终止 | 通知工具类或消息为空(notifyUtils=%s | notifyMsg=%s)",
|
||||
notifyUtils, notifyMsg));
|
||||
LogUtils.e(TAG, "通知工具或消息为空");
|
||||
return;
|
||||
}
|
||||
|
||||
notifyUtils.updateForegroundServiceNotify(notifyMsg);
|
||||
LogUtils.d(TAG, String.format("handleUpdateForegroundNotification() 完成 | 标题=%s", notifyMsg.getTitle()));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification() 失败", e);
|
||||
LogUtils.e(TAG, "更新通知异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 广播注册/注销(强化容错,避免重复操作) ======================
|
||||
/**
|
||||
* 注册广播接收器
|
||||
* @param context 上下文
|
||||
*/
|
||||
// ====================== 注册/注销 ======================
|
||||
public void registerAction(Context context) {
|
||||
LogUtils.d(TAG, "registerAction() 执行 | 注册广播接收器");
|
||||
if (context == null || isRegistered) {
|
||||
LogUtils.e(TAG, "registerAction() 失败 | 上下文为空或已注册");
|
||||
return;
|
||||
}
|
||||
|
||||
if (context == null || isRegistered) return;
|
||||
try {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
filter.addAction(ACTION_UPDATE_FOREGROUND_NOTIFICATION);
|
||||
filter.addAction(ACTION_APPCONFIG_CHANGED);
|
||||
filter.setPriority(BROADCAST_PRIORITY);
|
||||
|
||||
context.registerReceiver(this, filter);
|
||||
isRegistered = true;
|
||||
LogUtils.d(TAG, String.format("registerAction() 完成 | 优先级=%d", BROADCAST_PRIORITY));
|
||||
LogUtils.d(TAG, "广播注册完成");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "registerAction() 失败", e);
|
||||
LogUtils.e(TAG, "注册异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销广播接收器
|
||||
* @param context 上下文
|
||||
*/
|
||||
public void unregisterAction(Context context) {
|
||||
LogUtils.d(TAG, "unregisterAction() 执行 | 注销广播接收器");
|
||||
if (context == null || !isRegistered) {
|
||||
LogUtils.e(TAG, "unregisterAction() 失败 | 上下文为空或未注册");
|
||||
return;
|
||||
}
|
||||
|
||||
if (context == null || !isRegistered) return;
|
||||
try {
|
||||
context.unregisterReceiver(this);
|
||||
isRegistered = false;
|
||||
LogUtils.d(TAG, "unregisterAction() 完成 | 广播注销成功");
|
||||
} catch (IllegalArgumentException e) {
|
||||
LogUtils.w(TAG, "unregisterAction() 警告 | 广播未注册,跳过注销");
|
||||
LogUtils.d(TAG, "广播已注销");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "unregisterAction() 失败", e);
|
||||
LogUtils.w(TAG, "注销异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== 资源释放与Getter方法(按需开放,防泄漏) ======================
|
||||
/**
|
||||
* 主动释放资源,避免内存泄漏
|
||||
*/
|
||||
// ====================== 释放 ======================
|
||||
public void release() {
|
||||
LogUtils.d(TAG, "release() 执行 | 释放广播接收器资源");
|
||||
// 清空弱引用,帮助GC回收
|
||||
LogUtils.d(TAG, "release() 释放资源");
|
||||
if (mwrControlCenterService != null) {
|
||||
mwrControlCenterService.clear();
|
||||
mwrControlCenterService = null;
|
||||
LogUtils.d(TAG, "release() 步骤 | 弱引用已清空");
|
||||
}
|
||||
// 重置静态状态缓存
|
||||
sLastBatteryLevel = -1;
|
||||
// 重置静态状态
|
||||
sLastBatteryLevel = INVALID_BATTERY;
|
||||
sIsCharging = false;
|
||||
LogUtils.d(TAG, "release() 完成 | 静态状态缓存已重置");
|
||||
sLastTriggerTime = 0; // 【新增】重置防抖时间
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次记录的电池电量
|
||||
* @return 电量值(0-100),未初始化返回-1
|
||||
*/
|
||||
// ====================== Getter ======================
|
||||
public static int getLastBatteryLevel() {
|
||||
return sLastBatteryLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次记录的充电状态
|
||||
* @return true=充电中,false=未充电
|
||||
*/
|
||||
public static boolean isLastCharging() {
|
||||
return sIsCharging;
|
||||
}
|
||||
|
||||
@@ -19,161 +19,203 @@ import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
*/
|
||||
public class ThoughtfulService extends Service {
|
||||
|
||||
// ====================================== 常量区 - 置顶排序 ======================================
|
||||
// ====================================== 常量区 ======================================
|
||||
public static final String TAG = "ThoughtfulService";
|
||||
/** Intent传递 服务类型 的Key值 */
|
||||
public static final String EXTRA_SERVICE_TYPE = "EXTRA_SERVICE_TYPE";
|
||||
|
||||
// ====================================== 枚举类 - 服务类型 充电/放电状态 ======================================
|
||||
/**
|
||||
* 服务执行类型枚举
|
||||
* CHARGE_STATE : 充电状态服务
|
||||
* DISCHARGE_STATE : 放电(耗电)状态服务
|
||||
*/
|
||||
// 防止重复播报的标志(静态,全局唯一)
|
||||
private static boolean sIsPlaying = false;
|
||||
|
||||
// ====================================== 枚举 ======================================
|
||||
public enum ServiceType {
|
||||
CHARGE_STATE, //充电状态服务
|
||||
DISCHARGE_STATE, //放电状态服务
|
||||
CHARGE_STATE,
|
||||
DISCHARGE_STATE
|
||||
}
|
||||
|
||||
// ====================================== 对外公开静态启动函数【新增核心】入参Context + 枚举 ======================================
|
||||
/**
|
||||
* 公开静态方法:传入上下文+服务类型枚举,一键构建意图并启动当前服务
|
||||
* @param context 上下文对象
|
||||
* @param serviceType 服务类型枚举【充电/放电】
|
||||
*/
|
||||
// ====================================== 外部启动入口(加固) ======================================
|
||||
public static void startServiceWithType(Context context, ServiceType serviceType) {
|
||||
LogUtils.d(TAG, "【startServiceWithType】静态启动方法调用 | Context=" + context + " | ServiceType=" + (serviceType == null ? "null" : serviceType.name()));
|
||||
|
||||
ThoughtfulServiceBean thoughtfulServiceBean = ThoughtfulServiceBean.loadBean(context, ThoughtfulServiceBean.class);
|
||||
if (thoughtfulServiceBean == null) {
|
||||
thoughtfulServiceBean = new ThoughtfulServiceBean();
|
||||
}
|
||||
|
||||
// 对应TTS服务提醒没有启用,就退出
|
||||
if((serviceType == ServiceType.CHARGE_STATE && !thoughtfulServiceBean.isEnableChargeTts())
|
||||
||(serviceType == ServiceType.DISCHARGE_STATE && !thoughtfulServiceBean.isEnableUsePowerTts())){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 判空健壮性校验
|
||||
if (context != null && serviceType != null) {
|
||||
// 构建意图 + 封装枚举参数
|
||||
Intent intent = new Intent(context, ThoughtfulService.class);
|
||||
intent.putExtra(EXTRA_SERVICE_TYPE, serviceType);
|
||||
// 启动服务
|
||||
context.startService(intent);
|
||||
LogUtils.d(TAG, "【startServiceWithType】服务启动成功,执行[" + serviceType.name() + "]任务");
|
||||
} else {
|
||||
LogUtils.d(TAG, "【startServiceWithType】上下文为空 或 服务类型枚举为空,跳过启动服务");
|
||||
LogUtils.d(TAG, "【startServiceWithType】调用 | type=" + (serviceType == null ? "null" : serviceType.name()));
|
||||
|
||||
if (context == null || serviceType == null) {
|
||||
LogUtils.d(TAG, "【startServiceWithType】空参数,直接返回");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 预先读取配置,不满足直接不启动服务(最关键拦截)
|
||||
ThoughtfulServiceBean ttsBean = ThoughtfulServiceBean.loadBean(context, ThoughtfulServiceBean.class);
|
||||
if (ttsBean == null) {
|
||||
ttsBean = new ThoughtfulServiceBean();
|
||||
}
|
||||
|
||||
// 充电TTS未开 → 不启动
|
||||
if (serviceType == ServiceType.CHARGE_STATE && !ttsBean.isEnableChargeTts()) {
|
||||
LogUtils.d(TAG, "【startServiceWithType】充电TTS未启用,不启动服务");
|
||||
return;
|
||||
}
|
||||
|
||||
// 用电TTS未开 → 不启动
|
||||
if (serviceType == ServiceType.DISCHARGE_STATE && !ttsBean.isEnableUsePowerTts()) {
|
||||
LogUtils.d(TAG, "【startServiceWithType】用电TTS未启用,不启动服务");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 防止重复启动导致叠加播报
|
||||
if (sIsPlaying) {
|
||||
LogUtils.d(TAG, "【startServiceWithType】已有播报任务,跳过本次启动");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 真正启动
|
||||
Intent intent = new Intent(context, ThoughtfulService.class);
|
||||
intent.putExtra(EXTRA_SERVICE_TYPE, serviceType);
|
||||
context.startService(intent);
|
||||
LogUtils.d(TAG, "【startServiceWithType】服务启动成功");
|
||||
}
|
||||
|
||||
// ====================================== 生命周期方法 - 绑定服务 (原逻辑保留) ======================================
|
||||
// ====================================== 生命周期 ======================================
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
LogUtils.d(TAG, "【onBind】服务绑定方法调用,入参Intent:" + intent);
|
||||
return null;
|
||||
}
|
||||
|
||||
// ====================================== 生命周期方法 - 启动服务【核心逻辑】接收枚举+分支执行任务 ======================================
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
LogUtils.d(TAG, "【onStartCommand】服务启动方法调用 | intent=" + intent + " | flags=" + flags + " | startId=" + startId);
|
||||
// 判断意图非空,解析服务类型参数
|
||||
if (intent != null) {
|
||||
LogUtils.d(TAG, "【onStartCommand】Intent不为空,开始解析服务类型枚举参数");
|
||||
// 获取传递的服务类型枚举
|
||||
ServiceType serviceType = (ServiceType) intent.getSerializableExtra(EXTRA_SERVICE_TYPE);
|
||||
// 根据服务类型,执行对应任务
|
||||
if (serviceType != null) {
|
||||
LogUtils.d(TAG, "【onStartCommand】解析到服务类型:" + serviceType.name());
|
||||
switch (serviceType) {
|
||||
case CHARGE_STATE:
|
||||
// 执行【充电状态】对应的业务任务
|
||||
executeChargeStateTask();
|
||||
break;
|
||||
case DISCHARGE_STATE:
|
||||
// 执行【放电状态】对应的业务任务
|
||||
executeDischargeStateTask();
|
||||
break;
|
||||
default:
|
||||
LogUtils.d(TAG, "【onStartCommand】未知的服务类型,不执行任何任务");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LogUtils.d(TAG, "【onStartCommand】未解析到有效服务类型参数,参数为空");
|
||||
}
|
||||
} else {
|
||||
LogUtils.d(TAG, "【onStartCommand】启动服务的Intent为空,直接返回");
|
||||
LogUtils.d(TAG, "【onStartCommand】进入");
|
||||
|
||||
if (intent == null) {
|
||||
LogUtils.d(TAG, "【onStartCommand】intent = null,停止");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// 返回默认策略,与原生逻辑一致
|
||||
int result = super.onStartCommand(intent, flags, startId);
|
||||
LogUtils.d(TAG, "【onStartCommand】服务执行完成,返回值:" + result);
|
||||
return result;
|
||||
// 再次防止重复播报(双重保险)
|
||||
if (sIsPlaying) {
|
||||
LogUtils.d(TAG, "【onStartCommand】已有播报,直接停止服务");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// 解析类型
|
||||
ServiceType type = (ServiceType) intent.getSerializableExtra(EXTRA_SERVICE_TYPE);
|
||||
if (type == null) {
|
||||
LogUtils.d(TAG, "【onStartCommand】type = null,停止");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// 二次校验开关(防止外部绕过 startServiceWithType 直接启动)
|
||||
ThoughtfulServiceBean ttsBean = ThoughtfulServiceBean.loadBean(this, ThoughtfulServiceBean.class);
|
||||
if (ttsBean == null) ttsBean = new ThoughtfulServiceBean();
|
||||
|
||||
boolean allowPlay = false;
|
||||
if (type == ServiceType.CHARGE_STATE && ttsBean.isEnableChargeTts()) {
|
||||
allowPlay = true;
|
||||
}
|
||||
if (type == ServiceType.DISCHARGE_STATE && ttsBean.isEnableUsePowerTts()) {
|
||||
allowPlay = true;
|
||||
}
|
||||
|
||||
if (!allowPlay) {
|
||||
LogUtils.d(TAG, "【onStartCommand】TTS开关已关闭,不执行播报");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
// 执行任务
|
||||
if (type == ServiceType.CHARGE_STATE) {
|
||||
executeChargeStateTask();
|
||||
} else if (type == ServiceType.DISCHARGE_STATE) {
|
||||
executeDischargeStateTask();
|
||||
}
|
||||
|
||||
return START_NOT_STICKY; // 重要:执行完自动销毁,不保留服务
|
||||
}
|
||||
|
||||
// ====================================== 私有业务方法 充电/放电 分任务执行 ======================================
|
||||
/**
|
||||
* 执行【充电状态】的业务任务
|
||||
* 可在此方法内编写 充电时的逻辑(语音提醒/电量监控/弹窗等)
|
||||
*/
|
||||
// ====================================== 充电任务 ======================================
|
||||
private void executeChargeStateTask() {
|
||||
LogUtils.d(TAG, "【executeChargeStateTask】执行【充电状态】业务任务 >>> ");
|
||||
//ToastUtils.show("【executeChargeStateTask】执行【充电状态】业务任务 >>> ");
|
||||
// TODO 此处添加充电状态需要执行的业务逻辑代码
|
||||
// 加载最新配置
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(this).loadAppConfig();
|
||||
if (latestConfig == null) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 终止 | 最新配置为空");
|
||||
return;
|
||||
}
|
||||
|
||||
ThoughtfulServiceBean thoughtfulServiceBean = ThoughtfulServiceBean.loadBean(this, ThoughtfulServiceBean.class);
|
||||
if (thoughtfulServiceBean == null) {
|
||||
thoughtfulServiceBean = new ThoughtfulServiceBean();
|
||||
}
|
||||
|
||||
if (latestConfig.isEnableChargeReminder()) {
|
||||
int nChargeReminderValue = latestConfig.getChargeReminderValue();
|
||||
String szCurrentBattery = thoughtfulServiceBean.isEnableChargeTtsWithBattary()? String.format("现在电量为百分之%d。", App.sQuantityOfElectricity) : "";
|
||||
String szRemind = String.format("限量充电提醒已启用,限量值为百分之%d。", nChargeReminderValue);
|
||||
szRemind = szCurrentBattery + szRemind + szRemind + szRemind;
|
||||
TTSPlayService.startPlayTTS(this, szRemind);
|
||||
}
|
||||
LogUtils.d(TAG, "【executeChargeStateTask】执行充电任务");
|
||||
|
||||
sIsPlaying = true; // 锁定播报
|
||||
|
||||
try {
|
||||
AppConfigBean config = AppConfigUtils.getInstance(this).loadAppConfig();
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, "配置为空,停止");
|
||||
return;
|
||||
}
|
||||
|
||||
ThoughtfulServiceBean ttsBean = ThoughtfulServiceBean.loadBean(this, ThoughtfulServiceBean.class);
|
||||
if (ttsBean == null) ttsBean = new ThoughtfulServiceBean();
|
||||
|
||||
// 主提醒开关未开 → 直接不播
|
||||
if (!config.isEnableChargeReminder()) {
|
||||
LogUtils.d(TAG, "充电提醒总开关关闭,不播报");
|
||||
return;
|
||||
}
|
||||
|
||||
int limit = config.getChargeReminderValue();
|
||||
int battery = App.sQuantityOfElectricity;
|
||||
|
||||
// 电量无效值 → 不拼接电量
|
||||
String batteryStr = "";
|
||||
if (battery >= 0 && battery <= 100 && ttsBean.isEnableChargeTtsWithBattary()) {
|
||||
batteryStr = String.format("当前电量百分之%d。", battery);
|
||||
}
|
||||
|
||||
String text = batteryStr + String.format("限量充电提醒已启用,限值百分之%d。", limit);
|
||||
TTSPlayService.startPlayTTS(this, text);
|
||||
LogUtils.d(TAG, "充电TTS已下发:" + text);
|
||||
|
||||
} finally {
|
||||
sIsPlaying = false; // 释放锁
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行【放电(耗电)状态】的业务任务
|
||||
* 可在此方法内编写 放电时的逻辑(语音提醒/电量监控/弹窗等)
|
||||
*/
|
||||
// ====================================== 放电任务 ======================================
|
||||
private void executeDischargeStateTask() {
|
||||
LogUtils.d(TAG, "【executeDischargeStateTask】执行【放电状态】业务任务 >>> ");
|
||||
//ToastUtils.show("【executeDischargeStateTask】执行【放电状态】业务任务 >>> ");
|
||||
// TODO 此处添加放电状态需要执行的业务逻辑代码
|
||||
// 加载最新配置
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(this).loadAppConfig();
|
||||
if (latestConfig == null) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 终止 | 最新配置为空");
|
||||
return;
|
||||
}
|
||||
|
||||
ThoughtfulServiceBean thoughtfulServiceBean = ThoughtfulServiceBean.loadBean(this, ThoughtfulServiceBean.class);
|
||||
if (thoughtfulServiceBean == null) {
|
||||
thoughtfulServiceBean = new ThoughtfulServiceBean();
|
||||
}
|
||||
LogUtils.d(TAG, "【executeDischargeStateTask】执行放电任务");
|
||||
|
||||
if (latestConfig.isEnableUsageReminder()) {
|
||||
int nUsageReminderValue = latestConfig.getUsageReminderValue();
|
||||
String szCurrentBattery = thoughtfulServiceBean.isEnableUseageTtsWithBattary()? String.format("现在电量为百分之%d。", App.sQuantityOfElectricity) : "";
|
||||
String szRemind = szCurrentBattery + String.format("电量不足提醒已启用,低电值为百分之%d。", nUsageReminderValue);
|
||||
sIsPlaying = true;
|
||||
|
||||
//szRemind = szRemind + szRemind + szRemind;
|
||||
TTSPlayService.startPlayTTS(this, szRemind);
|
||||
}
|
||||
try {
|
||||
AppConfigBean config = AppConfigUtils.getInstance(this).loadAppConfig();
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, "配置为空,停止");
|
||||
return;
|
||||
}
|
||||
|
||||
ThoughtfulServiceBean ttsBean = ThoughtfulServiceBean.loadBean(this, ThoughtfulServiceBean.class);
|
||||
if (ttsBean == null) ttsBean = new ThoughtfulServiceBean();
|
||||
|
||||
// 主提醒开关未开 → 不播
|
||||
if (!config.isEnableUsageReminder()) {
|
||||
LogUtils.d(TAG, "低电提醒总开关关闭,不播报");
|
||||
return;
|
||||
}
|
||||
|
||||
int limit = config.getUsageReminderValue();
|
||||
int battery = App.sQuantityOfElectricity;
|
||||
|
||||
String batteryStr = "";
|
||||
if (battery >= 0 && battery <= 100 && ttsBean.isEnableUseageTtsWithBattary()) {
|
||||
batteryStr = String.format("当前电量百分之%d。", battery);
|
||||
}
|
||||
|
||||
String text = batteryStr + String.format("低电量提醒已启用,限值百分之%d。", limit);
|
||||
TTSPlayService.startPlayTTS(this, text);
|
||||
LogUtils.d(TAG, "放电TTS已下发:" + text);
|
||||
|
||||
} finally {
|
||||
sIsPlaying = false;
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
LogUtils.d(TAG, "【onDestroy】服务已销毁");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
// 中断当前线程(如果存活)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user