Compare commits

...

23 Commits

Author SHA1 Message Date
9124303fd3 <powerbell>APK 15.14.40 release Publish. 2025-12-28 20:43:38 +08:00
414541093a <powerbell>Start New Stage Version. 2025-12-28 20:42:24 +08:00
13265be66e 添加点阵能量块风格。 2025-12-28 20:41:19 +08:00
ebd32adb68 <powerbell>APK 15.14.39 release Publish. 2025-12-28 13:54:20 +08:00
56a65cd10a 能量风格绘图方法切换回老式算法,修复能量条间隔缝隙问题。 2025-12-28 13:52:51 +08:00
e379684002 <powerbell>APK 15.14.38 release Publish. 2025-12-28 13:16:31 +08:00
4077ac18f6 <powerbell>Start New Stage Version. 2025-12-28 13:15:17 +08:00
278e690795 能量条绘图风格调试完成。 2025-12-28 13:14:24 +08:00
e81fc65b90 BatteryStyleView控件调试中。。。 2025-12-27 21:19:20 +08:00
abd956d7d0 添加BatteryStyleView控件,添加能量与斑马绘图风格。 2025-12-27 21:12:54 +08:00
fca17908b2 <powerbell>APK 15.14.37 release Publish. 2025-12-27 14:48:34 +08:00
39a3a5aeb0 更新黑白主题风格。 2025-12-27 14:45:13 +08:00
2e30f577b5 <powerbell>APK 15.14.36 release Publish. 2025-12-26 21:00:10 +08:00
dcb5355233 添加在切换主题时把主题基准色配置为背景图背景像素底色。 2025-12-26 20:58:31 +08:00
d1ced7ac63 <powerbell>APK 15.14.35 release Publish. 2025-12-26 20:13:09 +08:00
bf0cf23144 <powerbell>Start New Stage Version. 2025-12-26 20:11:34 +08:00
890b32ceae 修复像素拾取窗口菜单栏风格未统一问题。 2025-12-26 20:10:28 +08:00
c347d51c84 简化代码使用全局变量 2025-12-26 20:04:25 +08:00
7278e9f22f 源码整理 2025-12-26 19:47:06 +08:00
4e98c8d699 优化函数使用方式 2025-12-26 18:56:24 +08:00
3ec1bbe264 源码整理 2025-12-26 18:31:25 +08:00
f4a2a1585d 源码整理 2025-12-26 18:00:24 +08:00
35f4aa8730 源码整理 2025-12-26 17:42:30 +08:00
23 changed files with 910 additions and 330 deletions

View File

