源码整理

This commit is contained in:
2025-12-20 13:23:07 +08:00
parent 9c1e9dc75b
commit 23beabe99b
5 changed files with 184 additions and 104 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Fri Dec 19 19:04:54 GMT 2025 #Sat Dec 20 05:22:35 GMT 2025
stageCount=10 stageCount=10
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.9 publishVersion=15.14.9
buildCount=49 buildCount=51
baseBetaVersion=15.14.10 baseBetaVersion=15.14.10

View File

@@ -20,13 +20,11 @@ import cc.winboll.studio.libaes.utils.DevelopUtils;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager; import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libaes.views.ADsBannerView; import cc.winboll.studio.libaes.views.ADsBannerView;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity; import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.activities.BatteryReportActivity; import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
import cc.winboll.studio.powerbell.activities.ClearRecordActivity; import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
import cc.winboll.studio.powerbell.activities.SettingsActivity; import cc.winboll.studio.powerbell.activities.SettingsActivity;
import cc.winboll.studio.powerbell.activities.WinBoLLActivity; 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.BackgroundBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean; import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService; import cc.winboll.studio.powerbell.services.ControlCenterService;
@@ -38,9 +36,7 @@ import cc.winboll.studio.powerbell.utils.ServiceUtils;
import cc.winboll.studio.powerbell.views.MainContentView; import cc.winboll.studio.powerbell.views.MainContentView;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * 应用核心主活动
* @Date 2025/12/19 20:26
* @Describe 应用核心主活动
* 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能 * 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能
* 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步 * 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
*/ */
@@ -50,7 +46,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// 请求码常量 // 请求码常量
private static final int REQUEST_READ_MEDIA_IMAGES = 1001; private static final int REQUEST_READ_MEDIA_IMAGES = 1001;
// 延迟加载常量 // 延迟加载常量(非核心视图延迟加载时长)
private static final long DELAY_LOAD_NON_CRITICAL = 500L; private static final long DELAY_LOAD_NON_CRITICAL = 500L;
// Handler消息标识按业务优先级排序 // Handler消息标识按业务优先级排序
public static final int MSG_RELOAD_APPCONFIG = 0; public static final int MSG_RELOAD_APPCONFIG = 0;
@@ -92,7 +88,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 页面启动,开始初始化流程"); LogUtils.d(TAG, "onCreate: 页面启动,开始初始化流程 | savedInstanceState=" + savedInstanceState);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// 优先初始化全局Handler避免消息丢失 // 优先初始化全局Handler避免消息丢失
@@ -126,6 +122,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// 恢复广告 // 恢复广告
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.resumeADs(this); mADsBannerView.resumeADs(this);
LogUtils.d(TAG, "onResume: 广告视图恢复展示");
} }
} }
@@ -143,11 +140,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.releaseAdResources(); mADsBannerView.releaseAdResources();
mADsBannerView = null; mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 广告资源已释放");
} }
// 释放核心视图 // 释放核心视图
if (mMainContentView != null) { if (mMainContentView != null) {
mMainContentView.releaseResources(); mMainContentView.releaseResources();
mMainContentView = null; mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
} }
// 销毁Handler防止内存泄漏 // 销毁Handler防止内存泄漏
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
@@ -159,6 +158,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mFrameDrawable != null) { if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null); mFrameDrawable.setCallback(null);
mFrameDrawable = null; mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 框架背景Drawable已释放");
} }
// 置空所有引用帮助GC回收 // 置空所有引用帮助GC回收
sMainActivity = null; sMainActivity = null;
@@ -176,7 +176,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + ", resultCode=" + resultCode); LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data); mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 背景设置完成后重新加载 // 背景设置完成后重新加载
if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) { if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) {
@@ -194,6 +194,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (App.isDebugging()) { if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu); DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu); getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载单元测试菜单");
} }
getMenuInflater().inflate(R.menu.toolbar_main, mMenu); getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
return true; return true;
@@ -201,7 +202,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected: itemId=" + item.getItemId()); LogUtils.d(TAG, "onOptionsItemSelected: 菜单点击 | itemId=" + item.getItemId());
if (AESThemeUtil.onAppThemeItemSelected(this, item)) { if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate(); recreate();
return true; return true;
@@ -212,21 +213,27 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_settings: case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class)); startActivity(new Intent(this, SettingsActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转设置页面");
break; break;
case R.id.action_battery_report: case R.id.action_battery_report:
startActivity(new Intent(this, BatteryReportActivity.class)); startActivity(new Intent(this, BatteryReportActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转电池报告页面");
break; break;
case R.id.action_clearrecord: case R.id.action_clearrecord:
startActivity(new Intent(this, ClearRecordActivity.class)); startActivity(new Intent(this, ClearRecordActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转记录清理页面");
break; break;
case R.id.action_changepicture: case R.id.action_changepicture:
startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES); startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES);
LogUtils.d(TAG, "onOptionsItemSelected: 跳转背景设置页面 | requestCode=" + REQUEST_READ_MEDIA_IMAGES);
break; break;
case R.id.action_unittestactivity: case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class)); startActivity(new Intent(this, MainUnitTestActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转单元测试页面");
break; break;
case R.id.action_about: case R.id.action_about:
startAboutActivity(); startAboutActivity();
LogUtils.d(TAG, "onOptionsItemSelected: 跳转关于页面");
break; break;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@@ -239,6 +246,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
super.setupToolbar(); super.setupToolbar();
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 隐藏返回按钮");
} }
} }
@@ -267,10 +275,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
// 校验Activity状态避免销毁后操作UI // 校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) { if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 what=" + msg.what); LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what=" + msg.what);
return; return;
} }
LogUtils.d(TAG, "handleMessage: 处理消息 what=" + msg.what); LogUtils.d(TAG, "handleMessage: 处理消息 | what=" + msg.what);
switch (msg.what) { switch (msg.what) {
case MSG_RELOAD_APPCONFIG: case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData(); sMainActivity.updateViewData();
@@ -278,6 +286,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
case MSG_CURRENTVALUEBATTERY: case MSG_CURRENTVALUEBATTERY:
if (sMainActivity.mMainContentView != null) { if (sMainActivity.mMainContentView != null) {
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1); sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
LogUtils.d(TAG, "handleMessage: 更新当前电量 | value=" + msg.arg1);
} }
break; break;
case MSG_LOAD_BACKGROUND: case MSG_LOAD_BACKGROUND:
@@ -307,6 +316,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
if (mToolbar != null) { if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
} }
mAdsViewStub = findViewById(R.id.stub_ads_banner); mAdsViewStub = findViewById(R.id.stub_ads_banner);
} }
@@ -316,7 +326,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动"); LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动 | threadId=" + Thread.currentThread().getId());
mApplication = (App) getApplication(); mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext()); mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity()); mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
@@ -332,6 +342,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// 根据配置启停服务 // 根据配置启停服务
final boolean isServiceEnable = mServiceControlBean.isEnableService(); final boolean isServiceEnable = mServiceControlBean.isEnableService();
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName()); final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置状态 | isServiceEnable=" + isServiceEnable + " | isServiceAlive=" + isServiceAlive);
if (isServiceEnable && !isServiceAlive) { if (isServiceEnable && !isServiceAlive) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@Override @Override
@@ -358,7 +369,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新"); LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
return; return;
} }
// 加载框架背景 // 加载框架背景适配API23+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme()); mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
} else { } else {
@@ -375,11 +386,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
private void loadNonCriticalViewDelayed() { private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 延迟加载非核心视图"); LogUtils.d(TAG, "loadNonCriticalViewDelayed: 延迟加载非核心视图 | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms");
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
if (isFinishing() || isDestroyed()) { if (isFinishing() || isDestroyed()) {
LogUtils.w(TAG, "loadNonCriticalViewDelayed: Activity已销毁跳过广告加载");
return; return;
} }
loadAdsView(); loadAdsView();
@@ -391,7 +403,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
private void loadAdsView() { private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 加载广告视图"); LogUtils.d(TAG, "loadAdsView: 加载广告视图");
if (mAdsViewStub == null) { if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空"); LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空,加载失败");
return; return;
} }
if (mADsBannerView == null) { if (mADsBannerView == null) {
@@ -408,6 +420,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
return; return;
} }
mMainContentView.updateViewData(mFrameDrawable); mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
} }
private void reloadBackground() { private void reloadBackground() {
@@ -419,6 +432,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean); mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
LogUtils.d(TAG, "reloadBackground: 加载自定义背景成功");
} else { } else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background); mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
LogUtils.w(TAG, "reloadBackground: 无自定义背景,使用默认背景"); LogUtils.w(TAG, "reloadBackground: 无自定义背景,使用默认背景");
@@ -434,6 +448,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor()); mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局背景色设置完成 | color=" + currentBgBean.getPixelColor());
} }
} }
@@ -448,19 +463,21 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView.setServiceSwitchEnabled(false); mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled); mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true); mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI状态更新完成");
} }
// ======================== 服务与线程管理方法 ======================== // ======================== 服务与线程管理方法 ========================
private void toggleServiceEnableState(boolean isEnable) { private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: 切换服务状态目标状态=" + isEnable); LogUtils.d(TAG, "toggleServiceEnableState: 切换服务状态 | 目标状态=" + isEnable);
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败"); LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return; return;
} }
mServiceControlBean.setIsEnableService(isEnable); mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 服务配置已保存");
// UI开关联动服务启停 + 线程销毁 // UI开关联动服务启停
if (isEnable) { if (isEnable) {
// 开启:启动服务 // 开启:启动服务
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) { if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
@@ -488,8 +505,8 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 消息发送方法 ======================== // ======================== 消息发送方法 ========================
private void notifyServiceAppConfigChange() { private void notifyServiceAppConfigChange() {
LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更"); LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更");
ControlCenterService.updateStatus(this); ControlCenterService.updateStatus(this);
reloadAppConfig(); reloadAppConfig();
} }
// ======================== 静态工具方法 ======================== // ======================== 静态工具方法 ========================
@@ -497,18 +514,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "reloadAppConfig: 发送配置重载消息"); LogUtils.d(TAG, "reloadAppConfig: 发送配置重载消息");
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG); sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
} else {
LogUtils.w(TAG, "reloadAppConfig: 全局Handler为空消息发送失败");
} }
} }
public static void sendCurrentBatteryValueMessage(int value) { public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 发送当前电量消息电量=" + value); LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 发送当前电量消息 | 电量=" + value);
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY); Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value; msg.arg1 = value;
sGlobalHandler.sendMessage(msg); sGlobalHandler.sendMessage(msg);
} else {
LogUtils.w(TAG, "sendCurrentBatteryValueMessage: 全局Handler为空消息发送失败");
} }
} }
// ======================== 辅助工具方法 ========================
private APPInfo genDefaultAppInfo() { private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 生成默认应用信息"); LogUtils.d(TAG, "genDefaultAppInfo: 生成默认应用信息");
String branchName = "powerbell"; String branchName = "powerbell";
@@ -529,31 +551,31 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== MainContentView 事件回调 ======================== // ======================== MainContentView 事件回调 ========================
@Override @Override
public void onChargeReminderSwitchChanged(boolean isChecked) { public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 充电提醒开关状态=" + isChecked); LogUtils.d(TAG, "onChargeReminderSwitchChanged: 充电提醒开关状态变更 | isChecked=" + isChecked);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderSwitchChanged(boolean isChecked) { public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 耗电提醒开关状态=" + isChecked); LogUtils.d(TAG, "onUsageReminderSwitchChanged: 耗电提醒开关状态变更 | isChecked=" + isChecked);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onServiceSwitchChanged(boolean isChecked) { public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 服务总开关状态=" + isChecked); LogUtils.d(TAG, "onServiceSwitchChanged: 服务总开关状态变更 | isChecked=" + isChecked);
toggleServiceEnableState(isChecked); toggleServiceEnableState(isChecked);
} }
@Override @Override
public void onChargeReminderProgressChanged(int progress) { public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: 充电提醒阈值=" + progress); LogUtils.d(TAG, "onChargeReminderProgressChanged: 充电提醒阈值变更 | progress=" + progress);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderProgressChanged(int progress) { public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: 耗电提醒阈值=" + progress); LogUtils.d(TAG, "onUsageReminderProgressChanged: 耗电提醒阈值变更 | progress=" + progress);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
} }

