Files
WinBoLL/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java

805 lines
37 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cc.winboll.studio.powerbell;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewStub;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libaes.activitys.AboutActivity;
import cc.winboll.studio.libaes.models.APPInfo;
import cc.winboll.studio.libaes.utils.AESThemeUtil;
import cc.winboll.studio.libaes.utils.DevelopUtils;
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libaes.views.ADsBannerView;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
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.MainContentView;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:14
* @Describe 主活动类:应用核心页面,管理电池监控、背景设置、服务控制等核心功能
* 适配Java7 | API30 | 小米手机,优化性能与稳定性,杜绝内存泄漏
*/
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
public static final String TAG = "MainActivity";
// 请求码
private static final int REQUEST_READ_MEDIA_IMAGES = 1001; // 背景设置请求码
// 延迟时间
private static final int DELAY_LOAD_NON_CRITICAL = 500; // 非核心视图延迟加载ms
// Handler消息标识按业务优先级排序
public static final int MSG_RELOAD_APPCONFIG = 0; // 重新加载配置
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实例销毁时必须置空
private static Handler sGlobalHandler; // 全局Handler统一消息分发避免多Handler混乱
// ======================== 成员属性(按「依赖→核心→辅助」分类,优先级递减)========================
// 工具类实例(单例,避免重复初始化)
private PermissionUtils mPermissionUtils;
private AppConfigUtils mAppConfigUtils;
private BackgroundSourceUtils mBgSourceUtils;
// 应用核心实例
private App mApplication;
private MainContentView mMainContentView; // 核心视图封装类(统一管理视图)
// 基础视图组件
private Toolbar mToolbar;
private ViewStub mAdsViewStub;
private ADsBannerView mADsBannerView; // 广告视图(非核心,延迟加载)
// 资源与菜单
private Menu mMenu;
private Drawable mFrameDrawable; // 框架背景资源适配API30主题
// 新增服务控制核心Bean本地持久化管理服务自启动状态
private ControlCenterServiceBean mServiceControlBean;
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环)========================
@Override
public Activity getActivity() {
return this;
}
@Override
public String getTag() {
return TAG;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 进入");
super.onCreate(savedInstanceState);
// 1. 初始化全局核心组件Handler优先避免消息丢失
initGlobalHandler();
// 2. 加载布局+初始化核心流程
setContentView(R.layout.activity_main);
initPermissionUtils(); // 权限工具类(提前初始化,保障权限请求时效)
initMainContentView(); // 核心视图封装替代原ViewHolder
initCriticalView(); // 首屏核心视图Toolbar等保障首屏加载速度
initCoreUtilsAsync(); // 异步初始化工具类(避免主线程阻塞)
loadNonCriticalViewDelayed(); // 延迟加载非核心视图(广告,不影响首屏体验)
LogUtils.d(TAG, "onCreate: 退出");
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onPostCreate: 进入");
super.onPostCreate(savedInstanceState);
// 视图初始化完成后请求权限(避免视图未就绪导致的异常)
mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 退出");
}
@Override
protected void onResume() {
LogUtils.d(TAG, "onResume: 进入");
super.onResume();
// 1. 恢复背景(适配后台切前台场景,小米手机保活优化)
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: 进入");
super.onDestroy();
// 1. 释放广告资源避免内存泄漏适配API30资源管控
if (mADsBannerView != null) {
mADsBannerView.releaseAdResources();
mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 释放广告资源完成");
}
// 2. 释放核心视图资源(调用封装类释放方法,彻底断开引用)
if (mMainContentView != null) {
mMainContentView.releaseResources();
mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 释放核心视图资源完成");
}
// 3. 关键调整Activity销毁强制销毁RemindThread单例彻底停止线程
RemindThread.destroyInstance();
LogUtils.d(TAG, "onDestroy: 强制销毁RemindThread单例完成");
// 4. 置空全局实例(杜绝内存泄漏,必须执行)
sMainActivity = null;
// 5. 清理Handler移除所有消息避免Activity销毁后回调
if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 清理全局Handler完成");
}
// 6. 释放Drawable资源断开回调辅助GC回收
if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null);
mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 释放Drawable资源完成");
}
// 7. 置空所有辅助实例辅助GC避免残留引用
mPermissionUtils = null;
mAppConfigUtils = null;
mBgSourceUtils = null;
mServiceControlBean = null; // 新增置空服务控制Bean
mMenu = null;
mApplication = null;
mToolbar = null;
mAdsViewStub = null;
LogUtils.d(TAG, "onDestroy: 退出");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
LogUtils.d(TAG, "onActivityResult: 进入requestCode=" + requestCode + "resultCode=" + resultCode);
super.onActivityResult(requestCode, resultCode, data);
// 1. 权限请求结果处理
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 2. 背景设置完成后重新加载背景
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送加载背景消息");
}
}
LogUtils.d(TAG, "onActivityResult: 退出");
}
// ======================== 菜单与导航方法(统一归类,用户交互入口)========================
@Override
public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu: 进入");
mMenu = menu;
// 1. 加载主题菜单
AESThemeUtil.inflateMenu(this, menu);
// 2. 调试模式加载开发菜单+单元测试菜单
if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载开发/单元测试菜单");
}
// 3. 加载主菜单
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 退出");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected: 进入itemId=" + item.getItemId());
// 1. 主题切换处理切换后重建Activity生效
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate();
LogUtils.d(TAG, "onOptionsItemSelected: 主题切换重建Activity");
return true;
}
// 2. 开发模式菜单处理
if (DevelopUtils.onDevelopItemSelected(this, item)) {
LogUtils.d(TAG, "onOptionsItemSelected: 开发菜单操作完成");
return true;
}
// 3. 主菜单逻辑分发(按功能分类,清晰易维护)
switch (item.getItemId()) {
case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class));
break;
case R.id.action_battery_report:
startActivity(new Intent(this, BatteryReportActivity.class));
break;
case R.id.action_clearrecord:
startActivity(new Intent(this, ClearRecordActivity.class));
break;
case R.id.action_changepicture:
startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES);
break;
case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class));
break;
case R.id.action_about:
startAboutActivity();
break;
default:
return super.onOptionsItemSelected(item);
}
LogUtils.d(TAG, "onOptionsItemSelected: 退出");
return true;
}
@Override
public void setupToolbar() {
super.setupToolbar();
// 主页面隐藏返回按钮(符合用户操作习惯)
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 隐藏Toolbar返回按钮");
}
}
// ======================== 页面交互方法(用户操作响应,统一归类)========================
@Override
public void onBackPressed() {
// 退到后台不销毁Activity提升用户体验小米手机后台保活优化
moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用退到后台");
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// 保留系统默认按键分发逻辑,无自定义需求
return super.dispatchKeyEvent(event);
}
// ======================== 核心初始化方法(按优先级排序,核心优先加载)========================
/**
* 初始化权限工具类(提前初始化,保障权限请求无延迟)
*/
private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: 进入");
mPermissionUtils = PermissionUtils.getInstance();
LogUtils.d(TAG, "initPermissionUtils: 退出");
}
/**
* 初始化全局Handler统一消息分发Java7显式实现避免内存泄漏
*/
private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: 进入");
if (sGlobalHandler == null) {
sGlobalHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
LogUtils.d(TAG, "handleMessage: 接收消息what=" + msg.what);
// 消息处理前先校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息处理");
return;
}
// 按消息类型分发逻辑
switch (msg.what) {
case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData();
break;
case MSG_CURRENTVALUEBATTERY:
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
break;
case MSG_LOAD_BACKGROUND:
sMainActivity.reloadBackground();
sMainActivity.setMainLayoutBackgroundColor();
break;
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);
}
};
LogUtils.d(TAG, "initGlobalHandler: 全局Handler初始化完成");
}
LogUtils.d(TAG, "initGlobalHandler: 退出");
}
/**
* 初始化核心视图封装类统一管理视图替代原ViewHolder模式
*/
private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: 进入");
View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this);
LogUtils.d(TAG, "initMainContentView: 核心视图封装类初始化完成");
LogUtils.d(TAG, "initMainContentView: 退出");
}
/**
* 初始化首屏核心视图Toolbar等保障首屏加载速度优先渲染
*/
private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: 进入");
sMainActivity = this; // 赋值全局实例用于Handler回调
// 初始化Toolbar
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
}
// 初始化广告ViewStub仅初始化Stub不立即加载广告
mAdsViewStub = findViewById(R.id.stub_ads_banner);
LogUtils.d(TAG, "initCriticalView: 退出");
}
/**
* 异步初始化核心工具类(子线程执行,避免主线程阻塞,提升首屏加载速度)
*/
private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: 进入");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动");
// 子线程初始化工具类无UI操作安全执行
mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
// 新增初始化服务控制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初始化完成");
// 切换主线程更新UIJava7显式runOnUiThread
runOnUiThread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "initCoreUtilsAsync: 切换主线程更新UI");
if (isFinishing()) {
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
return;
}
// 适配API30加载Drawable添加主题参数避免系统警告
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
} else {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame);
}
// 初始化完成后执行核心业务
updateViewData(); // 更新视图数据
checkServiceAsync(); // 异步检查服务状态
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); // 加载背景
// 新增初始化服务开关UI确保开关状态与本地配置一致
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
}
});
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程结束");
}
}).start();
LogUtils.d(TAG, "initCoreUtilsAsync: 退出");
}
/**
* 延迟加载非核心视图广告延迟500ms加载不影响首屏体验
*/
private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 进入");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (isFinishing()) {
LogUtils.w(TAG, "loadNonCriticalViewDelayed: Activity已销毁跳过广告加载");
return;
}
loadAdsView(); // 加载广告视图
}
}, DELAY_LOAD_NON_CRITICAL);
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 退出");
}
// ======================== 视图操作方法UI更新统一归类========================
/**
* 加载广告视图(非核心,容错处理,避免广告加载失败影响主功能)
*/
private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 进入");
if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空加载失败");
return;
}
if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: 广告视图加载完成");
}
LogUtils.d(TAG, "loadAdsView: 退出");
}
/**
* 更新视图数据调用核心视图封装类方法统一更新UI
*/
private void updateViewData() {
LogUtils.d(TAG, "updateViewData: 进入");
if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图/框架资源为空,跳过更新");
return;
}
mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
LogUtils.d(TAG, "updateViewData: 退出");
}
/**
* 重新加载背景(适配背景切换,小米手机图片加载优化,容错处理)
*/
private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: 进入");
if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图/背景工具类为空,跳过加载");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
LogUtils.d(TAG, "reloadBackground: 加载自定义背景完成");
} else {
LogUtils.e(TAG, "reloadBackground: 无自定义背景,加载默认背景");
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
}
LogUtils.d(TAG, "reloadBackground: 退出");
}
/**
* 设置主布局背景颜色适配背景配置API30安全防护
*/
private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 进入");
if (isFinishing() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 环境无效,跳过设置");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
int bgColor = currentBgBean.getPixelColor();
mMainContentView.mainLayout.setBackgroundColor(bgColor);
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局颜色设置完成");
}
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前台服务规范
*/
private void checkServiceAsync() {
LogUtils.d(TAG, "checkServiceAsync: 进入");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "checkServiceAsync: 异步线程启动");
if (mAppConfigUtils == null || mServiceControlBean == null || isFinishing()) {
LogUtils.e(TAG, "checkServiceAsync: 配置工具类/服务控制Bean/Activity无效跳过检查");
return;
}
// 服务启用本地配置且未运行时启动前台服务API30必须前台服务小米保活优化
if (mServiceControlBean.isEnableService() && !ServiceUtils.isServiceAlive(getActivity(), ControlCenterService.class.getName())) {
LogUtils.d(TAG, "checkServiceAsync: 服务未运行,启动前台服务");
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
ControlCenterService.startControlCenterService(getActivity());
}
}
});
}
LogUtils.d(TAG, "checkServiceAsync: 异步线程结束");
}
}).start();
LogUtils.d(TAG, "checkServiceAsync: 退出");
}
/**
* 重启RemindThread线程通过服务统一管理保障线程安全适配API30服务规范
*/
private void restartRemindThread(AppConfigBean configBean) {
LogUtils.d(TAG, "restartRemindThread: 进入");
if (configBean == null || mServiceControlBean == null) {
LogUtils.e(TAG, "restartRemindThread: 配置为空/服务控制Bean为空跳过重启");
return;
}
// 服务未启用时,不重启线程(直接返回)
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: 退出");
}
// ======================== 页面跳转方法(封装逻辑,减少冗余)========================
/**
* 启动关于页面(封装跳转逻辑,统一参数传递,便于维护)
*/
private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: 进入");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
LogUtils.d(TAG, "startAboutActivity: 启动关于页面完成");
LogUtils.d(TAG, "startAboutActivity: 退出");
}
// ======================== 消息发送方法(统一封装,避免冗余,保障消息安全)========================
/**
* 发送重启RemindThread线程消息携带最新配置确保线程使用最新参数
*/
private void sendRestartRemindThreadMessage() {
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 进入");
if (sGlobalHandler == null || mAppConfigUtils == null || mAppConfigUtils.mAppConfigBean == null) {
LogUtils.e(TAG, "sendRestartRemindThreadMessage: Handler/配置为空,跳过发送");
return;
}
// 复用Message避免内存抖动优化性能
Message msg = sGlobalHandler.obtainMessage(MSG_RESTART_REMIND_THREAD);
msg.obj = mAppConfigUtils.mAppConfigBean;
sGlobalHandler.sendMessage(msg);
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 发送线程重启消息完成");
LogUtils.d(TAG, "sendRestartRemindThreadMessage: 退出");
}
// ======================== 静态工具方法(全局调用,统一入口)========================
/**
* 重新加载应用配置(全局调用,触发视图更新)
*/
public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: 发送重新加载配置消息");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
}
}
/**
* 发送当前电量更新消息全局调用实时更新UI
*/
public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量=" + value + ",发送更新消息");
if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value;
sGlobalHandler.sendMessage(msg);
}
}
// ======================== 辅助工具方法(封装重复逻辑,提升复用性)========================
/**
* 从URI获取图片真实路径适配API30媒体存储权限Java7显式Cursor操作避免资源泄漏
*/
private String getRealPathFromUri(Uri contentUri) {
LogUtils.d(TAG, "getRealPathFromUri: 进入");
if (contentUri == null) {
LogUtils.e(TAG, "getRealPathFromUri: URI为空获取失败");
return null;
}
String realPath = null;
String[] projection = {MediaStore.MediaColumns.DATA};
Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToNext()) {
int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
if (columnIndex > -1) {
realPath = cursor.getString(columnIndex);
LogUtils.d(TAG, "getRealPathFromUri: 获取图片路径=" + realPath);
}
}
} finally {
// Java7必须显式关闭Cursor避免资源泄漏无try-with-resources语法
cursor.close();
}
}
if (realPath == null) {
LogUtils.e(TAG, "getRealPathFromUri: 获取图片路径失败");
}
LogUtils.d(TAG, "getRealPathFromUri: 退出");
return realPath;
}
/**
* 生成默认应用信息(关于页面使用,封装参数赋值,便于维护)
*/
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 进入");
String branchName = "powerbell";
APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name));
appInfo.setAppIcon(R.drawable.ic_launcher);
appInfo.setAppDescription(getString(R.string.app_description));
appInfo.setAppGitName("WinBoLL");
appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(branchName);
appInfo.setAppGitAPPSubProjectFolder(branchName);
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
appInfo.setAppAPKName("PowerBell");
appInfo.setAppAPKFolderName("PowerBell");
LogUtils.d(TAG, "genDefaultAppInfo: 生成应用信息完成");
LogUtils.d(TAG, "genDefaultAppInfo: 退出");
return appInfo;
}
// ======================== MainContentView 事件回调实现(视图事件触发业务逻辑)========================
@Override
public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 状态=" + isChecked);
sendRestartRemindThreadMessage();
}
@Override
public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 状态=" + isChecked);
sendRestartRemindThreadMessage();
}
@Override
public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 状态=" + isChecked);
// 核心修复:点击服务开关,触发「配置持久化+服务启停+UI更新」全链路逻辑
toggleServiceEnableState(isChecked);
}
@Override
public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: 进度=" + progress);
sendRestartRemindThreadMessage();
}
@Override
public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: 进度=" + progress);
sendRestartRemindThreadMessage();
}
}