@@ -87,7 +87,7 @@ dependencies {
//api 'cc.winboll.studio:libappbase:15.12.2'
// WinBoLL备用库 jitpack.io 地址
api 'com.github.ZhanGSKen:AES:aes-v15.12.7'
api 'com.github.ZhanGSKen:AES:aes-v15.12.8'
api 'com.github.ZhanGSKen:APPBase:appbase-v15.14.1'
//api fileTree(dir: 'libs', include: ['*.aar'])

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Dec 26 02:58:19 HKT 2025
stageCount=35
#Sun Dec 28 20:43:38 HKT 2025
stageCount=41
libraryProject=
baseVersion=15.14
publishVersion=15.14.34
publishVersion=15.14.40
buildCount=0
baseBetaVersion=15.14.35
baseBetaVersion=15.14.41

View File

@@ -64,11 +64,12 @@ public class App extends GlobalApplication {
// 全局广播接收器
private GlobalApplicationReceiver mGlobalReceiver;
// ===================== 公共静态方法区(工具类实例获取/单例 =====================
// ===================== 公共静态方法区(单例/工具类实例获取) =====================
/**
* 获取应用单例实例
*/
public static App getInstance() {
LogUtils.d(TAG, "getInstance() 调用 | 返回实例:" + sApp);
return sApp;
}
@@ -76,12 +77,14 @@ public class App extends GlobalApplication {
* 获取应用配置工具实例
*/
public static AppConfigUtils getAppConfigUtils(Context context) {
LogUtils.d(TAG, String.format("getAppConfigUtils() 调用 | 传入Context类型=%s",
context != null ? context.getClass().getSimpleName() : "null"));
String contextType = context != null ? context.getClass().getSimpleName() : "null";
LogUtils.d(TAG, "getAppConfigUtils() 调用 | 入参Context类型" + contextType);
if (sAppConfigUtils == null) {
sAppConfigUtils = AppConfigUtils.getInstance(context);
LogUtils.d(TAG, "getAppConfigUtils()AppConfigUtils实例初始化");
LogUtils.d(TAG, "getAppConfigUtils() | AppConfigUtils实例初始化完成");
}
LogUtils.d(TAG, "getAppConfigUtils() | 返回实例:" + sAppConfigUtils);
return sAppConfigUtils;
}
@@ -89,12 +92,14 @@ public class App extends GlobalApplication {
* 获取应用缓存工具实例
*/
public static AppCacheUtils getAppCacheUtils(Context context) {
LogUtils.d(TAG, String.format("getAppCacheUtils() 调用 | 传入Context类型=%s",
context != null ? context.getClass().getSimpleName() : "null"));
String contextType = context != null ? context.getClass().getSimpleName() : "null";
LogUtils.d(TAG, "getAppCacheUtils() 调用 | 入参Context类型" + contextType);
if (sAppCacheUtils == null) {
sAppCacheUtils = AppCacheUtils.getInstance(context);
LogUtils.d(TAG, "getAppCacheUtils()AppCacheUtils实例初始化");
LogUtils.d(TAG, "getAppCacheUtils() | AppCacheUtils实例初始化完成");
}
LogUtils.d(TAG, "getAppCacheUtils() | 返回实例:" + sAppCacheUtils);
return sAppCacheUtils;
}
@@ -106,9 +111,9 @@ public class App extends GlobalApplication {
LogUtils.d(TAG, "clearBatteryHistory() 调用");
if (sAppCacheUtils != null) {
sAppCacheUtils.clearBatteryHistory();
LogUtils.d(TAG, "clearBatteryHistory()电池历史数据清除");
LogUtils.d(TAG, "clearBatteryHistory() | 电池历史数据清除成功");
} else {
LogUtils.w(TAG, "clearBatteryHistory()AppCacheUtils未初始化,清除失败");
LogUtils.w(TAG, "clearBatteryHistory() | 失败AppCacheUtils未初始化");
}
}
@@ -117,28 +122,27 @@ public class App extends GlobalApplication {
* 极致强制缓存策略下,仅提供手动清理入口,永不自动调用
*/
public static void manualClearAllCache() {
LogUtils.w(TAG, String.format("%s 手动清理缓存调用(极致强制缓存策略下,需谨慎使用", CACHE_PROTECT_TAG));
LogUtils.w(CACHE_PROTECT_TAG, "manualClearAllCache() 调用 | 极致缓存策略下谨慎使用");
// 清理Bitmap缓存
if (sBitmapCacheUtils != null) {
sBitmapCacheUtils.clearAllCache();
LogUtils.d(TAG, String.format("%s Bitmap缓存手动清理", CACHE_PROTECT_TAG));
LogUtils.d(CACHE_PROTECT_TAG, "manualClearAllCache() | Bitmap缓存手动清理完成");
}
// 清理视图控件缓存(仅清除静态引用,不销毁实例)
if (sMemoryCachedBackgroundView != null) {
LogUtils.d(TAG, String.format("%s 视图控件缓存实例保持,仅清除静态引用", CACHE_PROTECT_TAG));
LogUtils.d(CACHE_PROTECT_TAG, "manualClearAllCache() | 视图缓存保留实例,仅清除静态引用");
sMemoryCachedBackgroundView = null;
}
LogUtils.w(TAG, String.format("%s 手动清理缓存完成(部分缓存实例仍可能保留在内存中)", CACHE_PROTECT_TAG));
LogUtils.w(CACHE_PROTECT_TAG, "manualClearAllCache() | 手动清理完成 | 部分缓存实例仍驻留内存");
}
/**
* 获取视图控件缓存实例非通用仅通过App实例调用避免全局直接访问
*/
public MemoryCachedBackgroundView getMemoryCachedBackgroundView() {
LogUtils.d(TAG, "getMemoryCachedBackgroundView() 调用 | 视图控件缓存实例获取");
if (sMemoryCachedBackgroundView == null) {
LogUtils.w(TAG, "getMemoryCachedBackgroundView()视图控件缓存实例未初始化返回null");
}
LogUtils.d(TAG, "getMemoryCachedBackgroundView() 调用 | 当前实例:" + sMemoryCachedBackgroundView);
return sMemoryCachedBackgroundView;
}
@@ -146,13 +150,15 @@ public class App extends GlobalApplication {
* 发送调试通知
*/
public static void notifyMessage(String title, String content) {
LogUtils.d(TAG, String.format("notifyMessage() 调用 | title=%s | content=%s", title, content));
if (isDebugging() && sApp != null && sNotificationManagerUtils != null) {
LogUtils.d(TAG, "notifyMessage() 调用 | 入参title" + title + " | content" + content);
boolean canNotify = isDebugging() && sApp != null && sNotificationManagerUtils != null;
if (canNotify) {
NotificationMessage message = new NotificationMessage(title, content, "");
sNotificationManagerUtils.showMessageNotification(sApp, message);
LogUtils.d(TAG, "notifyMessage()调试通知发送成功");
LogUtils.d(TAG, "notifyMessage() | 调试通知发送成功");
} else {
LogUtils.d(TAG, "notifyMessage():调试通知发送失败(条件不满足)");
LogUtils.d(TAG, "notifyMessage() | 发送失败:调试模式未开启/工具类未初始化");
}
}
@@ -160,58 +166,51 @@ public class App extends GlobalApplication {
@Override
public void onCreate() {
super.onCreate();
LogUtils.d(TAG, "onCreate() 应用启动,开始初始化");
LogUtils.d(TAG, "onCreate() | 应用启动,开始初始化流程");
sApp = this;
// 初始化调试模式
setIsDebugging(BuildConfig.DEBUG);
LogUtils.d(TAG, String.format("onCreate() 调试模式=%b", BuildConfig.DEBUG));
LogUtils.d(TAG, "onCreate() | 调试模式状态:" + BuildConfig.DEBUG);
// 初始化基础工具
// 初始化核心组件
initBaseTools();
// 初始化工具类实例(核心:极致强制缓存,永不销毁)
initUtils();
// 初始化广播接收器
initReceiver();
LogUtils.d(TAG, "onCreate() 应用初始化完成极致强制缓存策略已启用");
LogUtils.d(TAG, "onCreate() | 应用初始化完成 | 极致强制缓存策略已启用");
}
@Override
public void onTerminate() {
super.onTerminate();
LogUtils.d(TAG, "onTerminate() 应用终止,开始释放非缓存资源");
LogUtils.d(TAG, "onTerminate() | 应用终止,释放非缓存资源");
// 释放Toast工具
// 释放轻量级工具
ToastUtils.release();
LogUtils.d(TAG, "onTerminate()Toast工具已释放");
// 释放通知工具
LogUtils.d(TAG, "onTerminate() | Toast工具资源释放完成");
releaseNotificationManager();
// 释放广播接收器
releaseReceiver();
// 核心修改:应用终止时也不清理缓存,保持静态实例
LogUtils.w(TAG, String.format("%s 应用终止,极致强制缓存策略生效,不清理任何缓存", CACHE_PROTECT_TAG));
LogUtils.d(TAG, "onTerminate() 非缓存资源释放完成,缓存实例保持");
// 核心策略:应用终止不清理任何缓存
LogUtils.w(CACHE_PROTECT_TAG, "onTerminate() | 极致缓存策略生效 | 所有缓存实例保持驻留");
LogUtils.d(TAG, "onTerminate() | 非缓存资源释放完成");
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
// 极致强制缓存:禁止任何缓存清理操作,仅记录日志
LogUtils.w(TAG, String.format("%s onTrimMemory() 调用 | 内存等级level=%d | 极致强制保持所有缓存",
CACHE_PROTECT_TAG, level));
// 记录详细缓存状态,不执行任何清理
// 极致缓存策略:拒绝系统触发的缓存清理
LogUtils.w(CACHE_PROTECT_TAG, "onTrimMemory() 调用 | 内存等级" + level + " | 强制保持所有缓存");
logDetailedCacheStatus();
}
@Override
public void onLowMemory() {
super.onLowMemory();
// 极致强制缓存:低内存时也不清理任何缓存
LogUtils.w(TAG, String.format("%s onLowMemory() 调用 | 极致强制保持所有缓存", CACHE_PROTECT_TAG));
// 记录详细缓存状态,不执行任何清理
// 低内存场景:不清理缓存,仅记录状态
LogUtils.w(CACHE_PROTECT_TAG, "onLowMemory() 调用 | 极致缓存策略:不执行任何清理操作");
logDetailedCacheStatus();
}
@@ -220,54 +219,46 @@ public class App extends GlobalApplication {
* 初始化基础工具Activity管理、Toast、通知工具
*/
private void initBaseTools() {
LogUtils.d(TAG, "initBaseTools() 开始初始化基础工具");
LogUtils.d(TAG, "initBaseTools() | 开始初始化基础工具");
WinBoLLActivityManager.init(this);
ToastUtils.init(this);
sNotificationManagerUtils = new NotificationManagerUtils(this);
LogUtils.d(TAG, "initBaseTools() 基础工具+通知工具初始化完成,极致强制缓存策略已生效");
LogUtils.d(TAG, "initBaseTools() | ActivityManager/Toast/Notification工具初始化完成");
}
/**
* 初始化工具类实例(核心:极致强制缓存一旦初始化永不销毁)
* 初始化核心工具类极致强制缓存一旦初始化永不销毁)
*/
private void initUtils() {
LogUtils.d(TAG, "initUtils() 开始初始化工具类启用极致强制缓存策略");
// 初始化配置&缓存工具
LogUtils.d(TAG, "initUtils() | 开始初始化核心工具类 | 启用极致强制缓存策略");
// 初始化配置与缓存工具
sAppConfigUtils = getAppConfigUtils(this);
sAppCacheUtils = getAppCacheUtils(this);
// 初始化背景资源工具
// 初始化背景资源与Bitmap缓存
sBackgroundSourceUtils = BackgroundSourceUtils.getInstance(this);
sBackgroundSourceUtils.loadSettings();
LogUtils.d(TAG, "initUtils() 背景资源工具已初始化");
// 极致强制初始化Bitmap缓存工具必初始化永不销毁
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "initUtils() Bitmap缓存工具初始化(极致强制保持,永不销毁)");
LogUtils.d(TAG, "initUtils() | BackgroundSource/BitmapCache工具初始化完成 | 永久驻留内存");
// 极致强制初始化视图控件缓存工具(必初始化,永不销毁)
// if(sMemoryCachedBackgroundView == null) {
// App.notifyMessage(TAG, "sMemoryCachedBackgroundView == null");
// }
// 初始化视图控件缓存
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getLastInstance(this);
if (sMemoryCachedBackgroundView == null) {
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, sBackgroundSourceUtils.getCurrentBackgroundBean(), true);
LogUtils.d(TAG, "initUtils() 视图控件缓存工具新建实例");
//App.notifyMessage(TAG, "没有使用缓存控件");
LogUtils.d(TAG, "initUtils() | 视图缓存工具新建实例完成");
}
//App.notifyMessage(TAG, "initUtils() 视图控件缓存工具已初始化(极致强制保持,永不销毁)");
LogUtils.d(TAG, "initUtils() 视图控件缓存工具已初始化(极致强制保持,永不销毁)");
LogUtils.d(TAG, "initUtils() | MemoryCachedBackgroundView初始化完成 | 永久驻留内存");
}
/**
* 初始化广播接收器
* 初始化全局广播接收器
*/
private void initReceiver() {
LogUtils.d(TAG, "initReceiver() 开始初始化广播接收器");
LogUtils.d(TAG, "initReceiver() | 开始初始化广播接收器");
mGlobalReceiver = new GlobalApplicationReceiver(this);
mGlobalReceiver.registerAction();
LogUtils.d(TAG, "initReceiver() 广播接收器注册完成");
LogUtils.d(TAG, "initReceiver() | 广播接收器注册完成");
}
// ===================== 私有释放方法区(按资源重要性排序) =====================
@@ -275,13 +266,13 @@ public class App extends GlobalApplication {
* 释放广播接收器资源
*/
private void releaseReceiver() {
LogUtils.d(TAG, "releaseReceiver() 开始释放广播接收器");
LogUtils.d(TAG, "releaseReceiver() | 开始释放广播接收器");
if (mGlobalReceiver != null) {
mGlobalReceiver.unregisterAction();
mGlobalReceiver = null;
LogUtils.d(TAG, "releaseReceiver() 广播接收器资源释放");
LogUtils.d(TAG, "releaseReceiver() | 广播接收器资源释放完成");
} else {
LogUtils.d(TAG, "releaseReceiver() 广播接收器未初始化,无需释放");
LogUtils.d(TAG, "releaseReceiver() | 无需释放:广播接收器未初始化");
}
}
@@ -289,13 +280,13 @@ public class App extends GlobalApplication {
* 释放通知管理工具资源
*/
private void releaseNotificationManager() {
LogUtils.d(TAG, "releaseNotificationManager() 开始释放通知工具");
LogUtils.d(TAG, "releaseNotificationManager() | 开始释放通知工具");
if (sNotificationManagerUtils != null) {
sNotificationManagerUtils.release();
sNotificationManagerUtils = null;
LogUtils.d(TAG, "releaseNotificationManager() 通知工具资源释放");
LogUtils.d(TAG, "releaseNotificationManager() | 通知工具资源释放完成");
} else {
LogUtils.d(TAG, "releaseNotificationManager() 通知工具未初始化,无需释放");
LogUtils.d(TAG, "releaseNotificationManager() | 无需释放:通知工具未初始化");
}
}
@@ -304,27 +295,26 @@ public class App extends GlobalApplication {
* 记录详细缓存状态(用于调试,监控极致强制缓存效果)
*/
private void logDetailedCacheStatus() {
LogUtils.d(TAG, "logDetailedCacheStatus() 开始记录详细缓存状态");
// Bitmap缓存状态
LogUtils.d(TAG, "logDetailedCacheStatus() | 开始记录缓存状态");
// 记录Bitmap缓存状态
if (sBitmapCacheUtils != null) {
LogUtils.d(TAG, String.format("%s Bitmap缓存工具实例有效极致强制保持)", CACHE_PROTECT_TAG));
// 假设BitmapCacheUtils有获取缓存数量的方法
LogUtils.d(CACHE_PROTECT_TAG, "Bitmap缓存工具实例有效(永久驻留)");
try {
int cacheCount = sBitmapCacheUtils.getCacheCount();
LogUtils.d(TAG, String.format("%s Bitmap缓存数量=%d", CACHE_PROTECT_TAG, cacheCount));
LogUtils.d(CACHE_PROTECT_TAG, "Bitmap缓存数量" + cacheCount);
} catch (Exception e) {
LogUtils.d(TAG, String.format("%s Bitmap缓存数量获取失败(不影响缓存)| 异常信息=%s",
CACHE_PROTECT_TAG, e.getMessage()));
LogUtils.d(CACHE_PROTECT_TAG, "Bitmap缓存数量获取失败 | 异常信息" + e.getMessage());
}
}
// 视图控件缓存状态
// 记录视图缓存状态
if (sMemoryCachedBackgroundView != null) {
LogUtils.d(TAG, String.format("%s 视图控件缓存工具实例有效(极致强制保持)", CACHE_PROTECT_TAG));
// 记录视图实例总数
int viewInstanceCount = MemoryCachedBackgroundView.getInstanceCount();
LogUtils.d(TAG, String.format("%s 视图控件实例总数=%d", CACHE_PROTECT_TAG, viewInstanceCount));
LogUtils.d(CACHE_PROTECT_TAG, "视图缓存工具实例有效(永久驻留)");
int viewCount = MemoryCachedBackgroundView.getInstanceCount();
LogUtils.d(CACHE_PROTECT_TAG, "视图缓存实例总数:" + viewCount);
}
LogUtils.d(TAG, "logDetailedCacheStatus() 详细缓存状态记录完成,所有缓存均极致强制保持");
LogUtils.d(TAG, "logDetailedCacheStatus() | 缓存状态记录完成");
}
}

View File

@@ -26,16 +26,18 @@ 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.BackgroundBean;
import cc.winboll.studio.powerbell.models.BatteryStyle;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.unittest.MainUnitTest2Activity;
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.ImageUtils;
import cc.winboll.studio.powerbell.utils.PermissionUtils;
import cc.winboll.studio.powerbell.utils.ServiceUtils;
import cc.winboll.studio.powerbell.views.BatteryStyleView;
import cc.winboll.studio.powerbell.views.MainContentView;
import cc.winboll.studio.libappbase.ToastUtils;
/**
* 应用核心主活动
@@ -45,38 +47,42 @@ import cc.winboll.studio.libappbase.ToastUtils;
*/
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值========================
// ======================== 静态常量区(抽离魔法值,按功能分类========================
public static final String TAG = "MainActivity";
private static final int REQUEST_BACKGROUND_SETTINGS_ACTIVITY = 1001;
public static final String EXTRA_ISRELOAD_BACKGROUNDVIEW = "EXTRA_ISRELOAD_BACKGROUNDVIEW";
public static final String EXTRA_ISRELOAD_ACCENTCOLOR = "EXTRA_ISRELOAD_ACCENTCOLOR";
private static final long DELAY_LOAD_NON_CRITICAL = 500L;
// 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_UPDATE_SERVICE_SWITCH = 3;
private static final int MSG_UPDATE_BATTERYDRAWABLE = 4;
// ======================== 静态成员(全局共享,严格管控生命周期)========================
// ======================== 静态成员(全局共享,管控生命周期)========================
private static MainActivity sMainActivity;
private static Handler sGlobalHandler;
// ======================== 工具类实例(单例,避免重复初始化)========================
// ======================== 工具类实例(单例,避免重复初始化)========================
private PermissionUtils mPermissionUtils;
private AppConfigUtils mAppConfigUtils;
private BackgroundSourceUtils mBgSourceUtils;
// ======================== 应用核心实例 =========================
// ======================== 应用核心实例 =========================
private App mApplication;
private MainContentView mMainContentView;
private ControlCenterServiceBean mServiceControlBean;
// ======================== 基础视图组件 =========================
// ======================== 基础视图组件 =========================
private Toolbar mToolbar;
private ViewStub mAdsViewStub;
private ADsBannerView mADsBannerView;
private Drawable mFrameDrawable;
private Menu mMenu;
// ======================== 生命周期方法(按系统调用顺序排列)========================
// ======================== 生命周期方法(按系统调用顺序排列)========================
@Override
public Activity getActivity() {
return this;
@@ -90,7 +96,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.d(TAG, String.format("onCreate() | savedInstanceState=%s", savedInstanceState));
LogUtils.d(TAG, "onCreate() 调用 | savedInstanceState: " + savedInstanceState);
initGlobalHandler();
setContentView(R.layout.activity_main);
@@ -99,51 +105,32 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
initCriticalView();
initCoreUtilsAsync();
loadNonCriticalViewDelayed();
// 处理首次启动参数
handleReloadBackgroundParam(getIntent());
// 处理首次启动参数
handleReloadBackgroundParam(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
LogUtils.d(TAG, "onNewIntent() 调用 | intent: " + intent);
// 关键更新Activity持有的Intent确保后续获取最新值
setIntent(intent);
// 统一处理刷新背景参数
handleReloadBackgroundParam(intent);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 关键:将新 Intent 赋值给 Activity 的 Intent确保后续 getIntent() 获取最新值
setIntent(intent);
// 统一处理参数
handleReloadBackgroundParam(intent);
}
/**
* 统一处理刷新背景的参数
* @param intent 启动 MainActivity 的 Intent
*/
private void handleReloadBackgroundParam(Intent intent) {
if (intent == null) {
LogUtils.d(TAG, "handleReloadBackgroundParam: Intent 为空");
return;
}
// 获取传递的参数,默认值为 false
boolean isReloadBackgroundView = intent.getBooleanExtra(EXTRA_ISRELOAD_BACKGROUNDVIEW, false);
if (isReloadBackgroundView) {
LogUtils.d(TAG, "接收到刷新背景视图指令");
// 执行背景刷新逻辑
//App.notifyMessage(TAG, "reloadBackgroundView");
reloadBackgroundView();
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, String.format("onPostCreate() | savedInstanceState=%s", savedInstanceState));
LogUtils.d(TAG, "onPostCreate() 调用 | savedInstanceState: " + savedInstanceState);
mPermissionUtils.startPermissionRequest(this);
}
@Override
protected void onResume() {
super.onResume();
LogUtils.d(TAG, "onResume()");
LogUtils.d(TAG, "onResume() 调用");
if (mADsBannerView != null) {
mADsBannerView.resumeADs(this);
@@ -154,13 +141,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onPause() {
super.onPause();
LogUtils.d(TAG, "onPause()");
LogUtils.d(TAG, "onPause() 调用");
}
@Override
protected void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy()");
LogUtils.d(TAG, "onDestroy() 调用");
// 释放广告资源
if (mADsBannerView != null) {
@@ -174,7 +161,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
}
// 销毁Handler防止内存泄漏
// 销毁Handler防止内存泄漏
if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null;
@@ -186,7 +173,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 框架Drawable已释放");
}
// 置空所有引用
// 置空所有引用,消除内存泄漏风险
sMainActivity = null;
mPermissionUtils = null;
mAppConfigUtils = null;
@@ -201,21 +188,23 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d | data=%s",
requestCode, resultCode, data));
LogUtils.d(TAG, "onActivityResult() 调用 | requestCode: " + requestCode + " | resultCode: " + resultCode + " | data: " + data);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
if (requestCode == REQUEST_BACKGROUND_SETTINGS_ACTIVITY && sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 发送背景加载消息");
}
}
// ======================== 菜单与导航方法 ========================
// ======================== 菜单与导航方法 ========================
@Override
public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, String.format("onCreateOptionsMenu() | menu=%s", menu));
LogUtils.d(TAG, "onCreateOptionsMenu() 调用 | menu: " + menu);
mMenu = menu;
AESThemeUtil.inflateMenu(this, menu);
// 调试模式加载测试菜单
if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
@@ -227,14 +216,21 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, String.format("onOptionsItemSelected() | itemId=%d", item.getItemId()));
LogUtils.d(TAG, "onOptionsItemSelected() 调用 | itemId: " + item.getItemId());
// 主题切换处理
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate();
Intent mainIntent = new Intent(MainActivity.this, MainActivity.class);
mainIntent.putExtra(MainActivity.EXTRA_ISRELOAD_BACKGROUNDVIEW, true);
mainIntent.putExtra(MainActivity.EXTRA_ISRELOAD_ACCENTCOLOR, true);
startActivity(mainIntent);
return true;
}
// 开发者功能处理
if (DevelopUtils.onDevelopItemSelected(this, item)) {
return true;
}
// 菜单点击事件分发
switch (item.getItemId()) {
case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class));
@@ -266,7 +262,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void setupToolbar() {
super.setupToolbar();
LogUtils.d(TAG, "setupToolbar()");
LogUtils.d(TAG, "setupToolbar() 调用");
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 已隐藏返回按钮");
@@ -275,35 +271,37 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override
public void onBackPressed() {
LogUtils.d(TAG, "onBackPressed()");
LogUtils.d(TAG, "onBackPressed() 调用");
moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用已退至后台");
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
LogUtils.d(TAG, String.format("dispatchKeyEvent() | event=%s", event));
LogUtils.d(TAG, "dispatchKeyEvent() 调用 | event: " + event);
return super.dispatchKeyEvent(event);
}
// ======================== 核心初始化方法 ========================
// ======================== 核心初始化方法 ========================
private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils()");
LogUtils.d(TAG, "initPermissionUtils() 调用");
mPermissionUtils = PermissionUtils.getInstance();
LogUtils.d(TAG, "initPermissionUtils: 权限工具类已初始化");
}
private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler()");
LogUtils.d(TAG, "initGlobalHandler() 调用");
if (sGlobalHandler == null) {
sGlobalHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Activity已销毁则跳过消息处理
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, String.format("handleMessage: Activity已销毁跳过消息 | what=%d", msg.what));
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what: " + msg.what);
return;
}
LogUtils.d(TAG, String.format("handleMessage() | what=%d", msg.what));
LogUtils.d(TAG, "handleMessage() 调用 | what: " + msg.what);
switch (msg.what) {
case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData();
@@ -311,7 +309,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
case MSG_CURRENTVALUEBATTERY:
if (sMainActivity.mMainContentView != null) {
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
LogUtils.d(TAG, String.format("handleMessage: 更新当前电量 | value=%d", msg.arg1));
LogUtils.d(TAG, "handleMessage: 更新当前电量 | value: " + msg.arg1);
}
break;
case MSG_LOAD_BACKGROUND:
@@ -319,6 +317,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
break;
case MSG_UPDATE_SERVICE_SWITCH:
sMainActivity.updateServiceSwitchUI();
break;
case MSG_UPDATE_BATTERYDRAWABLE:
sMainActivity.updateBatteryDrawable();
break;
}
}
@@ -330,18 +331,14 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView()");
LogUtils.d(TAG, "initMainContentView() 调用");
View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this);
LogUtils.d(TAG, "initMainContentView: 核心内容视图已初始化");
}
private void reloadBackgroundView() {
mMainContentView.reloadBackgroundView();
}
private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView()");
LogUtils.d(TAG, "initCriticalView() 调用");
sMainActivity = this;
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
@@ -354,11 +351,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync()");
LogUtils.d(TAG, "initCoreUtilsAsync() 调用");
new Thread(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, String.format("initCoreUtilsAsync: 异步线程启动 | threadId=%d", Thread.currentThread().getId()));
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动 | threadId: " + Thread.currentThread().getId());
mApplication = (App) getApplication();
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
@@ -374,8 +371,8 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// 根据配置启停服务
final boolean isServiceEnable = mServiceControlBean.isEnableService();
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
LogUtils.d(TAG, String.format("initCoreUtilsAsync: 服务配置状态 | isServiceEnable=%b | isServiceAlive=%b",
isServiceEnable, isServiceAlive));
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置状态 | isServiceEnable: " + isServiceEnable + " | isServiceAlive: " + isServiceAlive);
if (isServiceEnable && !isServiceAlive) {
runOnUiThread(new Runnable() {
@Override
@@ -402,7 +399,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.w(TAG, "initCoreUtilsAsync: Activity已销毁跳过UI更新");
return;
}
// 加载框架背景适配API23+
// 适配API30兼容低版本Drawable加载
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mFrameDrawable = getResources().getDrawable(R.drawable.bg_frame, getTheme());
} else {
@@ -419,7 +416,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, String.format("loadNonCriticalViewDelayed() | 延迟时长=%dms", DELAY_LOAD_NON_CRITICAL));
LogUtils.d(TAG, "loadNonCriticalViewDelayed() 调用 | 延迟时长: " + DELAY_LOAD_NON_CRITICAL + "ms");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
@@ -432,9 +429,34 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}, DELAY_LOAD_NON_CRITICAL);
}
// ======================== 视图操作方法 ========================
// ======================== 视图操作方法 ========================
private void handleReloadBackgroundParam(Intent intent) {
LogUtils.d(TAG, "handleReloadBackgroundParam() 调用 | intent: " + intent);
if (intent == null) {
LogUtils.d(TAG, "handleReloadBackgroundParam: Intent 为空");
return;
}
boolean isReloadAccentColor = intent.getBooleanExtra(EXTRA_ISRELOAD_ACCENTCOLOR, false);
if (isReloadAccentColor) {
App.sBackgroundSourceUtils.getCurrentBackgroundBean().setPixelColor(ImageUtils.getColorAccent(this));
App.sBackgroundSourceUtils.saveSettings();
}
boolean isReloadBackgroundView = intent.getBooleanExtra(EXTRA_ISRELOAD_BACKGROUNDVIEW, false);
if (isReloadBackgroundView) {
LogUtils.d(TAG, "handleReloadBackgroundParam: 接收到刷新背景视图指令");
reloadBackgroundView();
}
}
private void reloadBackgroundView() {
LogUtils.d(TAG, "reloadBackgroundView() 调用");
mMainContentView.reloadBackgroundView();
}
private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView()");
LogUtils.d(TAG, "loadAdsView() 调用");
if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空加载失败");
return;
@@ -449,7 +471,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void updateViewData() {
LogUtils.d(TAG, "updateViewData()");
LogUtils.d(TAG, "updateViewData() 调用");
if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图或框架背景为空,更新失败");
return;
@@ -458,15 +480,25 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "updateViewData: 视图数据已更新");
}
void updateBatteryDrawable() {
BatteryStyle batteryStyle = BatteryStyleView.getSavedBatteryStyle(this);
mMainContentView.updateBatteryDrawable(batteryStyle);
}
public static void sendUpdateBatteryDrawableMessage() {
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_BATTERYDRAWABLE);
}
}
private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground()");
LogUtils.d(TAG, "reloadBackground() 调用");
if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图或背景工具类为空,加载失败");
return;
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
//ToastUtils.show("currentBgBean");
mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean, true);
LogUtils.d(TAG, "reloadBackground: 已加载自定义背景");
} else {
@@ -476,7 +508,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI()");
LogUtils.d(TAG, "updateServiceSwitchUI() 调用");
if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图或服务配置为空,更新失败");
return;
@@ -485,12 +517,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, String.format("updateServiceSwitchUI: 服务开关已更新 | 状态=%b", configEnabled));
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关已更新 | 状态: " + configEnabled);
}
// ======================== 服务与线程管理方法 ========================
// ======================== 服务与线程管理方法 ========================
private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, String.format("toggleServiceEnableState() | 目标状态=%b", isEnable));
LogUtils.d(TAG, "toggleServiceEnableState() 调用 | 目标状态: " + isEnable);
if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return;
@@ -513,9 +545,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
}
// ======================== 页面跳转方法 ========================
// ======================== 页面跳转方法 ========================
private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity()");
LogUtils.d(TAG, "startAboutActivity() 调用");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
@@ -523,16 +555,16 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
LogUtils.d(TAG, "startAboutActivity: 关于页面已启动");
}
// ======================== 消息发送方法 ========================
// ======================== 消息发送方法 ========================
private void notifyServiceAppConfigChange() {
LogUtils.d(TAG, "notifyServiceAppConfigChange()");
LogUtils.d(TAG, "notifyServiceAppConfigChange() 调用");
ControlCenterService.sendAppConfigStatusUpdateMessage(this);
reloadAppConfig();
LogUtils.d(TAG, "notifyServiceAppConfigChange: 服务配置已通知更新");
}
public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig()");
LogUtils.d(TAG, "reloadAppConfig() 调用");
if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
LogUtils.d(TAG, "reloadAppConfig: 配置重载消息已发送");
@@ -542,7 +574,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, String.format("sendCurrentBatteryValueMessage() | 电量=%d", value));
LogUtils.d(TAG, "sendCurrentBatteryValueMessage() 调用 | 电量: " + value);
if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value;
@@ -553,9 +585,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
}
// ======================== 辅助工具方法 ========================
// ======================== 辅助工具方法 ========================
private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo()");
LogUtils.d(TAG, "genDefaultAppInfo() 调用");
String branchName = "powerbell";
APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name));
@@ -572,34 +604,34 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
return appInfo;
}
// ======================== MainContentView 事件回调 ========================
// ======================== MainContentView 事件回调 ========================
@Override
public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, String.format("onChargeReminderSwitchChanged() | isChecked=%b", isChecked));
LogUtils.d(TAG, "onChargeReminderSwitchChanged() 调用 | isChecked: " + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, String.format("onUsageReminderSwitchChanged() | isChecked=%b", isChecked));
LogUtils.d(TAG, "onUsageReminderSwitchChanged() 调用 | isChecked: " + isChecked);
notifyServiceAppConfigChange();
}
@Override
public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, String.format("onServiceSwitchChanged() | isChecked=%b", isChecked));
LogUtils.d(TAG, "onServiceSwitchChanged() 调用 | isChecked: " + isChecked);
toggleServiceEnableState(isChecked);
}
@Override
public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, String.format("onChargeReminderProgressChanged() | progress=%d", progress));
LogUtils.d(TAG, "onChargeReminderProgressChanged() 调用 | progress: " + progress);
notifyServiceAppConfigChange();
}
@Override
public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, String.format("onUsageReminderProgressChanged() | progress=%d", progress));
LogUtils.d(TAG, "onUsageReminderProgressChanged() 调用 | progress: " + progress);
notifyServiceAppConfigChange();
}
}