View File

@@ -8,9 +8,7 @@ import cc.winboll.studio.powerbell.services.ControlCenterService;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * 服务通信Handler
* @Date 2025/12/19 20:17
* @Describe 服务通信Handler
* 功能:处理电量提醒消息,构建并发送标准化通知 * 功能:处理电量提醒消息,构建并发送标准化通知
* 特性:弱引用防泄漏、参数严格校验、通知格式统一 * 特性:弱引用防泄漏、参数严格校验、通知格式统一
* 适配Java7 | API30 | 小米手机 * 适配Java7 | API30 | 小米手机
@@ -33,7 +31,7 @@ public class ControlCenterServiceHandler extends Handler {
// ================================== 构造方法(强制传入服务,初始化弱引用)================================= // ================================== 构造方法(强制传入服务,初始化弱引用)=================================
public ControlCenterServiceHandler(ControlCenterService service) { public ControlCenterServiceHandler(ControlCenterService service) {
LogUtils.d(TAG, "构造Handler | service=" + (service != null ? service.getClass().getSimpleName() : "null")); LogUtils.d(TAG, "ControlCenterServiceHandler: 构造方法执行 | service=" + (service != null ? service.getClass().getSimpleName() : "null"));
this.mwrControlCenterService = new WeakReference<>(service); this.mwrControlCenterService = new WeakReference<>(service);
} }
@@ -46,12 +44,12 @@ public class ControlCenterServiceHandler extends Handler {
int currentBattery = msg.arg1; int currentBattery = msg.arg1;
boolean isCharging = msg.arg2 == 1; boolean isCharging = msg.arg2 == 1;
LogUtils.d(TAG, "接收消息 | what=" + msg.what + " | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging); LogUtils.d(TAG, "handleMessage: 接收消息 | what=" + msg.what + " | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging);
// 弱引用获取服务,避免内存泄漏 // 弱引用获取服务,避免内存泄漏
ControlCenterService service = mwrControlCenterService.get(); ControlCenterService service = mwrControlCenterService.get();
if (service == null) { if (service == null) {
LogUtils.e(TAG, "服务实例已回收,终止消息处理"); LogUtils.e(TAG, "handleMessage: 服务实例已被GC回收,终止消息处理");
return; return;
} }
@@ -61,7 +59,7 @@ public class ControlCenterServiceHandler extends Handler {
handleRemindMessage(service, remindType, currentBattery, isCharging); handleRemindMessage(service, remindType, currentBattery, isCharging);
break; break;
default: default:
LogUtils.w(TAG, "未知消息类型 | what=" + msg.what); LogUtils.w(TAG, "handleMessage: 未知消息类型,忽略处理 | what=" + msg.what);
break; break;
} }
} }
@@ -75,19 +73,19 @@ public class ControlCenterServiceHandler extends Handler {
* @param isCharging 充电状态 * @param isCharging 充电状态
*/ */
private void handleRemindMessage(ControlCenterService service, String remindType, int currentBattery, boolean isCharging) { private void handleRemindMessage(ControlCenterService service, String remindType, int currentBattery, boolean isCharging) {
LogUtils.d(TAG, "处理提醒消息 | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging); LogUtils.d(TAG, "handleRemindMessage: 开始处理提醒消息 | type=" + remindType + " | battery=" + currentBattery + " | isCharging=" + isCharging);
// 1. 前置校验:通知工具类+参数有效性 // 1. 前置校验:通知工具类+参数有效性
if (service.getNotificationManager() == null) { if (service.getNotificationManager() == null) {
LogUtils.e(TAG, "通知管理工具类为空,无法发送提醒"); LogUtils.e(TAG, "handleRemindMessage: 通知管理工具类未初始化,无法发送提醒");
return; return;
} }
if (!REMIND_TYPE_CHARGE.equals(remindType) && !REMIND_TYPE_USAGE.equals(remindType)) { if (!REMIND_TYPE_CHARGE.equals(remindType) && !REMIND_TYPE_USAGE.equals(remindType)) {
LogUtils.w(TAG, "无效提醒类型 | type=" + remindType); LogUtils.w(TAG, "handleRemindMessage: 提醒类型无效,忽略 | type=" + remindType + " | 允许值:" + REMIND_TYPE_CHARGE + "/" + REMIND_TYPE_USAGE);
return; return;
} }
if (currentBattery < BATTERY_LEVEL_MIN || currentBattery > BATTERY_LEVEL_MAX) { if (currentBattery < BATTERY_LEVEL_MIN || currentBattery > BATTERY_LEVEL_MAX) {
LogUtils.w(TAG, "无效电量值 | battery=" + currentBattery + "需在0-100范围内"); LogUtils.w(TAG, "handleRemindMessage: 电量值超出范围,忽略 | battery=" + currentBattery + " | 允许范围:" + BATTERY_LEVEL_MIN + "-" + BATTERY_LEVEL_MAX);
return; return;
} }
@@ -103,11 +101,12 @@ public class ControlCenterServiceHandler extends Handler {
remindMsg.setContent(String.format("(-) 当前电量%d%%%s已偏低建议及时充电避免设备关机", currentBattery, chargeStateDesc)); remindMsg.setContent(String.format("(-) 当前电量%d%%%s已偏低建议及时充电避免设备关机", currentBattery, chargeStateDesc));
remindMsg.setRemindMSG("usage_remind"); remindMsg.setRemindMSG("usage_remind");
} }
LogUtils.d(TAG, "构建通知完成 | title=" + remindMsg.getTitle() + " | content=" + remindMsg.getContent()); LogUtils.d(TAG, "handleRemindMessage: 通知模型构建完成 | title=" + remindMsg.getTitle() + " | content=" + remindMsg.getContent());
// 3. 调用工具类发送通知 // 3. 直接调用通知工具类发送,不校验返回结果
LogUtils.d(TAG, "handleRemindMessage: 调用通知工具类发送提醒 | remindMSG=" + remindMsg.getRemindMSG());
service.getNotificationManager().showRemindNotification(service, remindMsg); service.getNotificationManager().showRemindNotification(service, remindMsg);
LogUtils.d(TAG, "提醒通知发送成功"); LogUtils.d(TAG, "handleRemindMessage: 提醒通知发送流程执行完毕");
} }
} }

