805 lines
37 KiB
Java
805 lines
37 KiB
Java
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初始化完成");
|
||
|
||
// 切换主线程更新UI(Java7显式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();
|
||
}
|
||
}
|
||
|