Compare commits
25 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| d1ced7ac63 | |||
| bf0cf23144 | |||
| 890b32ceae | |||
| c347d51c84 | |||
| 7278e9f22f | |||
| 4e98c8d699 | |||
| 3ec1bbe264 | |||
| f4a2a1585d | |||
| 35f4aa8730 | |||
| 5b1d160dac | |||
| db87ba51e3 | |||
| fd6e852061 | |||
| 8ff4b9e1f4 | |||
| 78a2d85150 | |||
| fd2d1d17ed | |||
| 37f3091103 | |||
| 6dc5f05702 | |||
| 77df2558b3 | |||
| 315541f2d2 | |||
| f52bb54d22 | |||
| 0742164f65 | |||
| fc785b9258 | |||
| 0abeb982d2 | |||
| 81f0e5c56e | |||
| 4fcce7edb3 |
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed Dec 24 21:23:33 HKT 2025
|
||||
stageCount=30
|
||||
#Fri Dec 26 20:13:09 HKT 2025
|
||||
stageCount=36
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.29
|
||||
publishVersion=15.14.35
|
||||
buildCount=0
|
||||
baseBetaVersion=15.14.30
|
||||
baseBetaVersion=15.14.36
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
|
||||
<!-- 外部存储权限 -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- 相机权限 -->
|
||||
@@ -51,6 +52,7 @@
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:process=":main"
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
@@ -62,14 +64,15 @@
|
||||
android:supportsRtl="true"
|
||||
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||
|
||||
<!-- 主活动 -->
|
||||
<!-- 主活动(主进程) -->
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"/>
|
||||
|
||||
<!-- 活动别名(启动器) -->
|
||||
<!-- 活动别名(启动器,主进程) -->
|
||||
<activity-alias
|
||||
android:name=".MainActivityEN1"
|
||||
android:targetActivity=".MainActivity"
|
||||
@@ -118,18 +121,21 @@
|
||||
android:resource="@xml/shortcutsmaincn2"/>
|
||||
</activity-alias>
|
||||
|
||||
<!-- 功能活动 -->
|
||||
<!-- 功能活动(主进程) -->
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.CrashActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.ClearRecordActivity"
|
||||
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.BackgroundSettingsActivity"
|
||||
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
||||
android:exported="true"
|
||||
@@ -146,41 +152,50 @@
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.BatteryReporterActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.PixelPickerActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.BatteryReportActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".unittest.MainUnitTestActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.ShortcutActionActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name=".activities.SettingsActivity"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name="cc.winboll.studio.powerbell.unittest.MainUnitTest2Activity"
|
||||
android:exported="false"/>
|
||||
|
||||
<!-- 第三方活动 -->
|
||||
<!-- 第三方活动(主进程) -->
|
||||
<activity
|
||||
android:process=":main"
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||
android:exported="true"/>
|
||||
|
||||
<!-- 广播接收器 -->
|
||||
<!-- 广播接收器(主进程) -->
|
||||
<receiver
|
||||
android:process=":main"
|
||||
android:name=".receivers.MainReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
@@ -192,13 +207,14 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- 服务 -->
|
||||
<!-- 服务(ControlCenterService主进程,AssistantService独立进程) -->
|
||||
<service
|
||||
android:name=".services.ControlCenterService"
|
||||
android:priority="1000"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=".controlcenterservice"
|
||||
android:process=":main"
|
||||
android:stopWithTask="false"
|
||||
android:foregroundServiceType="dataSync">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE"
|
||||
@@ -209,18 +225,21 @@
|
||||
android:name=".services.AssistantService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=".assistantservice">
|
||||
android:process=":assistant"
|
||||
android:stopWithTask="false"
|
||||
android:foregroundServiceType="dataSync">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE"
|
||||
android:value="辅助核心功能运行"/>
|
||||
</service>
|
||||
|
||||
<!-- 内容提供者 -->
|
||||
<!-- 内容提供者(主进程) -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
android:grantUriPermissions="true"
|
||||
android:process=":main">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_provider"/>
|
||||
|
||||
@@ -5,9 +5,11 @@ import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
|
||||
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
||||
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
|
||||
@@ -16,6 +18,8 @@ import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
|
||||
* 应用全局入口类(适配Android API 30,基于Java 7编写)
|
||||
* 核心策略:极致强制缓存 - 无论内存紧张程度,永不自动清理任何缓存(Bitmap/视图控件/路径记录)
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Version 1.0.0
|
||||
* @Date 2025-12-25
|
||||
*/
|
||||
public class App extends GlobalApplication {
|
||||
// ===================== 常量定义区(按功能分类排序) =====================
|
||||
@@ -33,36 +37,54 @@ public class App extends GlobalApplication {
|
||||
|
||||
// 缓存防护常量
|
||||
private static final String CACHE_PROTECT_TAG = "FORCE_CACHE_PROTECT";
|
||||
private static final int INVALID_BATTERY_VALUE = -1;
|
||||
|
||||
// ===================== 静态属性区(按工具类优先级排序) =====================
|
||||
// 应用单例
|
||||
private static App sApp;
|
||||
|
||||
// 数据配置工具
|
||||
public static AppConfigUtils sAppConfigUtils;
|
||||
private static AppCacheUtils sAppCacheUtils;
|
||||
|
||||
// 全局Bitmap缓存工具(极致强制保持:一旦初始化,永不销毁)
|
||||
public static BackgroundSourceUtils sBackgroundSourceUtils;
|
||||
public static BitmapCacheUtils sBitmapCacheUtils;
|
||||
|
||||
// 全局视图控件缓存工具(极致强制保持:一旦初始化,永不销毁)
|
||||
public static MemoryCachedBackgroundView sMemoryCachedBackgroundView;
|
||||
private static MemoryCachedBackgroundView sMemoryCachedBackgroundView;
|
||||
|
||||
// 电池状态
|
||||
public static volatile int sQuantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
|
||||
// 通知管理工具
|
||||
private static NotificationManagerUtils sNotificationManagerUtils;
|
||||
|
||||
// ===================== 成员属性区(按生命周期关联度排序) =====================
|
||||
// 全局广播接收器
|
||||
private GlobalApplicationReceiver mGlobalReceiver;
|
||||
|
||||
// 通知管理工具
|
||||
private NotificationManagerUtils mNotificationManager;
|
||||
// ===================== 公共静态方法区(单例/工具类实例获取) =====================
|
||||
/**
|
||||
* 获取应用单例实例
|
||||
*/
|
||||
public static App getInstance() {
|
||||
LogUtils.d(TAG, "getInstance() 调用 | 返回实例:" + sApp);
|
||||
return sApp;
|
||||
}
|
||||
|
||||
// ===================== 公共静态方法区(工具类实例获取) =====================
|
||||
/**
|
||||
* 获取应用配置工具实例
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -70,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;
|
||||
}
|
||||
|
||||
@@ -87,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未初始化");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,117 +122,143 @@ 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() 调用 | 当前实例:" + sMemoryCachedBackgroundView);
|
||||
return sMemoryCachedBackgroundView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送调试通知
|
||||
*/
|
||||
public static void notifyMessage(String title, String content) {
|
||||
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() | 调试通知发送成功");
|
||||
} else {
|
||||
LogUtils.d(TAG, "notifyMessage() | 发送失败:调试模式未开启/工具类未初始化");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 生命周期方法区(按执行顺序排序) =====================
|
||||
@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();
|
||||
}
|
||||
|
||||
// ===================== 私有初始化方法区(按初始化顺序排序) =====================
|
||||
/**
|
||||
* 初始化基础工具(Activity管理、Toast)
|
||||
* 初始化基础工具(Activity管理、Toast、通知工具)
|
||||
*/
|
||||
private void initBaseTools() {
|
||||
LogUtils.d(TAG, "initBaseTools() 开始初始化基础工具");
|
||||
LogUtils.d(TAG, "initBaseTools() | 开始初始化基础工具集");
|
||||
WinBoLLActivityManager.init(this);
|
||||
ToastUtils.init(this);
|
||||
LogUtils.d(TAG, "initBaseTools() 基础工具初始化完成");
|
||||
sNotificationManagerUtils = new NotificationManagerUtils(this);
|
||||
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缓存工具(必初始化,永不销毁)
|
||||
// 初始化背景资源与Bitmap缓存
|
||||
sBackgroundSourceUtils = BackgroundSourceUtils.getInstance(this);
|
||||
sBackgroundSourceUtils.loadSettings();
|
||||
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||
LogUtils.d(TAG, "initUtils() Bitmap缓存工具已初始化(极致强制保持,永不销毁)");
|
||||
LogUtils.d(TAG, "initUtils() | BackgroundSource/BitmapCache工具初始化完成 | 永久驻留内存");
|
||||
|
||||
// 极致强制初始化视图控件缓存工具(必初始化,永不销毁)
|
||||
// 初始化视图控件缓存
|
||||
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getLastInstance(this);
|
||||
LogUtils.d(TAG, "initUtils() 视图控件缓存工具已初始化(极致强制保持,永不销毁)");
|
||||
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "initUtils() 工具类初始化完成,极致强制缓存策略已生效");
|
||||
if (sMemoryCachedBackgroundView == null) {
|
||||
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, sBackgroundSourceUtils.getCurrentBackgroundBean(), true);
|
||||
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() | 广播接收器注册完成");
|
||||
}
|
||||
|
||||
// ===================== 私有释放方法区(按资源重要性排序) =====================
|
||||
@@ -216,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() | 无需释放:广播接收器未初始化");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +280,13 @@ public class App extends GlobalApplication {
|
||||
* 释放通知管理工具资源
|
||||
*/
|
||||
private void releaseNotificationManager() {
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 开始释放通知工具");
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.release();
|
||||
mNotificationManager = null;
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 通知工具资源已释放");
|
||||
LogUtils.d(TAG, "releaseNotificationManager() | 开始释放通知工具");
|
||||
if (sNotificationManagerUtils != null) {
|
||||
sNotificationManagerUtils.release();
|
||||
sNotificationManagerUtils = null;
|
||||
LogUtils.d(TAG, "releaseNotificationManager() | 通知工具资源释放完成");
|
||||
} else {
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 通知工具未初始化,无需释放");
|
||||
LogUtils.d(TAG, "releaseNotificationManager() | 无需释放:通知工具未初始化");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,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() | 缓存状态记录完成");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ 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;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
|
||||
/**
|
||||
* 应用核心主活动
|
||||
@@ -45,37 +44,40 @@ 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";
|
||||
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 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;
|
||||
@@ -89,7 +91,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);
|
||||
@@ -98,20 +100,32 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
initCriticalView();
|
||||
initCoreUtilsAsync();
|
||||
loadNonCriticalViewDelayed();
|
||||
|
||||
// 处理首次启动参数
|
||||
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 onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, String.format("onPostCreate() | savedInstanceState=%s", savedInstanceState));
|
||||
LogUtils.d(TAG, "onPostCreate() 调用 | savedInstanceState: " + savedInstanceState);
|
||||
mPermissionUtils.startPermissionRequest(this);
|
||||
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
LogUtils.d(TAG, "onResume()");
|
||||
LogUtils.d(TAG, "onResume() 调用");
|
||||
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.resumeADs(this);
|
||||
@@ -122,13 +136,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) {
|
||||
@@ -142,7 +156,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;
|
||||
@@ -154,7 +168,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
mFrameDrawable = null;
|
||||
LogUtils.d(TAG, "onDestroy: 框架Drawable已释放");
|
||||
}
|
||||
// 置空所有引用
|
||||
// 置空所有引用,消除内存泄漏风险
|
||||
sMainActivity = null;
|
||||
mPermissionUtils = null;
|
||||
mAppConfigUtils = null;
|
||||
@@ -169,21 +183,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);
|
||||
@@ -195,14 +211,17 @@ 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();
|
||||
return true;
|
||||
}
|
||||
// 开发者功能处理
|
||||
if (DevelopUtils.onDevelopItemSelected(this, item)) {
|
||||
return true;
|
||||
}
|
||||
// 菜单点击事件分发
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
@@ -234,7 +253,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: 已隐藏返回按钮");
|
||||
@@ -243,35 +262,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();
|
||||
@@ -279,7 +300,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:
|
||||
@@ -298,14 +319,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 initCriticalView() {
|
||||
LogUtils.d(TAG, "initCriticalView()");
|
||||
LogUtils.d(TAG, "initCriticalView() 调用");
|
||||
sMainActivity = this;
|
||||
mToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(mToolbar);
|
||||
@@ -318,11 +339,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());
|
||||
@@ -338,8 +359,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
|
||||
@@ -366,7 +387,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 {
|
||||
@@ -383,7 +404,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() {
|
||||
@@ -396,9 +417,27 @@ 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 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;
|
||||
@@ -413,7 +452,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;
|
||||
@@ -423,14 +462,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -440,7 +478,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;
|
||||
@@ -449,12 +487,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;
|
||||
@@ -477,9 +515,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);
|
||||
@@ -487,16 +525,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: 配置重载消息已发送");
|
||||
@@ -506,7 +544,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;
|
||||
@@ -517,9 +555,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));
|
||||
@@ -536,34 +574,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ 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.MainActivity;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
|
||||
import cc.winboll.studio.powerbell.dialogs.ColorPaletteDialog;
|
||||
@@ -46,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;
|
||||
@@ -64,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;
|
||||
@@ -90,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() 初始化完成");
|
||||
}
|
||||
|
||||
@@ -122,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();
|
||||
}
|
||||
}
|
||||
@@ -138,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 {
|
||||
@@ -167,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);
|
||||
}
|
||||
@@ -881,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();
|
||||
}
|
||||
|
||||
@@ -937,12 +949,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mBgSourceUtils.commitPreviewSourceToCurrent();
|
||||
isCommitSettings = true;
|
||||
finish();
|
||||
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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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() 配置完成");
|
||||
}
|
||||
|
||||
// ======================== 业务逻辑方法 =========================
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.MainActivity;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
||||
@@ -135,6 +136,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
|
||||
|
||||
// 解析Uri为文件路径
|
||||
String szSrcImage = UriUtils.getFilePathFromUri(mContext, mUriRecivedPicture);
|
||||
//App.notifyMessage(TAG, "szSrcImage : " + szSrcImage);
|
||||
if (TextUtils.isEmpty(szSrcImage)) {
|
||||
LogUtils.w(TAG, "【previewRecivedPicture】解析的文件路径为空");
|
||||
Toast.makeText(mContext, TOAST_MSG_EMPTY_FILE, Toast.LENGTH_SHORT).show();
|
||||
|
||||
@@ -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 字段常量,避免硬编码
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BatteryUtils;
|
||||
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
@@ -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分发处理) ======================
|
||||
@@ -142,7 +142,7 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
latestConfig.getChargeReminderValue(), latestConfig.getUsageReminderValue()));
|
||||
|
||||
// 同步缓存的电池状态到配置
|
||||
RemindThread.sQuantityOfElectricity = sLastBatteryLevel;
|
||||
App.sQuantityOfElectricity = sLastBatteryLevel;
|
||||
latestConfig.setIsCharging(sIsCharging);
|
||||
service.notifyAppConfigUpdate(latestConfig);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package cc.winboll.studio.powerbell.threads;
|
||||
import android.content.Context;
|
||||
import android.os.Message;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
||||
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -26,7 +27,6 @@ public class RemindThread extends Thread {
|
||||
private static final long THREAD_JOIN_TIMEOUT = 1000L;
|
||||
|
||||
// 状态常量
|
||||
private static final int INVALID_BATTERY_VALUE = -1;
|
||||
private static final int BATTERY_LEVEL_MIN = 0;
|
||||
private static final int BATTERY_LEVEL_MAX = 100;
|
||||
|
||||
@@ -55,7 +55,6 @@ public class RemindThread extends Thread {
|
||||
private volatile long sleepTime;
|
||||
private volatile int chargeReminderValue;
|
||||
private volatile int usageReminderValue;
|
||||
public static volatile int sQuantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
private volatile boolean isCharging;
|
||||
|
||||
// ====================== 私有构造器(禁止外部实例化) ======================
|
||||
@@ -170,21 +169,21 @@ public class RemindThread extends Thread {
|
||||
if (isExist) break;
|
||||
|
||||
// 电量有效性校验(非0-100视为无效),退出电量提醒线程
|
||||
if (sQuantityOfElectricity < BATTERY_LEVEL_MIN || sQuantityOfElectricity > BATTERY_LEVEL_MAX) {
|
||||
LogUtils.w(TAG, String.format("电量无效,退出电量提醒线程 | 当前电量=%d | threadId=%d", sQuantityOfElectricity, getId()));
|
||||
if (App.sQuantityOfElectricity < BATTERY_LEVEL_MIN || App.sQuantityOfElectricity > BATTERY_LEVEL_MAX) {
|
||||
LogUtils.w(TAG, String.format("电量无效,退出电量提醒线程 | 当前电量=%d | threadId=%d", App.sQuantityOfElectricity, getId()));
|
||||
break;
|
||||
}
|
||||
|
||||
// 充电/耗电提醒触发逻辑
|
||||
boolean chargeRemindTrigger = isCharging && isEnableChargeReminder && sQuantityOfElectricity >= chargeReminderValue;
|
||||
boolean usageRemindTrigger = !isCharging && isEnableUsageReminder && sQuantityOfElectricity <= usageReminderValue;
|
||||
boolean chargeRemindTrigger = isCharging && isEnableChargeReminder && App.sQuantityOfElectricity >= chargeReminderValue;
|
||||
boolean usageRemindTrigger = !isCharging && isEnableUsageReminder && App.sQuantityOfElectricity <= usageReminderValue;
|
||||
|
||||
if (chargeRemindTrigger) {
|
||||
LogUtils.d(TAG, String.format("触发充电提醒 | 当前电量=%d ≥ 阈值=%d | threadId=%d", sQuantityOfElectricity, chargeReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_CHARGE, sQuantityOfElectricity, isCharging);
|
||||
LogUtils.d(TAG, String.format("触发充电提醒 | 当前电量=%d ≥ 阈值=%d | threadId=%d", App.sQuantityOfElectricity, chargeReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_CHARGE, App.sQuantityOfElectricity, isCharging);
|
||||
} else if (usageRemindTrigger) {
|
||||
LogUtils.d(TAG, String.format("触发耗电提醒 | 当前电量=%d ≤ 阈值=%d | threadId=%d", sQuantityOfElectricity, usageReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_USAGE, sQuantityOfElectricity, isCharging);
|
||||
LogUtils.d(TAG, String.format("触发耗电提醒 | 当前电量=%d ≤ 阈值=%d | threadId=%d", App.sQuantityOfElectricity, usageReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_USAGE, App.sQuantityOfElectricity, isCharging);
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("未有合适类型提醒,退出提醒线程 | threadId=%d", getId()));
|
||||
break;
|
||||
@@ -194,7 +193,7 @@ public class RemindThread extends Thread {
|
||||
safeSleepInternal(sleepTime);
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, String.format("循环运行异常,退出电量提醒线程 | 当前电量=%d | threadId=%d", sQuantityOfElectricity, getId()), e);
|
||||
LogUtils.e(TAG, String.format("循环运行异常,退出电量提醒线程 | 当前电量=%d | threadId=%d", App.sQuantityOfElectricity, getId()), e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -283,7 +282,6 @@ public class RemindThread extends Thread {
|
||||
LogUtils.d(TAG, String.format("cleanThreadStateInternal() 调用 | threadId=%d", getId()));
|
||||
isReminding = false;
|
||||
isExist = true;
|
||||
sQuantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
// 中断当前线程(如果存活)
|
||||
if (isAlive()) {
|
||||
interrupt();
|
||||
@@ -300,7 +298,6 @@ public class RemindThread extends Thread {
|
||||
LogUtils.d(TAG, String.format("setAppConfigBean() 调用 | config=%s | threadId=%d", config, getId()));
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, String.format("配置同步失败:配置Bean为空 | threadId=%d", getId()));
|
||||
sQuantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -315,7 +312,7 @@ public class RemindThread extends Thread {
|
||||
isCharging = config.isCharging();
|
||||
|
||||
LogUtils.d(TAG, String.format("配置同步完成 | 休眠时间=%dms | 充电提醒=%b | 耗电提醒=%b | 当前电量=%d | 充电阈值=%d | 耗电阈值=%d | threadId=%d",
|
||||
sleepTime, isEnableChargeReminder, isEnableUsageReminder, sQuantityOfElectricity, chargeReminderValue, usageReminderValue, getId()));
|
||||
sleepTime, isEnableChargeReminder, isEnableUsageReminder, App.sQuantityOfElectricity, chargeReminderValue, usageReminderValue, getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,7 +345,7 @@ public class RemindThread extends Thread {
|
||||
", isReminding=" + isReminding +
|
||||
", chargeThreshold=" + chargeReminderValue +
|
||||
", usageThreshold=" + usageReminderValue +
|
||||
", currentBattery=" + sQuantityOfElectricity +
|
||||
", currentBattery=" + App.sQuantityOfElectricity +
|
||||
", isCharging=" + isCharging +
|
||||
", sleepTime=" + sleepTime + "ms" +
|
||||
'}';
|
||||
|
||||
@@ -106,7 +106,7 @@ public class MainUnitTest2Activity extends AppCompatActivity {
|
||||
|
||||
// 创建MemoryCachedBackgroundView单例并添加到布局
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
|
||||
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, nCurrentPixelColor, "", false);
|
||||
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getLastInstance(this);
|
||||
mllBackgroundView.addView(mMemoryCachedBackgroundView);
|
||||
LogUtils.d(TAG, "initViewAndEvent:内存缓存背景视图实例创建并添加完成");
|
||||
|
||||
|
||||
@@ -249,12 +249,12 @@ public class AppConfigUtils {
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue() 调用 | 传入电量=%d", value));
|
||||
int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
|
||||
if (calibratedValue == RemindThread.sQuantityOfElectricity) {
|
||||
if (calibratedValue == App.sQuantityOfElectricity) {
|
||||
LogUtils.d(TAG, "setCurrentBatteryValue():电池电量无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
RemindThread.sQuantityOfElectricity = calibratedValue;
|
||||
App.sQuantityOfElectricity = calibratedValue;
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue() 成功 | 电池电量=%d%%", calibratedValue));
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ public class AppConfigUtils {
|
||||
* @return 当前电池电量(0-100)
|
||||
*/
|
||||
public int getCurrentBatteryValue() {
|
||||
int value = RemindThread.sQuantityOfElectricity;
|
||||
int value = App.sQuantityOfElectricity;
|
||||
LogUtils.d(TAG, String.format("getCurrentBatteryValue():获取电池电量=%d%%", value));
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public class BitmapCacheUtils {
|
||||
*/
|
||||
private BitmapCacheUtils() {
|
||||
LogUtils.d(TAG, "【BitmapCacheUtils】单例构造开始");
|
||||
//App.notifyMessage(TAG, "【BitmapCacheUtils】单例构造开始");
|
||||
// 使用 ConcurrentHashMap 保证线程安全,避免手动同步
|
||||
mHardCacheMap = new ConcurrentHashMap<>();
|
||||
mRefCountMap = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -22,7 +22,7 @@ import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||
/**
|
||||
* 通知工具类:统一管理前台服务/电池提醒/应用配置信息通知
|
||||
* 适配:API19-30 | Java7 | 小米手机
|
||||
* 特性:前台服务无铃声、提醒通知系统默认铃声、配置通知低优先级无打扰、API分级适配、内存泄漏防护
|
||||
* 特性:前台服务无铃声、提醒通知系统默认铃声、配置通知系统默认铃声无振动、API分级适配、内存泄漏防护
|
||||
*/
|
||||
public class NotificationManagerUtils {
|
||||
// ================================== 静态常量(置顶统一管理,杜绝魔法值)=================================
|
||||
@@ -48,6 +48,7 @@ public class NotificationManagerUtils {
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_FOREGROUND = 0;
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_REMIND = 1;
|
||||
private static final int PENDING_INTENT_REQUEST_CODE_CONFIG = 2; // 新增:配置通知请求码
|
||||
private static int snMessageNotificationID = 10000;
|
||||
|
||||
// ================================== 成员变量(私有封装,按依赖优先级排序)=================================
|
||||
// 核心上下文(应用级,避免内存泄漏)
|
||||
@@ -59,35 +60,35 @@ public class NotificationManagerUtils {
|
||||
|
||||
// ================================== 构造方法(初始化核心资源,前置校验)=================================
|
||||
public NotificationManagerUtils(Context context) {
|
||||
LogUtils.d(TAG, "NotificationManagerUtils: 构造方法执行 | context=" + context);
|
||||
LogUtils.d(TAG, "NotificationManagerUtils() 构造 | context=" + context);
|
||||
// 前置校验:Context非空
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "NotificationManagerUtils: 构造失败:context is null");
|
||||
LogUtils.e(TAG, "NotificationManagerUtils() 构造失败:context is null");
|
||||
return;
|
||||
}
|
||||
// 初始化核心资源
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
LogUtils.d(TAG, "NotificationManagerUtils: 核心资源初始化完成 | mContext=" + mContext + " | mNotificationManager=" + mNotificationManager);
|
||||
LogUtils.d(TAG, "NotificationManagerUtils() 核心资源初始化完成 | mContext=" + mContext + " | mNotificationManager=" + mNotificationManager);
|
||||
// 初始化通知渠道(API26+ 必需)
|
||||
initNotificationChannels();
|
||||
LogUtils.d(TAG, "NotificationManagerUtils: 构造完成");
|
||||
LogUtils.d(TAG, "NotificationManagerUtils() 构造完成");
|
||||
}
|
||||
|
||||
// ================================== 核心初始化方法(通知渠道,API分级适配)=================================
|
||||
/**
|
||||
* 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动)、配置信息渠道(低优先级无打扰)
|
||||
* 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动)、配置信息渠道(系统默认铃声+无振动)
|
||||
*/
|
||||
private void initNotificationChannels() {
|
||||
LogUtils.d(TAG, "initNotificationChannels: 执行通知渠道初始化");
|
||||
LogUtils.d(TAG, "initNotificationChannels() 执行通知渠道初始化");
|
||||
// API<26 无渠道机制,直接返回
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
LogUtils.d(TAG, "initNotificationChannels: API<26,无需创建渠道");
|
||||
LogUtils.d(TAG, "initNotificationChannels() API<26,无需创建渠道");
|
||||
return;
|
||||
}
|
||||
// 通知服务为空,避免空指针
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "initNotificationChannels: 失败:NotificationManager is null");
|
||||
LogUtils.e(TAG, "initNotificationChannels() 失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ public class NotificationManagerUtils {
|
||||
foregroundChannel.setSound(null, null); // 强制无铃声
|
||||
foregroundChannel.setShowBadge(false);
|
||||
foregroundChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 前台服务渠道配置完成");
|
||||
LogUtils.d(TAG, "initNotificationChannels() 前台服务渠道配置完成");
|
||||
|
||||
// 2. 电池提醒渠道(中优先级,系统默认铃声,无振动)
|
||||
NotificationChannel remindChannel = new NotificationChannel(
|
||||
@@ -117,27 +118,27 @@ public class NotificationManagerUtils {
|
||||
remindChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
remindChannel.setShowBadge(false);
|
||||
remindChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 电池提醒渠道配置完成");
|
||||
LogUtils.d(TAG, "initNotificationChannels() 电池提醒渠道配置完成");
|
||||
|
||||
// 3. 应用配置信息渠道(新增:最低优先级,无铃声无振动,仅提示不打扰)
|
||||
// 3. 应用配置信息渠道(方案1修复:默认优先级,系统默认铃声,无振动)
|
||||
NotificationChannel configChannel = new NotificationChannel(
|
||||
CHANNEL_ID_CONFIG,
|
||||
"应用配置信息",
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
);
|
||||
configChannel.setDescription("应用配置更新、参数变更等提示,无声音、无振动");
|
||||
configChannel.enableLights(false);
|
||||
configChannel.setDescription("应用配置更新、参数变更等提示,系统默认铃声、无振动");
|
||||
configChannel.enableLights(true);
|
||||
configChannel.enableVibration(false);
|
||||
configChannel.setSound(null, null);
|
||||
configChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT);
|
||||
configChannel.setShowBadge(false);
|
||||
configChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||
LogUtils.d(TAG, "initNotificationChannels: 应用配置信息渠道配置完成");
|
||||
configChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||
LogUtils.d(TAG, "initNotificationChannels() 应用配置信息渠道配置完成");
|
||||
|
||||
// 注册渠道到系统
|
||||
mNotificationManager.createNotificationChannel(foregroundChannel);
|
||||
mNotificationManager.createNotificationChannel(remindChannel);
|
||||
mNotificationManager.createNotificationChannel(configChannel); // 注册新增渠道
|
||||
LogUtils.d(TAG, "initNotificationChannels: 成功:创建前台服务+电池提醒+应用配置信息渠道");
|
||||
LogUtils.d(TAG, "initNotificationChannels() 成功:创建前台服务+电池提醒+应用配置信息渠道");
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(前台服务通知:启动/更新/取消)=================================
|
||||
@@ -145,26 +146,26 @@ public class NotificationManagerUtils {
|
||||
* 启动前台服务通知(API30适配,无铃声)
|
||||
*/
|
||||
public void startForegroundServiceNotify(Service service, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify: 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | service=" + service + " | message=" + message);
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify() 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | service=" + service + " | message=" + message);
|
||||
// 前置校验:参数非空
|
||||
if (service == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify: 失败:param is null | service=" + service + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify() 失败:param is null | service=" + service + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建前台通知
|
||||
mForegroundServiceNotify = buildForegroundNotification(message);
|
||||
if (mForegroundServiceNotify == null) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify: 失败:构建通知为空");
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify() 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动前台服务(API30无FOREGROUND_SERVICE_TYPE限制,全版本通用)
|
||||
try {
|
||||
service.startForeground(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify: 成功");
|
||||
LogUtils.d(TAG, "startForegroundServiceNotify() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify: 异常", e);
|
||||
LogUtils.e(TAG, "startForegroundServiceNotify() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,23 +173,23 @@ public class NotificationManagerUtils {
|
||||
* 更新前台服务通知内容(复用通知ID,保持无铃声)
|
||||
*/
|
||||
public void updateForegroundServiceNotify(NotificationMessage message) {
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify: 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | message=" + message);
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify() 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | message=" + message);
|
||||
if (message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify: 失败:param is null | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify() 失败:param is null | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
mForegroundServiceNotify = buildForegroundNotification(message);
|
||||
if (mForegroundServiceNotify == null) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify: 失败:构建通知为空");
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify() 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify: 成功");
|
||||
LogUtils.d(TAG, "updateForegroundServiceNotify() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify: 异常", e);
|
||||
LogUtils.e(TAG, "updateForegroundServiceNotify() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +197,10 @@ public class NotificationManagerUtils {
|
||||
* 取消前台服务通知(Service销毁时调用)
|
||||
*/
|
||||
public void cancelForegroundServiceNotify() {
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify: 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify() 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
cancelNotification(NOTIFY_ID_FOREGROUND_SERVICE);
|
||||
mForegroundServiceNotify = null; // 置空释放
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify: 成功");
|
||||
LogUtils.d(TAG, "cancelForegroundServiceNotify() 成功");
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(电池提醒通知:发送)=================================
|
||||
@@ -207,48 +208,70 @@ public class NotificationManagerUtils {
|
||||
* 发送电池提醒通知(系统默认铃声,无振动)
|
||||
*/
|
||||
public void showRemindNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "showRemindNotification: 执行 | notifyId=" + NOTIFY_ID_REMIND + " | context=" + context + " | message=" + message);
|
||||
LogUtils.d(TAG, "showRemindNotification() 执行 | notifyId=" + NOTIFY_ID_REMIND + " | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "showRemindNotification: 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
LogUtils.e(TAG, "showRemindNotification() 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification remindNotify = buildRemindNotification(context, message);
|
||||
if (remindNotify == null) {
|
||||
LogUtils.e(TAG, "showRemindNotification: 失败:构建通知为空");
|
||||
LogUtils.e(TAG, "showRemindNotification() 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_REMIND, remindNotify);
|
||||
LogUtils.d(TAG, "showRemindNotification: 成功");
|
||||
LogUtils.d(TAG, "showRemindNotification() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "showRemindNotification: 异常", e);
|
||||
LogUtils.e(TAG, "showRemindNotification() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(应用配置信息通知:发送)=================================
|
||||
/**
|
||||
* 发送应用配置信息通知(新增:低优先级无铃声,仅提示不打扰)
|
||||
*/
|
||||
public void showConfigNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "showConfigNotification: 执行 | notifyId=" + NOTIFY_ID_CONFIG + " | context=" + context + " | message=" + message);
|
||||
public synchronized void showMessageNotification(Context context, NotificationMessage message) {
|
||||
snMessageNotificationID++;
|
||||
LogUtils.d(TAG, "showMessageNotification() 执行 | notifyId=" + snMessageNotificationID + " | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
LogUtils.e(TAG, "showMessageNotification() 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification configNotify = buildConfigNotification(context, message);
|
||||
if (configNotify == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 失败:构建通知为空");
|
||||
LogUtils.e(TAG, "showMessageNotification() 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(snMessageNotificationID, configNotify);
|
||||
LogUtils.d(TAG, "showMessageNotification() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "showMessageNotification() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 对外核心方法(应用配置信息通知:发送)=================================
|
||||
/**
|
||||
* 发送应用配置信息通知(方案1修复:系统默认铃声,无振动)
|
||||
*/
|
||||
public void showConfigNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "showConfigNotification() 执行 | notifyId=" + NOTIFY_ID_CONFIG + " | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null || mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification() 失败:param is null | context=" + context + " | message=" + message + " | mNotificationManager=" + mNotificationManager);
|
||||
return;
|
||||
}
|
||||
|
||||
Notification configNotify = buildConfigNotification(context, message);
|
||||
if (configNotify == null) {
|
||||
LogUtils.e(TAG, "showConfigNotification() 失败:构建通知为空");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mNotificationManager.notify(NOTIFY_ID_CONFIG, configNotify);
|
||||
LogUtils.d(TAG, "showConfigNotification: 成功");
|
||||
LogUtils.d(TAG, "showConfigNotification() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "showConfigNotification: 异常", e);
|
||||
LogUtils.e(TAG, "showConfigNotification() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,16 +280,16 @@ public class NotificationManagerUtils {
|
||||
* 取消指定ID的通知
|
||||
*/
|
||||
public void cancelNotification(int notifyId) {
|
||||
LogUtils.d(TAG, "cancelNotification: 执行 | notifyId=" + notifyId);
|
||||
LogUtils.d(TAG, "cancelNotification() 执行 | notifyId=" + notifyId);
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "cancelNotification: 失败:NotificationManager is null");
|
||||
LogUtils.e(TAG, "cancelNotification() 失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mNotificationManager.cancel(notifyId);
|
||||
LogUtils.d(TAG, "cancelNotification: 成功 | notifyId=" + notifyId);
|
||||
LogUtils.d(TAG, "cancelNotification() 成功 | notifyId=" + notifyId);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "cancelNotification: 异常 | notifyId=" + notifyId, e);
|
||||
LogUtils.e(TAG, "cancelNotification() 异常 | notifyId=" + notifyId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,16 +297,16 @@ public class NotificationManagerUtils {
|
||||
* 取消所有通知(兜底场景使用)
|
||||
*/
|
||||
public void cancelAllNotifications() {
|
||||
LogUtils.d(TAG, "cancelAllNotifications: 执行");
|
||||
LogUtils.d(TAG, "cancelAllNotifications() 执行");
|
||||
if (mNotificationManager == null) {
|
||||
LogUtils.e(TAG, "cancelAllNotifications: 失败:NotificationManager is null");
|
||||
LogUtils.e(TAG, "cancelAllNotifications() 失败:NotificationManager is null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mNotificationManager.cancelAll();
|
||||
LogUtils.d(TAG, "cancelAllNotifications: 成功");
|
||||
LogUtils.d(TAG, "cancelAllNotifications() 成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "cancelAllNotifications: 异常", e);
|
||||
LogUtils.e(TAG, "cancelAllNotifications() 异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,30 +315,30 @@ public class NotificationManagerUtils {
|
||||
* 构建前台服务通知(全版本无铃声+无振动)
|
||||
*/
|
||||
private Notification buildForegroundNotification(NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 执行 | message=" + message);
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 执行 | message=" + message);
|
||||
if (message == null || mContext == null) {
|
||||
LogUtils.e(TAG, "buildForegroundNotification: 失败:param is null | message=" + message + " | mContext=" + mContext);
|
||||
LogUtils.e(TAG, "buildForegroundNotification() 失败:param is null | message=" + message + " | mContext=" + mContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : FOREGROUND_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : FOREGROUND_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// API26+:绑定前台渠道(渠道已配置无铃声)
|
||||
builder = new Notification.Builder(mContext, CHANNEL_ID_FOREGROUND);
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 使用API26+渠道构建");
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 使用API26+渠道构建");
|
||||
} else {
|
||||
// API<26:直接构建,手动禁用铃声振动
|
||||
builder = new Notification.Builder(mContext);
|
||||
builder.setSound(null);
|
||||
builder.setVibrate(new long[]{0});
|
||||
builder.setDefaults(0);
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 使用API<26手动配置");
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 使用API<26手动配置");
|
||||
}
|
||||
|
||||
// 通用配置
|
||||
@@ -332,11 +355,11 @@ public class NotificationManagerUtils {
|
||||
builder.setLargeIcon(getAppIcon(mContext))
|
||||
.setColor(mContext.getResources().getColor(R.color.colorPrimary))
|
||||
.setPriority(Notification.PRIORITY_LOW);
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 补充API21+配置");
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 补充API21+配置");
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
LogUtils.d(TAG, "buildForegroundNotification: 成功构建前台通知");
|
||||
LogUtils.d(TAG, "buildForegroundNotification() 成功构建前台通知");
|
||||
return notification;
|
||||
}
|
||||
|
||||
@@ -345,30 +368,30 @@ public class NotificationManagerUtils {
|
||||
* 构建电池提醒通知(全版本系统默认铃声+无振动)
|
||||
*/
|
||||
private Notification buildRemindNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildRemindNotification: 执行 | context=" + context + " | message=" + message);
|
||||
LogUtils.d(TAG, "buildRemindNotification() 执行 | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null) {
|
||||
LogUtils.e(TAG, "buildRemindNotification: 失败:param is null | context=" + context + " | message=" + message);
|
||||
LogUtils.e(TAG, "buildRemindNotification() 失败:param is null | context=" + context + " | message=" + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : REMIND_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : REMIND_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildRemindNotification: 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
LogUtils.d(TAG, "buildRemindNotification() 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// API26+:绑定提醒渠道(渠道已配置默认铃声)
|
||||
builder = new Notification.Builder(context, CHANNEL_ID_REMIND);
|
||||
LogUtils.d(TAG, "buildRemindNotification: 使用API26+渠道构建");
|
||||
LogUtils.d(TAG, "buildRemindNotification() 使用API26+渠道构建");
|
||||
} else {
|
||||
// API<26:手动配置默认铃声,关闭振动
|
||||
builder = new Notification.Builder(context);
|
||||
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI) // 显式默认铃声
|
||||
.setVibrate(new long[]{0})
|
||||
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND);
|
||||
LogUtils.d(TAG, "buildRemindNotification: 使用API<26手动配置");
|
||||
LogUtils.d(TAG, "buildRemindNotification() 使用API<26手动配置");
|
||||
}
|
||||
|
||||
// 通用配置
|
||||
@@ -386,43 +409,43 @@ public class NotificationManagerUtils {
|
||||
builder.setLargeIcon(getAppIcon(context))
|
||||
.setColor(context.getResources().getColor(R.color.colorPrimary))
|
||||
.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
LogUtils.d(TAG, "buildRemindNotification: 补充API21+配置");
|
||||
LogUtils.d(TAG, "buildRemindNotification() 补充API21+配置");
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
LogUtils.d(TAG, "buildRemindNotification: 成功构建提醒通知");
|
||||
LogUtils.d(TAG, "buildRemindNotification() 成功构建提醒通知");
|
||||
return notification;
|
||||
}
|
||||
|
||||
// ================================== 内部辅助方法(通知构建:应用配置信息通知)=================================
|
||||
/**
|
||||
* 构建应用配置信息通知(新增:全版本无铃声+无振动,低优先级)
|
||||
* 构建应用配置信息通知(方案1修复:全版本系统默认铃声+无振动)
|
||||
*/
|
||||
private Notification buildConfigNotification(Context context, NotificationMessage message) {
|
||||
LogUtils.d(TAG, "buildConfigNotification: 执行 | context=" + context + " | message=" + message);
|
||||
LogUtils.d(TAG, "buildConfigNotification() 执行 | context=" + context + " | message=" + message);
|
||||
if (context == null || message == null) {
|
||||
LogUtils.e(TAG, "buildConfigNotification: 失败:param is null | context=" + context + " | message=" + message);
|
||||
LogUtils.e(TAG, "buildConfigNotification() 失败:param is null | context=" + context + " | message=" + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 内容兜底
|
||||
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : CONFIG_NOTIFY_TITLE_DEFAULT;
|
||||
String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : CONFIG_NOTIFY_CONTENT_DEFAULT;
|
||||
LogUtils.d(TAG, "buildConfigNotification: 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
LogUtils.d(TAG, "buildConfigNotification() 内容兜底完成 | title=" + title + " | content=" + content);
|
||||
|
||||
Notification.Builder builder;
|
||||
// API分级构建
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// API26+:绑定配置渠道(渠道已配置无铃声)
|
||||
// API26+:绑定配置渠道(渠道已配置默认铃声)
|
||||
builder = new Notification.Builder(context, CHANNEL_ID_CONFIG);
|
||||
LogUtils.d(TAG, "buildConfigNotification: 使用API26+渠道构建");
|
||||
LogUtils.d(TAG, "buildConfigNotification() 使用API26+渠道构建");
|
||||
} else {
|
||||
// API<26:直接构建,手动禁用铃声振动
|
||||
// API<26:手动配置默认铃声,关闭振动(方案1修复:保留铃声配置,删除冗余DEFAULT_SOUND)
|
||||
builder = new Notification.Builder(context);
|
||||
builder.setSound(null);
|
||||
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
|
||||
builder.setVibrate(new long[]{0});
|
||||
builder.setDefaults(0);
|
||||
LogUtils.d(TAG, "buildConfigNotification: 使用API<26手动配置");
|
||||
builder.setDefaults(Notification.DEFAULT_LIGHTS);
|
||||
LogUtils.d(TAG, "buildConfigNotification() 使用API<26手动配置");
|
||||
}
|
||||
|
||||
// 通用配置
|
||||
@@ -438,12 +461,12 @@ public class NotificationManagerUtils {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
builder.setLargeIcon(getAppIcon(context))
|
||||
.setColor(context.getResources().getColor(R.color.colorPrimary))
|
||||
.setPriority(Notification.PRIORITY_MIN); // 最低优先级
|
||||
LogUtils.d(TAG, "buildConfigNotification: 补充API21+配置");
|
||||
.setPriority(Notification.PRIORITY_DEFAULT);
|
||||
LogUtils.d(TAG, "buildConfigNotification() 补充API21+配置");
|
||||
}
|
||||
|
||||
Notification notification = builder.build();
|
||||
LogUtils.d(TAG, "buildConfigNotification: 成功构建配置信息通知");
|
||||
LogUtils.d(TAG, "buildConfigNotification() 成功构建配置信息通知");
|
||||
return notification;
|
||||
}
|
||||
|
||||
@@ -452,20 +475,20 @@ public class NotificationManagerUtils {
|
||||
* 创建跳转MainActivity的PendingIntent,API23+ 添加IMMUTABLE标记(避免安全异常)
|
||||
*/
|
||||
private PendingIntent createJumpPendingIntent(Context context, int requestCode) {
|
||||
LogUtils.d(TAG, "createJumpPendingIntent: 执行 | requestCode=" + requestCode + " | context=" + context);
|
||||
LogUtils.d(TAG, "createJumpPendingIntent() 执行 | requestCode=" + requestCode + " | context=" + context);
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
LogUtils.d(TAG, "createJumpPendingIntent: 跳转Intent配置完成");
|
||||
LogUtils.d(TAG, "createJumpPendingIntent() 跳转Intent配置完成");
|
||||
|
||||
// API23+ 必需添加IMMUTABLE,适配API30安全规范
|
||||
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
flags |= PendingIntent.FLAG_IMMUTABLE;
|
||||
LogUtils.d(TAG, "createJumpPendingIntent: 添加FLAG_IMMUTABLE标记(API23+)");
|
||||
LogUtils.d(TAG, "createJumpPendingIntent() 添加FLAG_IMMUTABLE标记(API23+)");
|
||||
}
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, flags);
|
||||
LogUtils.d(TAG, "createJumpPendingIntent: 成功 | requestCode=" + requestCode);
|
||||
LogUtils.d(TAG, "createJumpPendingIntent() 成功 | requestCode=" + requestCode);
|
||||
return pendingIntent;
|
||||
}
|
||||
|
||||
@@ -474,14 +497,14 @@ public class NotificationManagerUtils {
|
||||
* 获取APP图标,失败返回默认图标
|
||||
*/
|
||||
private Bitmap getAppIcon(Context context) {
|
||||
LogUtils.d(TAG, "getAppIcon: 执行 | context=" + context);
|
||||
LogUtils.d(TAG, "getAppIcon() 执行 | context=" + context);
|
||||
try {
|
||||
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||
Bitmap appIcon = BitmapFactory.decodeResource(context.getResources(), pkgInfo.applicationInfo.icon);
|
||||
LogUtils.d(TAG, "getAppIcon: 成功:获取应用图标");
|
||||
LogUtils.d(TAG, "getAppIcon() 成功:获取应用图标");
|
||||
return appIcon;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
LogUtils.e(TAG, "getAppIcon: 异常:获取应用图标失败,使用默认图标", e);
|
||||
LogUtils.e(TAG, "getAppIcon() 异常:获取应用图标失败,使用默认图标", e);
|
||||
return BitmapFactory.decodeResource(context.getResources(), NOTIFICATION_DEFAULT_ICON);
|
||||
}
|
||||
}
|
||||
@@ -491,11 +514,11 @@ public class NotificationManagerUtils {
|
||||
* 释放资源,销毁时调用
|
||||
*/
|
||||
public void release() {
|
||||
LogUtils.d(TAG, "release: 执行资源释放");
|
||||
LogUtils.d(TAG, "release() 执行资源释放");
|
||||
cancelForegroundServiceNotify();
|
||||
mNotificationManager = null;
|
||||
mContext = null;
|
||||
LogUtils.d(TAG, "release: 成功:所有资源已释放");
|
||||
LogUtils.d(TAG, "release() 成功:所有资源已释放");
|
||||
}
|
||||
|
||||
// ================================== 对外 getter 方法(仅前台通知实例,只读)=================================
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ import android.widget.TextView;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
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.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
|
||||
/**
|
||||
* 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑
|
||||
@@ -151,13 +153,20 @@ public class MainContentView {
|
||||
// 基础布局绑定
|
||||
mainLayout = (RelativeLayout) rootView.findViewById(R.id.activitymainRelativeLayout1);
|
||||
mllBackgroundView = (LinearLayout) rootView.findViewById(R.id.ll_backgroundview);
|
||||
backgroundView = App.sMemoryCachedBackgroundView.getLastInstance(mContext);
|
||||
|
||||
backgroundView = App.getInstance().getMemoryCachedBackgroundView();
|
||||
if (backgroundView == null) {
|
||||
App.sBackgroundSourceUtils.loadSettings();
|
||||
BackgroundBean backgroundBean = App.sBackgroundSourceUtils.getCurrentBackgroundBean();
|
||||
backgroundView = App.getInstance().getMemoryCachedBackgroundView().getInstance(mContext, backgroundBean, true);
|
||||
}
|
||||
if (backgroundView.getParent() != null) {
|
||||
((ViewGroup) backgroundView.getParent()).removeView(backgroundView);
|
||||
LogUtils.d(TAG, "【bindViews】移除背景视图旧父容器");
|
||||
}
|
||||
mllBackgroundView.addView(backgroundView);
|
||||
// 容器布局绑定
|
||||
|
||||
// 容器布局绑定
|
||||
llLeftSeekBar = (LinearLayout) rootView.findViewById(R.id.fragmentmainviewLinearLayout1);
|
||||
llRightSeekBar = (LinearLayout) rootView.findViewById(R.id.fragmentmainviewLinearLayout2);
|
||||
// 开关控件绑定
|
||||
@@ -188,6 +197,15 @@ public class MainContentView {
|
||||
LogUtils.d(TAG, "【bindViews】视图绑定完成");
|
||||
}
|
||||
|
||||
public void reloadBackgroundView() {
|
||||
if (backgroundView != null) {
|
||||
App.sBackgroundSourceUtils.loadSettings();
|
||||
BackgroundBean backgroundBean = App.sBackgroundSourceUtils.getCurrentBackgroundBean();
|
||||
backgroundView.loadByBackgroundBean(backgroundBean, true);
|
||||
//App.notifyMessage(TAG, "reloadBackgroundView");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化电池 Drawable(集成 BatteryDrawable,默认能量风格,适配小米机型渲染)
|
||||
*/
|
||||
|
||||
@@ -58,36 +58,27 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @param isReload 是否强制重新加载图片(路径匹配时仍刷新)
|
||||
* @return 缓存/新创建的MemoryCachedBackgroundView实例
|
||||
*/
|
||||
public static MemoryCachedBackgroundView getInstance(Context context, int bgColor, String imagePath, boolean isReload) {
|
||||
LogUtils.d(TAG, String.format("getInstance 调用 | 图片路径=%s | 是否重载=%b", imagePath, isReload));
|
||||
// 空路径校验
|
||||
if (TextUtils.isEmpty(imagePath)) {
|
||||
LogUtils.e(TAG, "getInstance: 图片路径为空,创建空实例");
|
||||
return new MemoryCachedBackgroundView(context);
|
||||
}
|
||||
|
||||
// 1. 路径匹配缓存 → 判断是否强制重载
|
||||
if (imagePath.equals(sCachedImagePath) && sCachedView != null) {
|
||||
LogUtils.d(TAG, "getInstance: 路径已缓存,当前缓存实例有效");
|
||||
if (isReload) {
|
||||
LogUtils.d(TAG, String.format("getInstance: 强制重载图片 | 路径=%s", imagePath));
|
||||
sCachedView.loadImage(bgColor, imagePath, isReload);
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("getInstance: 使用缓存实例,无需重载 | 路径=%s", imagePath));
|
||||
}
|
||||
return sCachedView;
|
||||
}
|
||||
|
||||
// 2. 路径不匹配/无缓存 → 新建实例并更新静态缓存(核心:保留旧实例,仅更新引用)
|
||||
LogUtils.d(TAG, String.format("getInstance: 路径未缓存,新建实例(保留旧实例) | 路径=%s", imagePath));
|
||||
String oldPath = sCachedImagePath;
|
||||
public static MemoryCachedBackgroundView getInstance(Context context, BackgroundBean bean, boolean isReload) {
|
||||
LogUtils.d(TAG, String.format("getInstance 调用 | BackgroundBean=%s | 是否重载=%b", bean.toString(), isReload));
|
||||
//App.notifyMessage(TAG, String.format("getInstance 调用 | BackgroundBean=%s | 是否重载=%b", bean.toString(), isReload));
|
||||
sCachedView = new MemoryCachedBackgroundView(context);
|
||||
sCachedImagePath = imagePath;
|
||||
sCachedView.loadImage(bgColor, imagePath, isReload);
|
||||
LogUtils.d(TAG, String.format("getInstance: 已更新当前缓存实例,旧实例路径=%s(强制保持)", oldPath));
|
||||
sCachedView.loadByBackgroundBean(bean, isReload);
|
||||
saveLastLoadImagePath(context, getBackgroundBeanImagePath(bean));
|
||||
LogUtils.d(TAG, String.format("getInstance: 已更新当前缓存实例,旧实例路径=%s(强制保持)", getBackgroundBeanImagePath(bean)));
|
||||
//App.notifyMessage(TAG, String.format("getInstance: 已更新当前缓存实例,旧实例路径=%s(强制保持)", getBackgroundBeanImagePath(bean)));
|
||||
return sCachedView;
|
||||
}
|
||||
|
||||
static String getBackgroundBeanImagePath(BackgroundBean bean) {
|
||||
if (bean.isUseBackgroundFile()) {
|
||||
if (bean.isUseBackgroundScaledCompressFile()) {
|
||||
return bean.getBackgroundScaledCompressFilePath();
|
||||
}
|
||||
return bean.getBackgroundFilePath();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// ====================================== 新增功能:获取最后加载的实例(强制缓存版) ======================================
|
||||
/**
|
||||
* 获取最后一次loadImage的路径对应的实例(强制保持所有实例)
|
||||
@@ -97,28 +88,19 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
*/
|
||||
public static MemoryCachedBackgroundView getLastInstance(Context context) {
|
||||
LogUtils.d(TAG, "getLastInstance 调用");
|
||||
//App.notifyMessage(TAG, "getLastInstance 调用");
|
||||
// 1. 从SP获取最后加载的路径(强制保持,不自动删除)
|
||||
String lastPath = getLastLoadImagePath(context);
|
||||
if (TextUtils.isEmpty(lastPath)) {
|
||||
LogUtils.e(TAG, "getLastInstance: 无最后加载路径,创建空实例");
|
||||
return new MemoryCachedBackgroundView(context);
|
||||
}
|
||||
|
||||
// 2. 路径匹配当前缓存 → 直接返回
|
||||
sCachedImagePath = getLastLoadImagePath(context);
|
||||
String lastPath = getBackgroundBeanImagePath(App.sBackgroundSourceUtils.getCurrentBackgroundBean());
|
||||
//App.notifyMessage(TAG, String.format("sCachedImagePath : %s", sCachedImagePath));
|
||||
//App.notifyMessage(TAG, String.format("lastPath : %s", lastPath));
|
||||
if (lastPath.equals(sCachedImagePath) && sCachedView != null) {
|
||||
LogUtils.d(TAG, String.format("getLastInstance: 使用最后路径缓存实例 | 路径=%s", lastPath));
|
||||
//App.notifyMessage(TAG, String.format("getLastInstance: 使用最后路径缓存实例 | 路径=%s", lastPath));
|
||||
return sCachedView;
|
||||
}
|
||||
|
||||
// 3. 路径不匹配 → 新建实例并更新缓存(保留旧实例)
|
||||
LogUtils.d(TAG, String.format("getLastInstance: 最后路径未缓存,新建实例并加载(保留旧实例) | 路径=%s", lastPath));
|
||||
String oldPath = sCachedImagePath;
|
||||
sCachedView = new MemoryCachedBackgroundView(context);
|
||||
sCachedImagePath = lastPath;
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(context).getCurrentBackgroundBean().getPixelColor();
|
||||
sCachedView.loadImage(nCurrentPixelColor, sCachedImagePath, false);
|
||||
LogUtils.d(TAG, String.format("getLastInstance: 已更新最后路径实例,旧实例路径=%s(强制保持)", oldPath));
|
||||
return sCachedView;
|
||||
//App.notifyMessage(TAG, "getLastInstance 返回 null");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ====================================== 工具方法:SP持久化最后加载路径(强制保持版) ======================================
|
||||
@@ -207,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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user