View File

@@ -5,101 +5,167 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils; import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.ServiceUtils; import cc.winboll.studio.powerbell.utils.ServiceUtils;
/**
* 电池提醒核心服务进程守护类
* 功能:监听主服务 {@link ControlCenterService} 存活状态,异常断开时自动重启并绑定
* 适配Java7 | API30 | 前台服务启动规则 | 服务绑定稳定性保障
*/
public class AssistantService extends Service { public class AssistantService extends Service {
private final static String TAG = "AssistantService"; // ================================== 静态常量区(置顶归类,消除魔法值)=================================
private static final String TAG = "AssistantService";
// 服务返回策略常量(统一定义,避免魔法值)
private static final int SERVICE_RETURN_STICKY = START_STICKY;
//MyBinder mMyBinder; // ================================== 成员变量区按功能分层volatile保证多线程可见性=================================
MyServiceConnection mMyServiceConnection; private MyServiceConnection mMyServiceConnection;
volatile boolean mIsThreadAlive; private volatile boolean mIsThreadAlive;
AppConfigUtils mAppConfigUtils; private AppConfigUtils mAppConfigUtils;
@Override
public IBinder onBind(Intent intent) {
//return mMyBinder;
return null;
}
// ================================== 服务生命周期方法按执行顺序排列onCreate→onStartCommand→onBind→onDestroy=================================
@Override @Override
public void onCreate() { public void onCreate() {
//LogUtils.d(TAG, "onCreate");
super.onCreate(); super.onCreate();
mAppConfigUtils = App.getAppConfigUtils(this); LogUtils.d(TAG, "onCreate: 守护服务启动 | 进程ID=" + android.os.Process.myPid());
//mMyBinder = new MyBinder(); // 初始化配置工具类,添加空指针防护
mAppConfigUtils = App.getAppConfigUtils(this);
if (mAppConfigUtils == null) {
LogUtils.e(TAG, "onCreate: AppConfigUtils初始化失败守护服务无法工作");
stopSelf();
return;
}
// 初始化服务连接对象
if (mMyServiceConnection == null) { if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection(); mMyServiceConnection = new MyServiceConnection();
LogUtils.d(TAG, "onCreate: ServiceConnection初始化完成");
} }
// 设置运行参数
// 初始化运行状态,执行核心守护逻辑
mIsThreadAlive = false; mIsThreadAlive = false;
run(); run();
LogUtils.d(TAG, "onCreate: 守护服务初始化完成 | 服务启用状态=" + mAppConfigUtils.isServiceEnabled());
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
//LogUtils.d(TAG, "call onStartCommand(...)"); LogUtils.d(TAG, "onStartCommand: 守护服务触发重启 | intent=" + intent + " | flags=" + flags + " | startId=" + startId);
// 配置工具类为空时,直接返回非粘性策略
if (mAppConfigUtils == null) {
LogUtils.e(TAG, "onStartCommand: AppConfigUtils未初始化终止服务");
stopSelf();
return START_NOT_STICKY;
}
run(); run();
return START_STICKY; int returnFlag = mAppConfigUtils.isServiceEnabled() ? SERVICE_RETURN_STICKY : super.onStartCommand(intent, flags, startId);
LogUtils.d(TAG, "onStartCommand: 处理完成 | 返回策略=" + (returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
return returnFlag;
} }
/*class MyBinder extends IMyAidlInterface.Stub { @Override
@Override public IBinder onBind(Intent intent) {
public String getServiceName() { LogUtils.d(TAG, "onBind: 服务绑定请求 | intent=" + intent);
return AssistantService.class.getSimpleName(); return null;
} }
}*/
@Override @Override
public void onDestroy() { public void onDestroy() {
//LogUtils.d(TAG, "onDestroy");
mIsThreadAlive = false;
super.onDestroy(); super.onDestroy();
LogUtils.d(TAG, "onDestroy: 守护服务销毁流程启动");
// 重置运行状态,终止守护逻辑
mIsThreadAlive = false;
// 解绑主服务,添加异常捕获防止重复解绑崩溃
if (mMyServiceConnection != null) {
try {
unbindService(mMyServiceConnection);
LogUtils.d(TAG, "onDestroy: 已成功解绑ControlCenterService");
} catch (IllegalArgumentException e) {
LogUtils.w(TAG, "onDestroy: 解绑服务失败,服务未绑定 | " + e.getMessage());
}
mMyServiceConnection = null;
}
// 置空工具类引用帮助GC回收
mAppConfigUtils = null;
LogUtils.d(TAG, "onDestroy: 守护服务销毁完成");
} }
// 运行服务内容 // ================================== 核心业务逻辑(守护主服务存活)=================================
// /**
void run() { * 执行守护逻辑:检查主服务状态,按需唤醒并绑定
//LogUtils.d(TAG, "run"); * 前置条件mAppConfigUtils 必须初始化完成
*/
private void run() {
LogUtils.d(TAG, "run: 执行守护逻辑 | 配置启用=" + mAppConfigUtils.isServiceEnabled() + " | 线程存活=" + mIsThreadAlive);
if (mAppConfigUtils.isServiceEnabled()) { if (mAppConfigUtils.isServiceEnabled()) {
if (mIsThreadAlive == false) { if (!mIsThreadAlive) {
// 设置运行状态
mIsThreadAlive = true; mIsThreadAlive = true;
// 唤醒和绑定主进程
wakeupAndBindMain(); wakeupAndBindMain();
} }
} else {
LogUtils.d(TAG, "run: 服务未启用,跳过守护逻辑");
// 服务未启用时,重置线程状态
mIsThreadAlive = false;
} }
} }
// 唤醒和绑定主进程 /**
// * 唤醒主服务并建立绑定,确保主服务持续运行
void wakeupAndBindMain() { * 适配 API26+ 前台服务启动规则,避免系统限制导致启动失败
if (ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName()) == false) { */
//LogUtils.d(TAG, "wakeupAndBindMain() Wakeup... ControlCenterService"); private void wakeupAndBindMain() {
startForegroundService(new Intent(AssistantService.this, ControlCenterService.class)); // 检查主服务存活状态
boolean isMainServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
LogUtils.d(TAG, "wakeupAndBindMain: 主服务存活状态=" + isMainServiceAlive);
// 主服务未存活时按需启动区分API版本
if (!isMainServiceAlive) {
Intent mainServiceIntent = new Intent(AssistantService.this, ControlCenterService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(mainServiceIntent);
LogUtils.d(TAG, "wakeupAndBindMain: API26+ 以前台服务方式启动主服务");
} else {
startService(mainServiceIntent);
LogUtils.d(TAG, "wakeupAndBindMain: 以普通服务方式启动主服务");
}
} }
//LogUtils.d(TAG, "wakeupAndBindMain() Bind... ControlCenterService");
bindService(new Intent(AssistantService.this, ControlCenterService.class), mMyServiceConnection, Context.BIND_IMPORTANT); // 绑定主服务,监听连接状态,添加结果日志
Intent bindIntent = new Intent(AssistantService.this, ControlCenterService.class);
boolean bindResult = bindService(bindIntent, mMyServiceConnection, Context.BIND_IMPORTANT);
LogUtils.d(TAG, "wakeupAndBindMain: 绑定主服务结果=" + bindResult + " | 绑定标记=BIND_IMPORTANT");
} }
// 主进程与守护进程连接时需要用到此类 // ================================== 内部类(服务连接状态监听)=================================
// /**
class MyServiceConnection implements ServiceConnection { * 服务连接状态监听器
* 主服务连接成功时记录状态,断开时自动重连
*/
private class MyServiceConnection implements ServiceConnection {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
//LogUtils.d(TAG, "call onServiceConnected(...)"); LogUtils.d(TAG, "onServiceConnected: 主服务连接成功 | 组件名=" + name.getClassName() + " | Binder=" + service);
} }
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
//LogUtils.d(TAG, "call onServiceDisconnected(...)"); LogUtils.d(TAG, "onServiceDisconnected: 主服务连接断开 | 组件名=" + name.getClassName());
if (mAppConfigUtils.isServiceEnabled()) { // 主服务断开且配置启用时,重新唤醒绑定
if (mAppConfigUtils != null && mAppConfigUtils.isServiceEnabled()) {
LogUtils.d(TAG, "onServiceDisconnected: 尝试重新唤醒并绑定主服务");
wakeupAndBindMain(); wakeupAndBindMain();
} }
} }
} }
} }