View File

@@ -25,7 +25,6 @@ import androidx.core.content.FileProvider;
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
@@ -48,16 +47,19 @@ import java.io.File;
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class BackgroundSettingsActivity extends WinBoLLActivity {
// ====================== 常量定义(按功能分类)======================
// ====================== 常量定义(按功能分类排序======================
public static final String TAG = "BackgroundSettingsActivity";
// 系统版本常量
private static final int SDK_VERSION_TIRAMISU = 33;
// 请求码(按功能分组)
// 请求码(按功能分组,从小到大排序)
public static final int REQUEST_SELECT_PICTURE = 0;
public static final int REQUEST_TAKE_PHOTO = 1;
public static final int REQUEST_CROP_IMAGE = 2;
private static final int REQUEST_PIXELPICKER = 1001;
private static final int REQUEST_CAMERA_PERMISSION = 1004;
// Bitmap解析常量
private static final int BITMAP_MAX_SIZE = 2048;
private static final int BITMAP_MAX_SAMPLE_SIZE = 16;
@@ -66,9 +68,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
// 工具类实例
private BackgroundSourceUtils mBgSourceUtils;
private BitmapCacheUtils mBitmapCache;
// 视图组件
private Toolbar mToolbar;
private BackgroundView mBackgroundView;
// 状态标记volatile保证多线程可见性
private volatile boolean isCommitSettings = false;
private volatile boolean isPreviewBackgroundChanged = false;
@@ -92,16 +96,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
// 初始化核心组件
initCoreComponents();
// 初始化界面与事件
// 初始化Toolbar与点击事件
initToolbar();
initClickListeners();
LogUtils.d(TAG, "界面与事件绑定完成");
LogUtils.d(TAG, "onCreate() 视图与事件绑定完成");
// 处理分享意图或初始化预览
handleIntentOrPreview();
// 初始化预览环境并刷新
initPreviewEnvironment();
LogUtils.d(TAG, "onCreate() 初始化完成");
}
@@ -124,13 +128,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
// 此时已获取真实宽高
int width = mBackgroundView.getWidth();
int height = mBackgroundView.getHeight();
LogUtils.d(TAG, String.format("onPostCreate() 获取视图尺寸 | width=%d | height=%d", width, height));
if (width > 0 && height > 0) {
AppConfigUtils appConfigUtils = AppConfigUtils.getInstance(BackgroundSettingsActivity.this);
appConfigUtils.loadAppConfig();
appConfigUtils.mAppConfigBean.setDefaultFrameWidth(width);
appConfigUtils.mAppConfigBean.setDefaultFrameHeight(height);
appConfigUtils.saveAppConfig();
LogUtils.d(TAG, String.format("保存默认相框尺寸 | width=%d | height=%d", width, height));
LogUtils.d(TAG, "onPostCreate() 保存默认相框尺寸成功");
doubleRefreshPreview();
}
}
@@ -140,24 +145,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d", requestCode, resultCode));
LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d | data=%s",
requestCode, resultCode, data != null ? data.toString() : "null"));
try {
if (resultCode != RESULT_OK) {
LogUtils.d(TAG, "结果非RESULT_OK执行取消逻辑");
LogUtils.d(TAG, String.format("onActivityResult() 操作取消 | requestCode=%d", requestCode));
handleOperationCancelOrFail();
return;
}
handleActivityResult(requestCode, data);
} catch (Exception e) {
LogUtils.e(TAG, String.format("onActivityResult() 异常 | requestCode=%d | 异常信息=%s", requestCode, e.getMessage()));
LogUtils.e(TAG, String.format("onActivityResult() 异常 | requestCode=%d | 异常信息=%s",
requestCode, e.getMessage()));
ToastUtils.show("操作失败");
}
}
@Override
public void finish() {
LogUtils.d(TAG, String.format("finish() | isCommitSettings=%b | isPreviewBackgroundChanged=%b", isCommitSettings, isPreviewBackgroundChanged));
LogUtils.d(TAG, String.format("finish() | isCommitSettings=%b | isPreviewBackgroundChanged=%b",
isCommitSettings, isPreviewBackgroundChanged));
if (isCommitSettings) {
super.finish();
} else {
@@ -169,7 +177,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
LogUtils.d(TAG, String.format("onRequestPermissionsResult() | requestCode=%d | 权限数量=%d", requestCode, permissions.length));
LogUtils.d(TAG, String.format("onRequestPermissionsResult() | requestCode=%d | 权限数量=%d | 结果数量=%d",
requestCode, permissions.length, grantResults.length));
if (requestCode == REQUEST_CAMERA_PERMISSION) {
handleCameraPermissionResult(grantResults);
}
@@ -883,7 +892,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
* @param fileSize 文件大小
*/
private void handleCropFailure(boolean isFileExist, boolean isFileReadable, long fileSize) {
LogUtils.e(TAG, String.format("handleCropFailure() | 裁剪失败,文件状态:存在=%b可读=%b大小=%d", isFileExist, isFileReadable, fileSize));
LogUtils.e(TAG, String.format("handleCropFailure() | 裁剪失败,文件状态:存在=%b可读=%b大小=%d",
isFileExist, isFileReadable, fileSize));
handleOperationCancelOrFail();
}
@@ -939,16 +949,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
mBgSourceUtils.commitPreviewSourceToCurrent();
isCommitSettings = true;
finish();
//App.notifyMessage(TAG, "startActivity");
Intent mainIntent = new Intent(BackgroundSettingsActivity.this, MainActivity.class);
mainIntent.putExtra(MainActivity.EXTRA_ISRELOAD_BACKGROUNDVIEW, true);
startActivity(mainIntent);
LogUtils.d(TAG, "handleFinishConfirmation() | 确认设置启动MainActivity并刷新背景");
}
@Override
public void onNo() {
isCommitSettings = true;
finish();
LogUtils.d(TAG, "handleFinishConfirmation() | 取消设置,关闭页面");
}
});
} else {

View File

@@ -34,32 +34,34 @@ import java.util.Map;
/**
* 电池报告页面统计应用24小时运行时长与电池消耗情况
* 支持应用搜索、累计耗电计算、电池广播监听,适配 API30
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/10/22 13:21
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLActivity {
// ======================== 静态常量 =========================
// ======================== 静态常量(按功能分类) =========================
public static final String TAG = "BatteryReportActivity";
private static final long ONE_DAY_MS = 24 * 3600 * 1000; // 24小时毫秒数
private static final long ONE_MINUTE_MS = 60 * 1000; // 1分钟毫秒数
private static final long ONE_DAY_MS = 24 * 3600 * 1000; // 24小时毫秒数
private static final long ONE_MINUTE_MS = 60 * 1000; // 1分钟毫秒数
// ======================== 成员变量 =========================
// ======================== 成员变量(按依赖优先级+功能分类) =========================
// UI组件
private Toolbar mToolbar;
private RecyclerView rvBatteryReport;
private EditText etSearch;
// 数据与适配器
private BatteryReportAdapter adapter;
private List<AppBatteryModel> dataList = new ArrayList<AppBatteryModel>();
private List<AppBatteryModel> filteredList = new ArrayList<AppBatteryModel>();
private List<AppBatteryModel> dataList = new ArrayList<>();
private List<AppBatteryModel> filteredList = new ArrayList<>();
// 电池相关
private BroadcastReceiver batteryReceiver;
private int batteryCapacity = 5400; // 电池容量mAh
private float lastBatteryPercent = 100.0f;
private long lastCheckTime = System.currentTimeMillis();
private int batteryCapacity = 5400; // 电池容量mAh
private float lastBatteryPercent = 100.0f; // 上次电池百分比
private long lastCheckTime = System.currentTimeMillis(); // 上次检查时间戳
// 缓存相关
private Map<String, Long> appRunTimeCache = new HashMap<String, Long>();
private Map<String, String> packageToAppNameCache = new HashMap<String, String>();
private Map<String, Long> appRunTimeCache = new HashMap<>();
private Map<String, String> packageToAppNameCache = new HashMap<>();
private PackageManager mPackageManager;
// ======================== 接口实现方法 =========================
@@ -73,7 +75,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
return TAG;
}
// ======================== 生命周期方法 =========================
// ======================== 生命周期方法(按执行顺序排列) =========================
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -84,6 +86,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
initView();
// 初始化PackageManager
mPackageManager = getPackageManager();
LogUtils.d(TAG, "【onCreate】基础组件初始化完成");
// 权限检查Java7 传统条件判断)
if (!hasUsageStatsPermission(this)) {
@@ -100,15 +103,15 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
updateAppRunTimeToModel();
calculateInitial24hTotalConsumption();
filteredList.addAll(dataList);
LogUtils.d(TAG, "【onCreate】数据初始化完成原始数据量" + dataList.size());
// 初始化适配器
adapter = new BatteryReportAdapter(this, filteredList, mPackageManager, packageToAppNameCache);
rvBatteryReport.setAdapter(adapter);
LogUtils.d(TAG, "【onCreate】适配器初始化完成数据量" + filteredList.size());
LogUtils.d(TAG, "【onCreate】适配器初始化完成过滤后数据量:" + filteredList.size());
// 绑定搜索监听
// 绑定搜索监听 + 注册电池广播
bindSearchListener();
// 注册电池广播
registerBatteryReceiver();
LogUtils.d(TAG, "【onCreate】BatteryReportActivity 初始化完成");
@@ -156,8 +159,9 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
LogUtils.d(TAG, "【bindSearchListener】搜索关键词变化" + s.toString());
filterAppsByPackageAndName(s.toString());
String keyword = s.toString().trim();
LogUtils.d(TAG, "【bindSearchListener】搜索关键词变化" + keyword);
filterAppsByPackageAndName(keyword);
}
@Override
@@ -180,11 +184,14 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
float dropPercent = lastBatteryPercent - currentPercent;
long duration = System.currentTimeMillis() - lastCheckTime;
LogUtils.d(TAG, "【电池广播】电池消耗:" + dropPercent + "%,时长:" + formatRunTime(duration));
// 更新运行时长并计算耗电
appRunTimeCache = getAppRunTime();
updateAppRunTimeToModel();
calculateSingleConsumptionAndAccumulate(dropPercent, appRunTimeCache);
}
// 刷新记录
lastBatteryPercent = currentPercent;
lastCheckTime = System.currentTimeMillis();
}
@@ -229,15 +236,12 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
private void loadAllAppPackage() {
List<ApplicationInfo> appList = mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);
dataList.clear();
LogUtils.d(TAG, "【loadAllAppPackage】开始加载应用包名列表共找到" + appList.size() + "个应用");
for (ApplicationInfo appInfo : appList) {
String packageName = appInfo.packageName;
// 初始化:单次耗电=0累计耗电=0运行时长=0
dataList.add(new AppBatteryModel(packageName, 0.0f, 0.0f, 0));
}
LogUtils.d(TAG, "【loadAllAppPackage】应用包名列表加载完成共添加" + dataList.size() + "个包名");
}
@@ -253,7 +257,6 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
String appName = getAppNameByPackage(packageName);
packageToAppNameCache.put(packageName, appName);
}
LogUtils.d(TAG, "【preCacheAllAppNames】预缓存完成共缓存" + packageToAppNameCache.size() + "个应用名称");
}
@@ -263,6 +266,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
* @return 应用名称,获取失败返回包名
*/
private String getAppNameByPackage(String packageName) {
LogUtils.v(TAG, "【getAppNameByPackage】查询包名" + packageName);
try {
ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
return mPackageManager.getApplicationLabel(appInfo).toString();
@@ -296,7 +300,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
* @return 应用包名-运行时长ms映射
*/
private Map<String, Long> getAppRunTime() {
Map<String, Long> runTimeMap = new HashMap<String, Long>();
Map<String, Long> runTimeMap = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
android.app.usage.UsageStatsManager manager =
@@ -341,7 +345,6 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
String packageName = model.getPackageName();
Long app24hRunTime = appRunTimeCache.getOrDefault(packageName, 0L);
// 计算占比与累计耗电
float ratio = (total24hRunTime > 0) ? (float) app24hRunTime / total24hRunTime : 0;
float initialTotalConsumption = batteryCapacity * ratio;
model.setTotalConsumption(initialTotalConsumption);
@@ -351,11 +354,12 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
}
/**
* 计算单次耗电赋值给consumption+ 累加至累计耗电totalConsumption = totalConsumption + consumption
* 计算单次耗电赋值给consumption+ 累加至累计耗电
* @param dropPercent 电池下降百分比
* @param runTimeMap 应用运行时长映射
* @param runTimeMap 应用运行时长映射
*/
private void calculateSingleConsumptionAndAccumulate(float dropPercent, Map<String, Long> runTimeMap) {
LogUtils.d(TAG, "【calculateSingleConsumptionAndAccumulate】开始计算电池下降百分比" + dropPercent);
long totalSingleRunTime = 0;
// 1. 计算本次电池下降期间的总运行时长
for (Map.Entry<String, Long> entry : runTimeMap.entrySet()) {
@@ -363,28 +367,25 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
}
LogUtils.d(TAG, "【calculateSingleConsumptionAndAccumulate】本次电池下降总运行时长" + formatRunTime(totalSingleRunTime));
// 2. 遍历计算每个应用的单次耗电”并“累加至累计”
// 2. 遍历计算每个应用的单次耗电并累加
for (AppBatteryModel model : dataList) {
String packageName = model.getPackageName();
Long appSingleRunTime = runTimeMap.getOrDefault(packageName, 0L);
// 步骤1计算本次单次耗电
float ratio = (totalSingleRunTime > 0) ? (float) appSingleRunTime / totalSingleRunTime : 0;
float singleConsumption = batteryCapacity * dropPercent / 100 * ratio;
model.setConsumption(singleConsumption);
// 步骤2累加单次耗电到累计耗电
// 累加至累计耗电
float newTotalConsumption = model.getTotalConsumption() + singleConsumption;
model.setTotalConsumption(newTotalConsumption);
// 同步运行时长
model.setRunTime(appSingleRunTime);
LogUtils.v(TAG, String.format("【calculateSingleConsumptionAndAccumulate】应用包%s单次耗电%.1f mAh累计耗电%.1f mAh",
packageName, singleConsumption, newTotalConsumption));
}
// 3. 按累计耗电排序(从高到低)
// 3. 按累计耗电降序排序
Collections.sort(dataList, new Comparator<AppBatteryModel>() {
@Override
public int compare(AppBatteryModel m1, AppBatteryModel m2) {
@@ -392,8 +393,8 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
}
});
// 4. 重新应用过滤并刷新列表
filterAppsByPackageAndName(etSearch.getText().toString());
// 4. 重新过滤并刷新列表
filterAppsByPackageAndName(etSearch.getText().toString().trim());
LogUtils.d(TAG, "【calculateSingleConsumptionAndAccumulate】单次耗电计算与累加完成列表已刷新");
}
@@ -414,9 +415,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
String appName = packageToAppNameCache.get(packageName);
String appNameLower = appName.toLowerCase();
boolean isMatched = packageNameLower.contains(lowerKeyword)
|| appNameLower.contains(lowerKeyword);
boolean isMatched = packageNameLower.contains(lowerKeyword) || appNameLower.contains(lowerKeyword);
if (isMatched) {
filteredList.add(model);
}
@@ -456,7 +455,6 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
* - consumption单次耗电两次电池广播间的消耗
* - totalConsumption累计耗电24小时初始化值+后续单次累加)
* - runTime运行时长ms
* - packageName应用包名
*/
public static class AppBatteryModel {
private String packageName; // 应用包名(核心标识)
@@ -519,6 +517,7 @@ public class BatteryReportActivity extends WinBoLLActivity implements IWinBoLLAc
this.mDataList = dataList;
this.mPm = pm;
this.mPackageToNameCache = packageToNameCache;
LogUtils.d(TAG, "【BatteryReportAdapter】适配器构造完成数据量" + dataList.size());
}
@Override

View File

@@ -22,19 +22,20 @@ import java.util.ArrayList;
/**
* 电池记录清理页面,支持滑动清理记录、切换记录显示格式
* 适配 API30基于 Java7 开发
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActivity {
// ======================== 静态常量 =========================
// ======================== 静态常量(按功能分类) =========================
public static final String TAG = "ClearRecordActivity";
private static final String TOAST_MSG_CLEAR_SUCCESS = "The APP battery record is cleaned.";
// ======================== 成员变量 =========================
// ======================== 成员变量(按依赖优先级+功能分类) =========================
// UI组件
private Toolbar mToolbar;
private TextView mtvRecordText;
private TextView tvAOHPCTCSeekBarMSG;
private AOHPCTCSeekBar aOHPCTCSeekBar;
// 应用与配置
private App mApplication;
private boolean mIsShowRecordWithEnter = false; // 记录是否带换行显示
@@ -50,7 +51,7 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
return TAG;
}
// ======================== 生命周期方法 =========================
// ======================== 生命周期方法(按执行顺序排列) =========================
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -59,11 +60,11 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
// 初始化应用实例
mApplication = (App) getApplication();
// 初始化UI组件
LogUtils.d(TAG, "【onCreate】应用实例初始化完成");
// 初始化核心逻辑
initView();
// 初始化滑动清理控件
initSeekBar();
// 初始化记录显示文本
initRecordText();
LogUtils.d(TAG, "【onCreate】ClearRecordActivity 初始化完成");
@@ -75,7 +76,7 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
*/
private void initView() {
// 初始化Toolbar
mToolbar = findViewById(R.id.toolbar);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
mToolbar.setSubtitle(getTag());
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
@@ -83,29 +84,30 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "【导航栏】点击返回");
LogUtils.d(TAG, "【导航栏】点击返回按钮,关闭当前页面");
finish();
}
});
// 初始化显示文本组件
tvAOHPCTCSeekBarMSG = findViewById(R.id.activityclearrecordTextView1);
mtvRecordText = findViewById(R.id.activityclearrecordTextView2);
tvAOHPCTCSeekBarMSG = (TextView) findViewById(R.id.activityclearrecordTextView1);
mtvRecordText = (TextView) findViewById(R.id.activityclearrecordTextView2);
tvAOHPCTCSeekBarMSG.setText(R.string.msg_AOHPCTCSeekBar_ClearRecord);
LogUtils.d(TAG, "【initView】UI组件初始化完成");
}
/**
* 初始化滑动清理控件
* 初始化滑动清理控件,设置回调监听
*/
private void initSeekBar() {
aOHPCTCSeekBar = findViewById(R.id.activityclearrecordAOHPCTCSeekBar1);
aOHPCTCSeekBar = (AOHPCTCSeekBar) findViewById(R.id.activityclearrecordAOHPCTCSeekBar1);
aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.cursor_pointer));
aOHPCTCSeekBar.setThumbOffset(0);
aOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
@Override
public void onOHPCommit() {
LogUtils.d(TAG, "【onOHPCommit】滑动清理触发");
LogUtils.d(TAG, "【onOHPCommit】滑动清理触发,开始执行记录清理逻辑");
// 清理电池历史记录
mApplication.clearBatteryHistory();
// 发送广播更新前台通知
@@ -114,10 +116,11 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
initRecordText();
// 提示清理成功
ToastUtils.show(TOAST_MSG_CLEAR_SUCCESS);
LogUtils.d(TAG, "【onOHPCommit】电池记录清理完成已发送更新广播");
LogUtils.d(TAG, "【onOHPCommit】电池记录清理完成已发送前台通知更新广播");
}
});
LogUtils.d(TAG, "【initSeekBar】滑动清理控件初始化完成");
LogUtils.d(TAG, "【initSeekBar】滑动清理控件初始化完成回调监听已绑定");
}
// ======================== 业务逻辑方法 =========================
@@ -131,20 +134,20 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
// 判空处理:避免空列表导致异常
if (listBatteryInfo == null || listBatteryInfo.isEmpty()) {
szRecordText = getString(R.string.msg_no_battery_record);
LogUtils.d(TAG, "【initRecordText】无电池记录数据");
LogUtils.d(TAG, "【initRecordText】无电池记录数据,显示空记录提示文本");
} else {
// 根据配置切换显示格式
if (mIsShowRecordWithEnter) {
szRecordText = StringUtils.formatPCMListStringWithEnter(listBatteryInfo);
LogUtils.d(TAG, "【initRecordText】使用带换行格式显示记录数量" + listBatteryInfo.size());
LogUtils.d(TAG, String.format("【initRecordText】使用带换行格式显示记录记录数量:%d", listBatteryInfo.size()));
} else {
szRecordText = StringUtils.formatPCMListString(listBatteryInfo);
LogUtils.d(TAG, "【initRecordText】使用无换行格式显示记录数量" + listBatteryInfo.size());
LogUtils.d(TAG, String.format("【initRecordText】使用无换行格式显示记录记录数量:%d", listBatteryInfo.size()));
}
}
mtvRecordText.setText(szRecordText);
LogUtils.d(TAG, "【initRecordText】记录显示文本初始化完成");
LogUtils.d(TAG, "【initRecordText】记录显示文本刷新完成");
}
// ======================== 事件回调方法 =========================
@@ -155,7 +158,7 @@ public class ClearRecordActivity extends WinBoLLActivity implements IWinBoLLActi
public void onShowRecordWithEnter(View view) {
Switch swShowRecordWithEnter = (Switch) view;
mIsShowRecordWithEnter = swShowRecordWithEnter.isChecked();
LogUtils.d(TAG, "【onShowRecordWithEnter】记录显示格式切换带换行" + mIsShowRecordWithEnter);
LogUtils.d(TAG, String.format("【onShowRecordWithEnter】记录显示格式切换带换行显示:%b", mIsShowRecordWithEnter));
// 刷新记录显示
initRecordText();
}

