Compare commits
24 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b1d160dac | |||
| db87ba51e3 | |||
| fd6e852061 | |||
| 8ff4b9e1f4 | |||
| 78a2d85150 | |||
| fd2d1d17ed | |||
| 37f3091103 | |||
| 6dc5f05702 | |||
| 77df2558b3 | |||
| 315541f2d2 | |||
| f52bb54d22 | |||
| 0742164f65 | |||
| fc785b9258 | |||
| 0abeb982d2 | |||
| 81f0e5c56e | |||
| 4fcce7edb3 | |||
| 59f5eae136 | |||
| bf9479c53f | |||
| f4a485f1ff | |||
| 80da7677f8 | |||
| e1c3c8f072 | |||
| 2238d632f7 | |||
| 558bc16013 | |||
| 7d50453e34 |
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Wed Dec 24 12:22:06 HKT 2025
|
||||
stageCount=29
|
||||
#Fri Dec 26 02:58:19 HKT 2025
|
||||
stageCount=35
|
||||
libraryProject=
|
||||
baseVersion=15.14
|
||||
publishVersion=15.14.28
|
||||
publishVersion=15.14.34
|
||||
buildCount=0
|
||||
baseBetaVersion=15.14.29
|
||||
baseBetaVersion=15.14.35
|
||||
|
||||
@@ -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;
|
||||
@@ -15,6 +17,9 @@ 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 {
|
||||
// ===================== 常量定义区(按功能分类排序) =====================
|
||||
@@ -32,31 +37,47 @@ 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;
|
||||
|
||||
// 数据配置工具
|
||||
private static AppConfigUtils sAppConfigUtils;
|
||||
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() {
|
||||
return sApp;
|
||||
}
|
||||
|
||||
// ===================== 公共静态方法区(工具类实例获取) =====================
|
||||
/**
|
||||
* 获取应用配置工具实例
|
||||
*/
|
||||
public static AppConfigUtils getAppConfigUtils(Context context) {
|
||||
LogUtils.d(TAG, "getAppConfigUtils() 调用,传入Context类型:" + (context != null ? context.getClass().getSimpleName() : "null"));
|
||||
LogUtils.d(TAG, String.format("getAppConfigUtils() 调用 | 传入Context类型=%s",
|
||||
context != null ? context.getClass().getSimpleName() : "null"));
|
||||
if (sAppConfigUtils == null) {
|
||||
sAppConfigUtils = AppConfigUtils.getInstance(context);
|
||||
LogUtils.d(TAG, "getAppConfigUtils():AppConfigUtils实例已初始化");
|
||||
@@ -68,7 +89,8 @@ public class App extends GlobalApplication {
|
||||
* 获取应用缓存工具实例
|
||||
*/
|
||||
public static AppCacheUtils getAppCacheUtils(Context context) {
|
||||
LogUtils.d(TAG, "getAppCacheUtils() 调用,传入Context类型:" + (context != null ? context.getClass().getSimpleName() : "null"));
|
||||
LogUtils.d(TAG, String.format("getAppCacheUtils() 调用 | 传入Context类型=%s",
|
||||
context != null ? context.getClass().getSimpleName() : "null"));
|
||||
if (sAppCacheUtils == null) {
|
||||
sAppCacheUtils = AppCacheUtils.getInstance(context);
|
||||
LogUtils.d(TAG, "getAppCacheUtils():AppCacheUtils实例已初始化");
|
||||
@@ -95,18 +117,43 @@ public class App extends GlobalApplication {
|
||||
* 极致强制缓存策略下,仅提供手动清理入口,永不自动调用
|
||||
*/
|
||||
public static void manualClearAllCache() {
|
||||
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 手动清理缓存调用(极致强制缓存策略下,需谨慎使用)");
|
||||
LogUtils.w(TAG, String.format("%s 手动清理缓存调用(极致强制缓存策略下,需谨慎使用)", CACHE_PROTECT_TAG));
|
||||
// 清理Bitmap缓存
|
||||
if (sBitmapCacheUtils != null) {
|
||||
sBitmapCacheUtils.clearAllCache();
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存已手动清理");
|
||||
LogUtils.d(TAG, String.format("%s Bitmap缓存已手动清理", CACHE_PROTECT_TAG));
|
||||
}
|
||||
// 清理视图控件缓存(仅清除静态引用,不销毁实例)
|
||||
if (sMemoryCachedBackgroundView != null) {
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件缓存实例保持,仅清除静态引用");
|
||||
LogUtils.d(TAG, String.format("%s 视图控件缓存实例保持,仅清除静态引用", CACHE_PROTECT_TAG));
|
||||
sMemoryCachedBackgroundView = null;
|
||||
}
|
||||
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 手动清理缓存完成(部分缓存实例仍可能保留在内存中)");
|
||||
LogUtils.w(TAG, String.format("%s 手动清理缓存完成(部分缓存实例仍可能保留在内存中)", CACHE_PROTECT_TAG));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视图控件缓存实例(非通用:仅通过App实例调用,避免全局直接访问)
|
||||
*/
|
||||
public MemoryCachedBackgroundView getMemoryCachedBackgroundView() {
|
||||
LogUtils.d(TAG, "getMemoryCachedBackgroundView() 调用 | 视图控件缓存实例获取");
|
||||
if (sMemoryCachedBackgroundView == null) {
|
||||
LogUtils.w(TAG, "getMemoryCachedBackgroundView():视图控件缓存实例未初始化,返回null");
|
||||
}
|
||||
return sMemoryCachedBackgroundView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送调试通知
|
||||
*/
|
||||
public static void notifyMessage(String title, String content) {
|
||||
LogUtils.d(TAG, String.format("notifyMessage() 调用 | title=%s | content=%s", title, content));
|
||||
if (isDebugging() && sApp != null && sNotificationManagerUtils != null) {
|
||||
NotificationMessage message = new NotificationMessage(title, content, "");
|
||||
sNotificationManagerUtils.showMessageNotification(sApp, message);
|
||||
LogUtils.d(TAG, "notifyMessage():调试通知发送成功");
|
||||
} else {
|
||||
LogUtils.d(TAG, "notifyMessage():调试通知发送失败(条件不满足)");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== 生命周期方法区(按执行顺序排序) =====================
|
||||
@@ -114,10 +161,11 @@ public class App extends GlobalApplication {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, "onCreate() 应用启动,开始初始化");
|
||||
sApp = this;
|
||||
|
||||
// 初始化调试模式
|
||||
setIsDebugging(BuildConfig.DEBUG);
|
||||
LogUtils.d(TAG, "onCreate() 调试模式:" + BuildConfig.DEBUG);
|
||||
LogUtils.d(TAG, String.format("onCreate() 调试模式=%b", BuildConfig.DEBUG));
|
||||
|
||||
// 初始化基础工具
|
||||
initBaseTools();
|
||||
@@ -143,7 +191,7 @@ public class App extends GlobalApplication {
|
||||
releaseReceiver();
|
||||
|
||||
// 核心修改:应用终止时也不清理缓存,保持静态实例
|
||||
LogUtils.w(TAG, CACHE_PROTECT_TAG + " 应用终止,极致强制缓存策略生效,不清理任何缓存");
|
||||
LogUtils.w(TAG, String.format("%s 应用终止,极致强制缓存策略生效,不清理任何缓存", CACHE_PROTECT_TAG));
|
||||
|
||||
LogUtils.d(TAG, "onTerminate() 非缓存资源释放完成,缓存实例保持");
|
||||
}
|
||||
@@ -152,7 +200,8 @@ public class App extends GlobalApplication {
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
// 极致强制缓存:禁止任何缓存清理操作,仅记录日志
|
||||
LogUtils.w(TAG, CACHE_PROTECT_TAG + " onTrimMemory() 调用,内存等级level:" + level + ",极致强制保持所有缓存");
|
||||
LogUtils.w(TAG, String.format("%s onTrimMemory() 调用 | 内存等级level=%d | 极致强制保持所有缓存",
|
||||
CACHE_PROTECT_TAG, level));
|
||||
// 记录详细缓存状态,不执行任何清理
|
||||
logDetailedCacheStatus();
|
||||
}
|
||||
@@ -161,20 +210,21 @@ public class App extends GlobalApplication {
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
// 极致强制缓存:低内存时也不清理任何缓存
|
||||
LogUtils.w(TAG, CACHE_PROTECT_TAG + " onLowMemory() 调用,极致强制保持所有缓存");
|
||||
LogUtils.w(TAG, String.format("%s onLowMemory() 调用 | 极致强制保持所有缓存", CACHE_PROTECT_TAG));
|
||||
// 记录详细缓存状态,不执行任何清理
|
||||
logDetailedCacheStatus();
|
||||
}
|
||||
|
||||
// ===================== 私有初始化方法区(按初始化顺序排序) =====================
|
||||
/**
|
||||
* 初始化基础工具(Activity管理、Toast)
|
||||
* 初始化基础工具(Activity管理、Toast、通知工具)
|
||||
*/
|
||||
private void initBaseTools() {
|
||||
LogUtils.d(TAG, "initBaseTools() 开始初始化基础工具");
|
||||
WinBoLLActivityManager.init(this);
|
||||
ToastUtils.init(this);
|
||||
LogUtils.d(TAG, "initBaseTools() 基础工具初始化完成");
|
||||
sNotificationManagerUtils = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "initBaseTools() 基础工具+通知工具初始化完成,极致强制缓存策略已生效");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,19 +232,32 @@ public class App extends GlobalApplication {
|
||||
*/
|
||||
private void initUtils() {
|
||||
LogUtils.d(TAG, "initUtils() 开始初始化工具类,启用极致强制缓存策略");
|
||||
// 初始化配置&缓存工具
|
||||
sAppConfigUtils = getAppConfigUtils(this);
|
||||
sAppCacheUtils = getAppCacheUtils(this);
|
||||
|
||||
// 初始化背景资源工具
|
||||
sBackgroundSourceUtils = BackgroundSourceUtils.getInstance(this);
|
||||
sBackgroundSourceUtils.loadSettings();
|
||||
LogUtils.d(TAG, "initUtils() 背景资源工具已初始化");
|
||||
|
||||
// 极致强制初始化Bitmap缓存工具(必初始化,永不销毁)
|
||||
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||
LogUtils.d(TAG, "initUtils() Bitmap缓存工具已初始化(极致强制保持,永不销毁)");
|
||||
|
||||
// 极致强制初始化视图控件缓存工具(必初始化,永不销毁)
|
||||
// if(sMemoryCachedBackgroundView == null) {
|
||||
// App.notifyMessage(TAG, "sMemoryCachedBackgroundView == null");
|
||||
// }
|
||||
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getLastInstance(this);
|
||||
if (sMemoryCachedBackgroundView == null) {
|
||||
sMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, sBackgroundSourceUtils.getCurrentBackgroundBean(), true);
|
||||
LogUtils.d(TAG, "initUtils() 视图控件缓存工具已新建实例");
|
||||
//App.notifyMessage(TAG, "没有使用缓存控件");
|
||||
}
|
||||
|
||||
//App.notifyMessage(TAG, "initUtils() 视图控件缓存工具已初始化(极致强制保持,永不销毁)");
|
||||
LogUtils.d(TAG, "initUtils() 视图控件缓存工具已初始化(极致强制保持,永不销毁)");
|
||||
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "initUtils() 工具类初始化完成,极致强制缓存策略已生效");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,9 +290,9 @@ public class App extends GlobalApplication {
|
||||
*/
|
||||
private void releaseNotificationManager() {
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 开始释放通知工具");
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.release();
|
||||
mNotificationManager = null;
|
||||
if (sNotificationManagerUtils != null) {
|
||||
sNotificationManagerUtils.release();
|
||||
sNotificationManagerUtils = null;
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 通知工具资源已释放");
|
||||
} else {
|
||||
LogUtils.d(TAG, "releaseNotificationManager() 通知工具未初始化,无需释放");
|
||||
@@ -244,21 +307,22 @@ public class App extends GlobalApplication {
|
||||
LogUtils.d(TAG, "logDetailedCacheStatus() 开始记录详细缓存状态");
|
||||
// Bitmap缓存状态
|
||||
if (sBitmapCacheUtils != null) {
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存工具实例有效(极致强制保持)");
|
||||
LogUtils.d(TAG, String.format("%s Bitmap缓存工具实例有效(极致强制保持)", CACHE_PROTECT_TAG));
|
||||
// 假设BitmapCacheUtils有获取缓存数量的方法
|
||||
try {
|
||||
int cacheCount = sBitmapCacheUtils.getCacheCount();
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存数量:" + cacheCount);
|
||||
LogUtils.d(TAG, String.format("%s Bitmap缓存数量=%d", CACHE_PROTECT_TAG, cacheCount));
|
||||
} catch (Exception e) {
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " Bitmap缓存数量获取失败(不影响缓存),异常信息:" + e.getMessage());
|
||||
LogUtils.d(TAG, String.format("%s Bitmap缓存数量获取失败(不影响缓存)| 异常信息=%s",
|
||||
CACHE_PROTECT_TAG, e.getMessage()));
|
||||
}
|
||||
}
|
||||
// 视图控件缓存状态
|
||||
if (sMemoryCachedBackgroundView != null) {
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件缓存工具实例有效(极致强制保持)");
|
||||
LogUtils.d(TAG, String.format("%s 视图控件缓存工具实例有效(极致强制保持)", CACHE_PROTECT_TAG));
|
||||
// 记录视图实例总数
|
||||
int viewInstanceCount = MemoryCachedBackgroundView.getInstanceCount();
|
||||
LogUtils.d(TAG, CACHE_PROTECT_TAG + " 视图控件实例总数:" + viewInstanceCount);
|
||||
LogUtils.d(TAG, String.format("%s 视图控件实例总数=%d", CACHE_PROTECT_TAG, viewInstanceCount));
|
||||
}
|
||||
LogUtils.d(TAG, "logDetailedCacheStatus() 详细缓存状态记录完成,所有缓存均极致强制保持");
|
||||
}
|
||||
|
||||
@@ -35,17 +35,20 @@ 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;
|
||||
|
||||
/**
|
||||
* 应用核心主活动
|
||||
* 功能:管理电池监控、背景设置、服务启停、权限申请等核心功能
|
||||
* 适配:Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
*/
|
||||
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;
|
||||
public static final int MSG_RELOAD_APPCONFIG = 0;
|
||||
public static final int MSG_CURRENTVALUEBATTERY = 1;
|
||||
@@ -87,7 +90,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onCreate() | savedInstanceState=" + savedInstanceState);
|
||||
LogUtils.d(TAG, String.format("onCreate() | savedInstanceState=%s", savedInstanceState));
|
||||
|
||||
initGlobalHandler();
|
||||
setContentView(R.layout.activity_main);
|
||||
@@ -96,23 +99,55 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
initCriticalView();
|
||||
initCoreUtilsAsync();
|
||||
loadNonCriticalViewDelayed();
|
||||
|
||||
// 处理首次启动的参数
|
||||
handleReloadBackgroundParam(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
// 关键:将新 Intent 赋值给 Activity 的 Intent,确保后续 getIntent() 获取最新值
|
||||
setIntent(intent);
|
||||
// 统一处理参数
|
||||
handleReloadBackgroundParam(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一处理刷新背景的参数
|
||||
* @param intent 启动 MainActivity 的 Intent
|
||||
*/
|
||||
private void handleReloadBackgroundParam(Intent intent) {
|
||||
if (intent == null) {
|
||||
LogUtils.d(TAG, "handleReloadBackgroundParam: Intent 为空");
|
||||
return;
|
||||
}
|
||||
// 获取传递的参数,默认值为 false
|
||||
boolean isReloadBackgroundView = intent.getBooleanExtra(EXTRA_ISRELOAD_BACKGROUNDVIEW, false);
|
||||
if (isReloadBackgroundView) {
|
||||
LogUtils.d(TAG, "接收到刷新背景视图指令");
|
||||
// 执行背景刷新逻辑
|
||||
//App.notifyMessage(TAG, "reloadBackgroundView");
|
||||
reloadBackgroundView();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "onPostCreate() | savedInstanceState=" + savedInstanceState);
|
||||
LogUtils.d(TAG, String.format("onPostCreate() | savedInstanceState=%s", savedInstanceState));
|
||||
mPermissionUtils.startPermissionRequest(this);
|
||||
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
LogUtils.d(TAG, "onResume()");
|
||||
|
||||
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.resumeADs(this);
|
||||
LogUtils.d(TAG, "onResume: 广告视图已恢复");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,21 +166,25 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
if (mADsBannerView != null) {
|
||||
mADsBannerView.releaseAdResources();
|
||||
mADsBannerView = null;
|
||||
LogUtils.d(TAG, "onDestroy: 广告资源已释放");
|
||||
}
|
||||
// 释放核心视图
|
||||
if (mMainContentView != null) {
|
||||
mMainContentView.releaseResources();
|
||||
mMainContentView = null;
|
||||
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
|
||||
}
|
||||
// 销毁Handler,防止内存泄漏
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.removeCallbacksAndMessages(null);
|
||||
sGlobalHandler = null;
|
||||
LogUtils.d(TAG, "onDestroy: 全局Handler已销毁");
|
||||
}
|
||||
// 释放Drawable
|
||||
if (mFrameDrawable != null) {
|
||||
mFrameDrawable.setCallback(null);
|
||||
mFrameDrawable = null;
|
||||
LogUtils.d(TAG, "onDestroy: 框架Drawable已释放");
|
||||
}
|
||||
// 置空所有引用
|
||||
sMainActivity = null;
|
||||
@@ -162,22 +201,25 @@ 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, "onActivityResult() | requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data);
|
||||
LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d | data=%s",
|
||||
requestCode, resultCode, 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, "onCreateOptionsMenu() | menu=" + menu);
|
||||
LogUtils.d(TAG, String.format("onCreateOptionsMenu() | menu=%s", menu));
|
||||
mMenu = menu;
|
||||
AESThemeUtil.inflateMenu(this, menu);
|
||||
if (App.isDebugging()) {
|
||||
DevelopUtils.inflateMenu(this, menu);
|
||||
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
|
||||
LogUtils.d(TAG, "onCreateOptionsMenu: 已加载测试菜单");
|
||||
}
|
||||
getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
|
||||
return true;
|
||||
@@ -185,7 +227,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
LogUtils.d(TAG, "onOptionsItemSelected() | itemId=" + item.getItemId());
|
||||
LogUtils.d(TAG, String.format("onOptionsItemSelected() | itemId=%d", item.getItemId()));
|
||||
if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
|
||||
recreate();
|
||||
return true;
|
||||
@@ -209,7 +251,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
case R.id.action_unittestactivity:
|
||||
startActivity(new Intent(this, MainUnitTestActivity.class));
|
||||
break;
|
||||
case R.id.action_unittest2activity:
|
||||
case R.id.action_unittest2activity:
|
||||
startActivity(new Intent(this, MainUnitTest2Activity.class));
|
||||
break;
|
||||
case R.id.action_about:
|
||||
@@ -227,6 +269,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "setupToolbar()");
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
LogUtils.d(TAG, "setupToolbar: 已隐藏返回按钮");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +277,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
public void onBackPressed() {
|
||||
LogUtils.d(TAG, "onBackPressed()");
|
||||
moveTaskToBack(true);
|
||||
LogUtils.d(TAG, "onBackPressed: 应用已退至后台");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
LogUtils.d(TAG, "dispatchKeyEvent() | event=" + event);
|
||||
LogUtils.d(TAG, String.format("dispatchKeyEvent() | event=%s", event));
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@@ -246,6 +290,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
private void initPermissionUtils() {
|
||||
LogUtils.d(TAG, "initPermissionUtils()");
|
||||
mPermissionUtils = PermissionUtils.getInstance();
|
||||
LogUtils.d(TAG, "initPermissionUtils: 权限工具类已初始化");
|
||||
}
|
||||
|
||||
private void initGlobalHandler() {
|
||||
@@ -255,10 +300,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
|
||||
LogUtils.w(TAG, "handleMessage: Activity已销毁,跳过消息 | what=" + msg.what);
|
||||
LogUtils.w(TAG, String.format("handleMessage: Activity已销毁,跳过消息 | what=%d", msg.what));
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "handleMessage() | what=" + msg.what);
|
||||
LogUtils.d(TAG, String.format("handleMessage() | what=%d", msg.what));
|
||||
switch (msg.what) {
|
||||
case MSG_RELOAD_APPCONFIG:
|
||||
sMainActivity.updateViewData();
|
||||
@@ -266,12 +311,11 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
case MSG_CURRENTVALUEBATTERY:
|
||||
if (sMainActivity.mMainContentView != null) {
|
||||
sMainActivity.mMainContentView.updateCurrentBattery(msg.arg1);
|
||||
LogUtils.d(TAG, "handleMessage: 更新当前电量 | value=" + msg.arg1);
|
||||
LogUtils.d(TAG, String.format("handleMessage: 更新当前电量 | value=%d", msg.arg1));
|
||||
}
|
||||
break;
|
||||
case MSG_LOAD_BACKGROUND:
|
||||
sMainActivity.reloadBackground();
|
||||
//sMainActivity.setMainLayoutBackgroundColor();
|
||||
break;
|
||||
case MSG_UPDATE_SERVICE_SWITCH:
|
||||
sMainActivity.updateServiceSwitchUI();
|
||||
@@ -279,6 +323,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
}
|
||||
};
|
||||
LogUtils.d(TAG, "initGlobalHandler: 全局Handler已创建");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initGlobalHandler: 全局Handler已存在,无需重复创建");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,8 +333,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "initMainContentView()");
|
||||
View rootView = findViewById(android.R.id.content);
|
||||
mMainContentView = new MainContentView(this, rootView, this);
|
||||
LogUtils.d(TAG, "initMainContentView: 核心内容视图已初始化");
|
||||
}
|
||||
|
||||
private void reloadBackgroundView() {
|
||||
mMainContentView.reloadBackgroundView();
|
||||
}
|
||||
|
||||
private void initCriticalView() {
|
||||
LogUtils.d(TAG, "initCriticalView()");
|
||||
sMainActivity = this;
|
||||
@@ -295,8 +347,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
setSupportActionBar(mToolbar);
|
||||
if (mToolbar != null) {
|
||||
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
|
||||
LogUtils.d(TAG, "initCriticalView: 工具栏已设置标题样式");
|
||||
}
|
||||
mAdsViewStub = findViewById(R.id.stub_ads_banner);
|
||||
LogUtils.d(TAG, "initCriticalView: 广告ViewStub已获取");
|
||||
}
|
||||
|
||||
private void initCoreUtilsAsync() {
|
||||
@@ -304,7 +358,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程启动 | threadId=" + Thread.currentThread().getId());
|
||||
LogUtils.d(TAG, String.format("initCoreUtilsAsync: 异步线程启动 | threadId=%d", Thread.currentThread().getId()));
|
||||
mApplication = (App) getApplication();
|
||||
mAppConfigUtils = AppConfigUtils.getInstance(getApplicationContext());
|
||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity());
|
||||
@@ -314,17 +368,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
if (mServiceControlBean == null) {
|
||||
mServiceControlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置不存在,已创建默认配置");
|
||||
}
|
||||
|
||||
// 根据配置启停服务
|
||||
final boolean isServiceEnable = mServiceControlBean.isEnableService();
|
||||
final boolean isServiceAlive = ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName());
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 服务配置状态 | isServiceEnable=" + isServiceEnable + " | isServiceAlive=" + isServiceAlive);
|
||||
LogUtils.d(TAG, String.format("initCoreUtilsAsync: 服务配置状态 | isServiceEnable=%b | isServiceAlive=%b",
|
||||
isServiceEnable, isServiceAlive));
|
||||
if (isServiceEnable && !isServiceAlive) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ControlCenterService.startControlCenterService(getApplicationContext());
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 服务已启动");
|
||||
}
|
||||
});
|
||||
} else if (!isServiceEnable && isServiceAlive) {
|
||||
@@ -332,6 +389,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
@Override
|
||||
public void run() {
|
||||
ControlCenterService.stopControlCenterService(getApplicationContext());
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: 服务已停止");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -353,6 +411,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
updateViewData();
|
||||
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
LogUtils.d(TAG, "initCoreUtilsAsync: UI更新消息已发送");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -360,7 +419,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
|
||||
private void loadNonCriticalViewDelayed() {
|
||||
LogUtils.d(TAG, "loadNonCriticalViewDelayed() | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms");
|
||||
LogUtils.d(TAG, String.format("loadNonCriticalViewDelayed() | 延迟时长=%dms", DELAY_LOAD_NON_CRITICAL));
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -383,6 +442,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
if (mADsBannerView == null) {
|
||||
View adsView = mAdsViewStub.inflate();
|
||||
mADsBannerView = adsView.findViewById(R.id.adsbanner);
|
||||
LogUtils.d(TAG, "loadAdsView: 广告视图已加载");
|
||||
} else {
|
||||
LogUtils.d(TAG, "loadAdsView: 广告视图已存在,无需重复加载");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,6 +455,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
return;
|
||||
}
|
||||
mMainContentView.updateViewData(mFrameDrawable);
|
||||
LogUtils.d(TAG, "updateViewData: 视图数据已更新");
|
||||
}
|
||||
|
||||
private void reloadBackground() {
|
||||
@@ -403,25 +466,15 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
}
|
||||
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||
if (currentBgBean != null) {
|
||||
//ToastUtils.show("currentBgBean");
|
||||
mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean, true);
|
||||
LogUtils.d(TAG, "reloadBackground: 已加载自定义背景");
|
||||
} else {
|
||||
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
|
||||
LogUtils.d(TAG, "reloadBackground: 已加载默认背景");
|
||||
}
|
||||
}
|
||||
|
||||
// private void setMainLayoutBackgroundColor() {
|
||||
// LogUtils.d(TAG, "setMainLayoutBackgroundColor()");
|
||||
// if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
|
||||
// LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败");
|
||||
// return;
|
||||
// }
|
||||
// BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
|
||||
// if (currentBgBean != null) {
|
||||
// mMainContentView.mainLayout.setBackgroundColor(currentBgBean.getPixelColor());
|
||||
// LogUtils.d(TAG, "setMainLayoutBackgroundColor: 主布局背景色设置完成 | color=" + currentBgBean.getPixelColor2());
|
||||
// }
|
||||
// }
|
||||
|
||||
private void updateServiceSwitchUI() {
|
||||
LogUtils.d(TAG, "updateServiceSwitchUI()");
|
||||
if (mMainContentView == null || mServiceControlBean == null) {
|
||||
@@ -432,25 +485,29 @@ 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));
|
||||
}
|
||||
|
||||
// ======================== 服务与线程管理方法 ========================
|
||||
private void toggleServiceEnableState(boolean isEnable) {
|
||||
LogUtils.d(TAG, "toggleServiceEnableState() | 目标状态=" + isEnable);
|
||||
LogUtils.d(TAG, String.format("toggleServiceEnableState() | 目标状态=%b", isEnable));
|
||||
if (mServiceControlBean == null) {
|
||||
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
|
||||
return;
|
||||
}
|
||||
mServiceControlBean.setIsEnableService(isEnable);
|
||||
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务配置已保存");
|
||||
|
||||
// UI开关联动服务启停
|
||||
if (isEnable) {
|
||||
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
|
||||
ControlCenterService.startControlCenterService(getApplicationContext());
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动");
|
||||
}
|
||||
} else {
|
||||
ControlCenterService.stopControlCenterService(getApplicationContext());
|
||||
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
|
||||
}
|
||||
|
||||
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
|
||||
@@ -463,6 +520,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
APPInfo appInfo = genDefaultAppInfo();
|
||||
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
|
||||
WinBoLLActivityManager.getInstance().startWinBoLLActivity(getApplicationContext(), aboutIntent, AboutActivity.class);
|
||||
LogUtils.d(TAG, "startAboutActivity: 关于页面已启动");
|
||||
}
|
||||
|
||||
// ======================== 消息发送方法 ========================
|
||||
@@ -470,23 +528,26 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
LogUtils.d(TAG, "notifyServiceAppConfigChange()");
|
||||
ControlCenterService.sendAppConfigStatusUpdateMessage(this);
|
||||
reloadAppConfig();
|
||||
LogUtils.d(TAG, "notifyServiceAppConfigChange: 服务配置已通知更新");
|
||||
}
|
||||
|
||||
public static void reloadAppConfig() {
|
||||
LogUtils.d(TAG, "reloadAppConfig()");
|
||||
if (sGlobalHandler != null) {
|
||||
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
|
||||
LogUtils.d(TAG, "reloadAppConfig: 配置重载消息已发送");
|
||||
} else {
|
||||
LogUtils.w(TAG, "reloadAppConfig: 全局Handler为空,消息发送失败");
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendCurrentBatteryValueMessage(int value) {
|
||||
LogUtils.d(TAG, "sendCurrentBatteryValueMessage() | 电量=" + value);
|
||||
LogUtils.d(TAG, String.format("sendCurrentBatteryValueMessage() | 电量=%d", value));
|
||||
if (sGlobalHandler != null) {
|
||||
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
|
||||
msg.arg1 = value;
|
||||
sGlobalHandler.sendMessage(msg);
|
||||
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 电量消息已发送");
|
||||
} else {
|
||||
LogUtils.w(TAG, "sendCurrentBatteryValueMessage: 全局Handler为空,消息发送失败");
|
||||
}
|
||||
@@ -507,37 +568,38 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
|
||||
appInfo.setAppHomePage("https://www.winboll.cc/apks/index.php?project=PowerBell");
|
||||
appInfo.setAppAPKName("PowerBell");
|
||||
appInfo.setAppAPKFolderName("PowerBell");
|
||||
LogUtils.d(TAG, "genDefaultAppInfo: 应用信息已生成");
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
// ======================== MainContentView 事件回调 ========================
|
||||
@Override
|
||||
public void onChargeReminderSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onChargeReminderSwitchChanged() | isChecked=" + isChecked);
|
||||
LogUtils.d(TAG, String.format("onChargeReminderSwitchChanged() | isChecked=%b", isChecked));
|
||||
notifyServiceAppConfigChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsageReminderSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onUsageReminderSwitchChanged() | isChecked=" + isChecked);
|
||||
LogUtils.d(TAG, String.format("onUsageReminderSwitchChanged() | isChecked=%b", isChecked));
|
||||
notifyServiceAppConfigChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceSwitchChanged(boolean isChecked) {
|
||||
LogUtils.d(TAG, "onServiceSwitchChanged() | isChecked=" + isChecked);
|
||||
LogUtils.d(TAG, String.format("onServiceSwitchChanged() | isChecked=%b", isChecked));
|
||||
toggleServiceEnableState(isChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChargeReminderProgressChanged(int progress) {
|
||||
LogUtils.d(TAG, "onChargeReminderProgressChanged() | progress=" + progress);
|
||||
LogUtils.d(TAG, String.format("onChargeReminderProgressChanged() | progress=%d", progress));
|
||||
notifyServiceAppConfigChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsageReminderProgressChanged(int progress) {
|
||||
LogUtils.d(TAG, "onUsageReminderProgressChanged() | progress=" + progress);
|
||||
LogUtils.d(TAG, String.format("onUsageReminderProgressChanged() | progress=%d", progress));
|
||||
notifyServiceAppConfigChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.provider.MediaStore;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
@@ -24,11 +25,14 @@ import androidx.core.content.FileProvider;
|
||||
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.MainActivity;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
|
||||
import cc.winboll.studio.powerbell.dialogs.ColorPaletteDialog;
|
||||
import cc.winboll.studio.powerbell.dialogs.NetworkBackgroundDialog;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
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.FileUtils;
|
||||
@@ -38,9 +42,13 @@ import cc.winboll.studio.powerbell.utils.UriUtils;
|
||||
import cc.winboll.studio.powerbell.views.BackgroundView;
|
||||
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;
|
||||
@@ -79,7 +87,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "【生命周期】onCreate 开始初始化");
|
||||
LogUtils.d(TAG, "onCreate() 开始初始化");
|
||||
setContentView(R.layout.activity_background_settings);
|
||||
|
||||
// 初始化核心组件
|
||||
@@ -87,44 +95,69 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
// 初始化界面与事件
|
||||
initToolbar();
|
||||
initClickListeners();
|
||||
LogUtils.d(TAG, "【初始化】界面与事件绑定完成");
|
||||
LogUtils.d(TAG, "界面与事件绑定完成");
|
||||
|
||||
// 处理分享意图或初始化预览
|
||||
handleIntentOrPreview();
|
||||
|
||||
// 初始化预览环境并刷新
|
||||
initPreviewEnvironment();
|
||||
LogUtils.d(TAG, "【生命周期】onCreate 初始化完成");
|
||||
LogUtils.d(TAG, "onCreate() 初始化完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
LogUtils.d(TAG, "【生命周期】onPostCreate 执行双重刷新预览");
|
||||
doubleRefreshPreview();
|
||||
LogUtils.d(TAG, "onPostCreate() 执行双重刷新预览");
|
||||
|
||||
// 监听视图布局完成事件
|
||||
mBackgroundView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
// 移除监听,避免重复回调
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mBackgroundView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
} else {
|
||||
mBackgroundView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
|
||||
// 此时已获取真实宽高
|
||||
int width = mBackgroundView.getWidth();
|
||||
int height = mBackgroundView.getHeight();
|
||||
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));
|
||||
doubleRefreshPreview();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
LogUtils.d(TAG, "【回调触发】requestCode:" + requestCode + ",resultCode:" + resultCode);
|
||||
LogUtils.d(TAG, String.format("onActivityResult() | requestCode=%d | resultCode=%d", requestCode, resultCode));
|
||||
|
||||
try {
|
||||
if (resultCode != RESULT_OK) {
|
||||
LogUtils.d(TAG, "【回调处理】结果非RESULT_OK,执行取消逻辑");
|
||||
LogUtils.d(TAG, "结果非RESULT_OK,执行取消逻辑");
|
||||
handleOperationCancelOrFail();
|
||||
return;
|
||||
}
|
||||
handleActivityResult(requestCode, data);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【回调异常】requestCode:" + requestCode + ",异常信息:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("onActivityResult() 异常 | requestCode=%d | 异常信息=%s", requestCode, e.getMessage()));
|
||||
ToastUtils.show("操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
LogUtils.d(TAG, "【生命周期】finish 触发,isCommitSettings:" + isCommitSettings + ",isPreviewBackgroundChanged:" + isPreviewBackgroundChanged);
|
||||
LogUtils.d(TAG, String.format("finish() | isCommitSettings=%b | isPreviewBackgroundChanged=%b", isCommitSettings, isPreviewBackgroundChanged));
|
||||
if (isCommitSettings) {
|
||||
super.finish();
|
||||
} else {
|
||||
@@ -136,7 +169,7 @@ 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, "【权限回调】requestCode:" + requestCode + ",权限数量:" + permissions.length);
|
||||
LogUtils.d(TAG, String.format("onRequestPermissionsResult() | requestCode=%d | 权限数量=%d", requestCode, permissions.length));
|
||||
if (requestCode == REQUEST_CAMERA_PERMISSION) {
|
||||
handleCameraPermissionResult(grantResults);
|
||||
}
|
||||
@@ -144,9 +177,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
|
||||
// ====================== 界面初始化方法(Toolbar + 点击事件)======================
|
||||
private void initToolbar() {
|
||||
LogUtils.d(TAG, "initToolbar() 开始初始化");
|
||||
mToolbar = findViewById(R.id.toolbar);
|
||||
if (mToolbar == null) {
|
||||
LogUtils.e(TAG, "【初始化异常】Toolbar未找到");
|
||||
LogUtils.e(TAG, "initToolbar() | Toolbar未找到");
|
||||
return;
|
||||
}
|
||||
setSupportActionBar(mToolbar);
|
||||
@@ -156,15 +190,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【导航栏】点击返回按钮");
|
||||
LogUtils.d(TAG, "导航栏 点击返回按钮");
|
||||
finish();
|
||||
}
|
||||
});
|
||||
LogUtils.d(TAG, "【界面初始化】Toolbar 配置完成");
|
||||
LogUtils.d(TAG, "initToolbar() 配置完成");
|
||||
}
|
||||
|
||||
private void initClickListeners() {
|
||||
LogUtils.d(TAG, "【界面初始化】开始绑定按钮点击事件");
|
||||
LogUtils.d(TAG, "initClickListeners() 开始绑定按钮点击事件");
|
||||
// 绑定所有按钮点击事件
|
||||
bindClickListener(R.id.activitybackgroundsettingsAButton1, onOriginNullClickListener);
|
||||
bindClickListener(R.id.activitybackgroundsettingsAButton2, onReceivedPictureClickListener);
|
||||
@@ -176,16 +210,18 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
bindClickListener(R.id.activitybackgroundsettingsAButton8, onPixelPickerClickListener);
|
||||
bindClickListener(R.id.activitybackgroundsettingsAButton9, onColorPaletteClickListener);
|
||||
bindClickListener(R.id.activitybackgroundsettingsAButton10, onCleanPixelClickListener);
|
||||
LogUtils.d(TAG, "【界面初始化】按钮点击事件绑定完成");
|
||||
LogUtils.d(TAG, "initClickListeners() 按钮点击事件绑定完成");
|
||||
}
|
||||
|
||||
// 通用按钮绑定工具方法
|
||||
private void bindClickListener(int resId, View.OnClickListener listener) {
|
||||
LogUtils.d(TAG, String.format("bindClickListener() | resId=%d", resId));
|
||||
View view = findViewById(resId);
|
||||
if (view != null) {
|
||||
view.setOnClickListener(listener);
|
||||
LogUtils.d(TAG, String.format("bindClickListener() | resId=%d 绑定成功", resId));
|
||||
} else {
|
||||
LogUtils.e(TAG, "【绑定异常】未找到视图:" + resId);
|
||||
LogUtils.e(TAG, String.format("bindClickListener() | 未找到视图:%d", resId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,10 +229,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】取消背景图片");
|
||||
LogUtils.d(TAG, "onOriginNullClickListener() | 取消背景图片");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【操作异常】预览Bean为空");
|
||||
LogUtils.e(TAG, "onOriginNullClickListener() | 预览Bean为空");
|
||||
return;
|
||||
}
|
||||
previewBean.setIsUseBackgroundFile(false);
|
||||
@@ -209,17 +245,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onSelectPictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】选择图片");
|
||||
LogUtils.d(TAG, "onSelectPictureClickListener() | 选择图片");
|
||||
launchImageSelector();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener onNetworkBackgroundDialog = new View.OnClickListener() {
|
||||
private View.OnClickListener onNetworkBackgroundDialog = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
NetworkBackgroundDialog networkBackgroundDialog = new NetworkBackgroundDialog(BackgroundSettingsActivity.this, new NetworkBackgroundDialog.OnDialogClickListener(){
|
||||
LogUtils.d(TAG, "onNetworkBackgroundDialog() | 打开网络背景对话框");
|
||||
NetworkBackgroundDialog networkBackgroundDialog = new NetworkBackgroundDialog(BackgroundSettingsActivity.this, new NetworkBackgroundDialog.OnDialogClickListener() {
|
||||
@Override
|
||||
public void onConfirm(String szConfirmFilePath) {
|
||||
LogUtils.d(TAG, String.format("网络背景确认 onConfirm() | 文件路径=%s", szConfirmFilePath));
|
||||
// 拷贝文件到预览数据并启动裁剪
|
||||
if (putUriFileToPreviewSource(new File(szConfirmFilePath))) {
|
||||
startImageCrop(false);
|
||||
@@ -228,16 +266,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
LogUtils.d(TAG, "网络背景取消 onCancel()");
|
||||
}
|
||||
});
|
||||
networkBackgroundDialog.show();
|
||||
networkBackgroundDialog.show();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener onCropPictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】固定比例裁剪");
|
||||
LogUtils.d(TAG, "onCropPictureClickListener() | 固定比例裁剪");
|
||||
startImageCrop(false);
|
||||
}
|
||||
};
|
||||
@@ -245,7 +284,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onCropFreePictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】自由裁剪");
|
||||
LogUtils.d(TAG, "onCropFreePictureClickListener() | 自由裁剪");
|
||||
startImageCrop(true);
|
||||
}
|
||||
};
|
||||
@@ -253,11 +292,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onTakePhotoClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】拍照");
|
||||
LogUtils.d(TAG, "onTakePhotoClickListener() | 拍照");
|
||||
// 动态申请相机权限
|
||||
if (ContextCompat.checkSelfPermission(BackgroundSettingsActivity.this, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.d(TAG, "【拍照准备】相机权限未授予,发起申请");
|
||||
LogUtils.d(TAG, "拍照准备 | 相机权限未授予,发起申请");
|
||||
ActivityCompat.requestPermissions(
|
||||
BackgroundSettingsActivity.this,
|
||||
new String[]{Manifest.permission.CAMERA},
|
||||
@@ -271,10 +310,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】恢复收到的图片");
|
||||
LogUtils.d(TAG, "onReceivedPictureClickListener() | 恢复收到的图片");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【操作异常】预览Bean为空");
|
||||
LogUtils.e(TAG, "onReceivedPictureClickListener() | 预览Bean为空");
|
||||
return;
|
||||
}
|
||||
previewBean.setIsUseBackgroundFile(true);
|
||||
@@ -287,10 +326,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】像素拾取");
|
||||
LogUtils.d(TAG, "onPixelPickerClickListener() | 像素拾取");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【操作异常】预览Bean为空");
|
||||
LogUtils.e(TAG, "onPixelPickerClickListener() | 预览Bean为空");
|
||||
ToastUtils.show("无有效图片可拾取像素");
|
||||
return;
|
||||
}
|
||||
@@ -298,23 +337,23 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
File targetFile = new File(targetImagePath);
|
||||
if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) {
|
||||
ToastUtils.show("无有效图片可拾取像素");
|
||||
LogUtils.e(TAG, "【像素拾取失败】文件无效:" + targetImagePath);
|
||||
LogUtils.e(TAG, String.format("像素拾取失败 | 文件无效:%s", targetImagePath));
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class);
|
||||
intent.putExtra("imagePath", targetImagePath);
|
||||
startActivityForResult(intent, REQUEST_PIXELPICKER);
|
||||
LogUtils.d(TAG, "【像素拾取启动】路径:" + targetImagePath);
|
||||
LogUtils.d(TAG, String.format("像素拾取启动 | 路径:%s", targetImagePath));
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener onCleanPixelClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】清空像素颜色");
|
||||
LogUtils.d(TAG, "onCleanPixelClickListener() | 清空像素颜色");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【操作异常】预览Bean为空");
|
||||
LogUtils.e(TAG, "onCleanPixelClickListener() | 预览Bean为空");
|
||||
return;
|
||||
}
|
||||
int oldColor = previewBean.getPixelColor();
|
||||
@@ -323,21 +362,21 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
doubleRefreshPreview();
|
||||
isPreviewBackgroundChanged = true;
|
||||
ToastUtils.show("像素颜色已清空");
|
||||
LogUtils.d(TAG, "【像素清空】旧颜色:" + String.format("#%08X", oldColor));
|
||||
LogUtils.d(TAG, String.format("像素清空 | 旧颜色:#%08X", oldColor));
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener onColorPaletteClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
LogUtils.d(TAG, "【按钮点击】调色板按钮");
|
||||
LogUtils.d(TAG, "onColorPaletteClickListener() | 调色板按钮");
|
||||
final BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【操作异常】预览Bean为空");
|
||||
LogUtils.e(TAG, "onColorPaletteClickListener() | 预览Bean为空");
|
||||
return;
|
||||
}
|
||||
int initialColor = previewBean.getPixelColor();
|
||||
LogUtils.d(TAG, "【调色板】初始颜色:" + String.format("#%08X", initialColor));
|
||||
LogUtils.d(TAG, String.format("调色板 | 初始颜色:#%08X", initialColor));
|
||||
ColorPaletteDialog dialog = new ColorPaletteDialog(BackgroundSettingsActivity.this, initialColor, new ColorPaletteDialog.OnColorSelectedListener() {
|
||||
@Override
|
||||
public void onColorSelected(int color) {
|
||||
@@ -345,11 +384,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mBgSourceUtils.saveSettings();
|
||||
doubleRefreshPreview();
|
||||
isPreviewBackgroundChanged = true;
|
||||
LogUtils.d(TAG, "【颜色选择】选中颜色:" + String.format("#%08X", color));
|
||||
LogUtils.d(TAG, String.format("颜色选择 | 选中颜色:#%08X", color));
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
LogUtils.d(TAG, "【调色板】对话框已显示");
|
||||
LogUtils.d(TAG, "调色板 | 对话框已显示");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -360,9 +399,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 适配后的Uri,失败返回null
|
||||
*/
|
||||
public Uri getFileProviderUri(File file) {
|
||||
LogUtils.d(TAG, "【工具方法】生成FileProvider Uri,文件路径:" + (file != null ? file.getAbsolutePath() : "null"));
|
||||
LogUtils.d(TAG, String.format("getFileProviderUri() | 文件路径:%s", (file != null ? file.getAbsolutePath() : "null")));
|
||||
if (file == null) {
|
||||
LogUtils.e(TAG, "【工具异常】文件为空");
|
||||
LogUtils.e(TAG, "getFileProviderUri() | 文件为空");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
@@ -373,7 +412,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【工具异常】生成Uri失败:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("getFileProviderUri() | 生成Uri失败:%s", e.getMessage()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -385,7 +424,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
*/
|
||||
private boolean isBitmapValid(Bitmap bitmap) {
|
||||
boolean isValid = bitmap != null && !bitmap.isRecycled();
|
||||
LogUtils.d(TAG, "【工具方法】Bitmap有效性校验:" + isValid);
|
||||
LogUtils.d(TAG, String.format("isBitmapValid() | Bitmap有效性校验:%b", isValid));
|
||||
return isValid;
|
||||
}
|
||||
|
||||
@@ -393,9 +432,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 双重刷新预览,确保背景加载最新数据
|
||||
*/
|
||||
private void doubleRefreshPreview() {
|
||||
LogUtils.d(TAG, "【工具方法】开始双重刷新预览");
|
||||
LogUtils.d(TAG, "doubleRefreshPreview() 开始双重刷新预览");
|
||||
if (mBgSourceUtils == null || mBackgroundView == null || isFinishing()) {
|
||||
LogUtils.w(TAG, "【双重刷新】跳过:对象为空或Activity已结束");
|
||||
LogUtils.w(TAG, "双重刷新 跳过:对象为空或Activity已结束");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -404,10 +443,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mBgSourceUtils.loadSettings();
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
mBackgroundView.loadByBackgroundBean(previewBean, true);
|
||||
//mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
|
||||
LogUtils.d(TAG, "【双重刷新】第一重完成");
|
||||
LogUtils.d(TAG, "双重刷新 第一重完成");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("双重刷新 第一重异常:%s", e.getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,10 +458,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mBgSourceUtils.loadSettings();
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
mBackgroundView.loadByBackgroundBean(previewBean, true);
|
||||
//mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
|
||||
LogUtils.d(TAG, "【双重刷新】第二重完成");
|
||||
LogUtils.d(TAG, "双重刷新 第二重完成");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("双重刷新 第二重异常:%s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,27 +472,30 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 初始化核心组件(工具类+视图)
|
||||
*/
|
||||
private void initCoreComponents() {
|
||||
LogUtils.d(TAG, "initCoreComponents() 开始初始化");
|
||||
// 初始化视图
|
||||
mBackgroundView = findViewById(R.id.background_view);
|
||||
if (mBackgroundView == null) {
|
||||
LogUtils.e(TAG, "【初始化异常】BackgroundView未找到");
|
||||
LogUtils.e(TAG, "initCoreComponents() | BackgroundView未找到");
|
||||
}
|
||||
// 初始化工具类
|
||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
|
||||
mBgSourceUtils.loadSettings();
|
||||
mBitmapCache = BitmapCacheUtils.getInstance();
|
||||
LogUtils.d(TAG, "【初始化】视图与工具类加载完成");
|
||||
LogUtils.d(TAG, "initCoreComponents() 视图与工具类加载完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理意图或初始化预览
|
||||
*/
|
||||
private void handleIntentOrPreview() {
|
||||
LogUtils.d(TAG, "handleIntentOrPreview() 开始处理");
|
||||
if (handleShareIntent()) {
|
||||
ToastUtils.show("已接收分享图片");
|
||||
LogUtils.d(TAG, "handleIntentOrPreview() | 处理分享意图成功");
|
||||
} else {
|
||||
mBgSourceUtils.setCurrentSourceToPreview();
|
||||
LogUtils.d(TAG, "【预览初始化】加载当前背景配置");
|
||||
LogUtils.d(TAG, "handleIntentOrPreview() | 加载当前背景配置");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,9 +503,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 初始化预览环境
|
||||
*/
|
||||
private void initPreviewEnvironment() {
|
||||
LogUtils.d(TAG, "initPreviewEnvironment() 开始初始化");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(previewBean);
|
||||
doubleRefreshPreview();
|
||||
LogUtils.d(TAG, "initPreviewEnvironment() 初始化完成");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -473,11 +515,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 处理成功返回true,否则false
|
||||
*/
|
||||
private boolean handleShareIntent() {
|
||||
LogUtils.d(TAG, "handleShareIntent() 开始处理");
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
String action = intent.getAction();
|
||||
String type = intent.getType();
|
||||
LogUtils.d(TAG, "【分享处理】action:" + action + ",type:" + type);
|
||||
LogUtils.d(TAG, String.format("分享处理 | action:%s,type:%s", action, type));
|
||||
if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) {
|
||||
showSharePreviewDialog();
|
||||
return true;
|
||||
@@ -490,17 +533,18 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 显示分享图片预览对话框
|
||||
*/
|
||||
private void showSharePreviewDialog() {
|
||||
LogUtils.d(TAG, "showSharePreviewDialog()");
|
||||
LogUtils.d(TAG, "showSharePreviewDialog() 开始显示");
|
||||
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener() {
|
||||
@Override
|
||||
public void onAcceptRecivedPicture(Uri uriRecivedPicture) {
|
||||
LogUtils.d(TAG, String.format("分享确认 | Uri:%s", uriRecivedPicture.toString()));
|
||||
if (putUriFileToPreviewSource(uriRecivedPicture)) {
|
||||
startImageCrop(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
dlg.show();
|
||||
LogUtils.d(TAG, "【分享处理】显示图片预览对话框");
|
||||
LogUtils.d(TAG, "分享处理 | 显示图片预览对话框");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,19 +553,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 是图片返回true,否则false
|
||||
*/
|
||||
private boolean isImageType(String mimeType) {
|
||||
if (mimeType == null) {
|
||||
return false;
|
||||
}
|
||||
String lowerMimeType = mimeType.toLowerCase();
|
||||
LogUtils.d("isImageType", "mimeType: " + mimeType + ", lowerMimeType: " + lowerMimeType);
|
||||
return lowerMimeType.startsWith("image/");
|
||||
}
|
||||
|
||||
if (mimeType == null) {
|
||||
return false;
|
||||
}
|
||||
String lowerMimeType = mimeType.toLowerCase();
|
||||
LogUtils.d(TAG, String.format("isImageType() | mimeType: %s, lowerMimeType: %s", mimeType, lowerMimeType));
|
||||
return lowerMimeType.startsWith("image/");
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动图片选择器
|
||||
*/
|
||||
private void launchImageSelector() {
|
||||
LogUtils.d(TAG, "【业务逻辑】启动图片选择器");
|
||||
LogUtils.d(TAG, "launchImageSelector() 启动图片选择器");
|
||||
Intent[] intents = createImageSelectorIntents();
|
||||
Intent validIntent = findValidIntent(intents);
|
||||
|
||||
@@ -537,6 +581,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 意图数组
|
||||
*/
|
||||
private Intent[] createImageSelectorIntents() {
|
||||
LogUtils.d(TAG, "createImageSelectorIntents() 开始创建");
|
||||
Intent[] intents = new Intent[3];
|
||||
// ACTION_GET_CONTENT
|
||||
Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
@@ -559,6 +604,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
openDocIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
intents[2] = openDocIntent;
|
||||
}
|
||||
LogUtils.d(TAG, "createImageSelectorIntents() 意图数组创建完成");
|
||||
return intents;
|
||||
}
|
||||
|
||||
@@ -568,11 +614,14 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 有效意图,无则返回null
|
||||
*/
|
||||
private Intent findValidIntent(Intent[] intents) {
|
||||
LogUtils.d(TAG, "findValidIntent() 开始查找");
|
||||
for (Intent intent : intents) {
|
||||
if (intent != null && intent.resolveActivity(getPackageManager()) != null) {
|
||||
LogUtils.d(TAG, "findValidIntent() | 找到有效意图");
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, "findValidIntent() | 无有效意图");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -581,17 +630,18 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param validIntent 有效意图
|
||||
*/
|
||||
private void launchImageChooser(Intent validIntent) {
|
||||
LogUtils.d(TAG, "launchImageChooser() 启动选择器");
|
||||
Intent chooser = Intent.createChooser(validIntent, "选择图片");
|
||||
chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
startActivityForResult(chooser, REQUEST_SELECT_PICTURE);
|
||||
LogUtils.d(TAG, "【选图意图】启动图片选择");
|
||||
LogUtils.d(TAG, "launchImageChooser() | 启动图片选择");
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示无相册应用提示对话框
|
||||
*/
|
||||
private void showNoGalleryDialog() {
|
||||
LogUtils.d(TAG, "【选图意图】无相册应用");
|
||||
LogUtils.d(TAG, "showNoGalleryDialog() | 无相册应用");
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -615,12 +665,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 启动应用商店下载相册
|
||||
*/
|
||||
private void launchGalleryMarket() {
|
||||
LogUtils.d(TAG, "launchGalleryMarket() 启动应用商店");
|
||||
Intent marketIntent = new Intent(Intent.ACTION_VIEW);
|
||||
marketIntent.setData(Uri.parse("market://details?id=com.android.gallery3d"));
|
||||
if (marketIntent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivity(marketIntent);
|
||||
LogUtils.d(TAG, "launchGalleryMarket() | 启动成功");
|
||||
} else {
|
||||
ToastUtils.show("无法打开应用商店");
|
||||
LogUtils.e(TAG, "launchGalleryMarket() | 启动失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,8 +681,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 处理操作取消或失败
|
||||
*/
|
||||
private void handleOperationCancelOrFail() {
|
||||
LogUtils.d(TAG, "handleOperationCancelOrFail() 操作取消或失败");
|
||||
mBgSourceUtils.setCurrentSourceToPreview();
|
||||
LogUtils.d(TAG, "【业务逻辑】操作取消或失败,恢复预览");
|
||||
ToastUtils.show("操作取消或失败");
|
||||
doubleRefreshPreview();
|
||||
}
|
||||
@@ -638,10 +691,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 处理拍照逻辑(权限通过后执行)
|
||||
*/
|
||||
void handleTakePhoto() {
|
||||
LogUtils.d(TAG, "【业务逻辑】开始处理拍照");
|
||||
LogUtils.d(TAG, "handleTakePhoto() 开始处理拍照");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【拍照失败】预览Bean为空");
|
||||
LogUtils.e(TAG, "handleTakePhoto() | 预览Bean为空");
|
||||
ToastUtils.show("拍照文件创建失败");
|
||||
return;
|
||||
}
|
||||
@@ -649,7 +702,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
File takePhotoFile = new File(previewBean.getBackgroundFilePath());
|
||||
if (!takePhotoFile.exists()) {
|
||||
ToastUtils.show("拍照文件创建失败");
|
||||
LogUtils.e(TAG, "【拍照失败】文件不存在:" + takePhotoFile.getAbsolutePath());
|
||||
LogUtils.e(TAG, String.format("handleTakePhoto() | 文件不存在:%s", takePhotoFile.getAbsolutePath()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -661,11 +714,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
}
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
|
||||
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
|
||||
LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString());
|
||||
LogUtils.d(TAG, String.format("handleTakePhoto() | Uri:%s", photoUri.toString()));
|
||||
} catch (Exception e) {
|
||||
String errMsg = "拍照启动异常:" + e.getMessage();
|
||||
ToastUtils.show(errMsg.substring(0, 20));
|
||||
LogUtils.e(TAG, "【拍照失败】" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("handleTakePhoto() | %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,6 +728,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param data 回调数据
|
||||
*/
|
||||
private void handleActivityResult(int requestCode, Intent data) {
|
||||
LogUtils.d(TAG, String.format("handleActivityResult() | 处理请求码:%d", requestCode));
|
||||
switch (requestCode) {
|
||||
case REQUEST_SELECT_PICTURE:
|
||||
handleSelectPictureResult(data);
|
||||
@@ -689,7 +743,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
handlePixelPickerResult();
|
||||
break;
|
||||
default:
|
||||
LogUtils.d(TAG, "【回调忽略】未知requestCode:" + requestCode);
|
||||
LogUtils.d(TAG, String.format("handleActivityResult() | 未知requestCode:%d", requestCode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -699,10 +753,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param data 回调数据
|
||||
*/
|
||||
private void handleTakePhotoResult(Intent data) {
|
||||
LogUtils.d(TAG, "【业务逻辑】处理拍照结果");
|
||||
LogUtils.d(TAG, "handleTakePhotoResult() 处理拍照结果");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【拍照结果处理】预览Bean为空");
|
||||
LogUtils.e(TAG, "handleTakePhotoResult() | 预览Bean为空");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -712,7 +766,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
doubleRefreshPreview();
|
||||
|
||||
startImageCrop(false);
|
||||
LogUtils.d(TAG, "【拍照完成】已启动裁剪");
|
||||
LogUtils.d(TAG, "handleTakePhotoResult() | 已启动裁剪");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -720,30 +774,30 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param data 回调数据
|
||||
*/
|
||||
private void handleSelectPictureResult(Intent data) {
|
||||
LogUtils.d(TAG, "【业务逻辑】处理选图结果");
|
||||
LogUtils.d(TAG, "handleSelectPictureResult() 处理选图结果");
|
||||
Uri selectedImage = data.getData();
|
||||
if (selectedImage == null) {
|
||||
ToastUtils.show("图片Uri为空");
|
||||
LogUtils.e(TAG, "【选图结果】Uri为空");
|
||||
LogUtils.e(TAG, "handleSelectPictureResult() | Uri为空");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "【选图回调】系统返回Uri : " + selectedImage.toString());
|
||||
LogUtils.d(TAG, String.format("handleSelectPictureResult() | 系统返回Uri : %s", selectedImage.toString()));
|
||||
|
||||
// 申请持久化权限(API33+)
|
||||
if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) {
|
||||
getContentResolver().takePersistableUriPermission(
|
||||
selectedImage,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
LogUtils.d(TAG, "【选图权限】已添加持久化权限");
|
||||
LogUtils.d(TAG, "handleSelectPictureResult() | 已添加持久化权限");
|
||||
}
|
||||
|
||||
// 同步文件并启动裁剪
|
||||
if (putUriFileToPreviewSource(selectedImage)) {
|
||||
LogUtils.d(TAG, "【选图同步】路径绑定完成");
|
||||
LogUtils.d(TAG, "handleSelectPictureResult() | 路径绑定完成");
|
||||
startImageCrop(false);
|
||||
} else {
|
||||
ToastUtils.show("图片同步失败");
|
||||
LogUtils.e(TAG, "【选图同步】文件复制失败");
|
||||
LogUtils.e(TAG, "handleSelectPictureResult() | 文件复制失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,9 +807,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 同步成功返回true,否则false
|
||||
*/
|
||||
private boolean putUriFileToPreviewSource(Uri srcUriFile) {
|
||||
LogUtils.d(TAG, String.format("putUriFileToPreviewSource() | 源Uri:%s", srcUriFile.toString()));
|
||||
String filePath = UriUtils.getFilePathFromUri(this, srcUriFile);
|
||||
if (TextUtils.isEmpty(filePath)) {
|
||||
LogUtils.e(TAG, "【选图同步】Uri解析路径为空");
|
||||
LogUtils.e(TAG, "putUriFileToPreviewSource() | Uri解析路径为空");
|
||||
return false;
|
||||
}
|
||||
File srcFile = new File(filePath);
|
||||
@@ -768,16 +823,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @return 同步成功返回true,否则false
|
||||
*/
|
||||
private boolean putUriFileToPreviewSource(File srcFile) {
|
||||
LogUtils.d(TAG, "【选图同步】源文件:" + srcFile.getAbsolutePath());
|
||||
LogUtils.d(TAG, String.format("putUriFileToPreviewSource() | 源文件:%s", srcFile.getAbsolutePath()));
|
||||
mBgSourceUtils.loadSettings();
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
File dstFile = new File(previewBean.getBackgroundFilePath());
|
||||
LogUtils.d(TAG, "【选图同步】目标文件:" + dstFile.getAbsolutePath());
|
||||
LogUtils.d(TAG, String.format("putUriFileToPreviewSource() | 目标文件:%s", dstFile.getAbsolutePath()));
|
||||
if (FileUtils.copyFile(srcFile, dstFile)) {
|
||||
LogUtils.d(TAG, "【选图同步】文件拷贝成功");
|
||||
LogUtils.d(TAG, "putUriFileToPreviewSource() | 文件拷贝成功");
|
||||
return true;
|
||||
}
|
||||
LogUtils.d(TAG, "【选图同步】文件无法拷贝");
|
||||
LogUtils.d(TAG, "putUriFileToPreviewSource() | 文件无法拷贝");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -786,10 +841,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param data 回调数据
|
||||
*/
|
||||
private void handleCropImageResult(Intent data) {
|
||||
LogUtils.d(TAG, "【业务逻辑】处理裁剪结果");
|
||||
LogUtils.d(TAG, "handleCropImageResult() 处理裁剪结果");
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【裁剪结果处理】预览Bean为空");
|
||||
LogUtils.e(TAG, "handleCropImageResult() | 预览Bean为空");
|
||||
handleOperationCancelOrFail();
|
||||
return;
|
||||
}
|
||||
@@ -813,8 +868,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param fileSize 文件大小
|
||||
*/
|
||||
private void handleCropSuccess(BackgroundBean previewBean, long fileSize) {
|
||||
LogUtils.d(TAG, String.format("handleCropSuccess() | 裁剪成功,文件大小:%d", fileSize));
|
||||
isPreviewBackgroundChanged = true;
|
||||
LogUtils.d(TAG, "【裁剪结果】裁剪成功,文件大小:" + fileSize);
|
||||
previewBean.setIsUseBackgroundFile(true);
|
||||
previewBean.setIsUseBackgroundScaledCompressFile(true);
|
||||
mBgSourceUtils.saveSettings();
|
||||
@@ -828,15 +883,15 @@ 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));
|
||||
handleOperationCancelOrFail();
|
||||
LogUtils.e(TAG, "【裁剪结果】裁剪失败,文件状态:存在=" + isFileExist + ",可读=" + isFileReadable + ",大小=" + fileSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理像素拾取结果
|
||||
*/
|
||||
private void handlePixelPickerResult() {
|
||||
LogUtils.d(TAG, "【业务逻辑】处理像素拾取结果");
|
||||
LogUtils.d(TAG, "handlePixelPickerResult() 处理像素拾取结果");
|
||||
doubleRefreshPreview();
|
||||
isPreviewBackgroundChanged = true;
|
||||
}
|
||||
@@ -846,11 +901,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param grantResults 权限结果数组
|
||||
*/
|
||||
private void handleCameraPermissionResult(int[] grantResults) {
|
||||
LogUtils.d(TAG, "handleCameraPermissionResult() 处理相机权限结果");
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.d(TAG, "【权限申请】相机权限授予成功");
|
||||
LogUtils.d(TAG, "handleCameraPermissionResult() | 相机权限授予成功");
|
||||
handleTakePhoto();
|
||||
} else {
|
||||
LogUtils.d(TAG, "【权限申请】相机权限授予失败");
|
||||
LogUtils.d(TAG, "handleCameraPermissionResult() | 相机权限授予失败");
|
||||
ToastUtils.show("相机权限被拒绝,无法拍照");
|
||||
// 引导用户到设置页面开启权限(用户选择不再询问时)
|
||||
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
|
||||
@@ -863,18 +919,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* 启动应用设置页面
|
||||
*/
|
||||
private void launchAppSettings() {
|
||||
LogUtils.d(TAG, "launchAppSettings() 启动应用设置页面");
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
Uri uri = Uri.fromParts("package", getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
startActivity(intent);
|
||||
ToastUtils.show("请在设置中开启相机权限");
|
||||
LogUtils.d(TAG, "【权限引导】启动应用设置页面");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Finish确认对话框
|
||||
*/
|
||||
private void handleFinishConfirmation() {
|
||||
LogUtils.d(TAG, "handleFinishConfirmation() 处理Finish确认");
|
||||
if (isPreviewBackgroundChanged) {
|
||||
YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener() {
|
||||
@Override
|
||||
@@ -882,6 +939,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
mBgSourceUtils.commitPreviewSourceToCurrent();
|
||||
isCommitSettings = true;
|
||||
finish();
|
||||
//App.notifyMessage(TAG, "startActivity");
|
||||
Intent mainIntent = new Intent(BackgroundSettingsActivity.this, MainActivity.class);
|
||||
mainIntent.putExtra(MainActivity.EXTRA_ISRELOAD_BACKGROUNDVIEW, true);
|
||||
startActivity(mainIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -901,9 +962,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
* @param isFreeCrop 是否自由裁剪
|
||||
*/
|
||||
private void startImageCrop(boolean isFreeCrop) {
|
||||
LogUtils.d(TAG, String.format("startImageCrop() | 是否自由裁剪:%b", isFreeCrop));
|
||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||
if (previewBean == null) {
|
||||
LogUtils.e(TAG, "【裁剪启动】预览Bean为空");
|
||||
LogUtils.e(TAG, "startImageCrop() | 预览Bean为空");
|
||||
ToastUtils.show("裁剪失败:无有效图片");
|
||||
return;
|
||||
}
|
||||
@@ -915,7 +977,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||
height,
|
||||
isFreeCrop,
|
||||
REQUEST_CROP_IMAGE);
|
||||
LogUtils.d(TAG, "【裁剪启动】是否自由裁剪:" + isFreeCrop + ",目标尺寸:" + width + "x" + height);
|
||||
LogUtils.d(TAG, String.format("startImageCrop() | 目标尺寸:%dx%d", width, height));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ 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;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.utils.UriUtils;
|
||||
import cc.winboll.studio.powerbell.views.BackgroundView;
|
||||
|
||||
@@ -134,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();
|
||||
@@ -142,7 +145,8 @@ public class BackgroundPicturePreviewDialog extends Dialog {
|
||||
}
|
||||
|
||||
// 加载图片到预览视图
|
||||
mBackgroundView.loadImage(szSrcImage);
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(mContext).getCurrentBackgroundBean().getPixelColor();
|
||||
mBackgroundView.loadImage(nCurrentPixelColor, szSrcImage, true);
|
||||
LogUtils.d(TAG, "【previewRecivedPicture】图片预览完成,文件路径:" + szSrcImage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
|
||||
// 图片加载成功,获取文件路径并设置背景
|
||||
mDownloadSavedPath = (String) msg.obj;
|
||||
LogUtils.d(TAG, String.format("handleMessage: 图片加载成功,保存路径:%s", mDownloadSavedPath));
|
||||
mBackgroundView.loadImage(mDownloadSavedPath);
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(mContext).getCurrentBackgroundBean().getPixelColor();
|
||||
|
||||
mBackgroundView.loadImage(nCurrentPixelColor, mDownloadSavedPath, true);
|
||||
break;
|
||||
case MSG_IMAGE_LOAD_FAILED:
|
||||
// 图片加载失败,设置默认背景
|
||||
|
||||
@@ -10,26 +10,28 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2024/04/29 17:24:53
|
||||
* @Describe 应用运行参数类
|
||||
* 适配 API30,支持 Serializable 持久化、Parcelable Intent 传递、JSON 序列化/反序列化
|
||||
* 包含耗电提醒、充电提醒、电量检测、铃声提醒等核心配置
|
||||
* 包含耗电提醒、充电提醒、电量检测、铃声提醒、相框尺寸等核心配置
|
||||
*/
|
||||
public class AppConfigBean extends BaseBean implements Serializable, Parcelable {
|
||||
// ====================== 静态常量(首屏可见,统一管理) ======================
|
||||
// ====================== 静态常量区(首屏可见,统一管理) ======================
|
||||
// 序列化版本号(Serializable 必备,避免反序列化失败)
|
||||
private static final long serialVersionUID = 1L;
|
||||
// 日志标签(全局统一,替换 Log 为 LogUtils)
|
||||
// 日志标签(全局统一)
|
||||
transient public static final String TAG = "AppConfigBean";
|
||||
// 字段校验常量(统一阈值,避免硬编码)
|
||||
private static final int MIN_INTERVAL = 500; // 最小检测间隔(ms)
|
||||
private static final int MIN_REMIND_INTERVAL = 1000; // 最小提醒间隔(ms)
|
||||
private static final int BATTERY_MIN = 0; // 电量最小值
|
||||
private static final int BATTERY_MAX = 100; // 电量最大值
|
||||
private static final int INVALID_BATTERY = -1; // 无效电量标识
|
||||
private static final int MIN_INTERVAL = 500; // 最小检测间隔(ms)
|
||||
private static final int MIN_REMIND_INTERVAL = 1000;// 最小提醒间隔(ms)
|
||||
private static final int BATTERY_MIN = 0; // 电量最小值
|
||||
private static final int BATTERY_MAX = 100; // 电量最大值
|
||||
private static final int INVALID_BATTERY = -1; // 无效电量标识
|
||||
private static final int DEFAULT_FRAME_WIDTH = 500; // 默认相框宽度(px)
|
||||
private static final int DEFAULT_FRAME_HEIGHT = 500;// 默认相框高度(px)
|
||||
|
||||
// ====================== 成员变量(按功能分类:提醒配置→电量状态→检测配置) ======================
|
||||
// ====================== 成员变量区(按功能分类:提醒配置→电量状态→检测配置→相框配置) ======================
|
||||
// 耗电提醒配置
|
||||
boolean isEnableUsageReminder = false; // 耗电提醒开关
|
||||
int usageReminderValue = 45; // 耗电提醒阈值(0-100)
|
||||
@@ -40,9 +42,11 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
int reminderIntervalTime = 5000; // 铃声提醒间隔(ms)
|
||||
// 电量状态
|
||||
boolean isCharging = false; // 是否充电
|
||||
int currentBatteryValue = INVALID_BATTERY; // 当前电池电量(统一命名,替代原 currentValue)
|
||||
// 电量检测配置
|
||||
int batteryDetectInterval = 2000; // 电量检测间隔(ms,适配 RemindThread)
|
||||
// 相框配置
|
||||
int defaultFrameWidth = DEFAULT_FRAME_WIDTH; // 默认相框宽度(px)
|
||||
int defaultFrameHeight = DEFAULT_FRAME_HEIGHT;// 默认相框高度(px)
|
||||
|
||||
// ====================== 构造方法(初始化默认配置,强化默认值校验) ======================
|
||||
public AppConfigBean() {
|
||||
@@ -51,55 +55,17 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
setUsageReminderValue(10);
|
||||
setEnableUsageReminder(false);
|
||||
setReminderIntervalTime(5000);
|
||||
setBatteryDetectInterval(1000); // 默认检测间隔1秒
|
||||
setCurrentBatteryValue(INVALID_BATTERY); // 初始化无效电量标识
|
||||
LogUtils.d(TAG, "AppConfigBean: 初始化默认配置完成");
|
||||
setBatteryDetectInterval(1000);
|
||||
setDefaultFrameWidth(DEFAULT_FRAME_WIDTH);
|
||||
setDefaultFrameHeight(DEFAULT_FRAME_HEIGHT);
|
||||
LogUtils.d(TAG, "AppConfigBean() 构造器执行 | 默认配置初始化完成");
|
||||
}
|
||||
|
||||
// ====================== 核心业务方法(Setter/Getter,按字段功能分类,补充调试日志) ======================
|
||||
// --------------- 电量状态相关 ---------------
|
||||
/**
|
||||
* 设置当前电池电量(Receiver 监听电池变化时调用)
|
||||
* @param currentBatteryValue 当前电量(0-100)
|
||||
*/
|
||||
public void setCurrentBatteryValue(int currentBatteryValue) {
|
||||
this.currentBatteryValue = (currentBatteryValue >= BATTERY_MIN && currentBatteryValue <= BATTERY_MAX)
|
||||
? currentBatteryValue : INVALID_BATTERY;
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue: 当前电量设置为 %d(输入值:%d)",
|
||||
this.currentBatteryValue, currentBatteryValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前电池电量(RemindThread 同步配置时调用)
|
||||
* @return 当前电量(0-100 或 INVALID_BATTERY)
|
||||
*/
|
||||
public int getCurrentBatteryValue() {
|
||||
return currentBatteryValue;
|
||||
}
|
||||
|
||||
// --------------- 铃声提醒配置相关 ---------------
|
||||
/**
|
||||
* 设置铃声提醒间隔
|
||||
* @param reminderIntervalTime 提醒间隔(ms,不小于 MIN_REMIND_INTERVAL)
|
||||
*/
|
||||
public void setReminderIntervalTime(int reminderIntervalTime) {
|
||||
this.reminderIntervalTime = Math.max(reminderIntervalTime, MIN_REMIND_INTERVAL);
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime: 提醒间隔设置为 %dms(输入值:%d)",
|
||||
this.reminderIntervalTime, reminderIntervalTime));
|
||||
}
|
||||
|
||||
public int getReminderIntervalTime() {
|
||||
return reminderIntervalTime;
|
||||
}
|
||||
|
||||
// --------------- 充电状态相关 ---------------
|
||||
/**
|
||||
* 设置是否充电
|
||||
* @param isCharging 充电状态
|
||||
*/
|
||||
public void setIsCharging(boolean isCharging) {
|
||||
this.isCharging = isCharging;
|
||||
LogUtils.d(TAG, String.format("setIsCharging: 充电状态设置为 %b", isCharging));
|
||||
LogUtils.d(TAG, String.format("setIsCharging() 执行 | 充电状态=%b", isCharging));
|
||||
}
|
||||
|
||||
public boolean isCharging() {
|
||||
@@ -109,21 +75,16 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
// --------------- 耗电提醒配置相关 ---------------
|
||||
public void setEnableUsageReminder(boolean isEnableUsageReminder) {
|
||||
this.isEnableUsageReminder = isEnableUsageReminder;
|
||||
LogUtils.d(TAG, String.format("setEnableUsageReminder: 耗电提醒开关设置为 %b", isEnableUsageReminder));
|
||||
LogUtils.d(TAG, String.format("setEnableUsageReminder() 执行 | 耗电提醒开关=%b", isEnableUsageReminder));
|
||||
}
|
||||
|
||||
public boolean isEnableUsageReminder() {
|
||||
return isEnableUsageReminder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置耗电提醒阈值
|
||||
* @param usageReminderValue 阈值(0-100)
|
||||
*/
|
||||
public void setUsageReminderValue(int usageReminderValue) {
|
||||
this.usageReminderValue = Math.min(Math.max(usageReminderValue, BATTERY_MIN), BATTERY_MAX);
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue: 耗电提醒阈值设置为 %d(输入值:%d)",
|
||||
this.usageReminderValue, usageReminderValue));
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue() 执行 | 最终阈值=%d | 输入值=%d", this.usageReminderValue, usageReminderValue));
|
||||
}
|
||||
|
||||
public int getUsageReminderValue() {
|
||||
@@ -133,43 +94,62 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
// --------------- 充电提醒配置相关 ---------------
|
||||
public void setEnableChargeReminder(boolean isEnableChargeReminder) {
|
||||
this.isEnableChargeReminder = isEnableChargeReminder;
|
||||
LogUtils.d(TAG, String.format("setEnableChargeReminder: 充电提醒开关设置为 %b", isEnableChargeReminder));
|
||||
LogUtils.d(TAG, String.format("setEnableChargeReminder() 执行 | 充电提醒开关=%b", isEnableChargeReminder));
|
||||
}
|
||||
|
||||
public boolean isEnableChargeReminder() {
|
||||
return isEnableChargeReminder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置充电提醒阈值
|
||||
* @param chargeReminderValue 阈值(0-100)
|
||||
*/
|
||||
public void setChargeReminderValue(int chargeReminderValue) {
|
||||
this.chargeReminderValue = Math.min(Math.max(chargeReminderValue, BATTERY_MIN), BATTERY_MAX);
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue: 充电提醒阈值设置为 %d(输入值:%d)",
|
||||
this.chargeReminderValue, chargeReminderValue));
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue() 执行 | 最终阈值=%d | 输入值=%d", this.chargeReminderValue, chargeReminderValue));
|
||||
}
|
||||
|
||||
public int getChargeReminderValue() {
|
||||
return chargeReminderValue;
|
||||
}
|
||||
|
||||
// --------------- 铃声提醒配置相关 ---------------
|
||||
public void setReminderIntervalTime(int reminderIntervalTime) {
|
||||
this.reminderIntervalTime = Math.max(reminderIntervalTime, MIN_REMIND_INTERVAL);
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime() 执行 | 最终间隔=%dms | 输入值=%dms", this.reminderIntervalTime, reminderIntervalTime));
|
||||
}
|
||||
|
||||
public int getReminderIntervalTime() {
|
||||
return reminderIntervalTime;
|
||||
}
|
||||
|
||||
// --------------- 电量检测配置相关 ---------------
|
||||
/**
|
||||
* 设置电量检测间隔
|
||||
* @param batteryDetectInterval 检测间隔(ms,不小于 MIN_INTERVAL)
|
||||
*/
|
||||
public void setBatteryDetectInterval(int batteryDetectInterval) {
|
||||
this.batteryDetectInterval = Math.max(batteryDetectInterval, MIN_INTERVAL);
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval: 检测间隔设置为 %dms(输入值:%d)",
|
||||
this.batteryDetectInterval, batteryDetectInterval));
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval() 执行 | 最终间隔=%dms | 输入值=%dms", this.batteryDetectInterval, batteryDetectInterval));
|
||||
}
|
||||
|
||||
public int getBatteryDetectInterval() {
|
||||
return batteryDetectInterval;
|
||||
}
|
||||
|
||||
// ====================== JSON 序列化/反序列化(兼容旧配置,补充调试日志) ======================
|
||||
// --------------- 相框配置相关 ---------------
|
||||
public void setDefaultFrameWidth(int defaultFrameWidth) {
|
||||
this.defaultFrameWidth = defaultFrameWidth;
|
||||
LogUtils.d(TAG, String.format("setDefaultFrameWidth() 执行 | 最终宽度=%dpx | 输入值=%dpx", this.defaultFrameWidth, defaultFrameWidth));
|
||||
}
|
||||
|
||||
public int getDefaultFrameWidth() {
|
||||
return defaultFrameWidth;
|
||||
}
|
||||
|
||||
public void setDefaultFrameHeight(int defaultFrameHeight) {
|
||||
this.defaultFrameHeight = defaultFrameHeight;
|
||||
LogUtils.d(TAG, String.format("setDefaultFrameHeight() 执行 | 最终高度=%dpx | 输入值=%dpx", this.defaultFrameHeight, defaultFrameHeight));
|
||||
}
|
||||
|
||||
public int getDefaultFrameHeight() {
|
||||
return defaultFrameHeight;
|
||||
}
|
||||
|
||||
// ====================== 父类重写方法(JSON 序列化/反序列化,兼容旧配置) ======================
|
||||
@Override
|
||||
public String getName() {
|
||||
return AppConfigBean.class.getName();
|
||||
@@ -178,62 +158,72 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
@Override
|
||||
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
|
||||
super.writeThisToJsonWriter(jsonWriter);
|
||||
AppConfigBean bean = this;
|
||||
LogUtils.d(TAG, "writeThisToJsonWriter() 执行 | 开始JSON序列化");
|
||||
|
||||
// 原有字段序列化
|
||||
jsonWriter.name("isEnableUsageReminder").value(bean.isEnableUsageReminder());
|
||||
jsonWriter.name("usageReminderValue").value(bean.getUsageReminderValue());
|
||||
jsonWriter.name("isEnableChargeReminder").value(bean.isEnableChargeReminder());
|
||||
jsonWriter.name("chargeReminderValue").value(bean.getChargeReminderValue());
|
||||
jsonWriter.name("reminderIntervalTime").value(bean.getReminderIntervalTime());
|
||||
jsonWriter.name("isCharging").value(bean.isCharging());
|
||||
// 兼容旧字段 currentValue,同步新字段 currentBatteryValue
|
||||
jsonWriter.name("currentBatteryValue").value(bean.getCurrentBatteryValue());
|
||||
jsonWriter.name("currentValue").value(bean.getCurrentBatteryValue());
|
||||
// 新增字段序列化
|
||||
jsonWriter.name("batteryDetectInterval").value(bean.getBatteryDetectInterval());
|
||||
LogUtils.d(TAG, "writeThisToJsonWriter: JSON 序列化完成");
|
||||
jsonWriter.name("isEnableUsageReminder").value(isEnableUsageReminder());
|
||||
jsonWriter.name("usageReminderValue").value(getUsageReminderValue());
|
||||
jsonWriter.name("isEnableChargeReminder").value(isEnableChargeReminder());
|
||||
jsonWriter.name("chargeReminderValue").value(getChargeReminderValue());
|
||||
jsonWriter.name("reminderIntervalTime").value(getReminderIntervalTime());
|
||||
jsonWriter.name("isCharging").value(isCharging());
|
||||
// 新增字段序列化(检测配置)
|
||||
jsonWriter.name("batteryDetectInterval").value(getBatteryDetectInterval());
|
||||
// 新增字段序列化(相框配置)
|
||||
jsonWriter.name("defaultFrameWidth").value(getDefaultFrameWidth());
|
||||
jsonWriter.name("defaultFrameHeight").value(getDefaultFrameHeight());
|
||||
|
||||
LogUtils.d(TAG, "writeThisToJsonWriter() 完成 | JSON序列化成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
|
||||
LogUtils.d(TAG, "readBeanFromJsonReader() 执行 | 开始JSON反序列化");
|
||||
AppConfigBean bean = new AppConfigBean();
|
||||
jsonReader.beginObject();
|
||||
|
||||
while (jsonReader.hasNext()) {
|
||||
String name = jsonReader.nextName();
|
||||
// 兼容拼写错误字段(isEnableUsegeReminder → isEnableUsageReminder)
|
||||
if (name.equals("isEnableUsageReminder") || name.equals("isEnableUsegeReminder")) {
|
||||
bean.setEnableUsageReminder(jsonReader.nextBoolean());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%b", name, bean.isEnableUsageReminder()));
|
||||
} else if (name.equals("usageReminderValue") || name.equals("usegeReminderValue")) {
|
||||
bean.setUsageReminderValue(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getUsageReminderValue()));
|
||||
} else if (name.equals("isEnableChargeReminder")) {
|
||||
bean.setEnableChargeReminder(jsonReader.nextBoolean());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%b", name, bean.isEnableChargeReminder()));
|
||||
} else if (name.equals("chargeReminderValue")) {
|
||||
bean.setChargeReminderValue(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getChargeReminderValue()));
|
||||
} else if (name.equals("reminderIntervalTime")) {
|
||||
bean.setReminderIntervalTime(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getReminderIntervalTime()));
|
||||
} else if (name.equals("isCharging")) {
|
||||
bean.setIsCharging(jsonReader.nextBoolean());
|
||||
} else if (name.equals("currentValue")) {
|
||||
// 优先读取旧字段,兼容历史配置
|
||||
bean.setCurrentBatteryValue(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, "readBeanFromJsonReader: 读取旧字段 currentValue 完成");
|
||||
} else if (name.equals("currentBatteryValue")) {
|
||||
// 新字段覆盖旧字段,保证数据最新
|
||||
bean.setCurrentBatteryValue(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, "readBeanFromJsonReader: 读取新字段 currentBatteryValue 完成");
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%b", name, bean.isCharging()));
|
||||
} else if (name.equals("batteryDetectInterval")) {
|
||||
bean.setBatteryDetectInterval(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getBatteryDetectInterval()));
|
||||
} else if (name.equals("defaultFrameWidth")) {
|
||||
bean.setDefaultFrameWidth(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getDefaultFrameWidth()));
|
||||
} else if (name.equals("defaultFrameHeight")) {
|
||||
bean.setDefaultFrameHeight(jsonReader.nextInt());
|
||||
LogUtils.d(TAG, String.format("readBeanFromJsonReader() 读取字段 | %s=%d", name, bean.getDefaultFrameHeight()));
|
||||
} else {
|
||||
jsonReader.skipValue();
|
||||
LogUtils.w(TAG, String.format("readBeanFromJsonReader: 跳过未知字段 %s", name));
|
||||
LogUtils.w(TAG, String.format("readBeanFromJsonReader() 跳过未知字段 | %s", name));
|
||||
}
|
||||
}
|
||||
|
||||
jsonReader.endObject();
|
||||
LogUtils.d(TAG, "readBeanFromJsonReader: JSON 反序列化完成");
|
||||
LogUtils.d(TAG, "readBeanFromJsonReader() 完成 | JSON反序列化成功");
|
||||
return bean;
|
||||
}
|
||||
|
||||
// ====================== Parcelable 接口实现(API30 Intent 传递必备,补充调试日志) ======================
|
||||
// ====================== Parcelable 接口实现(API30 Intent 传递必备) ======================
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0; // 无特殊内容描述,固定返回0
|
||||
@@ -241,6 +231,7 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
LogUtils.d(TAG, "writeToParcel() 执行 | 开始Parcel序列化");
|
||||
// 按成员变量顺序写入,boolean 转 byte 存储
|
||||
dest.writeByte((byte) (isEnableUsageReminder ? 1 : 0));
|
||||
dest.writeInt(usageReminderValue);
|
||||
@@ -248,15 +239,17 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
dest.writeInt(chargeReminderValue);
|
||||
dest.writeInt(reminderIntervalTime);
|
||||
dest.writeByte((byte) (isCharging ? 1 : 0));
|
||||
dest.writeInt(currentBatteryValue);
|
||||
dest.writeInt(batteryDetectInterval);
|
||||
LogUtils.d(TAG, "writeToParcel: Parcel 序列化完成");
|
||||
dest.writeInt(defaultFrameWidth);
|
||||
dest.writeInt(defaultFrameHeight);
|
||||
LogUtils.d(TAG, "writeToParcel() 完成 | Parcel序列化成功");
|
||||
}
|
||||
|
||||
// 反序列化 Creator(必须 public static final 修饰,Java7 适配)
|
||||
public static final Parcelable.Creator<AppConfigBean> CREATOR = new Parcelable.Creator<AppConfigBean>() {
|
||||
@Override
|
||||
public AppConfigBean createFromParcel(Parcel source) {
|
||||
LogUtils.d(TAG, "createFromParcel() 执行 | 开始Parcel反序列化");
|
||||
AppConfigBean bean = new AppConfigBean();
|
||||
// 按 writeToParcel 顺序读取
|
||||
bean.isEnableUsageReminder = source.readByte() != 0;
|
||||
@@ -265,9 +258,10 @@ public class AppConfigBean extends BaseBean implements Serializable, Parcelable
|
||||
bean.chargeReminderValue = source.readInt();
|
||||
bean.reminderIntervalTime = source.readInt();
|
||||
bean.isCharging = source.readByte() != 0;
|
||||
bean.currentBatteryValue = source.readInt();
|
||||
bean.batteryDetectInterval = source.readInt();
|
||||
LogUtils.d(TAG, "createFromParcel: Parcel 反序列化完成");
|
||||
bean.defaultFrameWidth = source.readInt();
|
||||
bean.defaultFrameHeight = source.readInt();
|
||||
LogUtils.d(TAG, "createFromParcel() 完成 | Parcel反序列化成功");
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
@@ -14,11 +15,12 @@ import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/19 20:23
|
||||
* @Describe 控制中心广播接收器
|
||||
* 控制中心广播接收器
|
||||
* 功能:监听电池状态变化、前台通知更新、配置变更指令
|
||||
* 适配:Java7 | API30 | 内存泄漏防护 | 多线程状态同步
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2025/12/19 20:23
|
||||
* @Describe 统一处理系统与应用内广播,同步电池状态与配置,保障多线程数据一致性
|
||||
*/
|
||||
public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// ====================== 静态常量区(置顶归类,消除魔法值) ======================
|
||||
@@ -44,7 +46,8 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
|
||||
// ====================== 构造方法(初始化弱引用,避免服务强引用泄漏) ======================
|
||||
public ControlCenterServiceReceiver(ControlCenterService service) {
|
||||
LogUtils.d(TAG, String.format("构造接收器 | 服务实例:%s", service != null ? service.getClass().getSimpleName() : "null"));
|
||||
LogUtils.d(TAG, String.format("ControlCenterServiceReceiver() 构造 | 服务实例:%s",
|
||||
service != null ? service.getClass().getSimpleName() : "null"));
|
||||
this.mwrControlCenterService = new WeakReference<>(service);
|
||||
}
|
||||
|
||||
@@ -52,18 +55,18 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent != null ? intent.getAction() : "null";
|
||||
LogUtils.d(TAG, String.format("onReceive: 接收广播 | Action:%s", action));
|
||||
LogUtils.d(TAG, String.format("onReceive() 执行 | 接收广播 Action:%s", action));
|
||||
|
||||
// 基础参数校验
|
||||
if (context == null || intent == null || action == null) {
|
||||
LogUtils.e(TAG, "onReceive: 参数无效(context=" + context + " | intent=" + intent + "),终止处理");
|
||||
LogUtils.e(TAG, "onReceive() 终止 | 参数无效(context=" + context + " | intent=" + intent + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
// 弱引用获取服务,双重校验服务有效性
|
||||
ControlCenterService service = mwrControlCenterService != null ? mwrControlCenterService.get() : null;
|
||||
if (service == null || service.isDestroyed()) {
|
||||
LogUtils.e(TAG, "onReceive: 服务已销毁或为空,注销广播");
|
||||
LogUtils.e(TAG, "onReceive() 终止 | 服务已销毁或为空,执行注销");
|
||||
unregisterAction(context);
|
||||
return;
|
||||
}
|
||||
@@ -77,14 +80,14 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
handleUpdateForegroundNotification(service);
|
||||
break;
|
||||
case ACTION_APPCONFIG_CHANGED:
|
||||
LogUtils.d(TAG, "onReceive: 开始处理配置更新广播");
|
||||
LogUtils.d(TAG, "onReceive() 分发 | 处理配置更新广播");
|
||||
handleNotifyAppConfigUpdate(service);
|
||||
break;
|
||||
default:
|
||||
LogUtils.w(TAG, String.format("onReceive: 未知Action=%s", action));
|
||||
LogUtils.w(TAG, String.format("onReceive() 警告 | 未知Action=%s", action));
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "onReceive: 广播处理完成");
|
||||
LogUtils.d(TAG, "onReceive() 完成 | 广播处理结束");
|
||||
}
|
||||
|
||||
// ====================== 业务处理方法(按功能拆分,强化容错与日志) ======================
|
||||
@@ -94,17 +97,17 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param intent 电池状态广播意图
|
||||
*/
|
||||
private void handleBatteryStateChanged(ControlCenterService service, Intent intent) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 解析电池状态");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged() 执行 | 解析电池状态");
|
||||
try {
|
||||
// 1. 解析并校验当前电池状态
|
||||
boolean currentCharging = BatteryUtils.isCharging(intent);
|
||||
int currentBatteryLevel = BatteryUtils.getCurrentBatteryLevel(intent);
|
||||
currentBatteryLevel = Math.min(Math.max(currentBatteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged: 当前状态 | 充电=%b | 电量=%d%%", currentCharging, currentBatteryLevel));
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged() 解析 | 充电=%b | 电量=%d%%", currentCharging, currentBatteryLevel));
|
||||
|
||||
// 2. 状态无变化则跳过,减少无效运算
|
||||
if (currentCharging == sIsCharging && currentBatteryLevel == sLastBatteryLevel) {
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged: 电池状态无变化,跳过处理");
|
||||
LogUtils.d(TAG, "handleBatteryStateChanged() 跳过 | 电池状态无变化");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,9 +118,10 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
// 4. 同步缓存状态到配置
|
||||
handleNotifyAppConfigUpdate(service);
|
||||
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged: 处理成功 | 缓存电量=%d%% | 缓存充电状态=%b", sLastBatteryLevel, sIsCharging));
|
||||
LogUtils.d(TAG, String.format("handleBatteryStateChanged() 完成 | 缓存电量=%d%% | 缓存充电状态=%b",
|
||||
sLastBatteryLevel, sIsCharging));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged: 处理失败", e);
|
||||
LogUtils.e(TAG, "handleBatteryStateChanged() 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,26 +130,26 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param service 控制中心服务实例
|
||||
*/
|
||||
private void handleNotifyAppConfigUpdate(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate: 同步缓存状态到配置");
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate() 执行 | 同步缓存状态到配置");
|
||||
try {
|
||||
// 加载最新配置
|
||||
AppConfigBean latestConfig = AppConfigUtils.getInstance(service).loadAppConfig();
|
||||
if (latestConfig == null) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate: 最新配置为空,终止处理");
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 终止 | 最新配置为空");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate: 加载最新配置 | 充电阈值=%d | 耗电阈值=%d",
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate() 加载 | 充电阈值=%d | 耗电阈值=%d",
|
||||
latestConfig.getChargeReminderValue(), latestConfig.getUsageReminderValue()));
|
||||
|
||||
// 同步缓存的电池状态到配置
|
||||
latestConfig.setCurrentBatteryValue(sLastBatteryLevel);
|
||||
App.sQuantityOfElectricity = sLastBatteryLevel;
|
||||
latestConfig.setIsCharging(sIsCharging);
|
||||
service.notifyAppConfigUpdate(latestConfig);
|
||||
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate: 配置同步成功 | 缓存电量=%d%% | 充电状态=%b", sLastBatteryLevel, sIsCharging));
|
||||
LogUtils.d(TAG, "handleNotifyAppConfigUpdate: 配置更新广播处理完成");
|
||||
LogUtils.d(TAG, String.format("handleNotifyAppConfigUpdate() 完成 | 缓存电量=%d%% | 充电状态=%b",
|
||||
sLastBatteryLevel, sIsCharging));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate: 处理失败", e);
|
||||
LogUtils.e(TAG, "handleNotifyAppConfigUpdate() 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,21 +158,22 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param service 控制中心服务实例
|
||||
*/
|
||||
private void handleUpdateForegroundNotification(ControlCenterService service) {
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification: 更新前台通知");
|
||||
LogUtils.d(TAG, "handleUpdateForegroundNotification() 执行 | 更新前台通知");
|
||||
try {
|
||||
NotificationManagerUtils notifyUtils = service.getNotificationManager();
|
||||
NotificationMessage notifyMsg = service.getForegroundNotifyMsg();
|
||||
|
||||
// 非空校验,避免空指针
|
||||
if (notifyUtils == null || notifyMsg == null) {
|
||||
LogUtils.e(TAG, String.format("handleUpdateForegroundNotification: 通知工具类或消息为空(notifyUtils=%s | notifyMsg=%s)", notifyUtils, notifyMsg));
|
||||
LogUtils.e(TAG, String.format("handleUpdateForegroundNotification() 终止 | 通知工具类或消息为空(notifyUtils=%s | notifyMsg=%s)",
|
||||
notifyUtils, notifyMsg));
|
||||
return;
|
||||
}
|
||||
|
||||
notifyUtils.updateForegroundServiceNotify(notifyMsg);
|
||||
LogUtils.d(TAG, String.format("handleUpdateForegroundNotification: 前台通知更新成功 | 标题=%s", notifyMsg.getTitle()));
|
||||
LogUtils.d(TAG, String.format("handleUpdateForegroundNotification() 完成 | 标题=%s", notifyMsg.getTitle()));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification: 处理失败", e);
|
||||
LogUtils.e(TAG, "handleUpdateForegroundNotification() 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,9 +183,9 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public void registerAction(Context context) {
|
||||
LogUtils.d(TAG, "registerAction: 注册广播接收器");
|
||||
LogUtils.d(TAG, "registerAction() 执行 | 注册广播接收器");
|
||||
if (context == null || isRegistered) {
|
||||
LogUtils.e(TAG, "registerAction: 上下文为空或已注册,注册失败");
|
||||
LogUtils.e(TAG, "registerAction() 失败 | 上下文为空或已注册");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,9 +198,9 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
|
||||
context.registerReceiver(this, filter);
|
||||
isRegistered = true;
|
||||
LogUtils.d(TAG, String.format("registerAction: 广播注册成功 | 优先级=%d", BROADCAST_PRIORITY));
|
||||
LogUtils.d(TAG, String.format("registerAction() 完成 | 优先级=%d", BROADCAST_PRIORITY));
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "registerAction: 注册失败", e);
|
||||
LogUtils.e(TAG, "registerAction() 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,20 +209,20 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public void unregisterAction(Context context) {
|
||||
LogUtils.d(TAG, "unregisterAction: 注销广播接收器");
|
||||
LogUtils.d(TAG, "unregisterAction() 执行 | 注销广播接收器");
|
||||
if (context == null || !isRegistered) {
|
||||
LogUtils.e(TAG, "unregisterAction: 上下文为空或未注册,注销失败");
|
||||
LogUtils.e(TAG, "unregisterAction() 失败 | 上下文为空或未注册");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
context.unregisterReceiver(this);
|
||||
isRegistered = false;
|
||||
LogUtils.d(TAG, "unregisterAction: 广播注销成功");
|
||||
LogUtils.d(TAG, "unregisterAction() 完成 | 广播注销成功");
|
||||
} catch (IllegalArgumentException e) {
|
||||
LogUtils.w(TAG, "unregisterAction: 广播未注册,跳过注销");
|
||||
LogUtils.w(TAG, "unregisterAction() 警告 | 广播未注册,跳过注销");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "unregisterAction: 注销失败", e);
|
||||
LogUtils.e(TAG, "unregisterAction() 失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,17 +231,17 @@ public class ControlCenterServiceReceiver extends BroadcastReceiver {
|
||||
* 主动释放资源,避免内存泄漏
|
||||
*/
|
||||
public void release() {
|
||||
LogUtils.d(TAG, "release: 释放广播接收器资源");
|
||||
LogUtils.d(TAG, "release() 执行 | 释放广播接收器资源");
|
||||
// 清空弱引用,帮助GC回收
|
||||
if (mwrControlCenterService != null) {
|
||||
mwrControlCenterService.clear();
|
||||
mwrControlCenterService = null;
|
||||
LogUtils.d(TAG, "release: 弱引用已清空");
|
||||
LogUtils.d(TAG, "release() 步骤 | 弱引用已清空");
|
||||
}
|
||||
// 重置静态状态缓存
|
||||
sLastBatteryLevel = -1;
|
||||
sIsCharging = false;
|
||||
LogUtils.d(TAG, "release: 静态状态缓存已重置");
|
||||
LogUtils.d(TAG, "release() 完成 | 静态状态缓存已重置");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
* 电池提醒核心服务
|
||||
* 功能:管理前台服务生命周期、控制提醒线程启停、处理配置更新
|
||||
* 适配:Java7 | API30 | 前台服务超时防护 | 电池优化忽略引导
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Describe 核心服务:实现电池监测、提醒控制与前台服务保活
|
||||
*/
|
||||
public class ControlCenterService extends Service {
|
||||
@@ -62,35 +62,35 @@ public class ControlCenterService extends Service {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LogUtils.d(TAG, String.format("onCreate执行 | 线程=%s | 进程ID=%d", Thread.currentThread().getName(), android.os.Process.myPid()));
|
||||
LogUtils.d(TAG, String.format("onCreate() 执行 | 线程=%s | 进程ID=%d", Thread.currentThread().getName(), android.os.Process.myPid()));
|
||||
runCoreServiceLogic();
|
||||
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, String.format("onCreate完成 | 前台状态=%b | 服务启用=%b", isServiceRunning, serviceEnabled));
|
||||
LogUtils.d(TAG, String.format("onCreate() 完成 | 前台状态=%b | 服务启用=%b", isServiceRunning, serviceEnabled));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = intent != null ? intent.getAction() : "null";
|
||||
LogUtils.d(TAG, String.format("onStartCommand执行 | startId=%d | action=%s", startId, action));
|
||||
LogUtils.d(TAG, String.format("onStartCommand() 执行 | startId=%d | action=%s", startId, action));
|
||||
loadLatestServiceControlConfig();
|
||||
runCoreServiceLogic();
|
||||
|
||||
int returnFlag = (mServiceControlBean != null && mServiceControlBean.isEnableService())
|
||||
? SERVICE_RETURN_STICKY
|
||||
: super.onStartCommand(intent, flags, startId);
|
||||
LogUtils.d(TAG, String.format("onStartCommand完成 | 返回策略=%s", returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
|
||||
LogUtils.d(TAG, String.format("onStartCommand() 完成 | 返回策略=%s", returnFlag == SERVICE_RETURN_STICKY ? "START_STICKY" : "DEFAULT"));
|
||||
return returnFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
LogUtils.d(TAG, String.format("onBind执行 | intent=%s", intent));
|
||||
LogUtils.d(TAG, String.format("onBind() 执行 | intent=%s", intent));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
LogUtils.d(TAG, "onDestroy执行:服务销毁流程启动");
|
||||
LogUtils.d(TAG, "onDestroy() 执行:服务销毁流程启动");
|
||||
super.onDestroy();
|
||||
|
||||
// 资源释放顺序:前台服务 → 线程 → 广播接收器 → Handler → 通知 → 引用(避免内存泄漏)
|
||||
@@ -108,7 +108,7 @@ public class ControlCenterService extends Service {
|
||||
isServiceRunning = false;
|
||||
mIsDestroyed = true;
|
||||
|
||||
LogUtils.d(TAG, "onDestroy完成:服务销毁完成");
|
||||
LogUtils.d(TAG, "onDestroy() 完成:服务销毁完成");
|
||||
}
|
||||
|
||||
// ====================== 核心业务逻辑(独立抽取,统一调用) ======================
|
||||
@@ -117,11 +117,11 @@ public class ControlCenterService extends Service {
|
||||
* 避免重复初始化,保证前台服务优先启动
|
||||
*/
|
||||
private synchronized void runCoreServiceLogic() {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic执行");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic() 执行");
|
||||
loadLatestServiceControlConfig();
|
||||
|
||||
boolean serviceEnabled = mServiceControlBean != null && mServiceControlBean.isEnableService();
|
||||
LogUtils.d(TAG, String.format("runCoreServiceLogic:服务启用=%b | 已运行=%b | 已销毁=%b", serviceEnabled, isServiceRunning, mIsDestroyed));
|
||||
LogUtils.d(TAG, String.format("runCoreServiceLogic() | 服务启用=%b | 已运行=%b | 已销毁=%b", serviceEnabled, isServiceRunning, mIsDestroyed));
|
||||
|
||||
if (serviceEnabled && !isServiceRunning) {
|
||||
isServiceRunning = true;
|
||||
@@ -130,14 +130,14 @@ public class ControlCenterService extends Service {
|
||||
if (initForegroundNotificationImmediately()) {
|
||||
loadDefaultConfig();
|
||||
initServiceBusinessLogic();
|
||||
LogUtils.d(TAG, "runCoreServiceLogic:核心组件初始化成功");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic() | 核心组件初始化成功");
|
||||
} else {
|
||||
LogUtils.e(TAG, "runCoreServiceLogic:前台通知初始化失败,终止业务");
|
||||
LogUtils.e(TAG, "runCoreServiceLogic() | 前台通知初始化失败,终止业务");
|
||||
stopForegroundService();
|
||||
isServiceRunning = false;
|
||||
}
|
||||
} else {
|
||||
LogUtils.d(TAG, "runCoreServiceLogic:无需执行核心逻辑");
|
||||
LogUtils.d(TAG, "runCoreServiceLogic() | 无需执行核心逻辑");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,11 +147,11 @@ public class ControlCenterService extends Service {
|
||||
* @return true=成功 false=失败
|
||||
*/
|
||||
private boolean initForegroundNotificationImmediately() {
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately执行");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately() 执行");
|
||||
try {
|
||||
if (mNotificationManager == null) {
|
||||
mNotificationManager = new NotificationManagerUtils(this);
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately:通知工具类初始化完成");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately() | 通知工具类初始化完成");
|
||||
}
|
||||
|
||||
if (mForegroundNotifyMsg == null) {
|
||||
@@ -159,15 +159,15 @@ public class ControlCenterService extends Service {
|
||||
mForegroundNotifyMsg.setTitle("电池监测服务");
|
||||
mForegroundNotifyMsg.setContent("后台运行中");
|
||||
mForegroundNotifyMsg.setRemindMSG("service_running");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately:通知消息构建完成");
|
||||
LogUtils.d(TAG, "initForegroundNotificationImmediately() | 通知消息构建完成");
|
||||
}
|
||||
|
||||
mNotificationManager.startForegroundServiceNotify(this, mForegroundNotifyMsg);
|
||||
ToastUtils.show("电池监测服务已启动");
|
||||
LogUtils.d(TAG, String.format("initForegroundNotificationImmediately:前台通知发送成功 | ID=%d", NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE));
|
||||
LogUtils.d(TAG, String.format("initForegroundNotificationImmediately() | 前台通知发送成功 | ID=%d", NotificationManagerUtils.NOTIFY_ID_FOREGROUND_SERVICE));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "initForegroundNotificationImmediately:通知初始化异常", e);
|
||||
LogUtils.e(TAG, "initForegroundNotificationImmediately() | 通知初始化异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -176,12 +176,12 @@ public class ControlCenterService extends Service {
|
||||
* 停止前台服务并取消通知
|
||||
*/
|
||||
private void stopForegroundService() {
|
||||
LogUtils.d(TAG, "stopForegroundService执行");
|
||||
LogUtils.d(TAG, "stopForegroundService() 执行");
|
||||
try {
|
||||
stopForeground(true);
|
||||
LogUtils.d(TAG, "stopForegroundService:前台服务已停止,通知已取消");
|
||||
LogUtils.d(TAG, "stopForegroundService() | 前台服务已停止,通知已取消");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "stopForegroundService:停止异常", e);
|
||||
LogUtils.e(TAG, "stopForegroundService() | 停止异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,13 +190,13 @@ public class ControlCenterService extends Service {
|
||||
* 加载本地最新服务控制配置
|
||||
*/
|
||||
private void loadLatestServiceControlConfig() {
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig执行");
|
||||
LogUtils.d(TAG, "loadLatestServiceControlConfig() 执行");
|
||||
ControlCenterServiceBean latestBean = ControlCenterServiceBean.loadBean(this, ControlCenterServiceBean.class);
|
||||
if (latestBean != null) {
|
||||
mServiceControlBean = latestBean;
|
||||
LogUtils.d(TAG, String.format("loadLatestServiceControlConfig:配置读取成功 | 启用=%b", mServiceControlBean.isEnableService()));
|
||||
LogUtils.d(TAG, String.format("loadLatestServiceControlConfig() | 配置读取成功 | 启用=%b", mServiceControlBean.isEnableService()));
|
||||
} else {
|
||||
LogUtils.w(TAG, "loadLatestServiceControlConfig:本地无配置,沿用内存配置");
|
||||
LogUtils.w(TAG, "loadLatestServiceControlConfig() | 本地无配置,沿用内存配置");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ public class ControlCenterService extends Service {
|
||||
* 加载默认业务配置(首次启动兜底)
|
||||
*/
|
||||
private void loadDefaultConfig() {
|
||||
LogUtils.d(TAG, "loadDefaultConfig执行");
|
||||
LogUtils.d(TAG, "loadDefaultConfig() 执行");
|
||||
if (mCurrentConfigBean == null) {
|
||||
mCurrentConfigBean = new AppConfigBean();
|
||||
mCurrentConfigBean.setEnableChargeReminder(true);
|
||||
@@ -212,10 +212,10 @@ public class ControlCenterService extends Service {
|
||||
mCurrentConfigBean.setEnableUsageReminder(true);
|
||||
mCurrentConfigBean.setUsageReminderValue(DEFAULT_USAGE_REMINDER_VALUE);
|
||||
mCurrentConfigBean.setBatteryDetectInterval(DEFAULT_BATTERY_DETECT_INTERVAL);
|
||||
LogUtils.d(TAG, String.format("loadDefaultConfig:默认配置加载完成 | 充电阈值=%d | 耗电阈值=%d | 检测间隔=%dms",
|
||||
LogUtils.d(TAG, String.format("loadDefaultConfig() | 默认配置加载完成 | 充电阈值=%d | 耗电阈值=%d | 检测间隔=%dms",
|
||||
DEFAULT_CHARGE_REMINDER_VALUE, DEFAULT_USAGE_REMINDER_VALUE, DEFAULT_BATTERY_DETECT_INTERVAL));
|
||||
} else {
|
||||
LogUtils.d(TAG, "loadDefaultConfig:内存已有配置,无需加载");
|
||||
LogUtils.d(TAG, "loadDefaultConfig() | 内存已有配置,无需加载");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,21 +224,21 @@ public class ControlCenterService extends Service {
|
||||
* 初始化Handler等核心业务组件
|
||||
*/
|
||||
private void initServiceBusinessLogic() {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic执行");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic() 执行");
|
||||
// 初始化Handler
|
||||
if (mServiceHandler == null) {
|
||||
mServiceHandler = new ControlCenterServiceHandler(this);
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:Handler初始化完成");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic() | Handler初始化完成");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:Handler已存在");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic() | Handler已存在");
|
||||
}
|
||||
// 初始化广播接收器
|
||||
if (mControlCenterServiceReceiver == null) {
|
||||
mControlCenterServiceReceiver = new ControlCenterServiceReceiver(this);
|
||||
mControlCenterServiceReceiver.registerAction(this);
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:广播接收器初始化并注册完成");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic() | 广播接收器初始化并注册完成");
|
||||
} else {
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic:广播接收器已存在");
|
||||
LogUtils.d(TAG, "initServiceBusinessLogic() | 广播接收器已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,13 +246,13 @@ public class ControlCenterService extends Service {
|
||||
* 释放广播接收器资源
|
||||
*/
|
||||
private void releaseBroadcastReceiver() {
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver执行");
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver() 执行");
|
||||
if (mControlCenterServiceReceiver != null) {
|
||||
mControlCenterServiceReceiver.release();
|
||||
mControlCenterServiceReceiver = null;
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver:广播接收器已释放");
|
||||
LogUtils.d(TAG, "releaseBroadcastReceiver() | 广播接收器已释放");
|
||||
} else {
|
||||
LogUtils.w(TAG, "releaseBroadcastReceiver:广播接收器实例为空");
|
||||
LogUtils.w(TAG, "releaseBroadcastReceiver() | 广播接收器实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,13 +260,13 @@ public class ControlCenterService extends Service {
|
||||
* 销毁Handler,移除所有消息和回调,防止内存泄漏
|
||||
*/
|
||||
private void destroyHandler() {
|
||||
LogUtils.d(TAG, "destroyHandler执行");
|
||||
LogUtils.d(TAG, "destroyHandler() 执行");
|
||||
if (mServiceHandler != null) {
|
||||
mServiceHandler.removeCallbacksAndMessages(null);
|
||||
mServiceHandler = null;
|
||||
LogUtils.d(TAG, "destroyHandler:Handler已销毁");
|
||||
LogUtils.d(TAG, "destroyHandler() | Handler已销毁");
|
||||
} else {
|
||||
LogUtils.w(TAG, "destroyHandler:Handler实例为空");
|
||||
LogUtils.w(TAG, "destroyHandler() | Handler实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,13 +274,13 @@ public class ControlCenterService extends Service {
|
||||
* 释放通知工具类资源
|
||||
*/
|
||||
private void releaseNotificationResource() {
|
||||
LogUtils.d(TAG, "releaseNotificationResource执行");
|
||||
LogUtils.d(TAG, "releaseNotificationResource() 执行");
|
||||
if (mNotificationManager != null) {
|
||||
mNotificationManager.release();
|
||||
mNotificationManager = null;
|
||||
LogUtils.d(TAG, "releaseNotificationResource:通知资源已释放");
|
||||
LogUtils.d(TAG, "releaseNotificationResource() | 通知资源已释放");
|
||||
} else {
|
||||
LogUtils.w(TAG, "releaseNotificationResource:通知工具类实例为空");
|
||||
LogUtils.w(TAG, "releaseNotificationResource() | 通知工具类实例为空");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,10 +288,10 @@ public class ControlCenterService extends Service {
|
||||
* 置空所有引用,防止内存泄漏
|
||||
*/
|
||||
private void clearAllReferences() {
|
||||
LogUtils.d(TAG, "clearAllReferences执行");
|
||||
LogUtils.d(TAG, "clearAllReferences() 执行");
|
||||
mForegroundNotifyMsg = null;
|
||||
mServiceControlBean = null;
|
||||
LogUtils.d(TAG, "clearAllReferences:引用清理完成");
|
||||
LogUtils.d(TAG, "clearAllReferences() | 引用清理完成");
|
||||
}
|
||||
|
||||
// ====================== 外部调用接口(静态方法,提供服务启停/配置更新入口) ======================
|
||||
@@ -300,25 +300,25 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void startControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, String.format("startControlCenterService执行 | context=%s", context));
|
||||
LogUtils.d(TAG, String.format("startControlCenterService() 执行 | context=%s", context));
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "startControlCenterService:Context为空,启动失败");
|
||||
LogUtils.e(TAG, "startControlCenterService() | Context为空,启动失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存启用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(true);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "startControlCenterService:服务启用配置已保存");
|
||||
LogUtils.d(TAG, "startControlCenterService() | 服务启用配置已保存");
|
||||
|
||||
// 启动服务(区分API版本)
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
if (Build.VERSION.SDK_INT >= API_LEVEL_26) {
|
||||
context.startForegroundService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService:以前台服务方式启动(API26+)");
|
||||
LogUtils.d(TAG, "startControlCenterService() | 以前台服务方式启动(API26+)");
|
||||
} else {
|
||||
context.startService(intent);
|
||||
LogUtils.d(TAG, "startControlCenterService:以普通服务方式启动(API26-)");
|
||||
LogUtils.d(TAG, "startControlCenterService() | 以普通服务方式启动(API26-)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,21 +327,21 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void stopControlCenterService(Context context) {
|
||||
LogUtils.d(TAG, String.format("stopControlCenterService执行 | context=%s", context));
|
||||
LogUtils.d(TAG, String.format("stopControlCenterService() 执行 | context=%s", context));
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "stopControlCenterService:Context为空,停止失败");
|
||||
LogUtils.e(TAG, "stopControlCenterService() | Context为空,停止失败");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存停用配置
|
||||
ControlCenterServiceBean controlBean = new ControlCenterServiceBean(false);
|
||||
ControlCenterServiceBean.saveBean(context, controlBean);
|
||||
LogUtils.d(TAG, "stopControlCenterService:服务停用配置已保存");
|
||||
LogUtils.d(TAG, "stopControlCenterService() | 服务停用配置已保存");
|
||||
|
||||
// 停止服务
|
||||
Intent intent = new Intent(context, ControlCenterService.class);
|
||||
context.stopService(intent);
|
||||
LogUtils.d(TAG, "stopControlCenterService:停止指令已发送");
|
||||
LogUtils.d(TAG, "stopControlCenterService() | 停止指令已发送");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,16 +349,16 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void sendAppConfigStatusUpdateMessage(Context context) {
|
||||
LogUtils.d(TAG, String.format("sendAppConfigStatusUpdateMessage执行 | context=%s", context));
|
||||
LogUtils.d(TAG, String.format("sendAppConfigStatusUpdateMessage() 执行 | context=%s", context));
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "sendAppConfigStatusUpdateMessage:参数为空,更新失败");
|
||||
LogUtils.e(TAG, "sendAppConfigStatusUpdateMessage() | 参数为空,更新失败");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED);
|
||||
intent.setPackage(context.getPackageName());
|
||||
context.sendBroadcast(intent);
|
||||
LogUtils.d(TAG, String.format("sendAppConfigStatusUpdateMessage:配置更新广播发送 | action=%s", ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED));
|
||||
LogUtils.d(TAG, String.format("sendAppConfigStatusUpdateMessage() | 配置更新广播发送 | action=%s", ControlCenterServiceReceiver.ACTION_APPCONFIG_CHANGED));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,28 +366,28 @@ public class ControlCenterService extends Service {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void checkIgnoreBatteryOptimization(Context context) {
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization执行 | context=%s", context));
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization() 执行 | context=%s", context));
|
||||
if (context == null || Build.VERSION.SDK_INT < API_LEVEL_23) {
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization:无需检查(Context为空或API<23)");
|
||||
LogUtils.w(TAG, "checkIgnoreBatteryOptimization() | 无需检查(Context为空或API<23)");
|
||||
return;
|
||||
}
|
||||
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
if (powerManager == null) {
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization:PowerManager获取失败");
|
||||
LogUtils.e(TAG, "checkIgnoreBatteryOptimization() | PowerManager获取失败");
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = context.getPackageName();
|
||||
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization:已忽略电池优化=%b", isIgnored));
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization() | 已忽略电池优化=%b", isIgnored));
|
||||
|
||||
if (!isIgnored) {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
context.startActivity(intent);
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization:已跳转至系统设置页 | package=%s", packageName));
|
||||
LogUtils.d(TAG, String.format("checkIgnoreBatteryOptimization() | 已跳转至系统设置页 | package=%s", packageName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,15 +398,15 @@ public class ControlCenterService extends Service {
|
||||
* @return true=运行中 false=未运行
|
||||
*/
|
||||
private static boolean isServiceRunning(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, String.format("isServiceRunning执行 | context=%s | service=%s", context, serviceClass != null ? serviceClass.getName() : "null"));
|
||||
LogUtils.d(TAG, String.format("isServiceRunning() 执行 | context=%s | service=%s", context, serviceClass != null ? serviceClass.getName() : "null"));
|
||||
if (context == null || serviceClass == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning:参数为空");
|
||||
LogUtils.e(TAG, "isServiceRunning() | 参数为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (am == null) {
|
||||
LogUtils.e(TAG, "isServiceRunning:ActivityManager获取失败");
|
||||
LogUtils.e(TAG, "isServiceRunning() | ActivityManager获取失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, String.format("isServiceRunning:API30+ 判断结果=%b", isRunning));
|
||||
LogUtils.d(TAG, String.format("isServiceRunning() | API30+ 判断结果=%b", isRunning));
|
||||
} else {
|
||||
// API30- 通过服务列表判断
|
||||
List<ActivityManager.RunningServiceInfo> services = am.getRunningServices(RUNNING_SERVICE_LIST_LIMIT);
|
||||
@@ -439,13 +439,13 @@ public class ControlCenterService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
LogUtils.d(TAG, String.format("isServiceRunning:API30- 判断结果=%b", isRunning));
|
||||
LogUtils.d(TAG, String.format("isServiceRunning() | API30- 判断结果=%b", isRunning));
|
||||
}
|
||||
|
||||
// 兜底判断:配置启用状态
|
||||
if (!isRunning) {
|
||||
isRunning = isServiceStarted(context, serviceClass);
|
||||
LogUtils.d(TAG, String.format("isServiceRunning:兜底判断结果=%b", isRunning));
|
||||
LogUtils.d(TAG, String.format("isServiceRunning() | 兜底判断结果=%b", isRunning));
|
||||
}
|
||||
return isRunning;
|
||||
}
|
||||
@@ -454,12 +454,12 @@ public class ControlCenterService extends Service {
|
||||
* 兜底判断服务是否已启动(通过配置文件)
|
||||
*/
|
||||
private static boolean isServiceStarted(Context context, Class<?> serviceClass) {
|
||||
LogUtils.d(TAG, "isServiceStarted执行");
|
||||
LogUtils.d(TAG, "isServiceStarted() 执行");
|
||||
try {
|
||||
ControlCenterServiceBean controlBean = ControlCenterServiceBean.loadBean(context, ControlCenterServiceBean.class);
|
||||
return controlBean != null && controlBean.isEnableService();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "isServiceStarted:兜底判断异常", e);
|
||||
LogUtils.e(TAG, "isServiceStarted() | 兜底判断异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -472,13 +472,13 @@ public class ControlCenterService extends Service {
|
||||
public void notifyAppConfigUpdate(AppConfigBean latestConfig) {
|
||||
int chargeThreshold = latestConfig != null ? latestConfig.getChargeReminderValue() : -1;
|
||||
int usageThreshold = latestConfig != null ? latestConfig.getUsageReminderValue() : -1;
|
||||
LogUtils.d(TAG, String.format("notifyAppConfigUpdate执行 | 充电阈值=%d | 耗电阈值=%d", chargeThreshold, usageThreshold));
|
||||
LogUtils.d(TAG, String.format("notifyAppConfigUpdate() 执行 | 充电阈值=%d | 耗电阈值=%d", chargeThreshold, usageThreshold));
|
||||
if (latestConfig != null && mServiceHandler != null) {
|
||||
mCurrentConfigBean = latestConfig;
|
||||
RemindThread.startRemindThreadWithAppConfig(this, mServiceHandler, latestConfig);
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate:配置已同步到提醒线程");
|
||||
LogUtils.d(TAG, "notifyAppConfigUpdate() | 配置已同步到提醒线程");
|
||||
} else {
|
||||
LogUtils.e(TAG, String.format("notifyAppConfigUpdate:参数为空,同步失败 | latestConfig=%s | mServiceHandler=%s", latestConfig, mServiceHandler));
|
||||
LogUtils.e(TAG, String.format("notifyAppConfigUpdate() | 参数为空,同步失败 | latestConfig=%s | mServiceHandler=%s", latestConfig, mServiceHandler));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,16 +55,15 @@ public class RemindThread extends Thread {
|
||||
private volatile long sleepTime;
|
||||
private volatile int chargeReminderValue;
|
||||
private volatile int usageReminderValue;
|
||||
private volatile int quantityOfElectricity;
|
||||
private volatile boolean isCharging;
|
||||
|
||||
// ====================== 私有构造器(禁止外部实例化) ======================
|
||||
private RemindThread(Context context, ControlCenterServiceHandler handler) {
|
||||
LogUtils.d(TAG, String.format("构造器调用 | context=%s | handler=%s", context, handler));
|
||||
LogUtils.d(TAG, String.format("RemindThread() 构造器调用 | context=%s | handler=%s", context, handler));
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mwrControlCenterServiceHandler = new WeakReference<>(handler);
|
||||
resetThreadStateInternal();
|
||||
LogUtils.d(TAG, String.format("构造完成 | threadId=%d | 初始状态重置成功", getId()));
|
||||
LogUtils.d(TAG, String.format("RemindThread() 构造完成 | threadId=%d | 初始状态重置成功", getId()));
|
||||
}
|
||||
|
||||
// ====================== 对外公开静态接口(多实例列表管理) ======================
|
||||
@@ -77,7 +76,7 @@ public class RemindThread extends Thread {
|
||||
* @return true: 启动成功;false: 入参非法
|
||||
*/
|
||||
public static boolean startRemindThreadWithAppConfig(Context context, ControlCenterServiceHandler handler, AppConfigBean config) {
|
||||
LogUtils.d(TAG, String.format("startRemindThreadWithAppConfig调用 | context=%s | handler=%s | config=%s", context, handler, config));
|
||||
LogUtils.d(TAG, String.format("startRemindThreadWithAppConfig() 调用 | context=%s | handler=%s | config=%s", context, handler, config));
|
||||
|
||||
// 入参严格校验
|
||||
if (context == null || handler == null || config == null) {
|
||||
@@ -108,55 +107,12 @@ public class RemindThread extends Thread {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动提醒线程,同步电池状态信息
|
||||
* 逻辑:停止所有旧线程 → 创建新线程 → 同步电池状态 → 加入列表管理
|
||||
* @param context 上下文(非空)
|
||||
* @param handler 服务处理器(非空)
|
||||
* @param isCharging 充电状态
|
||||
* @param batteryLevel 当前电量
|
||||
* @return true: 启动成功;false: 入参非法
|
||||
*/
|
||||
public static boolean startRemindThreadWithBatteryInfo(Context context, ControlCenterServiceHandler handler, boolean isCharging, int batteryLevel) {
|
||||
LogUtils.d(TAG, String.format("startRemindThreadWithBatteryInfo调用 | context=%s | handler=%s | isCharging=%b | batteryLevel=%d", context, handler, isCharging, batteryLevel));
|
||||
|
||||
// 入参严格校验
|
||||
if (context == null || handler == null) {
|
||||
LogUtils.e(TAG, String.format("启动失败:入参为空 | context=%s | handler=%s", context, handler));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 初始化线程列表(双重校验锁)
|
||||
if (sRemindThreadList == null) {
|
||||
synchronized (RemindThread.class) {
|
||||
if (sRemindThreadList == null) {
|
||||
sRemindThreadList = new ArrayList<RemindThread>();
|
||||
LogUtils.d(TAG, "线程列表初始化完成");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 停止所有旧线程
|
||||
stopAllOldThreadsInternal();
|
||||
|
||||
// 创建并启动新线程
|
||||
RemindThread newRemindThread = new RemindThread(context, handler);
|
||||
// 同步电池状态(范围校验)
|
||||
newRemindThread.isCharging = isCharging;
|
||||
newRemindThread.quantityOfElectricity = Math.min(Math.max(batteryLevel, BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
newRemindThread.isExist = false;
|
||||
newRemindThread.start();
|
||||
sRemindThreadList.add(newRemindThread);
|
||||
LogUtils.d(TAG, String.format("新线程启动成功 | threadId=%d | 电池状态同步完成(电量=%d,充电=%b)", newRemindThread.getId(), newRemindThread.quantityOfElectricity, newRemindThread.isCharging));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全停止所有线程,清空列表
|
||||
*/
|
||||
public static void stopRemindThread() {
|
||||
int listSize = sRemindThreadList != null ? sRemindThreadList.size() : 0;
|
||||
LogUtils.d(TAG, String.format("stopRemindThread调用 | 列表存在=%b | 列表大小=%d", sRemindThreadList != null, listSize));
|
||||
LogUtils.d(TAG, String.format("stopRemindThread() 调用 | 列表存在=%b | 列表大小=%d", sRemindThreadList != null, listSize));
|
||||
if (sRemindThreadList == null || sRemindThreadList.isEmpty()) {
|
||||
LogUtils.w(TAG, "停止失败:线程列表为空");
|
||||
return;
|
||||
@@ -194,7 +150,7 @@ public class RemindThread extends Thread {
|
||||
// ====================== 线程核心运行逻辑 ======================
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, String.format("run执行 | threadId=%d | 状态=%s", getId(), getState()));
|
||||
LogUtils.d(TAG, String.format("run() 执行 | threadId=%d | 状态=%s", getId(), getState()));
|
||||
|
||||
// 初始化提醒状态(加锁保护,避免多线程竞争)
|
||||
synchronized (mRemindLock) {
|
||||
@@ -213,21 +169,21 @@ public class RemindThread extends Thread {
|
||||
if (isExist) break;
|
||||
|
||||
// 电量有效性校验(非0-100视为无效),退出电量提醒线程
|
||||
if (quantityOfElectricity < BATTERY_LEVEL_MIN || quantityOfElectricity > BATTERY_LEVEL_MAX) {
|
||||
LogUtils.w(TAG, String.format("电量无效,退出电量提醒线程 | 当前电量=%d | threadId=%d", quantityOfElectricity, 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 && quantityOfElectricity >= chargeReminderValue;
|
||||
boolean usageRemindTrigger = !isCharging && isEnableUsageReminder && quantityOfElectricity <= 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", quantityOfElectricity, chargeReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_CHARGE, quantityOfElectricity, 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", quantityOfElectricity, usageReminderValue, getId()));
|
||||
sendNotificationMessageInternal(REMIND_TYPE_USAGE, quantityOfElectricity, 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;
|
||||
@@ -237,14 +193,14 @@ public class RemindThread extends Thread {
|
||||
safeSleepInternal(sleepTime);
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, String.format("循环运行异常,退出电量提醒线程 | 当前电量=%d | threadId=%d", quantityOfElectricity, getId()), e);
|
||||
LogUtils.e(TAG, String.format("循环运行异常,退出电量提醒线程 | 当前电量=%d | threadId=%d", App.sQuantityOfElectricity, getId()), e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 循环退出,清理状态
|
||||
cleanThreadStateInternal();
|
||||
LogUtils.d(TAG, String.format("run结束 | threadId=%d", getId()));
|
||||
LogUtils.d(TAG, String.format("run() 结束 | threadId=%d", getId()));
|
||||
}
|
||||
|
||||
// ====================== 内部业务辅助方法 ======================
|
||||
@@ -255,7 +211,7 @@ public class RemindThread extends Thread {
|
||||
* @param isCharging 充电状态
|
||||
*/
|
||||
private void sendNotificationMessageInternal(String type, int battery, boolean isCharging) {
|
||||
LogUtils.d(TAG, String.format("sendNotificationMessageInternal调用 | 类型=%s | 电量=%d | isCharging=%b | threadId=%d", type, battery, isCharging, getId()));
|
||||
LogUtils.d(TAG, String.format("sendNotificationMessageInternal() 调用 | 类型=%s | 电量=%d | isCharging=%b | threadId=%d", type, battery, isCharging, getId()));
|
||||
// 前置状态校验
|
||||
if (isExist || !isReminding) {
|
||||
LogUtils.d(TAG, String.format("消息发送跳过:线程已退出或提醒关闭 | threadId=%d", getId()));
|
||||
@@ -292,7 +248,7 @@ public class RemindThread extends Thread {
|
||||
* @param millis 休眠时长(ms)
|
||||
*/
|
||||
private void safeSleepInternal(long millis) {
|
||||
LogUtils.d(TAG, String.format("safeSleepInternal调用 | 休眠时长=%dms | threadId=%d", millis, getId()));
|
||||
LogUtils.d(TAG, String.format("safeSleepInternal() 调用 | 休眠时长=%dms | threadId=%d", millis, getId()));
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
@@ -305,7 +261,7 @@ public class RemindThread extends Thread {
|
||||
* 重置线程初始状态(构造器专用)
|
||||
*/
|
||||
private void resetThreadStateInternal() {
|
||||
LogUtils.d(TAG, String.format("resetThreadStateInternal调用 | threadId=%d", getId()));
|
||||
LogUtils.d(TAG, String.format("resetThreadStateInternal() 调用 | threadId=%d", getId()));
|
||||
// 状态标记初始化
|
||||
isExist = false;
|
||||
isReminding = false;
|
||||
@@ -315,7 +271,6 @@ public class RemindThread extends Thread {
|
||||
sleepTime = MIN_SLEEP_TIME;
|
||||
chargeReminderValue = -1;
|
||||
usageReminderValue = -1;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
isCharging = false;
|
||||
LogUtils.d(TAG, String.format("线程初始状态重置完成 | threadId=%d", getId()));
|
||||
}
|
||||
@@ -324,10 +279,9 @@ public class RemindThread extends Thread {
|
||||
* 清理线程运行状态(循环退出时调用)
|
||||
*/
|
||||
private void cleanThreadStateInternal() {
|
||||
LogUtils.d(TAG, String.format("cleanThreadStateInternal调用 | threadId=%d", getId()));
|
||||
LogUtils.d(TAG, String.format("cleanThreadStateInternal() 调用 | threadId=%d", getId()));
|
||||
isReminding = false;
|
||||
isExist = true;
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
// 中断当前线程(如果存活)
|
||||
if (isAlive()) {
|
||||
interrupt();
|
||||
@@ -341,10 +295,9 @@ public class RemindThread extends Thread {
|
||||
* @param config 应用配置Bean
|
||||
*/
|
||||
public void setAppConfigBean(AppConfigBean config) {
|
||||
LogUtils.d(TAG, String.format("setAppConfigBean调用 | config=%s | threadId=%d", config, getId()));
|
||||
LogUtils.d(TAG, String.format("setAppConfigBean() 调用 | config=%s | threadId=%d", config, getId()));
|
||||
if (config == null) {
|
||||
LogUtils.e(TAG, String.format("配置同步失败:配置Bean为空 | threadId=%d", getId()));
|
||||
quantityOfElectricity = INVALID_BATTERY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -354,12 +307,12 @@ public class RemindThread extends Thread {
|
||||
chargeReminderValue = Math.min(Math.max(config.getChargeReminderValue(), BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
usageReminderValue = Math.min(Math.max(config.getUsageReminderValue(), BATTERY_LEVEL_MIN), BATTERY_LEVEL_MAX);
|
||||
sleepTime = Math.max(config.getBatteryDetectInterval(), MIN_SLEEP_TIME);
|
||||
quantityOfElectricity = (config.getCurrentBatteryValue() >= BATTERY_LEVEL_MIN && config.getCurrentBatteryValue() <= BATTERY_LEVEL_MAX)
|
||||
? config.getCurrentBatteryValue() : INVALID_BATTERY_VALUE;
|
||||
// sQuantityOfElectricity = (config.getCurrentBatteryValue() >= BATTERY_LEVEL_MIN && config.getCurrentBatteryValue() <= BATTERY_LEVEL_MAX)
|
||||
// ? config.getCurrentBatteryValue() : INVALID_BATTERY_VALUE;
|
||||
isCharging = config.isCharging();
|
||||
|
||||
LogUtils.d(TAG, String.format("配置同步完成 | 休眠时间=%dms | 充电提醒=%b | 耗电提醒=%b | 当前电量=%d | 充电阈值=%d | 耗电阈值=%d | threadId=%d",
|
||||
sleepTime, isEnableChargeReminder, isEnableUsageReminder, quantityOfElectricity, chargeReminderValue, usageReminderValue, getId()));
|
||||
sleepTime, isEnableChargeReminder, isEnableUsageReminder, App.sQuantityOfElectricity, chargeReminderValue, usageReminderValue, getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,13 +321,13 @@ public class RemindThread extends Thread {
|
||||
*/
|
||||
private boolean isRunning() {
|
||||
boolean running = !isExist && isAlive();
|
||||
LogUtils.d(TAG, String.format("isRunning调用 | 运行中=%b | 退出标记=%b | 存活=%b | threadId=%d", running, isExist, isAlive(), getId()));
|
||||
LogUtils.d(TAG, String.format("isRunning() 调用 | 运行中=%b | 退出标记=%b | 存活=%b | threadId=%d", running, isExist, isAlive(), getId()));
|
||||
return running;
|
||||
}
|
||||
|
||||
// ====================== Getter/Setter(按需开放) ======================
|
||||
public void setIsExist(boolean isExist) {
|
||||
LogUtils.d(TAG, String.format("setIsExist调用 | isExist=%b | threadId=%d", isExist, getId()));
|
||||
LogUtils.d(TAG, String.format("setIsExist() 调用 | isExist=%b | threadId=%d", isExist, getId()));
|
||||
this.isExist = isExist;
|
||||
}
|
||||
|
||||
@@ -386,16 +339,16 @@ public class RemindThread extends Thread {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RemindThread{" +
|
||||
"threadId=" + getId() +
|
||||
", threadName='" + getName() + '\'' +
|
||||
", isRunning=" + isRunning() +
|
||||
", isReminding=" + isReminding +
|
||||
", chargeThreshold=" + chargeReminderValue +
|
||||
", usageThreshold=" + usageReminderValue +
|
||||
", currentBattery=" + quantityOfElectricity +
|
||||
", isCharging=" + isCharging +
|
||||
", sleepTime=" + sleepTime + "ms" +
|
||||
'}';
|
||||
"threadId=" + getId() +
|
||||
", threadName='" + getName() + '\'' +
|
||||
", isRunning=" + isRunning() +
|
||||
", isReminding=" + isReminding +
|
||||
", chargeThreshold=" + chargeReminderValue +
|
||||
", usageThreshold=" + usageReminderValue +
|
||||
", currentBattery=" + App.sQuantityOfElectricity +
|
||||
", isCharging=" + isCharging +
|
||||
", sleepTime=" + sleepTime + "ms" +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.powerbell.MainActivity;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.utils.FileUtils;
|
||||
import cc.winboll.studio.powerbell.utils.ImageCropUtils;
|
||||
import cc.winboll.studio.powerbell.utils.ImageUtils;
|
||||
@@ -104,7 +105,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
|
||||
mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview);
|
||||
|
||||
// 创建MemoryCachedBackgroundView单例并添加到布局
|
||||
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, "", false);
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
|
||||
mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getLastInstance(this);
|
||||
mllBackgroundView.addView(mMemoryCachedBackgroundView);
|
||||
LogUtils.d(TAG, "initViewAndEvent:内存缓存背景视图实例创建并添加完成");
|
||||
|
||||
@@ -217,7 +219,8 @@ public class MainUnitTest2Activity extends AppCompatActivity {
|
||||
LogUtils.d(TAG, String.format("handleCropResult:裁剪回调处理 | resultCode=%d", resultCode));
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (isFileValid(mPrivateCropImageFile)) {
|
||||
mMemoryCachedBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
|
||||
int nCurrentPixelColor = BackgroundSourceUtils.getInstance(this).getCurrentBackgroundBean().getPixelColor();
|
||||
mMemoryCachedBackgroundView.loadImage(nCurrentPixelColor, mPrivateCropImageFile.getAbsolutePath(), true);
|
||||
LogUtils.d(TAG, String.format("handleCropResult:裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath()));
|
||||
ToastUtils.show("裁剪成功");
|
||||
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
|
||||
|
||||
@@ -207,25 +207,25 @@ public class MainUnitTestActivity extends AppCompatActivity {
|
||||
* @param resultCode 裁剪结果码
|
||||
*/
|
||||
private void handleCropResult(int resultCode) {
|
||||
LogUtils.d(TAG, String.format("handleCropResult:裁剪回调处理 | resultCode=%d", resultCode));
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (isFileValid(mPrivateCropImageFile)) {
|
||||
mBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
|
||||
LogUtils.d(TAG, String.format("handleCropResult:裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath()));
|
||||
ToastUtils.show("裁剪成功");
|
||||
mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
|
||||
doubleRefreshPreview();
|
||||
} else {
|
||||
LogUtils.e(TAG, "handleCropResult:裁剪成功但输出文件无效");
|
||||
ToastUtils.show("裁剪失败:输出文件无效");
|
||||
}
|
||||
} else if (resultCode == RESULT_CANCELED) {
|
||||
LogUtils.d(TAG, "handleCropResult:裁剪取消");
|
||||
ToastUtils.show("裁剪已取消");
|
||||
} else {
|
||||
LogUtils.e(TAG, String.format("handleCropResult:裁剪失败 | resultCode异常=%d", resultCode));
|
||||
ToastUtils.show("裁剪失败");
|
||||
}
|
||||
// LogUtils.d(TAG, String.format("handleCropResult:裁剪回调处理 | resultCode=%d", resultCode));
|
||||
// if (resultCode == RESULT_OK) {
|
||||
// if (isFileValid(mPrivateCropImageFile)) {
|
||||
// mBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
|
||||
// LogUtils.d(TAG, String.format("handleCropResult:裁剪成功 | 加载裁剪图=%s", mPrivateCropImageFile.getAbsolutePath()));
|
||||
// ToastUtils.show("裁剪成功");
|
||||
// mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
|
||||
// doubleRefreshPreview();
|
||||
// } else {
|
||||
// LogUtils.e(TAG, "handleCropResult:裁剪成功但输出文件无效");
|
||||
// ToastUtils.show("裁剪失败:输出文件无效");
|
||||
// }
|
||||
// } else if (resultCode == RESULT_CANCELED) {
|
||||
// LogUtils.d(TAG, "handleCropResult:裁剪取消");
|
||||
// ToastUtils.show("裁剪已取消");
|
||||
// } else {
|
||||
// LogUtils.e(TAG, String.format("handleCropResult:裁剪失败 | resultCode异常=%d", resultCode));
|
||||
// ToastUtils.show("裁剪失败");
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ 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.ControlCenterServiceBean;
|
||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||
|
||||
/**
|
||||
* 应用配置工具类:管理应用核心配置(服务开关、电池提醒阈值、背景设置等)
|
||||
@@ -38,10 +39,10 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public static AppConfigUtils getInstance(Context context) {
|
||||
String contextType = context != null ? context.getClass().getSimpleName() : "null";
|
||||
LogUtils.d(TAG, String.format("getInstance调用 | 传入Context类型=%s", contextType));
|
||||
LogUtils.d(TAG, String.format("getInstance() 调用 | 传入Context类型=%s", contextType));
|
||||
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "getInstance失败:Context不能为空");
|
||||
LogUtils.e(TAG, "getInstance() 失败:Context不能为空");
|
||||
throw new IllegalArgumentException("Context cannot be null");
|
||||
}
|
||||
|
||||
@@ -49,12 +50,12 @@ public class AppConfigUtils {
|
||||
synchronized (AppConfigUtils.class) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new AppConfigUtils(context);
|
||||
LogUtils.d(TAG, "getInstance:单例实例创建成功");
|
||||
LogUtils.d(TAG, "getInstance():单例实例创建成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "getInstance:单例实例获取成功");
|
||||
LogUtils.d(TAG, "getInstance():单例实例获取成功");
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
@@ -63,12 +64,12 @@ public class AppConfigUtils {
|
||||
* @param context 上下文(内部转换为ApplicationContext)
|
||||
*/
|
||||
private AppConfigUtils(Context context) {
|
||||
LogUtils.d(TAG, "AppConfigUtils构造方法调用");
|
||||
LogUtils.d(TAG, "AppConfigUtils() 构造方法调用");
|
||||
this.mContext = context.getApplicationContext();
|
||||
this.mApplication = (App) context.getApplicationContext();
|
||||
mAppConfigBean = new AppConfigBean();
|
||||
loadAppConfig(); // 加载持久化配置
|
||||
LogUtils.d(TAG, "AppConfigUtils构造完成,配置初始化成功");
|
||||
LogUtils.d(TAG, "AppConfigUtils() 构造完成,配置初始化成功");
|
||||
}
|
||||
|
||||
// ======================== 核心配置持久化方法区(加载+保存)========================
|
||||
@@ -77,17 +78,17 @@ public class AppConfigUtils {
|
||||
* @return 加载后的应用配置Bean
|
||||
*/
|
||||
public AppConfigBean loadAppConfig() {
|
||||
LogUtils.d(TAG, "loadAppConfig调用:开始加载应用配置");
|
||||
LogUtils.d(TAG, "loadAppConfig() 调用 | 开始加载应用配置");
|
||||
AppConfigBean savedAppBean = (AppConfigBean) AppConfigBean.loadBean(mContext, AppConfigBean.class);
|
||||
|
||||
if (savedAppBean != null) {
|
||||
mAppConfigBean = savedAppBean;
|
||||
LogUtils.d(TAG, String.format("loadAppConfig成功 | 充电阈值=%d%% | 耗电阈值=%d%%",
|
||||
mAppConfigBean.getChargeReminderValue(), mAppConfigBean.getUsageReminderValue()));
|
||||
LogUtils.d(TAG, String.format("loadAppConfig() 成功 | 充电阈值=%d%% | 耗电阈值=%d%%",
|
||||
mAppConfigBean.getChargeReminderValue(), mAppConfigBean.getUsageReminderValue()));
|
||||
} else {
|
||||
mAppConfigBean = new AppConfigBean();
|
||||
AppConfigBean.saveBean(mContext, mAppConfigBean);
|
||||
LogUtils.d(TAG, "loadAppConfig:无已保存配置,使用默认值并持久化");
|
||||
LogUtils.d(TAG, "loadAppConfig():无已保存配置,使用默认值并持久化");
|
||||
}
|
||||
|
||||
return mAppConfigBean;
|
||||
@@ -96,9 +97,9 @@ public class AppConfigUtils {
|
||||
/**
|
||||
* 保存应用配置(内部核心方法,直接持久化)
|
||||
*/
|
||||
private void saveAppConfig() {
|
||||
public void saveAppConfig() {
|
||||
AppConfigBean.saveBean(mContext, mAppConfigBean);
|
||||
LogUtils.d(TAG, "saveAppConfig:应用配置保存成功");
|
||||
LogUtils.d(TAG, "saveAppConfig():应用配置保存成功");
|
||||
}
|
||||
|
||||
// ======================== 充电提醒配置方法区(开关+阈值)========================
|
||||
@@ -107,16 +108,16 @@ public class AppConfigUtils {
|
||||
* @param isEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setChargeReminderEnabled(final boolean isEnabled) {
|
||||
LogUtils.d(TAG, String.format("setChargeReminderEnabled调用 | 传入状态=%b", isEnabled));
|
||||
LogUtils.d(TAG, String.format("setChargeReminderEnabled() 调用 | 传入状态=%b", isEnabled));
|
||||
|
||||
if (isEnabled == mAppConfigBean.isEnableChargeReminder()) {
|
||||
LogUtils.d(TAG, "setChargeReminderEnabled:充电提醒状态无变化,无需操作");
|
||||
LogUtils.d(TAG, "setChargeReminderEnabled():充电提醒状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setEnableChargeReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setChargeReminderEnabled成功 | 充电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
LogUtils.d(TAG, String.format("setChargeReminderEnabled() 成功 | 充电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +126,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public boolean isChargeReminderEnabled() {
|
||||
boolean isEnabled = mAppConfigBean.isEnableChargeReminder();
|
||||
LogUtils.d(TAG, String.format("isChargeReminderEnabled:获取充电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
LogUtils.d(TAG, String.format("isChargeReminderEnabled():获取充电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
@@ -134,17 +135,17 @@ public class AppConfigUtils {
|
||||
* @param value 目标阈值
|
||||
*/
|
||||
public void setChargeReminderValue(final int value) {
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue调用 | 传入阈值=%d", value));
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue() 调用 | 传入阈值=%d", value));
|
||||
final int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
|
||||
if (calibratedValue == mAppConfigBean.getChargeReminderValue()) {
|
||||
LogUtils.d(TAG, "setChargeReminderValue:充电提醒阈值无变化,无需操作");
|
||||
LogUtils.d(TAG, "setChargeReminderValue():充电提醒阈值无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setChargeReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue成功 | 充电提醒阈值=%d%%", calibratedValue));
|
||||
LogUtils.d(TAG, String.format("setChargeReminderValue() 成功 | 充电提醒阈值=%d%%", calibratedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +154,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public int getChargeReminderValue() {
|
||||
int value = mAppConfigBean.getChargeReminderValue();
|
||||
LogUtils.d(TAG, String.format("getChargeReminderValue:获取充电提醒阈值=%d%%", value));
|
||||
LogUtils.d(TAG, String.format("getChargeReminderValue():获取充电提醒阈值=%d%%", value));
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -163,16 +164,16 @@ public class AppConfigUtils {
|
||||
* @param isEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setUsageReminderEnabled(final boolean isEnabled) {
|
||||
LogUtils.d(TAG, String.format("setUsageReminderEnabled调用 | 传入状态=%b", isEnabled));
|
||||
LogUtils.d(TAG, String.format("setUsageReminderEnabled() 调用 | 传入状态=%b", isEnabled));
|
||||
|
||||
if (isEnabled == mAppConfigBean.isEnableUsageReminder()) {
|
||||
LogUtils.d(TAG, "setUsageReminderEnabled:耗电提醒状态无变化,无需操作");
|
||||
LogUtils.d(TAG, "setUsageReminderEnabled():耗电提醒状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setEnableUsageReminder(isEnabled);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setUsageReminderEnabled成功 | 耗电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
LogUtils.d(TAG, String.format("setUsageReminderEnabled() 成功 | 耗电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +182,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public boolean isUsageReminderEnabled() {
|
||||
boolean isEnabled = mAppConfigBean.isEnableUsageReminder();
|
||||
LogUtils.d(TAG, String.format("isUsageReminderEnabled:获取耗电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
LogUtils.d(TAG, String.format("isUsageReminderEnabled():获取耗电提醒状态=%s", isEnabled ? "开启" : "关闭"));
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
@@ -190,17 +191,17 @@ public class AppConfigUtils {
|
||||
* @param value 目标阈值
|
||||
*/
|
||||
public void setUsageReminderValue(final int value) {
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue调用 | 传入阈值=%d", value));
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue() 调用 | 传入阈值=%d", value));
|
||||
final int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
|
||||
if (calibratedValue == mAppConfigBean.getUsageReminderValue()) {
|
||||
LogUtils.d(TAG, "setUsageReminderValue:耗电提醒阈值无变化,无需操作");
|
||||
LogUtils.d(TAG, "setUsageReminderValue():耗电提醒阈值无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setUsageReminderValue(calibratedValue);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue成功 | 耗电提醒阈值=%d%%", calibratedValue));
|
||||
LogUtils.d(TAG, String.format("setUsageReminderValue() 成功 | 耗电提醒阈值=%d%%", calibratedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +210,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public int getUsageReminderValue() {
|
||||
int value = mAppConfigBean.getUsageReminderValue();
|
||||
LogUtils.d(TAG, String.format("getUsageReminderValue:获取耗电提醒阈值=%d%%", value));
|
||||
LogUtils.d(TAG, String.format("getUsageReminderValue():获取耗电提醒阈值=%d%%", value));
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -219,15 +220,15 @@ public class AppConfigUtils {
|
||||
* @param isCharging 充电状态(true=充电中,false=未充电)
|
||||
*/
|
||||
public void setCharging(boolean isCharging) {
|
||||
LogUtils.d(TAG, String.format("setCharging调用 | 传入状态=%b", isCharging));
|
||||
LogUtils.d(TAG, String.format("setCharging() 调用 | 传入状态=%b", isCharging));
|
||||
|
||||
if (isCharging == mAppConfigBean.isCharging()) {
|
||||
LogUtils.d(TAG, "setCharging:充电状态无变化,无需操作");
|
||||
LogUtils.d(TAG, "setCharging():充电状态无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setIsCharging(isCharging);
|
||||
LogUtils.d(TAG, String.format("setCharging成功 | 充电状态=%s", isCharging ? "充电中" : "未充电"));
|
||||
LogUtils.d(TAG, String.format("setCharging() 成功 | 充电状态=%s", isCharging ? "充电中" : "未充电"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,7 +237,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public boolean isCharging() {
|
||||
boolean isCharging = mAppConfigBean.isCharging();
|
||||
LogUtils.d(TAG, String.format("isCharging:获取充电状态=%s", isCharging ? "充电中" : "未充电"));
|
||||
LogUtils.d(TAG, String.format("isCharging():获取充电状态=%s", isCharging ? "充电中" : "未充电"));
|
||||
return isCharging;
|
||||
}
|
||||
|
||||
@@ -245,16 +246,16 @@ public class AppConfigUtils {
|
||||
* @param value 当前电量
|
||||
*/
|
||||
public void setCurrentBatteryValue(int value) {
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue调用 | 传入电量=%d", value));
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue() 调用 | 传入电量=%d", value));
|
||||
int calibratedValue = Math.min(Math.max(value, MIN_REMINDER_VALUE), MAX_REMINDER_VALUE);
|
||||
|
||||
if (calibratedValue == mAppConfigBean.getCurrentBatteryValue()) {
|
||||
LogUtils.d(TAG, "setCurrentBatteryValue:电池电量无变化,无需操作");
|
||||
if (calibratedValue == App.sQuantityOfElectricity) {
|
||||
LogUtils.d(TAG, "setCurrentBatteryValue():电池电量无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setCurrentBatteryValue(calibratedValue);
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue成功 | 电池电量=%d%%", calibratedValue));
|
||||
App.sQuantityOfElectricity = calibratedValue;
|
||||
LogUtils.d(TAG, String.format("setCurrentBatteryValue() 成功 | 电池电量=%d%%", calibratedValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,8 +263,8 @@ public class AppConfigUtils {
|
||||
* @return 当前电池电量(0-100)
|
||||
*/
|
||||
public int getCurrentBatteryValue() {
|
||||
int value = mAppConfigBean.getCurrentBatteryValue();
|
||||
LogUtils.d(TAG, String.format("getCurrentBatteryValue:获取电池电量=%d%%", value));
|
||||
int value = App.sQuantityOfElectricity;
|
||||
LogUtils.d(TAG, String.format("getCurrentBatteryValue():获取电池电量=%d%%", value));
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -273,17 +274,17 @@ public class AppConfigUtils {
|
||||
* @param interval 目标间隔(单位:ms)
|
||||
*/
|
||||
public void setReminderIntervalTime(final int interval) {
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime调用 | 传入间隔=%dms", interval));
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime() 调用 | 传入间隔=%dms", interval));
|
||||
final int calibratedInterval = Math.max(interval, MIN_INTERVAL_TIME);
|
||||
|
||||
if (calibratedInterval == mAppConfigBean.getReminderIntervalTime()) {
|
||||
LogUtils.d(TAG, "setReminderIntervalTime:提醒间隔无变化,无需操作");
|
||||
LogUtils.d(TAG, "setReminderIntervalTime():提醒间隔无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setReminderIntervalTime(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime成功 | 提醒间隔=%dms", calibratedInterval));
|
||||
LogUtils.d(TAG, String.format("setReminderIntervalTime() 成功 | 提醒间隔=%dms", calibratedInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +293,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public int getReminderIntervalTime() {
|
||||
int interval = mAppConfigBean.getReminderIntervalTime();
|
||||
LogUtils.d(TAG, String.format("getReminderIntervalTime:获取提醒间隔=%dms", interval));
|
||||
LogUtils.d(TAG, String.format("getReminderIntervalTime():获取提醒间隔=%dms", interval));
|
||||
return interval;
|
||||
}
|
||||
|
||||
@@ -301,17 +302,17 @@ public class AppConfigUtils {
|
||||
* @param interval 目标间隔(单位:ms)
|
||||
*/
|
||||
public void setBatteryDetectInterval(final int interval) {
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval调用 | 传入间隔=%dms", interval));
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval() 调用 | 传入间隔=%dms", interval));
|
||||
final int calibratedInterval = Math.max(interval, MIN_DETECT_INTERVAL);
|
||||
|
||||
if (calibratedInterval == mAppConfigBean.getBatteryDetectInterval()) {
|
||||
LogUtils.d(TAG, "setBatteryDetectInterval:检测间隔无变化,无需操作");
|
||||
LogUtils.d(TAG, "setBatteryDetectInterval():检测间隔无变化,无需操作");
|
||||
return;
|
||||
}
|
||||
|
||||
mAppConfigBean.setBatteryDetectInterval(calibratedInterval);
|
||||
saveAppConfig();
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval成功 | 电量检测间隔=%dms", calibratedInterval));
|
||||
LogUtils.d(TAG, String.format("setBatteryDetectInterval() 成功 | 电量检测间隔=%dms", calibratedInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +321,7 @@ public class AppConfigUtils {
|
||||
*/
|
||||
public int getBatteryDetectInterval() {
|
||||
int interval = mAppConfigBean.getBatteryDetectInterval();
|
||||
LogUtils.d(TAG, String.format("getBatteryDetectInterval:获取电量检测间隔=%dms", interval));
|
||||
LogUtils.d(TAG, String.format("getBatteryDetectInterval():获取电量检测间隔=%dms", interval));
|
||||
return interval;
|
||||
}
|
||||
|
||||
@@ -330,16 +331,16 @@ public class AppConfigUtils {
|
||||
* @return 服务开关状态(true=开启,false=关闭)
|
||||
*/
|
||||
public boolean isServiceEnabled() {
|
||||
LogUtils.d(TAG, "isServiceEnabled调用:开始获取服务开关状态");
|
||||
LogUtils.d(TAG, "isServiceEnabled() 调用 | 开始获取服务开关状态");
|
||||
ControlCenterServiceBean savedServiceBean = (ControlCenterServiceBean) ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
|
||||
|
||||
if (savedServiceBean != null) {
|
||||
boolean isEnabled = savedServiceBean.isEnableService();
|
||||
LogUtils.d(TAG, String.format("isServiceEnabled:服务开关状态=%b", isEnabled));
|
||||
LogUtils.d(TAG, String.format("isServiceEnabled():服务开关状态=%b", isEnabled));
|
||||
return isEnabled;
|
||||
} else {
|
||||
ControlCenterServiceBean.saveBean(mContext, new ControlCenterServiceBean(false));
|
||||
LogUtils.d(TAG, "isServiceEnabled:无已保存服务配置,默认关闭并持久化");
|
||||
LogUtils.d(TAG, "isServiceEnabled():无已保存服务配置,默认关闭并持久化");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -349,9 +350,9 @@ public class AppConfigUtils {
|
||||
* @param isServiceEnabled 目标状态(true=开启,false=关闭)
|
||||
*/
|
||||
public void setIsServiceEnabled(boolean isServiceEnabled) {
|
||||
LogUtils.d(TAG, String.format("setIsServiceEnabled调用 | 传入状态=%b", isServiceEnabled));
|
||||
LogUtils.d(TAG, String.format("setIsServiceEnabled() 调用 | 传入状态=%b", isServiceEnabled));
|
||||
ControlCenterServiceBean.saveBean(mContext, new ControlCenterServiceBean(isServiceEnabled));
|
||||
LogUtils.d(TAG, String.format("setIsServiceEnabled成功 | 服务开关状态=%b", isServiceEnabled));
|
||||
LogUtils.d(TAG, String.format("setIsServiceEnabled() 成功 | 服务开关状态=%b", isServiceEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ public class BitmapCacheUtils {
|
||||
*/
|
||||
private BitmapCacheUtils() {
|
||||
LogUtils.d(TAG, "【BitmapCacheUtils】单例构造开始");
|
||||
//App.notifyMessage(TAG, "【BitmapCacheUtils】单例构造开始");
|
||||
// 使用 ConcurrentHashMap 保证线程安全,避免手动同步
|
||||
mHardCacheMap = new ConcurrentHashMap<>();
|
||||
mRefCountMap = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -4,7 +4,10 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.R;
|
||||
import java.io.File;
|
||||
@@ -15,44 +18,51 @@ import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 图片处理工具类(质量压缩专用)
|
||||
* 功能:对图片进行JPEG质量压缩,并将压缩结果覆盖源文件;获取主题colorPrimary颜色值
|
||||
* 功能:1. 图片JPEG质量压缩(覆盖源文件);2. 获取主题colorAccent颜色;3. 位图纯色背景合成
|
||||
* 适配:Java 7 + Android API 30
|
||||
* 核心逻辑:Bitmap.compress 质量压缩 + FileChannel 高效文件复制;主题属性解析
|
||||
* 核心逻辑:
|
||||
* - 压缩:Bitmap.compress + FileChannel 高效文件复制
|
||||
* - 主题颜色:TypedArray 解析主题属性
|
||||
* - 位图合成:Canvas 绘制(支持透明通道)
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
||||
// ================================== 静态常量区(置顶归类,消除魔法值)=================================
|
||||
public static final String TAG = ImageUtils.class.getSimpleName();
|
||||
public static final String TAG = "ImageUtils";
|
||||
private static final Bitmap.CompressFormat COMPRESS_FORMAT = Bitmap.CompressFormat.JPEG;
|
||||
private static final int MIN_COMPRESS_QUALITY = 0;
|
||||
private static final int MAX_COMPRESS_QUALITY = 100;
|
||||
private static final int[] COLOR_ACCENT_ATTR = new int[]{R.attr.colorAccent}; // colorPrimary属性数组
|
||||
private static final int[] COLOR_ACCENT_ATTR = new int[]{R.attr.colorAccent}; // colorAccent属性数组
|
||||
private static final int DEFAULT_COLOR = Color.parseColor("#FFFFFFFF"); // 默认返回颜色
|
||||
|
||||
// ================================== 新增:Accent 颜色获取方法 =================================
|
||||
// ================================== 主题颜色获取方法 =================================
|
||||
/**
|
||||
* 从当前应用主题中获取 colorAccent 颜色值
|
||||
* @param context 上下文,用于获取主题与资源
|
||||
* @return 解析到的 colorAccent 颜色值,解析失败返回默认白色#FFFFFFFF
|
||||
*/
|
||||
public static int getColorAccent(Context context) {
|
||||
// 方法调用日志
|
||||
LogUtils.d(TAG, "【getColorAccent】方法调用");
|
||||
// 参数校验
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "【getColorAccent】参数异常:Context为空,返回默认颜色");
|
||||
return Color.parseColor("#FFFFFFFF");
|
||||
LogUtils.e(TAG, "【getColorAccent】参数异常:Context为空");
|
||||
return DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
TypedArray typedArray = null;
|
||||
try {
|
||||
// 从当前主题中解析 colorAccent 属性
|
||||
// 从主题解析属性
|
||||
typedArray = context.obtainStyledAttributes(COLOR_ACCENT_ATTR);
|
||||
int colorAccent = typedArray.getColor(0, Color.parseColor("#FFFFFFFF"));
|
||||
int colorAccent = typedArray.getColor(0, DEFAULT_COLOR);
|
||||
LogUtils.d(TAG, String.format("【getColorAccent】解析成功 | colorAccent=0x%08X", colorAccent));
|
||||
return colorAccent;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【getColorAccent】解析失败,返回默认颜色", e);
|
||||
return Color.parseColor("#FFFFFFFF");
|
||||
return DEFAULT_COLOR;
|
||||
} finally {
|
||||
// 回收TypedArray资源,避免内存泄漏
|
||||
// 回收资源
|
||||
if (typedArray != null) {
|
||||
typedArray.recycle();
|
||||
LogUtils.d(TAG, "【getColorAccent】TypedArray资源已回收");
|
||||
@@ -60,17 +70,107 @@ public class ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 核心工具方法(图片质量压缩)=================================
|
||||
// ================================== 位图合成方法 =================================
|
||||
/**
|
||||
* 在纯色背景上绘制前景位图,实现FIT_CENTER居中效果
|
||||
* @param bgColor 背景颜色
|
||||
* @param originalFrameW 目标画布宽度
|
||||
* @param originalFrameH 目标画布高度
|
||||
* @param fgBitmap 前景位图
|
||||
* @return 合成后的位图,失败返回null
|
||||
*/
|
||||
public static Bitmap drawBitmapOnSolidBackground(final int bgColor, int originalFrameW, int originalFrameH, Bitmap fgBitmap) {
|
||||
// 方法调用及入参日志
|
||||
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】方法调用 | 背景色=0x%08X | 目标尺寸=%dx%d | 前景位图=%s",
|
||||
bgColor, originalFrameW, originalFrameH,
|
||||
(fgBitmap != null ? fgBitmap.getWidth() + "x" + fgBitmap.getHeight() : "null")));
|
||||
|
||||
// 1. 严格参数校验
|
||||
if (fgBitmap == null || fgBitmap.isRecycled()) {
|
||||
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常:前景Bitmap为空或已回收");
|
||||
return null;
|
||||
}
|
||||
if (fgBitmap.getWidth() <= 0 || fgBitmap.getHeight() <= 0) {
|
||||
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常:前景Bitmap尺寸无效");
|
||||
return null;
|
||||
}
|
||||
if (originalFrameW <= 0 || originalFrameH <= 0) {
|
||||
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】参数异常:原画框尺寸无效(宽高必须大于0)");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 强制画布尺寸为目标尺寸
|
||||
int canvasW = originalFrameW;
|
||||
int canvasH = originalFrameH;
|
||||
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】画布尺寸已确定:%dx%d", canvasW, canvasH));
|
||||
|
||||
// 3. 创建结果位图(ARGB_8888支持透明通道)
|
||||
Bitmap resultBitmap = Bitmap.createBitmap(canvasW, canvasH, Bitmap.Config.ARGB_8888);
|
||||
if (resultBitmap == null) {
|
||||
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】创建结果Bitmap失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4. 画布绘制
|
||||
Canvas canvas = new Canvas(resultBitmap);
|
||||
try {
|
||||
// 4.1 绘制纯色背景
|
||||
Paint bgPaint = new Paint();
|
||||
bgPaint.setColor(bgColor);
|
||||
bgPaint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawRect(0, 0, canvasW, canvasH, bgPaint);
|
||||
|
||||
// 4.2 计算前景 FIT_CENTER 变换参数(等比缩放至完全放入画布,居中显示)
|
||||
float fgWidth = fgBitmap.getWidth();
|
||||
float fgHeight = fgBitmap.getHeight();
|
||||
float scaleX = (float) canvasW / fgWidth;
|
||||
float scaleY = (float) canvasH / fgHeight;
|
||||
float scale = Math.min(scaleX, scaleY); // 取最小比例,保证完全放入画布
|
||||
|
||||
// 4.3 计算缩放后前景尺寸
|
||||
float scaledW = fgWidth * scale;
|
||||
float scaledH = fgHeight * scale;
|
||||
|
||||
// 4.4 计算居中位置(缩放后居中,无裁剪)
|
||||
float translateX = (canvasW - scaledW) / 2f;
|
||||
float translateY = (canvasH - scaledH) / 2f;
|
||||
|
||||
// 4.5 构建变换矩阵(缩放+平移,实现 FIT_CENTER 效果)
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scale, scale); // 等比缩放
|
||||
matrix.postTranslate(translateX, translateY); // 居中平移
|
||||
|
||||
// 4.6 绘制前景(保留透明通道,抗锯齿)
|
||||
Paint fgPaint = new Paint();
|
||||
fgPaint.setAntiAlias(true);
|
||||
fgPaint.setDither(true);
|
||||
canvas.drawBitmap(fgBitmap, matrix, fgPaint);
|
||||
|
||||
LogUtils.d(TAG, String.format("【drawBitmapOnSolidBackground】合成成功 | 缩放比例=%.2f | 居中位置=(%.1f,%.1f) | 效果=FIT_CENTER",
|
||||
scale, translateX, translateY));
|
||||
return resultBitmap;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "【drawBitmapOnSolidBackground】合成失败", e);
|
||||
if (resultBitmap != null && !resultBitmap.isRecycled()) {
|
||||
resultBitmap.recycle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================== 核心压缩方法 =================================
|
||||
/**
|
||||
* 图片质量压缩(JPEG格式),压缩后覆盖源文件
|
||||
* @param context 上下文(备用,当前逻辑未直接使用)
|
||||
* @param context 上下文(备用)
|
||||
* @param srcImagePath 源图片文件路径(非空,文件需存在)
|
||||
* @param dstImagePath 压缩后临时保存路径(非空,用于存储压缩中间文件)
|
||||
* @param dstImagePath 压缩后临时保存路径(非空)
|
||||
* @param compressQuality 压缩质量(0-100,数值越小压缩率越高)
|
||||
*/
|
||||
public static void bitmapCompress(Context context, String srcImagePath, String dstImagePath, int compressQuality) {
|
||||
LogUtils.d(TAG, String.format("【bitmapCompress】调用开始 | 源路径=%s | 临时路径=%s | 压缩质量=%d",
|
||||
// 方法调用及入参日志
|
||||
LogUtils.d(TAG, String.format("【bitmapCompress】方法调用 | 源路径=%s | 临时路径=%s | 压缩质量=%d",
|
||||
srcImagePath, dstImagePath, compressQuality));
|
||||
|
||||
// 1. 前置参数校验
|
||||
if (srcImagePath == null || srcImagePath.isEmpty()) {
|
||||
LogUtils.e(TAG, "【bitmapCompress】参数异常:源文件路径为空");
|
||||
@@ -103,7 +203,7 @@ public class ImageUtils {
|
||||
LogUtils.d(TAG, String.format("【bitmapCompress】Bitmap解码成功 | 尺寸=%dx%d",
|
||||
compressBitmap.getWidth(), compressBitmap.getHeight()));
|
||||
|
||||
// 3. 创建临时压缩文件
|
||||
// 3. 创建临时压缩文件目录
|
||||
File dstFile = new File(dstImagePath);
|
||||
File dstParentDir = dstFile.getParentFile();
|
||||
if (dstParentDir != null && !dstParentDir.exists()) {
|
||||
@@ -131,7 +231,7 @@ public class ImageUtils {
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "【bitmapCompress】IO异常", e);
|
||||
} finally {
|
||||
// 6. 资源释放:关闭输出流
|
||||
// 6. 关闭输出流
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
@@ -139,7 +239,7 @@ public class ImageUtils {
|
||||
LogUtils.e(TAG, "【bitmapCompress】输出流关闭失败", e);
|
||||
}
|
||||
}
|
||||
// 7. 资源释放:回收Bitmap
|
||||
// 7. 回收Bitmap
|
||||
if (compressBitmap != null && !compressBitmap.isRecycled()) {
|
||||
compressBitmap.recycle();
|
||||
LogUtils.d(TAG, "【bitmapCompress】Bitmap资源已回收");
|
||||
|
||||
@@ -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 方法(仅前台通知实例,只读)=================================
|
||||
|
||||
@@ -13,58 +13,62 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
import cc.winboll.studio.powerbell.utils.ImageUtils;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 基于Java7的BackgroundView(LinearLayout+ImageView,保持原图比例居中平铺)
|
||||
* 核心:ImageView保持原图比例,在LinearLayout中居中平铺,无拉伸、无裁剪、无压缩
|
||||
* 改进:强制保持缓存策略,无论内存是否紧张,不自动清理任何缓存,保留图片原始品质
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
*/
|
||||
public class BackgroundView extends RelativeLayout {
|
||||
// ====================================== 静态常量区 ======================================
|
||||
// ====================================== 静态常量区(首屏可见,统一管理) ======================================
|
||||
public static final String TAG = "BackgroundView";
|
||||
// Bitmap 配置常量(原始品质)
|
||||
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
|
||||
private static final int BITMAP_SAMPLE_SIZE = 1; // 不缩放采样率
|
||||
|
||||
// ====================================== 成员变量区 ======================================
|
||||
// 缓存相关
|
||||
private String mCurrentCachedPath = "";
|
||||
// 视图相关
|
||||
// ====================================== 成员变量区(按功能分类:上下文→视图→缓存→图片属性) ======================================
|
||||
// 上下文
|
||||
private Context mContext;
|
||||
private LinearLayout mLlContainer; // 主容器LinearLayout
|
||||
private ImageView mIvBackground; // 图片显示控件
|
||||
// 视图组件
|
||||
private LinearLayout mLlContainer; // 主容器LinearLayout
|
||||
private ImageView mIvBackground; // 图片显示控件
|
||||
// 缓存相关
|
||||
private String mCurrentCachedPath = "";// 当前缓存图片路径
|
||||
// 图片属性
|
||||
private float mImageAspectRatio = 1.0f; // 原图宽高比(宽/高)
|
||||
private float mImageAspectRatio = 1.0f;// 原图宽高比(宽/高)
|
||||
private int mBgColor = 0xFFFFFFFF; // 当前图片背景色
|
||||
|
||||
// ====================================== 构造器(Java7兼容) ======================================
|
||||
// ====================================== 构造器(Java7兼容,按参数重载顺序排列) ======================================
|
||||
public BackgroundView(Context context) {
|
||||
super(context);
|
||||
LogUtils.d(TAG, "=== BackgroundView 构造器1启动 [context] ===");
|
||||
LogUtils.d(TAG, String.format("【构造器1】启动 | context=%s", context.getClass().getSimpleName()));
|
||||
this.mContext = context;
|
||||
initView();
|
||||
}
|
||||
|
||||
public BackgroundView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
LogUtils.d(TAG, "=== BackgroundView 构造器2启动 [context, attrs] ===");
|
||||
LogUtils.d(TAG, String.format("【构造器2】启动 | context=%s", context.getClass().getSimpleName()));
|
||||
this.mContext = context;
|
||||
initView();
|
||||
}
|
||||
|
||||
public BackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LogUtils.d(TAG, "=== BackgroundView 构造器3启动 [context, attrs, defStyleAttr] ===");
|
||||
LogUtils.d(TAG, String.format("【构造器3】启动 | context=%s", context.getClass().getSimpleName()));
|
||||
this.mContext = context;
|
||||
initView();
|
||||
}
|
||||
|
||||
// ====================================== 初始化方法 ======================================
|
||||
// ====================================== 初始化方法(按执行顺序:主视图→子容器→图片控件→默认背景) ======================================
|
||||
private void initView() {
|
||||
LogUtils.d(TAG, "=== initView 启动 ===");
|
||||
LogUtils.d(TAG, "【initView】启动");
|
||||
// 1. 配置当前控件:全屏+透明
|
||||
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
// 2. 初始化主容器LinearLayout
|
||||
@@ -72,12 +76,12 @@ public class BackgroundView extends RelativeLayout {
|
||||
// 3. 初始化ImageView
|
||||
initImageView();
|
||||
// 4. 初始设置透明背景
|
||||
setDefaultTransparentBackground();
|
||||
LogUtils.d(TAG, "=== initView 完成 ===");
|
||||
setDefaultEmptyBackground();
|
||||
LogUtils.d(TAG, "【initView】完成");
|
||||
}
|
||||
|
||||
private void initLinearLayout() {
|
||||
LogUtils.d(TAG, "=== initLinearLayout 启动 ===");
|
||||
LogUtils.d(TAG, "【initLinearLayout】启动");
|
||||
mLlContainer = new LinearLayout(mContext);
|
||||
LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
@@ -86,13 +90,12 @@ public class BackgroundView extends RelativeLayout {
|
||||
mLlContainer.setLayoutParams(llParams);
|
||||
mLlContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
mLlContainer.setGravity(android.view.Gravity.CENTER);
|
||||
mLlContainer.setBackgroundColor(0x00000000);
|
||||
this.addView(mLlContainer);
|
||||
LogUtils.d(TAG, "=== initLinearLayout 完成 ===");
|
||||
LogUtils.d(TAG, "【initLinearLayout】完成");
|
||||
}
|
||||
|
||||
private void initImageView() {
|
||||
LogUtils.d(TAG, "=== initImageView 启动 ===");
|
||||
LogUtils.d(TAG, "【initImageView】启动");
|
||||
mIvBackground = new ImageView(mContext);
|
||||
LinearLayout.LayoutParams ivParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
@@ -100,142 +103,124 @@ public class BackgroundView extends RelativeLayout {
|
||||
);
|
||||
mIvBackground.setLayoutParams(ivParams);
|
||||
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mIvBackground.setBackgroundColor(0x00000000);
|
||||
mLlContainer.addView(mIvBackground);
|
||||
LogUtils.d(TAG, "=== initImageView 完成 ===");
|
||||
LogUtils.d(TAG, "【initImageView】完成");
|
||||
}
|
||||
|
||||
// ====================================== 对外方法 ======================================
|
||||
// ====================================== 对外公开方法(按功能分类:Bean加载→图片加载) ======================================
|
||||
public void loadByBackgroundBean(BackgroundBean bean) {
|
||||
loadByBackgroundBean(bean, false);
|
||||
}
|
||||
|
||||
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
|
||||
LogUtils.d(TAG, "=== loadByBackgroundBean 启动 [isRefresh:" + isRefresh + "] ===");
|
||||
LogUtils.d(TAG, String.format("【loadByBackgroundBean】启动 | isRefresh=%b | bean=%s", isRefresh, bean));
|
||||
// 参数校验
|
||||
if (bean == null) {
|
||||
LogUtils.e(TAG, "loadByBackgroundBean: BackgroundBean为空");
|
||||
setDefaultTransparentBackground();
|
||||
LogUtils.e(TAG, "【loadByBackgroundBean】异常:BackgroundBean为空");
|
||||
setDefaultEmptyBackground();
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置图片背景色
|
||||
mBgColor = bean.getPixelColor();
|
||||
LogUtils.d(TAG, String.format("【loadByBackgroundBean】背景色设置为 0x%08X", mBgColor));
|
||||
|
||||
// 判断是否使用背景文件
|
||||
if (!bean.isUseBackgroundFile()) {
|
||||
LogUtils.d(TAG, "loadByBackgroundBean: 不使用背景文件,设置透明背景");
|
||||
setDefaultTransparentBackground();
|
||||
LogUtils.d(TAG, "【loadByBackgroundBean】不使用背景文件,设置透明背景");
|
||||
setDefaultEmptyBackground();
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取目标路径
|
||||
String targetPath = bean.isUseBackgroundScaledCompressFile()
|
||||
? bean.getBackgroundScaledCompressFilePath()
|
||||
: bean.getBackgroundFilePath();
|
||||
LogUtils.d(TAG, "loadByBackgroundBean: 目标路径=" + targetPath);
|
||||
LogUtils.d(TAG, String.format("【loadByBackgroundBean】目标路径=%s | 使用压缩文件=%b",
|
||||
targetPath, bean.isUseBackgroundScaledCompressFile()));
|
||||
|
||||
// 校验文件是否存在
|
||||
File targetFile = new File(targetPath);
|
||||
if (!targetFile.exists() || !targetFile.isFile()) {
|
||||
LogUtils.e(TAG, "loadByBackgroundBean: 视图控件图片不存在:" + targetPath);
|
||||
LogUtils.e(TAG, String.format("【loadByBackgroundBean】异常:图片文件不存在 | path=%s", targetPath));
|
||||
setDefaultEmptyBackground();
|
||||
return;
|
||||
}
|
||||
// 刷新逻辑:重新解码原始品质图片并更新缓存
|
||||
if (isRefresh) {
|
||||
LogUtils.d(TAG, "loadByBackgroundBean: 刷新图片,重新解码原始品质图片并更新缓存");
|
||||
Bitmap newBitmap = decodeOriginalBitmap(targetFile);
|
||||
if (newBitmap != null) {
|
||||
App.sBitmapCacheUtils.cacheBitmap(targetPath, newBitmap);
|
||||
App.sBitmapCacheUtils.increaseRefCount(targetPath);
|
||||
LogUtils.d(TAG, "loadByBackgroundBean: 刷新缓存成功,路径=" + targetPath);
|
||||
} else {
|
||||
LogUtils.e(TAG, "loadByBackgroundBean: 刷新解码失败,路径=" + targetPath);
|
||||
}
|
||||
}
|
||||
// 加载图片
|
||||
loadImage(targetPath);
|
||||
setBackgroundColor(bean.getPixelColor());
|
||||
LogUtils.d(TAG, "=== loadByBackgroundBean 完成 ===");
|
||||
|
||||
loadImage(mBgColor, targetPath, isRefresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* 改进版:强制保持缓存策略,不自动清理任何缓存,强化引用计数管理,保留图片原始品质
|
||||
* @param imagePath 图片绝对路径
|
||||
*/
|
||||
public void loadImage(String imagePath) {
|
||||
LogUtils.d(TAG, "=== loadImage 启动,路径:" + imagePath + " ===");
|
||||
// 1. 路径空校验
|
||||
if (TextUtils.isEmpty(imagePath)) {
|
||||
LogUtils.e(TAG, "loadImage: 图片路径为空");
|
||||
setDefaultTransparentBackground();
|
||||
return;
|
||||
}
|
||||
// 2. 文件有效性校验
|
||||
File imageFile = new File(imagePath);
|
||||
if (!imageFile.exists() || !imageFile.isFile()) {
|
||||
LogUtils.e(TAG, "loadImage: 图片文件无效");
|
||||
setDefaultTransparentBackground();
|
||||
return;
|
||||
}
|
||||
// 3. 隐藏ImageView防止闪烁
|
||||
public void loadImage(int bgColor, String imagePath, boolean isRefresh) {
|
||||
LogUtils.d(TAG, String.format("【loadImage】启动 | bgColor=0x%08X | imagePath=%s | isRefresh=%b",
|
||||
bgColor, imagePath, isRefresh));
|
||||
// 隐藏ImageView防止闪烁
|
||||
mIvBackground.setVisibility(View.GONE);
|
||||
|
||||
// ======================== 路径判断逻辑(强制缓存版) ========================
|
||||
// 3.1 路径未变化:校验缓存有效性
|
||||
if (imagePath.equals(mCurrentCachedPath)) {
|
||||
Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
|
||||
if (isBitmapValid(cachedBitmap)) {
|
||||
LogUtils.d(TAG, "loadImage: 路径未变,使用有效缓存Bitmap(原始品质)");
|
||||
mImageAspectRatio = (float) cachedBitmap.getWidth() / cachedBitmap.getHeight();
|
||||
mIvBackground.setImageBitmap(cachedBitmap);
|
||||
adjustImageViewSize();
|
||||
LogUtils.d(TAG, "=== loadImage 完成(缓存命中) ===");
|
||||
return;
|
||||
} else {
|
||||
LogUtils.e(TAG, "loadImage: 缓存Bitmap无效,尝试重加载原始品质图片");
|
||||
}
|
||||
}
|
||||
// 3.2 路径已更新:保留旧缓存,仅更新路径记录
|
||||
if (!TextUtils.isEmpty(mCurrentCachedPath) && !mCurrentCachedPath.equals(imagePath)) {
|
||||
LogUtils.d(TAG, "loadImage: 路径已更新,保留旧缓存,原路径=" + mCurrentCachedPath + ",新路径=" + imagePath);
|
||||
}
|
||||
// ======================== 路径判断逻辑结束 ========================
|
||||
// 初始化配置工具类并保存默认相框尺寸
|
||||
AppConfigUtils appConfigUtils = AppConfigUtils.getInstance(mContext);
|
||||
appConfigUtils.loadAppConfig();
|
||||
LogUtils.d(TAG, String.format("【loadImage】默认相框尺寸 | W=%d | H=%d",
|
||||
appConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
|
||||
appConfigUtils.mAppConfigBean.getDefaultFrameHeight()));
|
||||
|
||||
// 4. 计算图片宽高比
|
||||
if (!calculateImageAspectRatio(imageFile)) {
|
||||
setDefaultTransparentBackground();
|
||||
return;
|
||||
}
|
||||
// 5. 获取或解码Bitmap
|
||||
Bitmap bitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
|
||||
if (isBitmapValid(bitmap)) {
|
||||
LogUtils.d(TAG, "loadImage: 从缓存获取有效Bitmap(原始品质)");
|
||||
} else {
|
||||
LogUtils.d(TAG, "loadImage: 缓存未命中,解码原始品质图片");
|
||||
bitmap = decodeOriginalBitmap(imageFile);
|
||||
if (bitmap == null) {
|
||||
LogUtils.e(TAG, "loadImage: 图片解码失败(原始品质)");
|
||||
ToastUtils.show("图片解码失败,无法加载");
|
||||
setDefaultTransparentBackground();
|
||||
return;
|
||||
// 刷新逻辑:重新解码原始品质图片并更新缓存
|
||||
if (isRefresh) {
|
||||
LogUtils.d(TAG, "【loadImage】执行刷新逻辑:重新解码原始品质图片");
|
||||
File imageFile = new File(imagePath);
|
||||
Bitmap newBitmap = decodeOriginalBitmap(imageFile);
|
||||
LogUtils.d(TAG, String.format("【loadImage】原始图片解码完成 | newBitmap=%s",
|
||||
newBitmap != null ? newBitmap.getWidth() + "x" + newBitmap.getHeight() : "null"));
|
||||
|
||||
// 合成纯色背景图片(使用配置文件中默认相框尺寸)
|
||||
Bitmap combinedBitmap = ImageUtils.drawBitmapOnSolidBackground(
|
||||
bgColor,
|
||||
appConfigUtils.mAppConfigBean.getDefaultFrameWidth(),
|
||||
appConfigUtils.mAppConfigBean.getDefaultFrameHeight(),
|
||||
newBitmap
|
||||
);
|
||||
|
||||
if (combinedBitmap == null) {
|
||||
LogUtils.e(TAG, "【loadImage】纯色背景合成失败,使用原始Bitmap");
|
||||
combinedBitmap = newBitmap;
|
||||
} else {
|
||||
LogUtils.d(TAG, String.format("【loadImage】纯色背景合成成功 | combinedBitmap=%dx%d",
|
||||
combinedBitmap.getWidth(), combinedBitmap.getHeight()));
|
||||
// 回收原始Bitmap(避免重复缓存)
|
||||
if (newBitmap != null && !newBitmap.isRecycled() && newBitmap != combinedBitmap) {
|
||||
newBitmap.recycle();
|
||||
LogUtils.d(TAG, "【loadImage】原始Bitmap已回收");
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
if (combinedBitmap != null) {
|
||||
App.sBitmapCacheUtils.cacheBitmap(imagePath, combinedBitmap);
|
||||
App.sBitmapCacheUtils.increaseRefCount(imagePath);
|
||||
mCurrentCachedPath = imagePath;
|
||||
LogUtils.d(TAG, String.format("【loadImage】刷新缓存成功 | path=%s", imagePath));
|
||||
} else {
|
||||
LogUtils.e(TAG, String.format("【loadImage】刷新解码失败 | path=%s", imagePath));
|
||||
}
|
||||
// 缓存新图片
|
||||
App.sBitmapCacheUtils.cacheBitmap(imagePath, bitmap);
|
||||
LogUtils.d(TAG, "loadImage: 新图片缓存成功,路径=" + imagePath);
|
||||
}
|
||||
// 6. 引用计数管理
|
||||
App.sBitmapCacheUtils.increaseRefCount(imagePath);
|
||||
// 7. 更新当前缓存路径
|
||||
mCurrentCachedPath = imagePath;
|
||||
// 8. 设置图片并调整尺寸
|
||||
mIvBackground.setImageBitmap(bitmap);
|
||||
adjustImageViewSize();
|
||||
LogUtils.d(TAG, "=== loadImage 完成 ===");
|
||||
|
||||
// 加载缓存图片
|
||||
Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
|
||||
LogUtils.d(TAG, String.format("【loadImage】加载缓存图片 | cachedBitmap=%s",
|
||||
cachedBitmap != null ? cachedBitmap.getWidth() + "x" + cachedBitmap.getHeight() : "null"));
|
||||
mIvBackground.setImageBitmap(cachedBitmap);
|
||||
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mIvBackground.setVisibility(View.VISIBLE);
|
||||
LogUtils.d(TAG, "【loadImage】完成");
|
||||
}
|
||||
|
||||
// ====================================== 内部工具方法 ======================================
|
||||
// ====================================== 内部工具方法(按功能分类:Bitmap校验→比例计算→解码→背景设置) ======================================
|
||||
/**
|
||||
* 工具方法:判断Bitmap是否有效(非空且未被回收)
|
||||
*/
|
||||
private boolean isBitmapValid(Bitmap bitmap) {
|
||||
boolean valid = bitmap != null && !bitmap.isRecycled();
|
||||
if (!valid) {
|
||||
LogUtils.w(TAG, "isBitmapValid: Bitmap无效(空或已回收)");
|
||||
LogUtils.w(TAG, "【isBitmapValid】无效:Bitmap为空或已回收");
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
@@ -244,25 +229,26 @@ public class BackgroundView extends RelativeLayout {
|
||||
* 计算图片宽高比
|
||||
*/
|
||||
private boolean calculateImageAspectRatio(File file) {
|
||||
LogUtils.d(TAG, "=== calculateImageAspectRatio 启动,文件=" + file.getAbsolutePath() + " ===");
|
||||
LogUtils.d(TAG, String.format("【calculateImageAspectRatio】启动 | file=%s", file.getAbsolutePath()));
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||
|
||||
// 尺寸校验
|
||||
int width = options.outWidth;
|
||||
int height = options.outHeight;
|
||||
if (width <= 0 || height <= 0) {
|
||||
LogUtils.e(TAG, "calculateImageAspectRatio: 图片尺寸无效,宽=" + width + ",高=" + height);
|
||||
LogUtils.e(TAG, String.format("【calculateImageAspectRatio】无效尺寸 | width=%d | height=%d", width, height));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算比例
|
||||
mImageAspectRatio = (float) width / height;
|
||||
LogUtils.d(TAG, "calculateImageAspectRatio: 原图比例=" + mImageAspectRatio);
|
||||
LogUtils.d(TAG, "=== calculateImageAspectRatio 完成 ===");
|
||||
LogUtils.d(TAG, String.format("【calculateImageAspectRatio】完成 | 比例=%.2f", mImageAspectRatio));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "calculateImageAspectRatio: 计算比例失败:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("【calculateImageAspectRatio】失败:%s", e.getMessage()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -271,7 +257,7 @@ public class BackgroundView extends RelativeLayout {
|
||||
* 移除压缩逻辑:解码原始品质图片(无缩放、无色彩损失)
|
||||
*/
|
||||
private Bitmap decodeOriginalBitmap(File file) {
|
||||
LogUtils.d(TAG, "=== decodeOriginalBitmap 启动,文件=" + file.getAbsolutePath() + " ===");
|
||||
LogUtils.d(TAG, String.format("【decodeOriginalBitmap】启动 | file=%s", file.getAbsolutePath()));
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
// 核心配置:原始品质
|
||||
@@ -281,83 +267,40 @@ public class BackgroundView extends RelativeLayout {
|
||||
options.inInputShareable = false;
|
||||
options.inDither = true;
|
||||
options.inScaled = false;
|
||||
|
||||
// 解码图片
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||
if (bitmap != null) {
|
||||
LogUtils.d(TAG, "decodeOriginalBitmap: 解码成功,宽=" + bitmap.getWidth() + ",高=" + bitmap.getHeight());
|
||||
LogUtils.d(TAG, String.format("【decodeOriginalBitmap】成功 | width=%d | height=%d", bitmap.getWidth(), bitmap.getHeight()));
|
||||
} else {
|
||||
LogUtils.e(TAG, "decodeOriginalBitmap: 解码返回null");
|
||||
LogUtils.e(TAG, "【decodeOriginalBitmap】失败:返回null");
|
||||
}
|
||||
LogUtils.d(TAG, "=== decodeOriginalBitmap 完成 ===");
|
||||
return bitmap;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "decodeOriginalBitmap: 原始品质解码失败:" + e.getMessage());
|
||||
LogUtils.e(TAG, String.format("【decodeOriginalBitmap】异常:%s", e.getMessage()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整ImageView尺寸,保持原图比例
|
||||
*/
|
||||
private void adjustImageViewSize() {
|
||||
LogUtils.d(TAG, "=== adjustImageViewSize 启动 ===");
|
||||
// 空指针校验
|
||||
if (mLlContainer == null || mIvBackground == null) {
|
||||
LogUtils.e(TAG, "adjustImageViewSize: 容器或ImageView未初始化");
|
||||
return;
|
||||
}
|
||||
// 获取容器尺寸
|
||||
int llWidth = mLlContainer.getWidth();
|
||||
int llHeight = mLlContainer.getHeight();
|
||||
if (llWidth == 0 || llHeight == 0) {
|
||||
LogUtils.w(TAG, "adjustImageViewSize: 容器尺寸未初始化,延迟调整");
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adjustImageViewSize();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 计算ImageView尺寸
|
||||
int ivWidth, ivHeight;
|
||||
if (mImageAspectRatio >= 1.0f) {
|
||||
ivWidth = Math.min((int) (llHeight * mImageAspectRatio), llWidth);
|
||||
ivHeight = (int) (ivWidth / mImageAspectRatio);
|
||||
} else {
|
||||
ivHeight = Math.min((int) (llWidth / mImageAspectRatio), llHeight);
|
||||
ivWidth = (int) (ivHeight * mImageAspectRatio);
|
||||
}
|
||||
// 设置尺寸
|
||||
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mIvBackground.getLayoutParams();
|
||||
params.width = ivWidth;
|
||||
params.height = ivHeight;
|
||||
mIvBackground.setLayoutParams(params);
|
||||
mIvBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
mIvBackground.setVisibility(View.VISIBLE);
|
||||
LogUtils.d(TAG, "adjustImageViewSize: 尺寸调整完成,宽=" + ivWidth + ",高=" + ivHeight);
|
||||
LogUtils.d(TAG, "=== adjustImageViewSize 完成 ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认透明背景,仅减少引用计数,不删除缓存
|
||||
*/
|
||||
private void setDefaultTransparentBackground() {
|
||||
LogUtils.d(TAG, "=== setDefaultTransparentBackground 启动 ===");
|
||||
private void setDefaultEmptyBackground() {
|
||||
LogUtils.d(TAG, "【setDefaultEmptyBackground】启动");
|
||||
// 清空ImageView
|
||||
mIvBackground.setImageDrawable(null);
|
||||
mIvBackground.setBackgroundColor(0x00000000);
|
||||
mImageAspectRatio = 1.0f;
|
||||
|
||||
// 减少引用计数,不删除缓存
|
||||
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
|
||||
LogUtils.d(TAG, "setDefaultTransparentBackground: 减少引用计数,路径=" + mCurrentCachedPath);
|
||||
LogUtils.d(TAG, String.format("【setDefaultEmptyBackground】减少引用计数 | path=%s", mCurrentCachedPath));
|
||||
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
|
||||
mCurrentCachedPath = "";
|
||||
}
|
||||
LogUtils.d(TAG, "=== setDefaultTransparentBackground 完成 ===");
|
||||
LogUtils.d(TAG, "【setDefaultEmptyBackground】完成");
|
||||
}
|
||||
|
||||
// ====================================== 重写生命周期方法 ======================================
|
||||
// ====================================== 重写生命周期方法(按执行顺序:绘制→尺寸变化→窗口分离) ======================================
|
||||
/**
|
||||
* 重写:绘制前强制校验Bitmap有效性,防止已回收Bitmap崩溃
|
||||
*/
|
||||
@@ -368,7 +311,7 @@ public class BackgroundView extends RelativeLayout {
|
||||
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
|
||||
Bitmap bitmap = bitmapDrawable.getBitmap();
|
||||
if (!isBitmapValid(bitmap)) {
|
||||
LogUtils.e(TAG, "onDraw: 检测到已回收Bitmap,清空本地绘制(保留全局缓存)");
|
||||
LogUtils.e(TAG, "【onDraw】检测到已回收Bitmap,清空绘制");
|
||||
mIvBackground.setImageDrawable(null);
|
||||
return;
|
||||
}
|
||||
@@ -376,32 +319,32 @@ public class BackgroundView extends RelativeLayout {
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写:View从窗口移除时仅减少引用计数,不删除全局缓存(强制保持策略)
|
||||
*/
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
LogUtils.d(TAG, "=== onDetachedFromWindow 启动 ===");
|
||||
// 清空ImageView的Drawable,释放本地引用
|
||||
mIvBackground.setImageDrawable(null);
|
||||
// 减少引用计数,不删除全局缓存
|
||||
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
|
||||
LogUtils.d(TAG, "onDetachedFromWindow: 减少引用计数,路径=" + mCurrentCachedPath);
|
||||
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
|
||||
mCurrentCachedPath = "";
|
||||
}
|
||||
LogUtils.d(TAG, "=== onDetachedFromWindow 完成 ===");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写:恢复尺寸调整逻辑,确保View尺寸变化时正确显示(无压缩)
|
||||
*/
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
LogUtils.d(TAG, "onSizeChanged: 尺寸变化,宽=" + w + ",高=" + h + ",调整ImageView尺寸");
|
||||
adjustImageViewSize();
|
||||
LogUtils.d(TAG, String.format("【onSizeChanged】尺寸变化 | newW=%d | newH=%d | oldW=%d | oldH=%d", w, h, oldw, oldh));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写:View从窗口移除时仅减少引用计数,不删除全局缓存(强制保持策略)
|
||||
*/
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
LogUtils.d(TAG, "【onDetachedFromWindow】启动");
|
||||
// 清空ImageView的Drawable,释放本地引用
|
||||
mIvBackground.setImageDrawable(null);
|
||||
|
||||
// 减少引用计数,不删除全局缓存
|
||||
if (!TextUtils.isEmpty(mCurrentCachedPath)) {
|
||||
LogUtils.d(TAG, String.format("【onDetachedFromWindow】减少引用计数 | path=%s", mCurrentCachedPath));
|
||||
App.sBitmapCacheUtils.decreaseRefCount(mCurrentCachedPath);
|
||||
mCurrentCachedPath = "";
|
||||
}
|
||||
LogUtils.d(TAG, "【onDetachedFromWindow】完成");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,默认能量风格,适配小米机型渲染)
|
||||
*/
|
||||
|
||||
@@ -6,14 +6,16 @@ import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||
import cc.winboll.studio.powerbell.App;
|
||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||
|
||||
/**
|
||||
* 单实例缓存版背景视图控件(基于Java7)- 强制缓存版
|
||||
* 核心:通过静态属性保存当前缓存路径和实例,支持强制重载图片
|
||||
* 新增:SP持久化最后加载路径、获取最后加载实例功能
|
||||
* 强制缓存策略:无论内存是否紧张,不自动清理任何缓存实例和路径记录
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/12/21 20:43
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
*/
|
||||
public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
// ====================================== 静态常量区(TAG + SP相关常量) ======================================
|
||||
@@ -33,19 +35,19 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
private MemoryCachedBackgroundView(Context context) {
|
||||
super(context);
|
||||
sInstanceCount++;
|
||||
LogUtils.d(TAG, "【构造器1】创建MemoryCachedBackgroundView实例,当前实例总数:" + sInstanceCount);
|
||||
LogUtils.d(TAG, String.format("构造器1启动 | 创建实例,当前实例总数=%d", sInstanceCount));
|
||||
}
|
||||
|
||||
private MemoryCachedBackgroundView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
sInstanceCount++;
|
||||
LogUtils.d(TAG, "【构造器2】创建MemoryCachedBackgroundView实例,当前实例总数:" + sInstanceCount);
|
||||
LogUtils.d(TAG, String.format("构造器2启动 | 创建实例,当前实例总数=%d", sInstanceCount));
|
||||
}
|
||||
|
||||
private MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
sInstanceCount++;
|
||||
LogUtils.d(TAG, "【构造器3】创建MemoryCachedBackgroundView实例,当前实例总数:" + sInstanceCount);
|
||||
LogUtils.d(TAG, String.format("构造器3启动 | 创建实例,当前实例总数=%d", sInstanceCount));
|
||||
}
|
||||
|
||||
// ====================================== 核心静态方法:获取/创建缓存实例(强制缓存版) ======================================
|
||||
@@ -56,36 +58,27 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @param isReload 是否强制重新加载图片(路径匹配时仍刷新)
|
||||
* @return 缓存/新创建的MemoryCachedBackgroundView实例
|
||||
*/
|
||||
public static MemoryCachedBackgroundView getInstance(Context context, String imagePath, boolean isReload) {
|
||||
LogUtils.d(TAG, "【getInstance】调用 | 图片路径:" + 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, "【getInstance】强制重载图片 | 路径:" + imagePath);
|
||||
sCachedView.loadImage(imagePath);
|
||||
} else {
|
||||
LogUtils.d(TAG, "【getInstance】使用缓存实例,无需重载 | 路径:" + imagePath);
|
||||
}
|
||||
return sCachedView;
|
||||
}
|
||||
|
||||
// 2. 路径不匹配/无缓存 → 新建实例并更新静态缓存(核心:保留旧实例,仅更新引用)
|
||||
LogUtils.d(TAG, "【getInstance】路径未缓存,新建实例(保留旧实例) | 路径:" + 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(imagePath);
|
||||
LogUtils.d(TAG, "【getInstance】已更新当前缓存实例,旧实例路径:" + 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的路径对应的实例(强制保持所有实例)
|
||||
@@ -94,28 +87,20 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @return 最后加载路径对应的实例
|
||||
*/
|
||||
public static MemoryCachedBackgroundView getLastInstance(Context context) {
|
||||
LogUtils.d(TAG, "【getLastInstance】调用");
|
||||
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, "【getLastInstance】使用最后路径缓存实例 | 路径:" + lastPath);
|
||||
LogUtils.d(TAG, String.format("getLastInstance: 使用最后路径缓存实例 | 路径=%s", lastPath));
|
||||
//App.notifyMessage(TAG, String.format("getLastInstance: 使用最后路径缓存实例 | 路径=%s", lastPath));
|
||||
return sCachedView;
|
||||
}
|
||||
|
||||
// 3. 路径不匹配 → 新建实例并更新缓存(保留旧实例)
|
||||
LogUtils.d(TAG, "【getLastInstance】最后路径未缓存,新建实例并加载(保留旧实例) | 路径:" + lastPath);
|
||||
String oldPath = sCachedImagePath;
|
||||
sCachedView = new MemoryCachedBackgroundView(context);
|
||||
sCachedImagePath = lastPath;
|
||||
sCachedView.loadImage(lastPath);
|
||||
LogUtils.d(TAG, "【getLastInstance】已更新最后路径实例,旧实例路径:" + oldPath + "(强制保持)");
|
||||
return sCachedView;
|
||||
//App.notifyMessage(TAG, "getLastInstance 返回 null");
|
||||
return null;
|
||||
}
|
||||
|
||||
// ====================================== 工具方法:SP持久化最后加载路径(强制保持版) ======================================
|
||||
@@ -126,12 +111,12 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
*/
|
||||
private static void saveLastLoadImagePath(Context context, String imagePath) {
|
||||
if (TextUtils.isEmpty(imagePath) || context == null) {
|
||||
LogUtils.w(TAG, "【saveLastLoadImagePath】路径或上下文为空,跳过保存");
|
||||
LogUtils.w(TAG, "saveLastLoadImagePath: 路径或上下文为空,跳过保存");
|
||||
return;
|
||||
}
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
sp.edit().putString(KEY_LAST_LOAD_IMAGE_PATH, imagePath).apply();
|
||||
LogUtils.d(TAG, "【saveLastLoadImagePath】已保存最后路径(强制保持) | 路径:" + imagePath);
|
||||
LogUtils.d(TAG, String.format("saveLastLoadImagePath: 已保存最后路径(强制保持) | 路径=%s", imagePath));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,12 +126,12 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
*/
|
||||
public static String getLastLoadImagePath(Context context) {
|
||||
if (context == null) {
|
||||
LogUtils.e(TAG, "【getLastLoadImagePath】上下文为空,返回null");
|
||||
LogUtils.e(TAG, "getLastLoadImagePath: 上下文为空,返回null");
|
||||
return null;
|
||||
}
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String lastPath = sp.getString(KEY_LAST_LOAD_IMAGE_PATH, null);
|
||||
LogUtils.d(TAG, "【getLastLoadImagePath】获取最后路径(强制保持) | 路径:" + lastPath);
|
||||
LogUtils.d(TAG, String.format("getLastLoadImagePath: 获取最后路径(强制保持) | 路径=%s", lastPath));
|
||||
return lastPath;
|
||||
}
|
||||
|
||||
@@ -155,8 +140,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* 清除当前缓存实例和路径(强制缓存策略:仅日志,不实际清理)
|
||||
*/
|
||||
public static void clearCache() {
|
||||
LogUtils.w(TAG, "【clearCache】调用(强制缓存策略:不实际清理缓存) | 当前缓存路径:" + sCachedImagePath);
|
||||
LogUtils.d(TAG, "【clearCache】强制缓存策略生效,未清除任何实例和路径");
|
||||
LogUtils.w(TAG, String.format("clearCache 调用(强制缓存策略:不实际清理缓存) | 当前缓存路径=%s", sCachedImagePath));
|
||||
LogUtils.d(TAG, "clearCache: 强制缓存策略生效,未清除任何实例和路径");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,20 +149,20 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @param imagePath 图片路径
|
||||
*/
|
||||
public static void removeCache(String imagePath) {
|
||||
LogUtils.w(TAG, "【removeCache】调用(强制缓存策略:不实际清理缓存) | 图片路径:" + imagePath);
|
||||
LogUtils.w(TAG, String.format("removeCache 调用(强制缓存策略:不实际清理缓存) | 图片路径=%s", imagePath));
|
||||
if (TextUtils.isEmpty(imagePath)) {
|
||||
LogUtils.e(TAG, "【removeCache】图片路径为空,清除失败");
|
||||
LogUtils.e(TAG, "removeCache: 图片路径为空,清除失败");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "【removeCache】强制缓存策略生效,未清除任何实例和路径");
|
||||
LogUtils.d(TAG, "removeCache: 强制缓存策略生效,未清除任何实例和路径");
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存(强制缓存策略:仅日志,不实际清理)
|
||||
*/
|
||||
public static void clearAllCache() {
|
||||
LogUtils.w(TAG, "【clearAllCache】调用(强制缓存策略:不实际清理缓存)");
|
||||
LogUtils.d(TAG, "【clearAllCache】强制缓存策略生效,未清除任何实例、路径和SP记录");
|
||||
LogUtils.w(TAG, "clearAllCache 调用(强制缓存策略:不实际清理缓存)");
|
||||
LogUtils.d(TAG, "clearAllCache: 强制缓存策略生效,未清除任何实例、路径和SP记录");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +171,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
*/
|
||||
public static boolean hasCache() {
|
||||
boolean hasCache = sCachedView != null && !TextUtils.isEmpty(sCachedImagePath);
|
||||
LogUtils.d(TAG, "【hasCache】缓存存在状态:" + hasCache);
|
||||
LogUtils.d(TAG, String.format("hasCache 调用 | 缓存存在状态=%b", hasCache));
|
||||
return hasCache;
|
||||
}
|
||||
|
||||
@@ -195,8 +180,8 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void clearLastLoadImagePath(Context context) {
|
||||
LogUtils.w(TAG, "【clearLastLoadImagePath】调用(强制缓存策略:不实际清理SP记录)");
|
||||
LogUtils.d(TAG, "【clearLastLoadImagePath】强制缓存策略生效,未清除SP中最后路径记录");
|
||||
LogUtils.w(TAG, "clearLastLoadImagePath 调用(强制缓存策略:不实际清理SP记录)");
|
||||
LogUtils.d(TAG, "clearLastLoadImagePath: 强制缓存策略生效,未清除SP中最后路径记录");
|
||||
}
|
||||
|
||||
// ====================================== 辅助方法:从缓存获取上下文 ======================================
|
||||
@@ -206,28 +191,20 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
*/
|
||||
private static Context getContextFromCache() {
|
||||
Context context = sCachedView != null ? sCachedView.getContext() : null;
|
||||
LogUtils.d(TAG, "【getContextFromCache】从缓存获取上下文:" + context);
|
||||
LogUtils.d(TAG, String.format("getContextFromCache 调用 | 从缓存获取上下文=%s", context));
|
||||
return context;
|
||||
}
|
||||
|
||||
// ====================================== 重写父类方法:增强日志+SP持久化(强制保持版) ======================================
|
||||
@Override
|
||||
public void loadImage(String imagePath) {
|
||||
LogUtils.d(TAG, "【loadImage】调用 | 图片路径:" + imagePath);
|
||||
super.loadImage(imagePath);
|
||||
// 保存最后加载路径到SP(强制保持,不自动删除)
|
||||
saveLastLoadImagePath(getContext(), imagePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadByBackgroundBean(BackgroundBean bean) {
|
||||
LogUtils.d(TAG, "【loadByBackgroundBean】调用 | BackgroundBean:" + (bean == null ? "null" : bean.toString()));
|
||||
LogUtils.d(TAG, String.format("loadByBackgroundBean 调用 | BackgroundBean=%s", (bean == null ? "null" : bean.toString())));
|
||||
super.loadByBackgroundBean(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
|
||||
LogUtils.d(TAG, "【loadByBackgroundBean】调用 | BackgroundBean:" + (bean == null ? "null" : bean.toString()) + " | 是否刷新:" + isRefresh);
|
||||
LogUtils.d(TAG, String.format("loadByBackgroundBean 调用 | BackgroundBean=%s | 是否刷新=%b", (bean == null ? "null" : bean.toString()), isRefresh));
|
||||
super.loadByBackgroundBean(bean, isRefresh);
|
||||
}
|
||||
|
||||
@@ -237,7 +214,7 @@ public class MemoryCachedBackgroundView extends BackgroundView {
|
||||
* @return 实例总数
|
||||
*/
|
||||
public static int getInstanceCount() {
|
||||
LogUtils.d(TAG, "【getInstanceCount】调用 | 当前实例总数:" + sInstanceCount);
|
||||
LogUtils.d(TAG, String.format("getInstanceCount 调用 | 当前实例总数=%d", sInstanceCount));
|
||||
return sInstanceCount;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user