View File

@@ -9,22 +9,19 @@ import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.PowerManager; import android.os.PowerManager;
import android.provider.Settings; import android.provider.Settings;
import java.util.List;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler; import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.models.AppConfigBean; import cc.winboll.studio.powerbell.models.AppConfigBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean; import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.models.NotificationMessage; import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
import cc.winboll.studio.powerbell.threads.RemindThread; import cc.winboll.studio.powerbell.threads.RemindThread;
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils; import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import java.io.Serializable;
import java.util.List;
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * 电池提醒核心服务
* @Date 2025/12/19 20:21
* @Describe 电池提醒核心服务
* 功能:管理前台服务生命周期、控制提醒线程启停、处理配置更新 * 功能:管理前台服务生命周期、控制提醒线程启停、处理配置更新
* 适配Java7 | API30 | 前台服务超时防护 | 电池优化忽略引导 * 适配Java7 | API30 | 前台服务超时防护 | 电池优化忽略引导
*/ */
@@ -32,10 +29,6 @@ public class ControlCenterService extends Service {
// ================================== 静态常量区(置顶归类,消除魔法值)================================= // ================================== 静态常量区(置顶归类,消除魔法值)=================================
public static final String TAG = "ControlCenterService"; public static final String TAG = "ControlCenterService";
// 服务指令Action常量带包名前缀防冲突
// 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";
// 超时/阈值常量 // 超时/阈值常量
private static final long THREAD_STOP_TIMEOUT = 1000L; private static final long THREAD_STOP_TIMEOUT = 1000L;
// 服务状态标记常量 // 服务状态标记常量
@@ -315,8 +308,7 @@ public class ControlCenterService extends Service {
/** /**
* 外部更新配置并触发线程重启 * 外部更新配置并触发线程重启
* @param context 上下文 * @param context 上下文
* @param configBean 新配置
*/ */
public static void updateStatus(Context context) { public static void updateStatus(Context context) {
LogUtils.d(TAG, "updateStatus: 外部更新配置 | context=" + context); LogUtils.d(TAG, "updateStatus: 外部更新配置 | context=" + context);
@@ -329,6 +321,7 @@ public class ControlCenterService extends Service {
intent.setAction(ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED); intent.setAction(ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
intent.setPackage(context.getPackageName()); intent.setPackage(context.getPackageName());
context.sendBroadcast(intent); context.sendBroadcast(intent);
LogUtils.d(TAG, "updateStatus: 配置更新广播已发送 | action=" + ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
} }
/** /**
@@ -357,7 +350,7 @@ public class ControlCenterService extends Service {
intent.setData(Uri.parse("package:" + packageName)); intent.setData(Uri.parse("package:" + packageName));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent); context.startActivity(intent);
LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已跳转至系统设置页"); LogUtils.d(TAG, "checkIgnoreBatteryOptimization: 已跳转至系统设置页 | package=" + packageName);
} }
} }
@@ -368,7 +361,7 @@ public class ControlCenterService extends Service {
* @return true=运行中 false=未运行 * @return true=运行中 false=未运行
*/ */
private static boolean isServiceRunning(Context context, Class<?> serviceClass) { private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
LogUtils.d(TAG, "isServiceRunning: 检查服务状态 | context=" + context + " | service=" + serviceClass); LogUtils.d(TAG, "isServiceRunning: 检查服务状态 | context=" + context + " | service=" + serviceClass.getName());
if (context == null || serviceClass == null) { if (context == null || serviceClass == null) {
LogUtils.e(TAG, "isServiceRunning: 参数为空"); LogUtils.e(TAG, "isServiceRunning: 参数为空");
return false; return false;
@@ -444,9 +437,9 @@ public class ControlCenterService extends Service {
if (latestConfig != null && mServiceHandler != null) { if (latestConfig != null && mServiceHandler != null) {
mCurrentConfigBean = latestConfig; mCurrentConfigBean = latestConfig;
RemindThread.startRemindThread(this, mServiceHandler, latestConfig); RemindThread.startRemindThread(this, mServiceHandler, latestConfig);
LogUtils.d(TAG, "notifyAppConfigUpdate: 配置已同步到线程"); LogUtils.d(TAG, "notifyAppConfigUpdate: 配置已同步到提醒线程");
} else { } else {
LogUtils.e(TAG, "notifyAppConfigUpdate: 参数为空,同步失败"); LogUtils.e(TAG, "notifyAppConfigUpdate: 参数为空,同步失败 | latestConfig=" + latestConfig + " | mServiceHandler=" + mServiceHandler);
} }
} }