View File

@@ -16,6 +16,7 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.views.AToolbar;
import cc.winboll.studio.libappbase.LogUtils;
@@ -49,7 +50,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
// ======================== 成员变量 =========================
// UI组件
private AToolbar mAToolbar;
private Toolbar mToolbar;
private ImageView imageView;
private TextView infoText;
private ViewGroup imageContainer;
@@ -112,7 +113,6 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
* 初始化所有UI组件
*/
private void initView() {
mAToolbar = (AToolbar) findViewById(R.id.toolbar);
imageView = findViewById(R.id.imageView);
infoText = findViewById(R.id.infoText);
imageContainer = findViewById(R.id.imageContainer);
@@ -125,17 +125,24 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
* 初始化工具栏,设置导航与标题
*/
private void initToolbar() {
setActionBar(mAToolbar);
mAToolbar.setSubtitle(R.string.subtitle_activity_pixelpicker);
getActionBar().setDisplayHomeAsUpEnabled(true);
mAToolbar.setNavigationOnClickListener(new View.OnClickListener() {
LogUtils.d(TAG, "initToolbar() 开始初始化");
mToolbar = findViewById(R.id.toolbar);
if (mToolbar == null) {
LogUtils.e(TAG, "initToolbar() | Toolbar未找到");
return;
}
setSupportActionBar(mToolbar);
mToolbar.setSubtitle(getTag());
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d(TAG, "导航栏点击返回");
LogUtils.d(TAG, "导航栏 点击返回按钮");
finish();
}
});
LogUtils.d(TAG, "initToolbar】工具栏初始化完成");
LogUtils.d(TAG, "initToolbar() 配置完成");
}
// ======================== 业务逻辑方法 =========================

