服务自启动修复中。。。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed Dec 17 08:23:18 GMT 2025
|
||||
#Wed Dec 17 08:49:06 GMT 2025
|
||||
stageCount=10
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.9
|
||||
buildCount=16
|
||||
buildCount=18
|
||||
baseBetaVersion=15.14.10
|
||||
|
||||
@@ -30,16 +30,15 @@ import cc.winboll.studio.powerbell.activities.SettingsActivity;
|
||||
import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.utils.PermissionUtils;
|
||||
import cc.winboll.studio.powerbell.utils.ServiceUtils;
|
||||
import cc.winboll.studio.powerbell.views.BackgroundView;
|
||||
import cc.winboll.studio.powerbell.views.MainContentView;
|
||||
import cc.winboll.studio.powerbell.views.VerticalSeekBar;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
@@ -59,6 +58,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
public static final int MSG_CURRENTVALUEBATTERY = 1; // 更新当前电量
|
||||
public static final int MSG_LOAD_BACKGROUND = 2; // 加载背景
|
||||
private static final int MSG_RESTART_REMIND_THREAD = 3; // 重启RemindThread线程
|
||||
private static final int MSG_UPDATE_SERVICE_SWITCH = 4; // 更新服务开关UI(新增)
|
||||
|
||||
// ======================== 静态成员(全局共享,严格管控生命周期)========================
|
||||
public static MainActivity sMainActivity; // 全局Activity实例(销毁时必须置空)
|
||||
@@ -79,6 +79,8 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
// 资源与菜单
|
||||
private Menu mMenu;
|
||||
private Drawable mFrameDrawable; // 框架背景资源(适配API30主题)
|
||||
// 新增:服务控制核心Bean(本地持久化,管理服务自启动状态)
|
||||
private ControlCenterServiceBean mServiceControlBean;
|
||||
|
||||
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
|
||||
@Override
|
||||
@@ -124,15 +126,28 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||
LogUtils.d(TAG, "onResume: 发送加载背景消息");
|
||||
// 新增:恢复时同步服务开关UI(避免开关状态与实际服务状态不一致)
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
}
|
||||
// 2. 恢复广告(非核心,容错处理)
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.resumeADs(this);
|
||||
LogUtils.d(TAG, "onResume: 恢复广告展示");
|
||||
}
|
||||
// 3. 关键调整:应用切前台,设置RemindThread为前台状态(开启提醒)
|
||||
setRemindThreadForeground(true);
|
||||
LogUtils.d(TAG, "onResume: 退出");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
LogUtils.d(TAG, "onPause: 进入");
|
||||
super.onPause();
|
||||
// 关键调整:应用切后台,设置RemindThread为后台状态(停止提醒+重置无效电量)
|
||||
setRemindThreadForeground(false);
|
||||
LogUtils.d(TAG, "onPause: 退出");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
LogUtils.d(TAG, "onDestroy: 进入");
|
||||
@@ -149,24 +164,28 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
mMainContentView = null;
|
||||
LogUtils.d(TAG, "onDestroy: 释放核心视图资源完成");
|
||||
}
|
||||
// 3. 置空全局实例(杜绝内存泄漏,必须执行)
|
||||
// 3. 关键调整:Activity销毁,强制销毁RemindThread单例(彻底停止线程)
|
||||
RemindThread.destroyInstance();
|
||||
LogUtils.d(TAG, "onDestroy: 强制销毁RemindThread单例完成");
|
||||
// 4. 置空全局实例(杜绝内存泄漏,必须执行)
|
||||
sMainActivity = null;
|
||||
// 4. 清理Handler(移除所有消息,避免Activity销毁后回调)
|
||||
// 5. 清理Handler(移除所有消息,避免Activity销毁后回调)
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.removeCallbacksAndMessages(null);
|
||||
sGlobalHandler = null;
|
||||
LogUtils.d(TAG, "onDestroy: 清理全局Handler完成");
|
||||
}
|
||||
// 5. 释放Drawable资源(断开回调,辅助GC回收)
|
||||
// 6. 释放Drawable资源(断开回调,辅助GC回收)
|
||||
if (mFrameDrawable != null) {
|
||||
mFrameDrawable.setCallback(null);
|
||||
mFrameDrawable = null;
|
||||
LogUtils.d(TAG, "onDestroy: 释放Drawable资源完成");
|
||||
}
|
||||
// 6. 置空所有辅助实例(辅助GC,避免残留引用)
|
||||
// 7. 置空所有辅助实例(辅助GC,避免残留引用)
|
||||
mPermissionUtils = null;
|
||||
mAppConfigUtils = null;
|
||||
mBgSourceUtils = null;
|
||||
mServiceControlBean = null; // 新增:置空服务控制Bean
|
||||
mMenu = null;
|
||||
mApplication = null;
|
||||
mToolbar = null;
|
||||
@@ -314,6 +333,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
case MSG_RESTART_REMIND_THREAD:
|
||||
AppConfigBean configBean = (AppConfigBean) msg.obj;
|
||||
sMainActivity.restartRemindThread(configBean);
|
||||
break;
|
||||
// 新增:更新服务开关UI(同步实际服务状态,避免开关与服务状态不一致)
|
||||
case MSG_UPDATE_SERVICE_SWITCH:
|
||||
sMainActivity.updateServiceSwitchUI();
|
||||
break;
|
||||
}
|
||||
super.handleMessage(msg);
|
||||
@@ -366,7 +389,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
mApplication = (App) getApplication();
|
||||
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
|
||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 核心工具类初始化完成");
|
||||
// 新增:初始化服务控制Bean(读取本地持久化状态,管理自启动)
|
||||
mServiceControlBean = ControlCenterServiceBean.loadBean(getApplicationContext(), ControlCenterServiceBean.class);
|
||||
if (mServiceControlBean == null) {
|
||||
// 本地无配置,默认禁用服务(与服务初始化逻辑一致)
|
||||
mServiceControlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无服务控制配置,创建默认禁用配置");
|
||||
}
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 核心工具类+服务控制Bean初始化完成");
|
||||
|
||||
// 切换主线程更新UI(Java7显式runOnUiThread)
|
||||
runOnUiThread(new Runnable() {
|
||||
@@ -387,6 +418,8 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
updateViewData(); // 更新视图数据
|
||||
checkServiceAsync(); // 异步检查服务状态
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); // 加载背景
|
||||
// 新增:初始化服务开关UI(确保开关状态与本地配置一致)
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
|
||||
@@ -483,6 +516,27 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:更新服务开关UI(同步「本地配置+实际服务状态」,避免开关与服务状态不一致)
|
||||
*/
|
||||
private void updateServiceSwitchUI() {
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 进入");
|
||||
if (mMainContentView == null || mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图/服务控制Bean为空,跳过更新");
|
||||
return;
|
||||
}
|
||||
// 开关状态 = 本地服务控制配置启用状态(自启动状态)
|
||||
boolean isServiceEnabled = mServiceControlBean.isEnableService();
|
||||
// 禁用开关点击(避免更新UI时触发重复回调)
|
||||
mMainContentView.setServiceSwitchEnabled(false);
|
||||
// 更新开关状态
|
||||
mMainContentView.setServiceSwitchChecked(isServiceEnabled);
|
||||
// 启用开关点击
|
||||
mMainContentView.setServiceSwitchEnabled(true);
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI更新完成,当前状态=" + isServiceEnabled);
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI: 退出");
|
||||
}
|
||||
|
||||
// ======================== 服务与线程管理方法(业务核心,统一归类)========================
|
||||
/**
|
||||
* 异步检查服务状态(子线程执行,避免主线程阻塞,适配API30前台服务规范)
|
||||
@@ -493,23 +547,18 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "checkServiceAsync: 异步线程启动");
|
||||
if (mAppConfigUtils == null || isFinishing()) {
|
||||
LogUtils.e(TAG, "checkServiceAsync: 配置工具类/Activity无效,跳过检查");
|
||||
if (mAppConfigUtils == null || mServiceControlBean == null || isFinishing()) {
|
||||
LogUtils.e(TAG, "checkServiceAsync: 配置工具类/服务控制Bean/Activity无效,跳过检查");
|
||||
return;
|
||||
}
|
||||
// 服务启用且未运行时,启动前台服务(API30必须前台服务,小米保活优化)
|
||||
if (mAppConfigUtils.isServiceEnabled() && !ServiceUtils.isServiceAlive(getActivity(), ControlCenterService.class.getName())) {
|
||||
// 服务启用(本地配置)且未运行时,启动前台服务(API30必须前台服务,小米保活优化)
|
||||
if (mServiceControlBean.isEnableService() && !ServiceUtils.isServiceAlive(getActivity(), ControlCenterService.class.getName())) {
|
||||
LogUtils.d(TAG, "checkServiceAsync: 服务未运行,启动前台服务");
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isFinishing()) {
|
||||
Intent serviceIntent = new Intent(getActivity(), ControlCenterService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
getActivity().startForegroundService(serviceIntent);
|
||||
} else {
|
||||
getActivity().startService(serviceIntent);
|
||||
}
|
||||
ControlCenterService.startControlCenterService(getActivity());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -525,24 +574,90 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
*/
|
||||
private void restartRemindThread(AppConfigBean configBean) {
|
||||
LogUtils.d(TAG, "restartRemindThread: 进入");
|
||||
if (configBean == null || !ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
|
||||
LogUtils.e(TAG, "restartRemindThread: 配置为空/服务未运行,跳过重启");
|
||||
if (configBean == null || mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "restartRemindThread: 配置为空/服务控制Bean为空,跳过重启");
|
||||
return;
|
||||
}
|
||||
// 发送重启指令到服务(通过Intent传递最新配置)
|
||||
Intent restartIntent = new Intent(this, ControlCenterService.class);
|
||||
restartIntent.setAction(ControlCenterService.ACTION_RESTART_REMIND_THREAD);
|
||||
restartIntent.putExtra(ControlCenterService.EXTRA_APP_CONFIG_BEAN, (Serializable) configBean);
|
||||
// 适配API26+前台服务启动规范
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(restartIntent);
|
||||
} else {
|
||||
startService(restartIntent);
|
||||
// 服务未启用时,不重启线程(直接返回)
|
||||
if (!mServiceControlBean.isEnableService()) {
|
||||
LogUtils.w(TAG, "restartRemindThread: 服务已禁用,跳过线程重启");
|
||||
return;
|
||||
}
|
||||
// 服务未运行时,先启动服务
|
||||
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
|
||||
ControlCenterService.startControlCenterService(this);
|
||||
LogUtils.d(TAG, "restartRemindThread: 服务未运行,先启动服务");
|
||||
}
|
||||
// 关键优化:重启前先销毁旧线程,避免线程复用导致的状态脏数据
|
||||
RemindThread.destroyInstance();
|
||||
LogUtils.d(TAG, "restartRemindThread: 销毁旧线程完成,准备启动新线程");
|
||||
|
||||
// 发送重启指令到服务(通过Intent传递最新配置)
|
||||
ControlCenterService.updateStatus(this, configBean);
|
||||
LogUtils.d(TAG, "restartRemindThread: 发送线程重启指令到服务完成");
|
||||
LogUtils.d(TAG, "restartRemindThread: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键新增:设置RemindThread前台/后台状态(核心修复无限提醒问题)
|
||||
* @param isForeground true=前台(开启提醒),false=后台(停止提醒)
|
||||
*/
|
||||
private void setRemindThreadForeground(boolean isForeground) {
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: 进入,前台状态=" + isForeground);
|
||||
// 服务未运行时,跳过状态设置(线程未启动)
|
||||
if (!ServiceUtils.isServiceAlive(this, ControlCenterService.class.getName())) {
|
||||
LogUtils.w(TAG, "setRemindThreadForeground: 服务未运行,跳过状态设置");
|
||||
return;
|
||||
}
|
||||
// 调用RemindThread新增方法,设置前台状态(线程安全)
|
||||
try {
|
||||
RemindThread.getInstance(this, null).setAppForeground(isForeground);
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: RemindThread状态设置完成");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 首次启动时Handler可能未就绪,容错处理(服务会后续同步状态)
|
||||
LogUtils.w(TAG, "setRemindThreadForeground: 线程未初始化完成,后续服务会同步状态", e);
|
||||
}
|
||||
LogUtils.d(TAG, "setRemindThreadForeground: 退出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:切换服务启用/禁用状态(核心修复:持久化配置+启停服务+更新UI+重启线程)
|
||||
* @param isEnable true=启用服务(自启动+启动服务),false=禁用服务(停止服务)
|
||||
*/
|
||||
private void toggleServiceEnableState(boolean isEnable) {
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 进入,目标状态=" + isEnable);
|
||||
if (mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "toggleServiceEnableState: 服务控制Bean为空,切换失败");
|
||||
return;
|
||||
}
|
||||
// 1. 更新本地服务控制配置(持久化,实现自启动)
|
||||
mServiceControlBean.setIsEnableService(isEnable);
|
||||
ControlCenterService.updateServiceControlConfig(this, mServiceControlBean);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务控制配置已持久化,自启动状态=" + isEnable);
|
||||
|
||||
// 2. 启停服务(通过服务静态方法,适配API30前台服务规范)
|
||||
if (isEnable) {
|
||||
// 启用:启动前台服务+检查电池优化(避免服务被杀死)
|
||||
ControlCenterService.startControlCenterService(this);
|
||||
ControlCenterService.checkIgnoreBatteryOptimization(this);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动,已引导忽略电池优化");
|
||||
} else {
|
||||
// 禁用:停止服务(服务内部会自动停止线程+释放资源)
|
||||
ControlCenterService.stopControlCenterService(this);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
|
||||
}
|
||||
|
||||
// 3. 服务启用时,重启线程(确保线程使用最新配置)
|
||||
if (isEnable && mAppConfigUtils != null && mAppConfigUtils.mAppConfigBean != null) {
|
||||
sendRestartRemindThreadMessage();
|
||||
}
|
||||
|
||||
// 4. 更新服务开关UI(确保开关状态与实际服务状态一致)
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务状态切换完成");
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 退出");
|
||||
}
|
||||
|
||||
// ======================== 页面跳转方法(封装逻辑,减少冗余)========================
|
||||
/**
|
||||
* 启动关于页面(封装跳转逻辑,统一参数传递,便于维护)
|
||||
@@ -670,7 +785,8 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void onServiceSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
|
||||
sendRestartRemindThreadMessage();
|
||||
// 核心修复:点击服务开关,触发「配置持久化+服务启停+UI更新」全链路逻辑
|
||||
toggleServiceEnableState(isChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,6 +31,9 @@ public class ControlCenterService extends Service {
|
||||
// 服务指令常量(带包名前缀,防止冲突)
|
||||
public static final String ACTION_RESTART_REMIND_THREAD = "cc.winboll.studio.powerbell.action.RESTART_REMIND_THREAD";
|
||||
public static final String EXTRA_APP_CONFIG_BEAN = "cc.winboll.studio.powerbell.extra.APP_CONFIG_BEAN";
|
||||
// 新增:应用前台/后台状态同步指令(用于MainActivity与服务联动)
|
||||
public static final String ACTION_SYNC_APP_FOREGROUND_STATE = "cc.winboll.studio.powerbell.action.SYNC_APP_FOREGROUND_STATE";
|
||||
public static final String EXTRA_APP_FOREGROUND_STATE = "cc.winboll.studio.powerbell.extra.APP_FOREGROUND_STATE";
|
||||
|
||||
// ================================== 核心成员变量(按依赖优先级排序,私有封装)=================================
|
||||
// 服务控制核心(本地持久化管理,替代Intent传递)
|
||||
@@ -42,6 +45,8 @@ public class ControlCenterService extends Service {
|
||||
private AppConfigBean mCurrentConfigBean; // 当前应用配置
|
||||
// 前台服务相关
|
||||
private NotificationMessage mForegroundNotifyMsg; // 前台保活通知模型
|
||||
// 新增:应用前台状态标记(内存缓存,同步MainActivity状态)
|
||||
private boolean mIsAppForeground = false;
|
||||
// 状态标记(并发安全)
|
||||
private boolean isServiceRunning = false; // 服务运行状态
|
||||
private boolean mIsDestroyed = false; // 服务销毁标记
|
||||
@@ -81,6 +86,8 @@ public class ControlCenterService extends Service {
|
||||
handleExternalCommand(intent);
|
||||
rebindForegroundNotify();
|
||||
initServiceBusinessIfNeed(); // 按需初始化业务(避免重复初始化)
|
||||
// 新增:业务初始化完成后,同步应用前台状态到线程(防止状态丢失)
|
||||
syncAppForegroundStateToThread();
|
||||
LogUtils.d(TAG, "onStartCommand: 核心逻辑执行完成,返回START_STICKY");
|
||||
return START_STICKY;
|
||||
} else {
|
||||
@@ -100,6 +107,7 @@ public class ControlCenterService extends Service {
|
||||
synchronized (mServiceLock) {
|
||||
isServiceRunning = false;
|
||||
mIsDestroyed = true;
|
||||
mIsAppForeground = false; // 新增:重置前台状态
|
||||
}
|
||||
// 顺序释放资源(前台服务→线程→Handler→通知→配置→控制Bean)
|
||||
stopForegroundService();
|
||||
@@ -187,6 +195,7 @@ public class ControlCenterService extends Service {
|
||||
releaseNotificationResource();
|
||||
mCurrentConfigBean = null;
|
||||
mForegroundNotifyMsg = null;
|
||||
mIsAppForeground = false; // 新增:重置前台状态
|
||||
LogUtils.d(TAG, "stopAllBusinessSafely: 所有核心业务已停止");
|
||||
}
|
||||
}
|
||||
@@ -308,12 +317,14 @@ public class ControlCenterService extends Service {
|
||||
mRemindThread = RemindThread.getInstance(this, mServiceHandler);
|
||||
// 同步配置并开启提醒
|
||||
syncConfigToRemindThread();
|
||||
// 新增:同步应用前台状态(确保新线程启动时状态正确)
|
||||
syncAppForegroundStateToThread();
|
||||
|
||||
// 双重校验,避免线程重复启动
|
||||
if (mRemindThread != null && !mRemindThread.isAlive() && !mRemindThread.isThreadStarted()) {
|
||||
try {
|
||||
mRemindThread.start();
|
||||
LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功,ID=" + mRemindThread.getId());
|
||||
LogUtils.d(TAG, "restartRemindThreadSafely: 新线程启动成功,ID=" + mRemindThread.getId() + ",前台状态=" + mIsAppForeground);
|
||||
} catch (IllegalThreadStateException e) {
|
||||
LogUtils.e(TAG, "restartRemindThreadSafely: 线程重复启动异常", e);
|
||||
mRemindThread = null;
|
||||
@@ -383,9 +394,26 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 外部指令处理方法(接收重启/更新配置指令,移除控制Bean传递)=================================
|
||||
/**
|
||||
* 处理外部发送的服务指令(如重启线程、更新配置)
|
||||
* 新增:同步应用前台状态到RemindThread(核心联动逻辑)
|
||||
* 确保线程实时感知应用前台/后台状态,控制提醒开关
|
||||
*/
|
||||
private void syncAppForegroundStateToThread() {
|
||||
LogUtils.d(TAG, "syncAppForegroundStateToThread: 同步前台状态,当前状态=" + mIsAppForeground);
|
||||
synchronized (mServiceLock) {
|
||||
if (mRemindThread == null || mIsDestroyed || !isServiceRunning) {
|
||||
LogUtils.w(TAG, "syncAppForegroundStateToThread: 线程未启动/服务已销毁,同步失败");
|
||||
return;
|
||||
}
|
||||
// 调用RemindThread新增方法,同步前台状态(线程安全)
|
||||
mRemindThread.setAppForeground(mIsAppForeground);
|
||||
LogUtils.d(TAG, "syncAppForegroundStateToThread: 前台状态同步完成");
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 外部指令处理方法(新增前台状态同步指令,完善链路)=================================
|
||||
/**
|
||||
* 处理外部发送的服务指令(如重启线程、更新配置、同步前台状态)
|
||||
*/
|
||||
private void handleExternalCommand(Intent intent) {
|
||||
LogUtils.d(TAG, "handleExternalCommand: 开始处理外部指令");
|
||||
@@ -400,7 +428,7 @@ public class ControlCenterService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理线程重启指令(仅同步业务配置,服务控制配置从本地读取)
|
||||
// 1. 处理线程重启指令(仅同步业务配置,服务控制配置从本地读取)
|
||||
if (ACTION_RESTART_REMIND_THREAD.equals(action)) {
|
||||
// 读取本地最新控制配置,确保状态同步
|
||||
loadLatestServiceControlConfig();
|
||||
@@ -420,6 +448,16 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. 新增:处理应用前台/后台状态同步指令(MainActivity触发)
|
||||
else if (ACTION_SYNC_APP_FOREGROUND_STATE.equals(action)) {
|
||||
boolean isForeground = intent.getBooleanExtra(EXTRA_APP_FOREGROUND_STATE, false);
|
||||
synchronized (mServiceLock) {
|
||||
mIsAppForeground = isForeground;
|
||||
LogUtils.d(TAG, "handleExternalCommand: 收到前台状态同步指令,更新状态=" + isForeground);
|
||||
// 同步状态到线程(实时生效)
|
||||
syncAppForegroundStateToThread();
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "handleExternalCommand: 外部指令处理完成");
|
||||
}
|
||||
|
||||
@@ -476,7 +514,7 @@ public class ControlCenterService extends Service {
|
||||
LogUtils.d(TAG, "clearAllReferences: 所有引用已置空");
|
||||
}
|
||||
|
||||
// ================================== 静态工具方法(服务启动/停止/状态判断/电池优化,简化控制Bean传递)=================================
|
||||
// ================================== 静态工具方法(新增前台状态同步入口,完善保活优化)=================================
|
||||
/**
|
||||
* 启动服务(静态入口,从本地读取控制配置,显式绑定包名,适配API30+)
|
||||
*/
|
||||
@@ -572,7 +610,41 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断服务是否运行(适配API30+ ActivityManager限制)
|
||||
* 新增:同步应用前台/后台状态到服务(MainActivity专用入口)
|
||||
* @param context 上下文
|
||||
* @param isForeground true=前台,false=后台
|
||||
*/
|
||||
public static void syncAppForegroundState(Context context, boolean isForeground) {
|
||||
LogUtils.d(TAG, "syncAppForegroundState: 发送前台状态同步指令,状态=" + isForeground);
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "syncAppForegroundState: Context为空,同步失败");
|
||||
return;
|
||||
}
|
||||
if (!isServiceRunning(context, ControlCenterService.class)) {
|
||||
LogUtils.w(TAG, "syncAppForegroundState: 服务未运行,跳过同步");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
intent.setAction(ACTION_SYNC_APP_FOREGROUND_STATE);
|
||||
intent.putExtra(EXTRA_APP_FOREGROUND_STATE, isForeground);
|
||||
intent.setPackage(context.getPackageName());
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(intent);
|
||||
} else {
|
||||
context.startService(intent);
|
||||
}
|
||||
LogUtils.d(TAG, "syncAppForegroundState: 前台状态同步指令发送成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "syncAppForegroundState: 发送同步指令异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断服务是否运行(适配API30+ ActivityManager限制,优化判断逻辑)
|
||||
*/
|
||||
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
||||
if (context == null || serviceClass == null) {
|
||||
@@ -586,21 +658,24 @@ public class ControlCenterService extends Service {
|
||||
return false;
|
||||
}
|
||||
|
||||
// API30+ 兼容:getRunningServices失效,通过进程状态判断
|
||||
// API30+ 兼容:getRunningServices失效,通过进程状态判断(优化兜底逻辑)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
try {
|
||||
String packageName = context.getPackageName();
|
||||
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
|
||||
if (processes != null && !processes.isEmpty()) {
|
||||
for (ActivityManager.RunningAppProcessInfo process : processes) {
|
||||
if (packageName.equals(process.processName)
|
||||
&& process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
|
||||
return true;
|
||||
if (packageName.equals(process.processName)) {
|
||||
// 前台服务/前台进程均视为服务运行(适配部分机型保活机制)
|
||||
if (process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
|
||||
|| process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 兜底:进程存活则视为服务运行(适配部分机型)
|
||||
return true;
|
||||
// 兜底:检查服务是否已启动(避免进程后台时误判)
|
||||
return isServiceStarted(context, serviceClass);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "isServiceRunning: API30+ 判断服务状态异常", e);
|
||||
return false;
|
||||
@@ -621,7 +696,21 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导用户开启忽略电池优化(避免服务被后台杀死,适配API23+)
|
||||
* 新增:辅助判断服务是否已启动(API30+ 兜底,避免进程后台误判)
|
||||
*/
|
||||
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
|
||||
try {
|
||||
// 通过ServiceControlBean状态兜底(服务启动时会初始化配置)
|
||||
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
|
||||
return controlBean != null && controlBean.isEnableService();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "isServiceStarted: 兜底判断服务状态异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导用户开启忽略电池优化(避免服务被后台杀死,适配API23+,优化机型兼容)
|
||||
*/
|
||||
public static void checkIgnoreBatteryOptimization(Context context) {
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 检查电池优化状态");
|
||||
@@ -643,11 +732,14 @@ public class ControlCenterService extends Service {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
intent.setData(Uri.parse("package:" + context.getPackageName()));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
// 适配部分机型限制,添加异常捕获
|
||||
context.startActivity(intent);
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已引导用户开启忽略电池优化");
|
||||
} else {
|
||||
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已开启忽略电池优化,无需操作");
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 机型限制,无法引导电池优化(系统权限管控)", e);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization: 引导优化异常(部分机型限制)", e);
|
||||
}
|
||||
@@ -684,7 +776,7 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== Getter/Setter 方法(按需提供,线程安全)=================================
|
||||
// ================================== Getter/Setter 方法(新增前台状态相关,线程安全)=================================
|
||||
public RemindThread getRemindThread() {
|
||||
synchronized (mServiceLock) {
|
||||
return mRemindThread;
|
||||
@@ -744,5 +836,21 @@ public class ControlCenterService extends Service {
|
||||
return mIsDestroyed;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:获取应用前台状态(外部查询,线程安全)
|
||||
public boolean isAppForeground() {
|
||||
synchronized (mServiceLock) {
|
||||
return mIsAppForeground;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:设置应用前台状态(内部/外部调用,同步到线程)
|
||||
public void setAppForeground(boolean isForeground) {
|
||||
LogUtils.d(TAG, "setAppForeground: 更新应用前台状态=" + isForeground);
|
||||
synchronized (mServiceLock) {
|
||||
mIsAppForeground = isForeground;
|
||||
syncAppForegroundStateToThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ public class RemindThread extends Thread {
|
||||
private static final int DEFAULT_SLEEP_TIME = 1000; // 默认检测间隔(ms)
|
||||
private static final long REMIND_INTERVAL = 3000L; // 重复提醒间隔(ms,防骚扰)
|
||||
private static final int CONFIG_RETRY_MAX = 3; // 配置同步重试次数(兜底)
|
||||
private static final int INVALID_BATTERY_VALUE = -1; // 无效电量标记(新增)
|
||||
private static final long BACKGROUND_SLEEP_TIME = 5000L;// 后台休眠间隔(ms,减少资源占用,新增)
|
||||
|
||||
// ================================== 单例核心(线程安全,避免复用旧实例)=================================
|
||||
private static volatile RemindThread sInstance;
|
||||
@@ -34,14 +36,15 @@ public class RemindThread extends Thread {
|
||||
private volatile boolean isThreadStarted; // 启动标记(区分isAlive())
|
||||
private volatile boolean isReminding; // 全局提醒开关
|
||||
private volatile boolean isRemindTimerRunning; // 提醒恢复计时器状态
|
||||
private volatile boolean isAppForeground; // 应用前台状态(新增:控制提醒开关)
|
||||
|
||||
// 业务配置(实时同步,范围校验)
|
||||
private volatile boolean isEnableChargeReminder; // 充电提醒开关
|
||||
private volatile boolean isEnableUsageReminder; // 耗电提醒开关
|
||||
private volatile int sleepTime; // 检测间隔(ms)
|
||||
private volatile long sleepTime; // 检测间隔(ms,改为long适配大间隔)
|
||||
private volatile int chargeReminderValue; // 充电提醒阈值(0-100)
|
||||
private volatile int usageReminderValue; // 耗电提醒阈值(0-100)
|
||||
private volatile int quantityOfElectricity; // 当前电量(0-100)
|
||||
private volatile int quantityOfElectricity; // 当前电量(0-100,无效为-1)
|
||||
private volatile boolean isCharging; // 充电状态标记
|
||||
|
||||
// 辅助变量(并发安全+防重复提醒)
|
||||
@@ -102,7 +105,7 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 线程核心逻辑(run方法,高效退出+异常容错)=================================
|
||||
// ================================== 线程核心逻辑(run方法,高效退出+异常容错+前台判断)=================================
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "线程启动,ID:" + Thread.currentThread().getId() + ",状态:" + getState());
|
||||
@@ -114,6 +117,7 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
isThreadStarted = true;
|
||||
lastRemindTime = 0;
|
||||
isAppForeground = true; // 初始默认前台(窗口打开状态)
|
||||
}
|
||||
|
||||
// 配置同步重试(失败则兜底默认值)
|
||||
@@ -138,26 +142,39 @@ public class RemindThread extends Thread {
|
||||
return;
|
||||
}
|
||||
|
||||
// 核心检测循环(快速退出+并发安全)
|
||||
// 核心检测循环(快速退出+并发安全+前台判断)
|
||||
LogUtils.d(TAG, "进入电量检测循环,间隔:" + sleepTime + "ms");
|
||||
while (!isExist) {
|
||||
try {
|
||||
if (isExist) break;
|
||||
|
||||
// 提醒关闭/电量无效,直接休眠
|
||||
if (!isReminding) {
|
||||
safeSleep(sleepTime);
|
||||
continue;
|
||||
}
|
||||
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
||||
LogUtils.w(TAG, "电量无效(" + quantityOfElectricity + "),休眠重试");
|
||||
safeSleep(sleepTime);
|
||||
continue;
|
||||
// 核心防护:应用后台/提醒关闭/电量无效,直接休眠(跳过提醒检测)
|
||||
synchronized (mLock) {
|
||||
// 应用后台:延长休眠间隔,减少资源占用+停止提醒
|
||||
if (!isAppForeground) {
|
||||
safeSleep(BACKGROUND_SLEEP_TIME);
|
||||
continue;
|
||||
}
|
||||
// 提醒关闭/电量无效:正常休眠,不检测
|
||||
if (!isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
|
||||
safeSleep(sleepTime);
|
||||
continue;
|
||||
}
|
||||
// 电量超出范围:修正为无效,休眠重试
|
||||
if (quantityOfElectricity < 0 || quantityOfElectricity > 100) {
|
||||
LogUtils.w(TAG, "电量无效(" + quantityOfElectricity + "),标记为无效值");
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
safeSleep(sleepTime);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 锁保护核心提醒逻辑
|
||||
// 锁保护核心提醒逻辑(仅前台+提醒开启+电量有效时执行)
|
||||
synchronized (mLock) {
|
||||
if (isExist) break;
|
||||
if (isExist || !isAppForeground || !isReminding || quantityOfElectricity == INVALID_BATTERY_VALUE) {
|
||||
safeSleep(sleepTime);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 防重复提醒(间隔未到/计时器运行中)
|
||||
long currentTime = System.currentTimeMillis();
|
||||
@@ -166,14 +183,14 @@ public class RemindThread extends Thread {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 充电提醒触发(新增:携带当前电量+充电状态发送)
|
||||
// 充电提醒触发(携带当前电量+充电状态发送)
|
||||
if (isCharging && isEnableChargeReminder && quantityOfElectricity >= chargeReminderValue) {
|
||||
LogUtils.d(TAG, "触发充电提醒:充电中,电量" + quantityOfElectricity + "≥阈值" + chargeReminderValue);
|
||||
sendNotificationMessage("+", quantityOfElectricity, isCharging);
|
||||
lastRemindTime = currentTime;
|
||||
startRemindRecoveryTimer();
|
||||
}
|
||||
// 耗电提醒触发(新增:携带当前电量+充电状态发送)
|
||||
// 耗电提醒触发(携带当前电量+充电状态发送)
|
||||
else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
|
||||
LogUtils.d(TAG, "触发耗电提醒:未充电,电量" + quantityOfElectricity + "≤阈值" + usageReminderValue);
|
||||
sendNotificationMessage("-", quantityOfElectricity, isCharging);
|
||||
@@ -218,25 +235,27 @@ public class RemindThread extends Thread {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 兜底默认阈值
|
||||
// 兜底默认阈值(避免无效值触发提醒)
|
||||
synchronized (mLock) {
|
||||
chargeReminderValue = (chargeReminderValue < 0 || chargeReminderValue > 100) ? 80 : chargeReminderValue;
|
||||
usageReminderValue = (usageReminderValue < 0 || usageReminderValue > 100) ? 20 : usageReminderValue;
|
||||
LogUtils.e(TAG, "配置重试失败,兜底阈值:充电" + chargeReminderValue + ",耗电" + usageReminderValue);
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 兜底电量设为无效,防止误触发
|
||||
LogUtils.e(TAG, "配置重试失败,兜底阈值:充电" + chargeReminderValue + ",耗电" + usageReminderValue + "RuntimeException : Config sync failed.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送提醒消息(新增:携带当前电量+充电状态,弱引用Handler+Message复用,防泄漏)
|
||||
* 发送提醒消息(携带当前电量+充电状态,弱引用Handler+Message复用,防泄漏)
|
||||
* @param type 提醒类型(+:充电提醒,-:耗电提醒)
|
||||
* @param battery 当前电量(0-100)
|
||||
* @param isCharging 当前充电状态(true=充电中)
|
||||
*/
|
||||
private void sendNotificationMessage(String type, int battery, boolean isCharging) {
|
||||
LogUtils.d(TAG, "准备发送提醒消息:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
|
||||
if (isExist || !isReminding) {
|
||||
LogUtils.d(TAG, "线程退出/提醒关闭,跳过发送");
|
||||
// 双重防护:线程退出/应用后台/提醒关闭,跳过发送
|
||||
if (isExist || !isAppForeground || !isReminding) {
|
||||
LogUtils.d(TAG, "线程退出/应用后台/提醒关闭,跳过发送");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -250,7 +269,7 @@ public class RemindThread extends Thread {
|
||||
Message message = Message.obtain(handler, ControlCenterServiceHandler.MSG_REMIND_TEXT);
|
||||
message.obj = type;
|
||||
message.arg1 = battery;
|
||||
message.arg2 = isCharging ? 1 : 0; // boolean转int(Message无boolean参数,兼容Java7)
|
||||
message.arg2 = isCharging ? 1 : 0; // boolean转int(兼容Java7)
|
||||
try {
|
||||
handler.sendMessage(message);
|
||||
LogUtils.d(TAG, "提醒消息发送成功:类型=" + type + ",电量=" + battery + ",充电状态=" + isCharging);
|
||||
@@ -266,7 +285,7 @@ public class RemindThread extends Thread {
|
||||
private void startRemindRecoveryTimer() {
|
||||
LogUtils.d(TAG, "启动提醒恢复计时器,间隔:" + REMIND_INTERVAL + "ms");
|
||||
synchronized (mLock) {
|
||||
if (isExist || isRemindTimerRunning || sInstance != this) {
|
||||
if (isExist || isRemindTimerRunning || sInstance != this || !isAppForeground) {
|
||||
LogUtils.w(TAG, "计时器启动条件不满足,跳过");
|
||||
return;
|
||||
}
|
||||
@@ -287,8 +306,9 @@ public class RemindThread extends Thread {
|
||||
}
|
||||
|
||||
synchronized (thread.mLock) {
|
||||
if (!thread.isExist && sInstance == thread
|
||||
&& (thread.isEnableChargeReminder || thread.isEnableUsageReminder)) {
|
||||
// 仅前台+有启用提醒时,才恢复提醒
|
||||
if (!thread.isExist && sInstance == thread && thread.isAppForeground
|
||||
&& (thread.isEnableChargeReminder || thread.isEnableUsageReminder)) {
|
||||
thread.isReminding = true;
|
||||
LogUtils.d(TAG, "提醒功能恢复开启");
|
||||
}
|
||||
@@ -319,6 +339,7 @@ public class RemindThread extends Thread {
|
||||
isExist = true;
|
||||
isReminding = false;
|
||||
isRemindTimerRunning = false;
|
||||
isAppForeground = false; // 标记后台,强制停止提醒
|
||||
}
|
||||
if (isAlive()) {
|
||||
interrupt();
|
||||
@@ -358,7 +379,9 @@ public class RemindThread extends Thread {
|
||||
isExist = true;
|
||||
isThreadStarted = false;
|
||||
isRemindTimerRunning = false;
|
||||
isAppForeground = false;
|
||||
lastRemindTime = 0;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 重置为无效电量,防残留
|
||||
}
|
||||
if (isAlive()) interrupt();
|
||||
if (sInstance == this) sInstance = null;
|
||||
@@ -376,6 +399,7 @@ public class RemindThread extends Thread {
|
||||
isReminding = false;
|
||||
isThreadStarted = false;
|
||||
isRemindTimerRunning = false;
|
||||
isAppForeground = false;
|
||||
lastRemindTime = 0;
|
||||
// 业务配置
|
||||
isEnableChargeReminder = false;
|
||||
@@ -383,7 +407,7 @@ public class RemindThread extends Thread {
|
||||
sleepTime = DEFAULT_SLEEP_TIME;
|
||||
chargeReminderValue = -1;
|
||||
usageReminderValue = -1;
|
||||
quantityOfElectricity = -1;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 初始设为无效
|
||||
isCharging = false;
|
||||
}
|
||||
}
|
||||
@@ -397,39 +421,44 @@ public class RemindThread extends Thread {
|
||||
isExist = false;
|
||||
isRemindTimerRunning = false;
|
||||
lastRemindTime = 0;
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder) && isAppForeground; // 仅前台时开启提醒
|
||||
}
|
||||
LogUtils.d(TAG, "运行状态重置完成,全局提醒:" + isReminding);
|
||||
}
|
||||
|
||||
// ================================== 配置同步方法(完整同步配置,原子操作)=================================
|
||||
// ================================== 配置同步方法(完整同步配置,原子操作+无效电量防护)=================================
|
||||
/**
|
||||
* 同步应用配置(参数校验+范围限制,立即生效)
|
||||
*/
|
||||
public void setAppConfigBean(AppConfigBean config) {
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, "配置Bean为空,同步失败");
|
||||
synchronized (mLock) {
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE; // 配置为空,标记电量无效
|
||||
}
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "开始同步配置:充电阈值" + config.getChargeReminderValue() + ",耗电阈值" + config.getUsageReminderValue());
|
||||
LogUtils.d(TAG, "开始同步配置:充电阈值" + config.getChargeReminderValue() + ",耗电阈值" + config.getUsageReminderValue() + ",当前电量" + config.getCurrentBatteryValue());
|
||||
synchronized (mLock) {
|
||||
// 同步开关
|
||||
isEnableChargeReminder = config.isEnableChargeReminder();
|
||||
isEnableUsageReminder = config.isEnableUsageReminder();
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
||||
// 同步阈值(0-100限制)
|
||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), 0), 100);
|
||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), 0), 100);
|
||||
// 同步检测间隔(≥最小间隔)
|
||||
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
||||
// 同步电池状态
|
||||
quantityOfElectricity = Math.min(Math.max(config.getCurrentBatteryValue(), 0), 100);
|
||||
// 同步电池状态(校验有效,无效则标记为-1)
|
||||
int currentBattery = config.getCurrentBatteryValue();
|
||||
quantityOfElectricity = (currentBattery >= 0 && currentBattery <= 100) ? currentBattery : INVALID_BATTERY_VALUE;
|
||||
isCharging = config.isCharging();
|
||||
// 提醒开关:前台+有启用提醒才开启
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder) && isAppForeground;
|
||||
}
|
||||
LogUtils.d(TAG, "配置同步完成:检测间隔" + sleepTime + "ms,全局提醒" + isReminding);
|
||||
LogUtils.d(TAG, "配置同步完成:检测间隔" + sleepTime + "ms,全局提醒" + isReminding + ",当前电量" + quantityOfElectricity);
|
||||
}
|
||||
|
||||
// ================================== Setter/Getter(锁保护,线程安全+精准日志)=================================
|
||||
// ================================== Setter/Getter(锁保护,线程安全+精准日志,新增前台状态控制)=================================
|
||||
public boolean isExist() {
|
||||
synchronized (mLock) {
|
||||
return isExist;
|
||||
@@ -451,8 +480,32 @@ public class RemindThread extends Thread {
|
||||
|
||||
public void setIsReminding(boolean isReminding) {
|
||||
synchronized (mLock) {
|
||||
this.isReminding = isReminding;
|
||||
LogUtils.d(TAG, "设置全局提醒开关:" + isReminding);
|
||||
// 仅前台时可开启提醒
|
||||
this.isReminding = isReminding && isAppForeground;
|
||||
LogUtils.d(TAG, "设置全局提醒开关:" + this.isReminding + "(应用前台状态:" + isAppForeground + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:应用前台/后台状态设置(主窗口关闭/打开时调用)
|
||||
public void setAppForeground(boolean isForeground) {
|
||||
synchronized (mLock) {
|
||||
this.isAppForeground = isForeground;
|
||||
// 后台时强制关闭提醒,前台时根据开关自动开启
|
||||
if (!isForeground) {
|
||||
this.isReminding = false;
|
||||
this.quantityOfElectricity = INVALID_BATTERY_VALUE; // 后台重置为无效电量
|
||||
LogUtils.d(TAG, "应用切换到后台,停止提醒+重置无效电量");
|
||||
} else {
|
||||
this.isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
||||
LogUtils.d(TAG, "应用切换到前台,提醒状态:" + this.isReminding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:获取应用前台状态
|
||||
public boolean isAppForeground() {
|
||||
synchronized (mLock) {
|
||||
return isAppForeground;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,7 +524,7 @@ public class RemindThread extends Thread {
|
||||
public void setIsEnableUsageReminder(boolean isEnableUsageReminder) {
|
||||
synchronized (mLock) {
|
||||
this.isEnableUsageReminder = isEnableUsageReminder;
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder) && isAppForeground;
|
||||
LogUtils.d(TAG, "设置耗电提醒开关:" + isEnableUsageReminder + ",全局提醒:" + isReminding);
|
||||
}
|
||||
}
|
||||
@@ -485,18 +538,18 @@ public class RemindThread extends Thread {
|
||||
public void setIsEnableChargeReminder(boolean isEnableChargeReminder) {
|
||||
synchronized (mLock) {
|
||||
this.isEnableChargeReminder = isEnableChargeReminder;
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder);
|
||||
isReminding = (isEnableChargeReminder || isEnableUsageReminder) && isAppForeground;
|
||||
LogUtils.d(TAG, "设置充电提醒开关:" + isEnableChargeReminder + ",全局提醒:" + isReminding);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSleepTime() {
|
||||
public long getSleepTime() {
|
||||
synchronized (mLock) {
|
||||
return sleepTime;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSleepTime(int sleepTime) {
|
||||
public void setSleepTime(long sleepTime) {
|
||||
synchronized (mLock) {
|
||||
this.sleepTime = Math.max(sleepTime, MIN_SLEEP_TIME);
|
||||
LogUtils.d(TAG, "设置检测间隔:" + this.sleepTime + "ms");
|
||||
@@ -537,8 +590,14 @@ public class RemindThread extends Thread {
|
||||
|
||||
public void setQuantityOfElectricity(int quantityOfElectricity) {
|
||||
synchronized (mLock) {
|
||||
this.quantityOfElectricity = Math.min(Math.max(quantityOfElectricity, 0), 100);
|
||||
LogUtils.d(TAG, "更新当前电量:" + this.quantityOfElectricity);
|
||||
// 仅前台时更新电量,后台直接设为无效
|
||||
if (isAppForeground) {
|
||||
this.quantityOfElectricity = Math.min(Math.max(quantityOfElectricity, 0), 100);
|
||||
LogUtils.d(TAG, "更新当前电量:" + this.quantityOfElectricity);
|
||||
} else {
|
||||
this.quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
LogUtils.w(TAG, "应用后台,不更新电量,标记为无效");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +618,7 @@ public class RemindThread extends Thread {
|
||||
public boolean isRunning() {
|
||||
synchronized (mLock) {
|
||||
boolean running = !isExist && isThreadStarted && isAlive();
|
||||
LogUtils.d(TAG, "线程运行状态:" + running + "(退出:" + isExist + ",已启动:" + isThreadStarted + ",存活:" + isAlive() + ")");
|
||||
LogUtils.d(TAG, "线程运行状态:" + running + "(退出:" + isExist + ",已启动:" + isThreadStarted + ",存活:" + isAlive() + ",前台:" + isAppForeground + ")");
|
||||
return running;
|
||||
}
|
||||
}
|
||||
@@ -585,6 +644,7 @@ public class RemindThread extends Thread {
|
||||
"threadId=" + getId() +
|
||||
", threadName='" + getName() + '\'' +
|
||||
", isRunning=" + isRunning() +
|
||||
", isForeground=" + isAppForeground() +
|
||||
", isReminding=" + isReminding() +
|
||||
", chargeThreshold=" + getChargeReminderValue() +
|
||||
", usageThreshold=" + getUsageReminderValue() +
|
||||
|
||||
@@ -15,6 +15,8 @@ import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
|
||||
/**
|
||||
@@ -186,6 +188,7 @@ public class MainContentView {
|
||||
// 构建无模式对话框(点击外部可关闭,取消改动)
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
|
||||
builder.setTitle("配置变更确认");
|
||||
// 优化:区分服务开关/普通配置,显示不同提示语(提升用户体验)
|
||||
builder.setMessage("是否确认修改当前配置?");
|
||||
// 确定按钮:保存配置+回调+更新视图
|
||||
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
@@ -332,17 +335,19 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成");
|
||||
}
|
||||
|
||||
// 服务总开关监听
|
||||
// 服务总开关监听(核心优化:从 AppConfig 改为读取服务控制Bean,确保状态一致)
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean originalValue = mAppConfigUtils.isServiceEnabled();
|
||||
// 关键调整:服务开关状态从服务控制Bean读取,而非AppConfig
|
||||
boolean originalValue = getServiceEnableState();
|
||||
boolean newValue = ((Switch) v).isChecked();
|
||||
// 状态无变化,不处理
|
||||
if (originalValue == newValue) return;
|
||||
// 缓存变更数据,显示确认对话框
|
||||
// 缓存变更数据,显示确认对话框(优化:服务开关弹窗提示语差异化)
|
||||
mTempConfigData = new TempConfigData(CHANGE_TYPE_SERVICE_SWITCH, originalValue, newValue);
|
||||
updateDialogMessageByChangeType();
|
||||
showConfigConfirmDialog();
|
||||
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue);
|
||||
}
|
||||
@@ -371,8 +376,9 @@ public class MainContentView {
|
||||
int currentVal = mAppConfigUtils.getCurrentBatteryValue();
|
||||
boolean chargeEnable = mAppConfigUtils.isChargeReminderEnabled();
|
||||
boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled();
|
||||
boolean serviceEnable = mAppConfigUtils.isServiceEnabled();
|
||||
LogUtils.d(TAG, "updateViewData: 配置数据读取完成,charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal);
|
||||
// 关键调整:服务开关状态从服务控制Bean读取,确保与服务实际状态一致
|
||||
boolean serviceEnable = getServiceEnableState();
|
||||
LogUtils.d(TAG, "updateViewData: 配置数据读取完成,charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal + ", serviceEnable=" + serviceEnable);
|
||||
|
||||
// 进度条背景更新
|
||||
if (frameDrawable != null) {
|
||||
@@ -418,7 +424,7 @@ public class MainContentView {
|
||||
if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable);
|
||||
LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成");
|
||||
|
||||
// 服务开关+提示文本更新
|
||||
// 服务开关+提示文本更新(核心调整:使用服务控制Bean状态)
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(serviceEnable);
|
||||
swEnableService.setText(mContext.getString(R.string.txt_aboveswitch));
|
||||
@@ -499,6 +505,28 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "releaseResources: 所有资源释放完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:设置服务开关启用状态(外部调用,同步 UI 与服务状态,适配 Activity 视图刷新)
|
||||
* @param enabled 服务启用状态
|
||||
*/
|
||||
public void setServiceSwitchChecked(boolean enabled) {
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(enabled);
|
||||
LogUtils.d(TAG, "setServiceSwitchChecked: 服务开关UI更新为=" + enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:设置服务开关点击状态(外部调用,避免更新 UI 时触发重复回调)
|
||||
* @param enabled 是否允许点击
|
||||
*/
|
||||
public void setServiceSwitchEnabled(boolean enabled) {
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setEnabled(enabled);
|
||||
LogUtils.d(TAG, "setServiceSwitchEnabled: 服务开关点击状态更新为=" + enabled);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 内部核心逻辑方法(对话框相关,封装确认/取消逻辑)========================
|
||||
/**
|
||||
* 显示配置变更确认对话框(确保 Activity 处于前台,避免异常,防止重复弹窗)
|
||||
@@ -560,11 +588,16 @@ public class MainContentView {
|
||||
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
break;
|
||||
// 服务总开关(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
// 服务总开关(核心优化:同步更新服务控制Bean,而非AppConfig)
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
mAppConfigUtils.setServiceEnabled(mTempConfigData.newBooleanValue);
|
||||
// 1. 保存服务控制配置到本地(持久化自启动状态)
|
||||
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
|
||||
if (serviceBean == null) serviceBean = new ControlCenterServiceBean(false);
|
||||
serviceBean.setIsEnableService(mTempConfigData.newBooleanValue);
|
||||
ControlCenterService.updateServiceControlConfig(mContext, serviceBean);
|
||||
// 2. 回调 Activity,触发服务启停
|
||||
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue);
|
||||
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认,值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
|
||||
break;
|
||||
// 充电提醒进度条(适配 AppConfigUtils 无 Activity 参数调用)
|
||||
case CHANGE_TYPE_CHARGE_SEEKBAR:
|
||||
@@ -611,7 +644,7 @@ public class MainContentView {
|
||||
}
|
||||
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消,恢复值=" + mTempConfigData.originalBooleanValue);
|
||||
break;
|
||||
// 服务总开关:恢复原始状态
|
||||
// 服务总开关:恢复原始状态(核心优化:从服务控制Bean读取原始值)
|
||||
case CHANGE_TYPE_SERVICE_SWITCH:
|
||||
if (swEnableService != null) {
|
||||
swEnableService.setChecked(mTempConfigData.originalBooleanValue);
|
||||
@@ -671,6 +704,30 @@ public class MainContentView {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:获取服务启用状态(统一从服务控制Bean读取,确保全链路状态一致)
|
||||
* @return 服务启用状态(true=启用,false=禁用)
|
||||
*/
|
||||
private boolean getServiceEnableState() {
|
||||
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
|
||||
// 本地无配置时,默认禁用服务(与服务初始化逻辑对齐)
|
||||
return serviceBean != null && serviceBean.isEnableService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增:根据变更类型更新对话框提示语(差异化提示,提升用户体验)
|
||||
*/
|
||||
private void updateDialogMessageByChangeType() {
|
||||
if (mConfigConfirmDialog == null || mTempConfigData == null) return;
|
||||
String message;
|
||||
if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) {
|
||||
message = mTempConfigData.newBooleanValue ? "启用服务后,将后台持续监控电池状态,是否确认?" : "禁用服务后,电池监控功能将停止,是否确认?";
|
||||
} else {
|
||||
message = "是否确认修改当前配置?";
|
||||
}
|
||||
mConfigConfirmDialog.setMessage(message);
|
||||
}
|
||||
|
||||
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
|
||||
public interface OnViewActionListener {
|
||||
void onChargeReminderSwitchChanged(boolean isChecked);
|
||||
|
||||
Reference in New Issue
Block a user