View File

@@ -0,0 +1,12 @@
package cc.winboll.studio.powerbell.models;
/**
* 电池绘制样式枚举 (单选选项)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public enum BatteryStyle {
ENERGY_STYLE, // 能量样式
ZEBRA_STYLE, // 条纹样式
POINT_STYLE // 点阵样式
}

View File

@@ -17,7 +17,7 @@ import cc.winboll.studio.libappbase.LogUtils;
*/
public class ControlCenterServiceBean extends BaseBean implements Parcelable, Serializable {
// ====================== 静态常量(置顶统一管理,避免魔法值) ======================
private static final long serialVersionUID = 1L; // Serializable 必备,保障反序列化兼容
//private static final long serialVersionUID = 1L; // Serializable 必备,保障反序列化兼容
private static final String TAG = "ControlCenterServiceBean";
private static final String JSON_FIELD_IS_ENABLE_SERVICE = "isEnableService"; // JSON 字段常量,避免硬编码

View File

@@ -48,7 +48,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
public ControlCenterServiceReceiver(ControlCenterService service) {
LogUtils.d(TAG, String.format("ControlCenterServiceReceiver() 构造 | 服务实例:%s",
service != null ? service.getClass().getSimpleName() : "null"));
this.mwrControlCenterService = new WeakReference<>(service);
this.mwrControlCenterService = new WeakReference<ControlCenterService>(service);
}
// ====================== 广播核心接收逻辑入口方法分Action分发处理 ======================

View File

@@ -78,7 +78,7 @@ public class ImageCropUtils {
// 3. 初始化 uCrop + 强制 PNG 配置(保留透明核心)
UCrop uCrop = UCrop.of(inputUri, outputUri);
uCrop.withAspectRatio(aspectX, aspectY);
//uCrop.withAspectRatio(aspectX, aspectY);
UCrop.Options options = initCropOptions(activity, isFreeCrop, aspectX, aspectY);
// 4. 启动裁剪
@@ -129,7 +129,7 @@ public class ImageCropUtils {
// 3. 初始化 uCrop + 强制 PNG 配置
UCrop uCrop = UCrop.of(inputUri, outputUri);
uCrop.withAspectRatio(aspectX, aspectY);
//uCrop.withAspectRatio(aspectX, aspectY);
UCrop.Options options = initCropOptions(activity, isFreeCrop, aspectX, aspectY);
// 4. 启动裁剪
@@ -296,7 +296,8 @@ public class ImageCropUtils {
// 裁剪模式配置(自由裁剪/固定比例)
options.setFreeStyleCropEnabled(isFreeCrop);
options.withAspectRatio(aspectX, aspectY);
// 核心:强制 PNG 保留透明(固定配置,无需判断原图格式)
options.setCompressionFormat(FORCE_COMPRESS_FORMAT); // 强制 PNG 压缩
options.setCompressionQuality(100); // PNG 100% 质量,不损失透明
@@ -305,7 +306,8 @@ public class ImageCropUtils {
options.setCropGridColor(activity.getResources().getColor(R.color.colorAccent)); // 网格线主题色
// 通用 UI 配置(保持原有风格)
options.setHideBottomControls(true); // 隐藏底部控制栏
//options.setHideBottomControls(true); // 隐藏底部控制栏
options.setToolbarTitle("图片裁剪");
options.setToolbarColor(activity.getResources().getColor(R.color.colorPrimary));
options.setToolbarWidgetColor(activity.getResources().getColor(android.R.color.white));

View File

@@ -156,13 +156,6 @@ public class BackgroundView extends RelativeLayout {
// 隐藏ImageView防止闪烁
mIvBackground.setVisibility(View.GONE);
// 初始化配置工具类并保存默认相框尺寸
AppConfigUtils appConfigUtils = AppConfigUtils.getInstance(mContext);
appConfigUtils.loadAppConfig();
LogUtils.d(TAG, String.format("【loadImage】默认相框尺寸 | W=%d | H=%d",
appConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
appConfigUtils.mAppConfigBean.getDefaultFrameHeight()));
// 刷新逻辑:重新解码原始品质图片并更新缓存
if (isRefresh) {
LogUtils.d(TAG, "【loadImage】执行刷新逻辑重新解码原始品质图片");
@@ -174,8 +167,8 @@ public class BackgroundView extends RelativeLayout {
// 合成纯色背景图片(使用配置文件中默认相框尺寸)
Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(
bgColor,
appConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
appConfigUtils.mAppConfigBean.getDefaultFrameHeight(),
App.sAppConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
App.sAppConfigUtils.mAppConfigBean.getDefaultFrameHeight(),
newBitmap
);

View File

@@ -7,6 +7,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.models.BatteryStyle;
/**
* 电池电量Drawable适配API30兼容小米机型支持能量/条纹两种绘制风格切换
@@ -31,7 +32,7 @@ public class BatteryDrawable extends Drawable {
private final Paint mBatteryPaint;
// 业务控制变量
private int mBatteryValue = -1; // 当前电量0-100-1=未初始化)
private boolean mIsEnergyStyle = true; // 绘制风格true=能量false=条纹)
private BatteryStyle mBatteryStyle = BatteryStyle.ENERGY_STYLE; // 绘制风格true=能量false=条纹)
// ====================================== 构造方法(重载适配,优先暴露常用构造) ======================================
/**
@@ -49,13 +50,16 @@ public class BatteryDrawable extends Drawable {
* @param batteryColor 电量显示颜色
* @param isEnergyStyle 是否启用能量风格
*/
public BatteryDrawable(int batteryColor, boolean isEnergyStyle) {
LogUtils.d(TAG, "【BatteryDrawable】构造器2调用 | 颜色=" + Integer.toHexString(batteryColor) + " | 风格=" + (isEnergyStyle ? "能量" : "条纹"));
public BatteryDrawable(int batteryColor, BatteryStyle batteryStyle) {
mBatteryPaint = new Paint();
mIsEnergyStyle = isEnergyStyle;
mBatteryStyle = batteryStyle;
initPaintConfig(batteryColor);
}
public void setIsEnergyStyle(BatteryStyle batteryStyle) {
this.mBatteryStyle = batteryStyle;
}
// ====================================== 私有初始化方法(封装复用,隐藏内部逻辑) ======================================
/**
* 初始化画笔配置适配API30渲染特性优化小米机型兼容性
@@ -74,8 +78,7 @@ public class BatteryDrawable extends Drawable {
// ====================================== 核心绘制方法Drawable抽象方法优先级最高 ======================================
@Override
public void draw(Canvas canvas) {
LogUtils.d(TAG, "【draw】绘制开始 | 当前电量=" + mBatteryValue + " | 风格=" + (mIsEnergyStyle ? "能量" : "条纹"));
// 未初始化/异常电量,直接跳过,避免无效绘制
// 未初始化/异常电量,直接跳过,避免无效绘制
if (mBatteryValue < 0) {
LogUtils.w(TAG, "【draw】电量未初始化跳过绘制");
return;
@@ -99,10 +102,12 @@ public class BatteryDrawable extends Drawable {
LogUtils.d(TAG, "【draw】绘制参数校准 | 左边界=" + left + " | 右边界=" + right + " | 高度=" + drawHeight);
// 按风格执行绘制
if (mIsEnergyStyle) {
if (mBatteryStyle == BatteryStyle.ENERGY_STYLE) {
drawEnergyStyle(canvas, validBattery, left, right, drawHeight);
} else {
drawStripeStyle(canvas, validBattery, left, right, drawHeight);
} else if (mBatteryStyle == BatteryStyle.ZEBRA_STYLE) {
drawZebraStyle(canvas, validBattery, left, right, drawHeight);
} else if (mBatteryStyle == BatteryStyle.POINT_STYLE) {
drawPointStyle(canvas, validBattery, left, right, drawHeight);
}
LogUtils.d(TAG, "【draw】绘制完成");
}
@@ -118,9 +123,25 @@ public class BatteryDrawable extends Drawable {
*/
private void drawEnergyStyle(Canvas canvas, int battery, int left, int right, int height) {
LogUtils.d(TAG, "【drawEnergyStyle】能量风格绘制开始 | 电量=" + battery);
int top = height - (height * battery / BATTERY_MAX); // 计算电量对应顶部坐标
canvas.drawRect(new Rect(left, top, right, height), mBatteryPaint);
LogUtils.d(TAG, "【drawEnergyStyle】能量风格绘制完成 | 顶部坐标=" + top);
// int top = height - (height * battery / BATTERY_MAX); // 计算电量对应顶部坐标
// canvas.drawRect(new Rect(left, top, right, height), mBatteryPaint);
// LogUtils.d(TAG, "【drawEnergyStyle】能量风格绘制完成 | 顶部坐标=" + top);
int nWidth = getBounds().width();
int nHeight = getBounds().height();
int mnDx = nHeight / 203;
// 绘制耗电电量提醒值电量
// 能量绘图风格
int nTop;
int nLeft = 0;
int nBottom;
int nRight = nWidth;
//for (int i = 0; i < mnValue; i ++) {
nBottom = nHeight;
nTop = nHeight - (nHeight * mBatteryValue / 100);
canvas.drawRect(new Rect(nLeft, nTop, nRight, nBottom), mBatteryPaint);
}
/**
@@ -131,15 +152,75 @@ public class BatteryDrawable extends Drawable {
* @param right 右边界
* @param height 绘制高度
*/
private void drawStripeStyle(Canvas canvas, int battery, int left, int right, int height) {
private void drawZebraStyle(Canvas canvas, int battery, int left, int right, int height) {
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制开始 | 电量=" + battery);
int stripeHeight = height / STRIPE_COUNT; // 单条条纹高度(均匀拆分)
// 从底部向上绘制对应电量条纹
for (int i = 0; i < battery; i++) {
int bottom = height - (stripeHeight * i);
int top = bottom - stripeHeight;
canvas.drawRect(new Rect(left, top, right, bottom), mBatteryPaint);
}
// int stripeHeight = height / STRIPE_COUNT; // 单条条纹高度(均匀拆分)
// // 从底部向上绘制对应电量条纹
// for (int i = 0; i < battery; i++) {
// int bottom = height - (stripeHeight * i);
// int top = bottom - stripeHeight;
// canvas.drawRect(new Rect(left, top, right, bottom), mBatteryPaint);
// }
int nWidth = getBounds().width();
int nHeight = getBounds().height();
int mnDx = nHeight / 203;
// 意兴阑珊绘图风格
int nTop;
int nLeft = 0;
int nBottom;
int nRight = nWidth;
for (int i = 0; i < mBatteryValue; i ++) {
nBottom = (nHeight * (100 - i) / 100) - mnDx;
nTop = nBottom + mnDx;
canvas.drawRect(new Rect(nLeft, nTop, nRight, nBottom), mBatteryPaint);
}
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制完成 | 条纹数量=" + battery);
}
/**
* 点阵风格绘制
* @param canvas 绘制画布
* @param battery 有效电量0-100
* @param left 左边界
* @param right 右边界
* @param height 绘制高度
*/
private void drawPointStyle(Canvas canvas, int battery, int left, int right, int height) {
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制开始 | 电量=" + battery);
int nWidth = getBounds().width();
int nHeight = getBounds().height();
int mnDx = nHeight / 203;
// 意兴阑珊绘图风格
int nTop;
int nLeft = 0;
int nBottom;
int nRight = nWidth;
int nLineWidth = nRight - nLeft;
int radius_horizontal = (nLineWidth / 10) / 2;
int radius_vertical = mnDx/2;
int radius = Math.min(radius_horizontal, radius_vertical);
for (int i = 0; i < mBatteryValue; i ++) {
nBottom = (nHeight * (100 - i) / 100) - mnDx;
nTop = nBottom + mnDx;
//canvas.drawRect(new Rect(nLeft, nTop, nRight, nBottom), mBatteryPaint);
for (int j = 0; j < 10; j++) {
// cx, cy 圆心坐标radius 半径paint 画笔
int cx = radius_horizontal + radius_horizontal * j * 2;
int cy = nTop + radius_vertical;
canvas.drawCircle(cx, cy, radius, mBatteryPaint);
}
}
LogUtils.d(TAG, "【drawStripeStyle】条纹风格绘制完成 | 条纹数量=" + battery);
}
@@ -159,9 +240,8 @@ public class BatteryDrawable extends Drawable {
* 切换绘制风格
* @param isEnergyStyle true=能量风格false=条纹风格
*/
public void switchDrawStyle(boolean isEnergyStyle) {
LogUtils.d(TAG, "【switchDrawStyle】风格切换 | 旧风格=" + (mIsEnergyStyle ? "能量" : "条纹") + " | 新风格=" + (isEnergyStyle ? "能量" : "条纹"));
mIsEnergyStyle = isEnergyStyle;
public void setDrawStyle(BatteryStyle batteryStyle) {
mBatteryStyle = batteryStyle;
invalidateSelf();
LogUtils.d(TAG, "【switchDrawStyle】已触发重绘");
}
@@ -188,12 +268,10 @@ public class BatteryDrawable extends Drawable {
return mBatteryValue;
}
/**
* 获取当前绘制风格
* @return true=能量风格false=条纹风格
*/
public boolean isEnergyStyle() {
return mIsEnergyStyle;
public BatteryStyle getEnergyStyle() {
return mBatteryStyle;
}
// ====================================== Drawable抽象方法必须实现精简逻辑 ======================================

View File

@@ -0,0 +1,285 @@
package cc.winboll.studio.powerbell.views;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.BatteryStyle;
/**
* 电池样式单选视图水平展示所有BatteryStyle枚举选项
* 每个选项 = RadioButton单选按钮 + BatteryDrawable预览控件
* 适配API30、Java7规范联动BatteryDrawable绘制样式
* 包含SP持久化存储 + 公共静态方法读取SP枚举值 + 彻底修复点击不回调+单选失效
* 默认选中BatteryStyle.ENERGY_STYLE
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
*/
public class BatteryStyleView extends LinearLayout implements RadioGroup.OnCheckedChangeListener {
// ====================== 常量区 ======================
public static final String TAG = "BatteryStyleView";
private static final int DEFAULT_BATTERY_COLOR = Color.parseColor("#FF4CAF50");
private static final int DEFAULT_CHECKED_STYLE_INDEX = 1; // ✅ 修改默认选中下标 1 = ENERGY_STYLE
public static final String SP_NAME = "sp_battery_style_config";
public static final String SP_KEY_BATTERY_STYLE = "key_selected_battery_style";
// ====================== 控件变量 ======================
private RadioGroup rgBatteryStyle;
private RadioButton rbZebraStyle;
private RadioButton rbEnergyStyle;
private RadioButton rbPointStyle; // ✅ 新增:圆点样式单选按钮
private RelativeLayout rlZebraPreview;
private RelativeLayout rlEnergyPreview;
private RelativeLayout rlPointPreview; // ✅ 新增:圆点样式预览布局
private BatteryDrawable mZebraDrawable;
private BatteryDrawable mEnergyDrawable;
private BatteryDrawable mPointDrawable; // ✅ 新增圆点样式Drawable实例
// ====================== 业务变量 ======================
private BatteryStyle mCurrentStyle = BatteryStyle.ENERGY_STYLE; // ✅ 修改默认样式为 能量样式
private OnBatteryStyleSelectedListener mStyleSelectedListener;
private int mBatteryColor = DEFAULT_BATTERY_COLOR;
private int mBatteryValue = 100;
private SharedPreferences mSp;
// ====================== 构造方法 ======================
public BatteryStyleView(Context context) {
super(context);
initSP(context);
initView(context, null);
}
public BatteryStyleView(Context context, AttributeSet attrs) {
super(context, attrs);
initSP(context);
initAttrs(context, attrs);
initView(context, attrs);
}
public BatteryStyleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initSP(context);
initAttrs(context, attrs);
initView(context, attrs);
}
// ====================== 初始化SP持久化 ======================
private void initSP(Context context) {
mSp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
LogUtils.d(TAG, "【initSP】SharedPreferences初始化完成文件名称 = " + SP_NAME);
}
// ====================== 初始化方法 ======================
private void initAttrs(Context context, AttributeSet attrs) {
if (attrs == null) return;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BatteryStyleView);
mBatteryColor = typedArray.getColor(R.styleable.BatteryStyleView_batteryPreviewColor, DEFAULT_BATTERY_COLOR);
mBatteryValue = typedArray.getInt(R.styleable.BatteryStyleView_previewBatteryValue, 100);
int styleIndex = typedArray.getInt(R.styleable.BatteryStyleView_defaultSelectedStyle, DEFAULT_CHECKED_STYLE_INDEX);
mCurrentStyle = getStyleFromSP() == null ? (styleIndex == 0 ? BatteryStyle.ENERGY_STYLE : styleIndex ==1 ? BatteryStyle.ZEBRA_STYLE : BatteryStyle.POINT_STYLE) : getStyleFromSP();
typedArray.recycle();
LogUtils.d(TAG, "【initAttrs】解析属性完成 电量颜色=" + Integer.toHexString(mBatteryColor) + " 预览电量=" + mBatteryValue + " 默认样式=" + mCurrentStyle.name());
}
private void initView(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.view_battery_style, this, true);
rgBatteryStyle = findViewById(R.id.rg_battery_style);
rbZebraStyle = findViewById(R.id.rb_zebra_style);
rbEnergyStyle = findViewById(R.id.rb_energy_style);
rbPointStyle = findViewById(R.id.rb_point_style); // ✅ 新增:绑定圆点样式单选按钮
rlZebraPreview = findViewById(R.id.rl_zebra_preview);
rlEnergyPreview = findViewById(R.id.rl_energy_preview);
rlPointPreview = findViewById(R.id.rl_point_preview); // ✅ 新增:绑定圆点样式预览布局
initPreviewDrawable();
rgBatteryStyle.setOnCheckedChangeListener(this);
addRadioBtnClickLister();
setDefaultChecked();
LogUtils.d(TAG, "【initView】视图初始化完成");
}
private void initPreviewDrawable() {
mZebraDrawable = new BatteryDrawable(mBatteryColor, BatteryStyle.ZEBRA_STYLE);
mZebraDrawable.setBatteryValue(mBatteryValue);
rlZebraPreview.setBackground(mZebraDrawable);
mEnergyDrawable = new BatteryDrawable(mBatteryColor, BatteryStyle.ENERGY_STYLE);
mEnergyDrawable.setBatteryValue(mBatteryValue);
rlEnergyPreview.setBackground(mEnergyDrawable);
// ✅ 新增初始化圆点样式Drawable + 绑定预览布局 + 设置电量值
mPointDrawable = new BatteryDrawable(mBatteryColor, BatteryStyle.POINT_STYLE);
mPointDrawable.setBatteryValue(mBatteryValue);
rlPointPreview.setBackground(mPointDrawable);
LogUtils.d(TAG, "【initPreviewDrawable】Drawable预览初始化完成");
}
private void setDefaultChecked() {
// ✅ 新增:圆点样式的默认选中判断
if (mCurrentStyle == BatteryStyle.ZEBRA_STYLE) {
rbZebraStyle.setChecked(true);
} else if (mCurrentStyle == BatteryStyle.POINT_STYLE) {
rbPointStyle.setChecked(true);
} else {
rbEnergyStyle.setChecked(true);
}
LogUtils.d(TAG, "【setDefaultChecked】默认选中样式 = " + mCurrentStyle.name());
}
private void addRadioBtnClickLister() {
rbZebraStyle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
rbZebraStyle.setChecked(true);
rbEnergyStyle.setChecked(false);
rbPointStyle.setChecked(false); // ✅ 新增:取消圆点样式选中
handleStyleSelect(BatteryStyle.ZEBRA_STYLE);
}
});
rbEnergyStyle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
rbEnergyStyle.setChecked(true);
rbZebraStyle.setChecked(false);
rbPointStyle.setChecked(false); // ✅ 新增:取消圆点样式选中
handleStyleSelect(BatteryStyle.ENERGY_STYLE);
}
});
// ✅ 新增:圆点样式单选按钮点击事件
rbPointStyle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
rbPointStyle.setChecked(true);
rbZebraStyle.setChecked(false);
rbEnergyStyle.setChecked(false);
handleStyleSelect(BatteryStyle.POINT_STYLE);
}
});
}
// ====================== RadioGroup 选中回调 (点击必触发) ======================
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
ToastUtils.show("onCheckedChanged");
if (checkedId == R.id.rb_zebra_style) {
handleStyleSelect(BatteryStyle.ZEBRA_STYLE);
} else if (checkedId == R.id.rb_energy_style) {
handleStyleSelect(BatteryStyle.ENERGY_STYLE);
} else if (checkedId == R.id.rb_point_style) { // ✅ 新增:圆点样式选中回调
handleStyleSelect(BatteryStyle.POINT_STYLE);
}
}
private void handleStyleSelect(BatteryStyle style) {
mCurrentStyle = style;
saveStyle2SP(mCurrentStyle);
MainActivity.sendUpdateBatteryDrawableMessage();
LogUtils.d(TAG, "【handleStyleSelect】选中样式 → " + mCurrentStyle.name() + "已存入SP");
if (mStyleSelectedListener != null) {
mStyleSelectedListener.onStyleSelected(mCurrentStyle);
}
}
// ====================== SP持久化 存储+读取 封装方法 ======================
private void saveStyle2SP(BatteryStyle style) {
mSp.edit().putString(SP_KEY_BATTERY_STYLE, style.name()).commit();
}
private BatteryStyle getStyleFromSP() {
String styleStr = mSp.getString(SP_KEY_BATTERY_STYLE, null);
if (styleStr == null) return null;
try {
return BatteryStyle.valueOf(styleStr);
} catch (IllegalArgumentException e) {
LogUtils.e(TAG, "【getStyleFromSP】SP读取样式异常 = " + e.getMessage());
return null;
}
}
// ====================== 公共静态方法 读取SP存储的枚举值 ======================
public static BatteryStyle getSavedBatteryStyle(Context context) {
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String styleStr = sp.getString(SP_KEY_BATTERY_STYLE, null);
if (styleStr == null) {
LogUtils.w(TAG, "【getSavedBatteryStyle】SP无存储值返回默认样式 ENERGY_STYLE");
return BatteryStyle.ENERGY_STYLE; // ✅ 静态方法默认值同步修改为能量样式
}
try {
BatteryStyle style = BatteryStyle.valueOf(styleStr);
LogUtils.d(TAG, "【getSavedBatteryStyle】SP读取成功 → " + style.name());
return style;
} catch (IllegalArgumentException e) {
LogUtils.e(TAG, "【getSavedBatteryStyle】SP读取异常 = " + e.getMessage() + ",返回默认样式 ENERGY_STYLE");
return BatteryStyle.ENERGY_STYLE; // ✅ 异常兜底值同步修改为能量样式
}
}
public static BatteryStyle getSavedBatteryStyle(Context context, BatteryStyle defaultStyle) {
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
String styleStr = sp.getString(SP_KEY_BATTERY_STYLE, null);
if (styleStr == null) {
LogUtils.w(TAG, "【getSavedBatteryStyle】SP无存储值返回自定义默认样式 → " + defaultStyle.name());
return defaultStyle;
}
try {
BatteryStyle style = BatteryStyle.valueOf(styleStr);
LogUtils.d(TAG, "【getSavedBatteryStyle】SP读取成功 → " + style.name());
return style;
} catch (IllegalArgumentException e) {
LogUtils.e(TAG, "【getSavedBatteryStyle】SP读取异常 = " + e.getMessage() + ",返回自定义默认样式 → " + defaultStyle.name());
return defaultStyle;
}
}
// ====================== 对外暴露方法 ======================
public void setSelectedStyle(BatteryStyle style) {
mCurrentStyle = style;
// ✅ 新增:圆点样式的手动选中赋值
rbZebraStyle.setChecked(style == BatteryStyle.ZEBRA_STYLE);
rbEnergyStyle.setChecked(style == BatteryStyle.ENERGY_STYLE);
rbPointStyle.setChecked(style == BatteryStyle.POINT_STYLE);
saveStyle2SP(style);
LogUtils.d(TAG, "【setSelectedStyle】手动设置选中样式 → " + style.name() + "已存入SP");
}
public BatteryStyle getCurrentStyle() {
return mCurrentStyle;
}
public void setPreviewBatteryValue(int batteryValue) {
this.mBatteryValue = batteryValue;
mZebraDrawable.setBatteryValue(batteryValue);
mEnergyDrawable.setBatteryValue(batteryValue);
mPointDrawable.setBatteryValue(batteryValue); // ✅ 新增:圆点样式同步电量值
}
public void setPreviewBatteryColor(int color) {
this.mBatteryColor = color;
mZebraDrawable.updateBatteryColor(color);
mEnergyDrawable.updateBatteryColor(color);
mPointDrawable.updateBatteryColor(color); // ✅ 新增:圆点样式同步颜色值
}
public void setOnBatteryStyleSelectedListener(OnBatteryStyleSelectedListener listener) {
this.mStyleSelectedListener = listener;
}
// ====================== 选中回调接口 ======================
public interface OnBatteryStyleSelectedListener {
void onStyleSelected(BatteryStyle batteryStyle);
}
}

View File

@@ -15,18 +15,20 @@ import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.models.BatteryStyle;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
/**
* 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑
* 适配Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏,配置变更确认对话框
* 新增:拖动进度条时实时预览 sbUsageReminder 与 sbChargeReminder 比值
* 修复updateBatteryDrawable() 电池样式切换后重绘失效问题
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 13:14
*/
@@ -43,7 +45,7 @@ public class MainContentView {
private static final int BATTERY_MIN = 0;
private static final int BATTERY_MAX = 100;
// ====================================== 内部静态类(临时数据载体,避免外部依赖 ======================================
// ====================================== 内部缓存类(解耦,避免冗余 ======================================
/**
* 临时配置数据实体(缓存变更信息,取消时恢复)
*/
@@ -89,6 +91,8 @@ public class MainContentView {
public RelativeLayout mainLayout;
public MemoryCachedBackgroundView backgroundView;
private LinearLayout mllBackgroundView;
private volatile BatteryStyle mBatteryStyle = BatteryStyle.ENERGY_STYLE;
// 容器布局控件
public LinearLayout llLeftSeekBar;
public LinearLayout llRightSeekBar;
@@ -133,6 +137,7 @@ public class MainContentView {
this.mContext = context;
this.mActionListener = actionListener;
this.mAppConfigUtils = AppConfigUtils.getInstance(context.getApplicationContext());
mBatteryStyle = BatteryStyleView.getSavedBatteryStyle(context);
// 执行核心初始化流程(按顺序执行,避免依赖空指针)
bindViews(rootView);
@@ -202,7 +207,6 @@ public class MainContentView {
App.sBackgroundSourceUtils.loadSettings();
BackgroundBean backgroundBean = App.sBackgroundSourceUtils.getCurrentBackgroundBean();
backgroundView.loadByBackgroundBean(backgroundBean, true);
//App.notifyMessage(TAG, "reloadBackgroundView");
}
}
@@ -210,19 +214,60 @@ public class MainContentView {
* 初始化电池 Drawable集成 BatteryDrawable默认能量风格适配小米机型渲染
*/
private void initBatteryDrawables() {
LogUtils.d(TAG, "【initBatteryDrawables】电池Drawable初始化开始");
LogUtils.d(TAG, "【initBatteryDrawables】电池Drawable初始化开始 | style="+mBatteryStyle.name());
// 当前电量 Drawable颜色从资源读取适配 API30 主题)
int colorCurrent = getResourceColor(R.color.colorCurrent);
mCurrentBatteryDrawable = new BatteryDrawable(colorCurrent);
mCurrentBatteryDrawable.setDrawStyle(mBatteryStyle);
// 充电提醒 Drawable
int colorCharge = getResourceColor(R.color.colorCharge);
mChargeReminderBatteryDrawable = new BatteryDrawable(colorCharge);
// 耗电提醒 Drawable
mChargeReminderBatteryDrawable.setDrawStyle(mBatteryStyle);
// 耗电提醒 Drawable
int colorUsage = getResourceColor(R.color.colorUsege);
mUsageReminderBatteryDrawable = new BatteryDrawable(colorUsage);
LogUtils.d(TAG, "【initBatteryDrawables】电池Drawable初始化完成");
mUsageReminderBatteryDrawable.setDrawStyle(mBatteryStyle);
LogUtils.d(TAG, "【initBatteryDrawables】电池Drawable初始化完成");
}
/**
* ✅ 核心修复:电池样式切换+强制重绘刷新 完整版
* 修复点1重新创建Drawable后重新给ImageView赋值Drawable
* 修复点2重置所有Drawable的电量值保证样式切换后数值不变
* 修复点3调用ImageView.invalidate()强制触发重绘API30必加
* 修复点4Drawable.invalidateSelf() 双保险刷新绘制内容
* @param batteryStyle 切换后的电池样式
*/
public void updateBatteryDrawable(BatteryStyle batteryStyle) {
if(batteryStyle == null || batteryStyle == mBatteryStyle){
LogUtils.d(TAG, "【updateBatteryDrawable】样式无变化跳过刷新");
return;
}
// 1. 更新样式标记
mBatteryStyle = batteryStyle;
// 2. 重新初始化Drawable并设置新样式
initBatteryDrawables();
// 3. 重置所有Drawable的电量值 → 保证样式切换后数值不变
mCurrentBatteryDrawable.setBatteryValue(mAppConfigUtils.getCurrentBatteryValue());
mChargeReminderBatteryDrawable.setBatteryValue(mCurrentChargeProgress);
mUsageReminderBatteryDrawable.setBatteryValue(mCurrentUsageProgress);
// 4. 重新给ImageView赋值Drawable → 核心修复:之前缺失这一步
if(ivCurrentBattery != null) ivCurrentBattery.setImageDrawable(mCurrentBatteryDrawable);
if(ivChargeReminderBattery != null) ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
if(ivUsageReminderBattery != null) ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
// 5. Drawable自身刷新 → 双保险
mCurrentBatteryDrawable.invalidateSelf();
mChargeReminderBatteryDrawable.invalidateSelf();
mUsageReminderBatteryDrawable.invalidateSelf();
// 6. ✅ API30关键修复ImageView强制重绘解决绘制缓存不刷新问题
if(ivCurrentBattery != null) ivCurrentBattery.invalidate();
if(ivChargeReminderBattery != null) ivChargeReminderBattery.invalidate();
if(ivUsageReminderBattery != null) ivUsageReminderBattery.invalidate();
LogUtils.d(TAG, "【updateBatteryDrawable】样式切换完成"+mBatteryStyle.name() + " | 重绘触发成功");
ToastUtils.show("电池样式已切换为:"+mBatteryStyle.name());
}
/**
* 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题)
*/

View File

@@ -189,11 +189,11 @@ public class MemoryCachedBackgroundView extends BackgroundView {
* 从缓存实例中获取上下文用于无外部上下文时的SP操作
* @return 上下文实例无则返回null
*/
private static Context getContextFromCache() {
Context context = sCachedView != null ? sCachedView.getContext() : null;
LogUtils.d(TAG, String.format("getContextFromCache 调用 | 从缓存获取上下文=%s", context));
return context;
}
// private static Context getContextFromCache() {
// Context context = sCachedView != null ? sCachedView.getContext() : null;
// LogUtils.d(TAG, String.format("getContextFromCache 调用 | 从缓存获取上下文=%s", context));
// return context;
// }
// ====================================== 重写父类方法:增强日志+SP持久化强制保持版 ======================================
@Override

View File

@@ -113,8 +113,9 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
<TextView
android:layout_width="match_parent"
@@ -127,7 +128,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView2"
android:layout_weight="1.0"/>
@@ -135,7 +136,7 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
@@ -150,7 +151,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView1"
android:layout_weight="1.0"/>
@@ -158,8 +159,9 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="match_parent">
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0">
<TextView
android:layout_width="match_parent"
@@ -172,7 +174,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:id="@+id/fragmentandroidviewImageView3"
android:layout_weight="1.0"/>

View File

@@ -6,7 +6,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
<cc.winboll.studio.libaes.views.AToolbar
<cc.winboll.studio.libaes.views.ASupportToolbar
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:id="@+id/toolbar"

View File

@@ -33,5 +33,20 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0">
<cc.winboll.studio.powerbell.views.BatteryStyleView
android:id="@+id/battery_style_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:batteryPreviewColor="@color/colorPrimary"
app:previewBatteryValue="100"
app:defaultSelectedStyle="zebra_style"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<RadioGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rg_battery_style"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="8dp"
android:spacing="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="4dp">
<RadioButton
android:id="@+id/rb_energy_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/energy_style"
android:textSize="14sp"
android:buttonTint="@color/colorPrimary"
android:textColor="@color/colorPrimary"/>
<RelativeLayout
android:id="@+id/rl_energy_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#F5F5F5"
android:padding="1dp"
android:layout_weight="1.0"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="4dp">
<RadioButton
android:id="@+id/rb_zebra_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/zebra_style"
android:textSize="14sp"
android:buttonTint="@color/colorPrimary"
android:textColor="@color/colorPrimary"/>
<RelativeLayout
android:id="@+id/rl_zebra_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#F5F5F5"
android:padding="1dp"
android:layout_weight="1.0"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="4dp">
<RadioButton
android:id="@+id/rb_point_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/point_style"
android:textSize="14sp"
android:buttonTint="@color/colorPrimary"
android:textColor="@color/colorPrimary"/>
<RelativeLayout
android:id="@+id/rl_point_preview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#F5F5F5"
android:padding="1dp"
android:layout_weight="1.0"/>
</LinearLayout>
</RadioGroup>

View File

@@ -1,3 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- BatteryStyleView 自定义属性 -->
<declare-styleable name="BatteryStyleView">
<attr name="batteryPreviewColor" format="color"/>
<attr name="previewBatteryValue" format="integer"/>
<attr name="defaultSelectedStyle" format="integer">
<enum name="zebra_style" value="0"/>
<enum name="energy_style" value="1"/>
</attr>
</declare-styleable>
</resources>

View File

@@ -32,6 +32,9 @@
<string name="subtitle_activity_about">About The APP</string>
<string name="msg_AOHPCTCSeekBar_ClearRecord">&gt;&gt;&gt;Seek 100% Right Is Clean Record.&gt;&gt;&gt;</string>
<string name="msg_no_battery_record">No Battery Record</string>
<string name="zebra_style">Zebra Style</string>
<string name="energy_style">Energy Style</string>
<string name="point_style">Point Style</string>
<!-- 权限申请相关字符串(统一管理,避免硬编码) -->
<string name="permission_title">权限申请</string>