Compare commits

...

17 Commits

Author SHA1 Message Date
2ef09e020e <powerbell>APK 15.14.16 release Publish. 2025-12-21 17:57:41 +08:00
6de9b7379b 添加每分钟加载一次位图缓存的功能。预防系统优化内存时位图缓存被清理。 2025-12-21 17:50:40 +08:00
7fba2c8812 <powerbell>APK 15.14.15 release Publish. 2025-12-21 13:40:20 +08:00
20e3a5f974 修复系统分享图片的接收功能。 2025-12-21 13:38:46 +08:00
c8333e1e81 <powerbell>APK 15.14.14 release Publish. 2025-12-21 11:22:23 +08:00
6beb56efae <powerbell>Start New Stage Version. 2025-12-21 11:21:35 +08:00
eb51b2c8f4 网络下载按钮修复完成 2025-12-21 11:20:51 +08:00
36bdd059b0 修复空白图片背景按钮与图片背景按钮。 2025-12-21 09:49:40 +08:00
bf051dcc9f <powerbell>APK 15.14.13 release Publish. 2025-12-21 09:22:26 +08:00
b38a8df462 添加应用内存整理后重新缓存位图的功能。 2025-12-21 09:20:15 +08:00
a8dbe43d4b 源码整理 2025-12-21 02:05:38 +08:00
05a8dc5205 <powerbell>APK 15.14.12 release Publish. 2025-12-20 22:59:40 +08:00
280fc1abd6 <powerbell>Start New Stage Version. 2025-12-20 22:58:26 +08:00
fe2084f5ff 优化RemindThread线程,节约电量。 2025-12-20 22:57:42 +08:00
2a75aa140e 修改背景控件默认背景颜色。 2025-12-20 21:23:52 +08:00
04b597cbe7 <powerbell>APK 15.14.11 release Publish. 2025-12-20 19:28:00 +08:00
35d210c378 添加滚动条拉动时,实时预览数值的功能。 2025-12-20 19:26:32 +08:00
18 changed files with 1578 additions and 1069 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sat Dec 20 18:45:13 HKT 2025 #Sun Dec 21 17:57:40 HKT 2025
stageCount=11 stageCount=17
libraryProject= libraryProject=
baseVersion=15.14 baseVersion=15.14
publishVersion=15.14.10 publishVersion=15.14.16
buildCount=0 buildCount=0
baseBetaVersion=15.14.11 baseBetaVersion=15.14.17

View File

@@ -4,54 +4,73 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="cc.winboll.studio.powerbell"> package="cc.winboll.studio.powerbell">
<!-- ====================== 原有权限保留 + 补充核心权限 ====================== --> <!-- 运行前台服务 -->
<!-- 运行前台服务(原有保留,补充 Android 12+ 特殊前台服务权限) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<!-- 开机启动(原有保留,确保自启广播生效) --> <!-- 运行“specialUse”类型的前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<!-- 开机启动 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- 显示通知(原有保留,前台服务/保活必备) --> <!-- 显示通知 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- 应用使用统计相关(原有保留,忽略保护权限警告) --> <!-- PACKAGE_USAGE_STATS -->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<!-- BATTERY_STATS -->
<uses-permission android:name="android.permission.BATTERY_STATS"/> <uses-permission android:name="android.permission.BATTERY_STATS"/>
<!-- 计算应用存储空间 -->
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
<!-- 读取您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 修改或删除您共享存储空间中的内容 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- MANAGE_EXTERNAL_STORAGE -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- 请求忽略电池优化 -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- 拍摄照片和视频 -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission <uses-permission
android:name="android.permission.ACCESS_PACKAGE_USAGE_STATS" android:name="android.permission.ACCESS_PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions"/> tools:ignore="ProtectedPermissions"/>
<!-- 相机相关(原有保留,补充权限等级声明,避免安装警告) --> <uses-feature
<uses-feature android:name="android.hardware.camera"
android:name="android.hardware.camera"
android:required="false"/> <!-- 非核心功能设为非必须,兼容无相机设备 -->
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false"/> android:required="false"/>
<uses-permission android:name="android.permission.CAMERA" /> <!-- 补充相机权限原有仅声明feature无权限 -->
<!-- 应用信息相关(原有保留) --> <uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/> <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
<uses-permission <uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES" android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission"/> tools:ignore="QueryAllPackagesPermission"/>
<!-- 新增:文件管理权限(对应 PermissionUtils 全文件管理逻辑) --> <uses-permission android:name="android.permission.READ_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" /> <!-- API30+ 全文件权限 -->
<!-- 新增:忽略电池优化权限(对应 PermissionUtils 电池优化逻辑,必须声明) --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- 新增API30+ 跳转系统权限页兼容(避免自启/文件权限跳转失败) -->
<queries> <queries>
<!-- 全文件管理权限跳转兼容 -->
<!-- 小米自启权限跳转兼容(精准匹配安全中心包名) --> <package android:name="com.miui.securitycenter"/>
<package android:name="com.miui.securitycenter" />
<!-- 电池优化权限跳转兼容 -->
</queries> </queries>
@@ -68,17 +87,17 @@
android:supportsRtl="true" android:supportsRtl="true"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"> tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<!-- ====================== 页面配置(原有保留,优化 exported 安全) ====================== -->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:exported="true" android:exported="true"
android:launchMode="singleTask"> android:launchMode="singleTask">
</activity> </activity>
<activity <activity
android:name=".activities.CrashActivity" android:name=".activities.CrashActivity"
android:exported="false"/> <!-- 新增:非外部调用,设为 false提升安全 --> android:exported="false"/>
<activity-alias <activity-alias
android:name=".MainActivityEN1" android:name=".MainActivityEN1"
@@ -87,13 +106,19 @@
android:label="@string/app_name" android:label="@string/app_name"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:enabled="true"> android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmainen1"/> android:resource="@xml/shortcutsmainen1"/>
</activity-alias> </activity-alias>
<activity-alias <activity-alias
@@ -103,13 +128,19 @@
android:label="@string/app_name_cn1" android:label="@string/app_name_cn1"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:enabled="false"> android:enabled="false">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmaincn1"/> android:resource="@xml/shortcutsmaincn1"/>
</activity-alias> </activity-alias>
<activity-alias <activity-alias
@@ -119,53 +150,71 @@
android:label="@string/app_name_cn2" android:label="@string/app_name_cn2"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:enabled="false"> android:enabled="false">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcutsmaincn2"/> android:resource="@xml/shortcutsmaincn2"/>
</activity-alias> </activity-alias>
<activity <activity
android:name=".activities.ClearRecordActivity" android:name=".activities.ClearRecordActivity"
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity" android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
android:launchMode="singleTask" android:launchMode="singleTask"
android:exported="false"/> <!-- 新增:非外部调用,设为 false --> android:exported="false"/>
<activity <activity
android:name=".activities.BackgroundSettingsActivity" android:name=".activities.BackgroundSettingsActivity"
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity" android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/jpeg"/> <data android:mimeType="image/jpeg"/>
<data android:mimeType="image/jpg"/> <data android:mimeType="image/jpg"/>
<data android:mimeType="image/png"/> <data android:mimeType="image/png"/>
<data android:mimeType="image/webp"/> <data android:mimeType="image/webp"/>
<data android:mimeType="image/*"/> <data android:mimeType="image/*"/>
</intent-filter> </intent-filter>
</activity> </activity>
<!-- ====================== 广播接收器(优化自启广播,提升保活成功率) ====================== -->
<receiver <receiver
android:name=".receivers.MainReceiver" android:name=".receivers.MainReceiver"
android:enabled="true" android:enabled="true"
android:exported="true" android:exported="true"
android:directBootAware="true"> android:directBootAware="true">
<intent-filter android:priority="1000"> <!-- 新增:广播优先级最高,确保优先接收开机广播 -->
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/>
<!-- 补充:充电/解锁广播,增强后台唤醒机会 -->
<action android:name="android.intent.action.POWER_CONNECTED"/> <action android:name="android.intent.action.POWER_CONNECTED"/>
<action android:name="android.intent.action.USER_PRESENT"/> <action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- ====================== 服务配置(核心优化:前台服务保活,适配 API29-30 ====================== -->
<!-- 核心前台服务ControlCenterService保活核心重点优化 -->
<service <service
android:name=".services.ControlCenterService" android:name=".services.ControlCenterService"
android:priority="1000" android:priority="1000"
@@ -173,67 +222,72 @@
android:exported="false" android:exported="false"
android:process=".controlcenterservice" android:process=".controlcenterservice"
android:foregroundServiceType="dataSync"> android:foregroundServiceType="dataSync">
<!-- 新增Android 12+ 前台服务用途声明(系统强制,否则拦截服务启动) -->
<property <property
android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE" android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE"
android:value="后台核心功能运行、持续保活" /> <!-- 按实际用途填写,不可空 --> android:value="后台核心功能运行、持续保活"/>
</service> </service>
<!-- 辅助服务AssistantService按需优化增强稳定性 -->
<service <service
android:name=".services.AssistantService" android:name=".services.AssistantService"
android:enabled="true" android:enabled="true"
android:exported="false" android:exported="false"
android:process=".assistantservice"> <!-- 若需前台启动,添加此配置;纯后台可移除 --> android:process=".assistantservice">
<property <property
android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE" android:name="android.app.PROPERTY_SPECIAL_USE_FOREGROUND_SERVICE"
android:value="辅助核心功能运行" /> android:value="辅助核心功能运行"/>
</service> </service>
<!-- ====================== 其他配置(原有保留,补充优化) ====================== -->
<meta-data <meta-data
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="4.0"/> android:value="4.0"/>
<!-- 所有非外部调用的 Activity统一设 exported=false提升安全 --> <activity
<activity
android:name=".activities.BatteryReporterActivity" android:name=".activities.BatteryReporterActivity"
android:exported="false"/> android:exported="false"/>
<activity
<activity
android:name=".activities.PixelPickerActivity" android:name=".activities.PixelPickerActivity"
android:exported="false"/> android:exported="false"/>
<activity
<activity
android:name=".activities.BatteryReportActivity" android:name=".activities.BatteryReportActivity"
android:exported="false"/> android:exported="false"/>
<activity
<activity
android:name=".unittest.MainUnitTestActivity" android:name=".unittest.MainUnitTestActivity"
android:exported="false"/> android:exported="false"/>
<activity
<activity
android:name=".activities.ShortcutActionActivity" android:name=".activities.ShortcutActionActivity"
android:exported="false"/> android:exported="false"/>
<activity
<activity
android:name=".activities.SettingsActivity" android:name=".activities.SettingsActivity"
android:exported="false"/> android:exported="false"/>
<!-- 文件提供者(原有保留,正常使用) -->
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider" android:authorities="${applicationId}.fileprovider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider"/> android:resource="@xml/file_provider"/>
</provider> </provider>
<!-- UCrop 第三方页面原有保留exported=true 正常) -->
<activity <activity
android:name="com.yalantis.ucrop.UCropActivity" android:name="com.yalantis.ucrop.UCropActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:exported="true"> android:exported="true">
</activity> </activity>
</application> </application>
</manifest> </manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

View File

@@ -1,5 +1,6 @@
package cc.winboll.studio.powerbell; package cc.winboll.studio.powerbell;
import android.content.ComponentCallbacks2;
import android.content.Context; import android.content.Context;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
@@ -8,133 +9,330 @@ import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.NotificationMessage;
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver; import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
import cc.winboll.studio.powerbell.utils.AppCacheUtils; import cc.winboll.studio.powerbell.utils.AppCacheUtils;
import cc.winboll.studio.powerbell.utils.AppConfigUtils; 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.BitmapCacheUtils;
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
import java.io.File; import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* 应用全局入口类适配Android API 30基于Java 7编写
*/
public class App extends GlobalApplication { public class App extends GlobalApplication {
// ===================== 常量定义区 =====================
public static final String TAG = "App"; public static final String TAG = "App";
// 组件跳转常量
public static final String COMPONENT_EN1 = "cc.winboll.studio.powerbell.MainActivityEN1"; public static final String COMPONENT_EN1 = "cc.winboll.studio.powerbell.MainActivityEN1";
public static final String COMPONENT_CN1 = "cc.winboll.studio.powerbell.MainActivityCN1"; public static final String COMPONENT_CN1 = "cc.winboll.studio.powerbell.MainActivityCN1";
public static final String COMPONENT_CN2 = "cc.winboll.studio.powerbell.MainActivityCN2"; public static final String COMPONENT_CN2 = "cc.winboll.studio.powerbell.MainActivityCN2";
// 动作跳转常量
public static final String ACTION_SWITCHTO_EN1 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_EN1"; public static final String ACTION_SWITCHTO_EN1 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_EN1";
public static final String ACTION_SWITCHTO_CN1 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN1"; public static final String ACTION_SWITCHTO_CN1 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN1";
public static final String ACTION_SWITCHTO_CN2 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN2"; public static final String ACTION_SWITCHTO_CN2 = "cc.winboll.studio.powerbell.App.ACTION_SWITCHTO_CN2";
// 数据配置存储工具 // 内存紧张通知文案常量
static AppConfigUtils _mAppConfigUtils; private static final String TRIM_MEMORY_NOTIFY_TITLE = "应用使用时内存紧张提醒";
static AppCacheUtils _mAppCacheUtils; private static final String TRIM_MEMORY_NOTIFY_CONTENT = "由于本应用使用时,系统通知内存紧张程度级别较高,图片缓存功能暂时不启用。";
// 新增:全局 Bitmap 缓存工具(常驻内存)
public static BitmapCacheUtils _mBitmapCacheUtils;
GlobalApplicationReceiver mReceiver; // 定时任务间隔常量(分钟)
static String szTempDir = ""; private static final long TIMER_INTERVAL_MINUTES = 1;
// ===================== 静态属性区 =====================
// 数据配置工具
private static AppConfigUtils sAppConfigUtils;
private static AppCacheUtils sAppCacheUtils;
// 全局Bitmap缓存工具
public static BitmapCacheUtils sBitmapCacheUtils;
// 临时文件夹路径
private static String sTempDirPath = "";
// 定时任务静态属性(全局唯一)
private static Handler sTimerHandler;
private static Runnable sTimerRunnable;
private static boolean sIsTimerRunning = false;
// ===================== 成员属性区 =====================
// 全局广播接收器
private GlobalApplicationReceiver mGlobalReceiver;
// 通知管理工具
private NotificationManagerUtils mNotificationManager;
// ===================== 公共方法区 =====================
/**
* 获取临时文件夹路径
*/
public static String getTempDirPath() { public static String getTempDirPath() {
return szTempDir; return sTempDirPath;
} }
/**
* 获取应用配置工具实例
*/
public static AppConfigUtils getAppConfigUtils(Context context) {
LogUtils.d(TAG, "getAppConfigUtils() 调用传入Context" + context.getClass().getSimpleName());
if (sAppConfigUtils == null) {
sAppConfigUtils = AppConfigUtils.getInstance(context);
LogUtils.d(TAG, "getAppConfigUtils()AppConfigUtils实例已初始化");
}
return sAppConfigUtils;
}
/**
* 获取应用缓存工具实例
*/
public static AppCacheUtils getAppCacheUtils(Context context) {
LogUtils.d(TAG, "getAppCacheUtils() 调用传入Context" + context.getClass().getSimpleName());
if (sAppCacheUtils == null) {
sAppCacheUtils = AppCacheUtils.getInstance(context);
LogUtils.d(TAG, "getAppCacheUtils()AppCacheUtils实例已初始化");
}
return sAppCacheUtils;
}
/**
* 清除电池历史数据
*/
public void clearBatteryHistory() {
LogUtils.d(TAG, "clearBatteryHistory() 调用");
sAppCacheUtils.clearBatteryHistory();
}
// ===================== 生命周期方法区 =====================
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
LogUtils.d(TAG, "onCreate() 应用启动,开始初始化");
// 初始化调试模式
setIsDebugging(BuildConfig.DEBUG); setIsDebugging(BuildConfig.DEBUG);
LogUtils.d(TAG, "onCreate() 调试模式:" + BuildConfig.DEBUG);
// 初始化活动窗口管理 // 初始化基础工具
WinBoLLActivityManager.init(this); initBaseTools();
// 初始化 Toast 框架 // 初始化临时文件夹
ToastUtils.init(this); initTempDir();
// 初始化工具类实例
initUtils();
// 初始化广播接收器
initReceiver();
// 启动定时任务
initTimerTask();
// 临时文件夹初始化(保持原有逻辑) LogUtils.d(TAG, "onCreate() 应用初始化完成");
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File powerBellDir = new File(picturesDir, "PowerBell");
if (!powerBellDir.exists()) {
powerBellDir.mkdirs();
}
szTempDir = powerBellDir.getAbsolutePath();
// 设置数据配置存储工具
_mAppConfigUtils = getAppConfigUtils(this);
_mAppCacheUtils = getAppCacheUtils(this);
// 初始化全局 Bitmap 缓存工具关键App 启动时初始化,常驻内存)
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
mReceiver = new GlobalApplicationReceiver(this);
mReceiver.registerAction();
// ======================== 新增:异步预加载背景图 ========================
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 1. 获取背景源工具类实例
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(App.this);
if (bgSourceUtils == null) {
LogUtils.e(TAG, "preloadBitmap: BackgroundSourceUtils 实例为空");
return;
}
// 2. 获取当前背景Bean
BackgroundBean bgBean = bgSourceUtils.getCurrentBackgroundBean();
if (bgBean == null || !bgBean.isUseBackgroundFile()) {
LogUtils.d(TAG, "preloadBitmap: 无有效背景文件,跳过预加载");
return;
}
// 3. 获取背景图路径(优先取压缩图路径)
String bgPath = bgBean.isUseBackgroundScaledCompressFile()
? bgBean.getBackgroundScaledCompressFilePath()
: bgBean.getBackgroundFilePath();
// 4. 预加载到全局缓存
if (_mBitmapCacheUtils != null) {
_mBitmapCacheUtils.cacheBitmap(bgPath);
LogUtils.d(TAG, "preloadBitmap: 应用启动时预加载成功 - " + bgPath);
} else {
LogUtils.e(TAG, "preloadBitmap: 全局 BitmapCacheUtils 未初始化");
}
} catch (Exception e) {
LogUtils.e(TAG, "preloadBitmap: 预加载失败 - " + e.getMessage());
}
}
}).start();
}
}, 1000); // 延迟1秒执行避免阻塞应用初始化
// ======================== 预加载逻辑结束 ========================
}
// 保持原有方法不变
public static AppConfigUtils getAppConfigUtils(Context context) {
if (_mAppConfigUtils == null) {
_mAppConfigUtils = AppConfigUtils.getInstance(context);
}
return _mAppConfigUtils;
}
public static AppCacheUtils getAppCacheUtils(Context context) {
if (_mAppCacheUtils == null) {
_mAppCacheUtils = AppCacheUtils.getInstance(context);
}
return _mAppCacheUtils;
}
public void clearBatteryHistory() {
_mAppCacheUtils.clearBatteryHistory();
} }
@Override @Override
public void onTerminate() { public void onTerminate() {
super.onTerminate(); super.onTerminate();
LogUtils.d(TAG, "onTerminate() 应用终止,开始释放资源");
// 释放Toast工具
ToastUtils.release(); ToastUtils.release();
// 释放通知工具
releaseNotificationManager();
// 停止定时任务
stopTimerTask();
LogUtils.d(TAG, "onTerminate() 应用资源释放完成");
} }
@Override @Override
public void onTrimMemory(int level) { public void onTrimMemory(int level) {
super.onTrimMemory(level); super.onTrimMemory(level);
} LogUtils.d(TAG, "onTrimMemory() 调用内存等级level" + level);
// 初始化通知工具(若未初始化)
if (mNotificationManager == null) {
mNotificationManager = new NotificationManagerUtils(this);
LogUtils.d(TAG, "onTrimMemory()NotificationManagerUtils实例已初始化");
}
// 内存紧张等级判断
if (level > ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
sendTrimMemoryNotification(level);
} else {
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "onTrimMemory()Bitmap缓存已启用");
}
}
// ===================== 私有初始化方法区 =====================
/**
* 初始化基础工具Activity管理、Toast
*/
private void initBaseTools() {
LogUtils.d(TAG, "initBaseTools() 开始初始化基础工具");
WinBoLLActivityManager.init(this);
ToastUtils.init(this);
LogUtils.d(TAG, "initBaseTools() 基础工具初始化完成");
}
/**
* 初始化临时文件夹适配API 30外部存储访问
*/
private void initTempDir() {
LogUtils.d(TAG, "initTempDir() 开始初始化临时文件夹");
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File powerBellDir = new File(picturesDir, "PowerBell");
if (!powerBellDir.exists()) {
boolean isMkSuccess = powerBellDir.mkdirs();
LogUtils.d(TAG, "initTempDir() 文件夹创建结果:" + isMkSuccess);
}
sTempDirPath = powerBellDir.getAbsolutePath();
LogUtils.d(TAG, "initTempDir() 临时文件夹路径:" + sTempDirPath);
}
/**
* 初始化工具类实例
*/
private void initUtils() {
LogUtils.d(TAG, "initUtils() 开始初始化工具类");
sAppConfigUtils = getAppConfigUtils(this);
sAppCacheUtils = getAppCacheUtils(this);
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
mNotificationManager = new NotificationManagerUtils(this);
LogUtils.d(TAG, "initUtils() 工具类初始化完成");
}
/**
* 初始化广播接收器
*/
private void initReceiver() {
LogUtils.d(TAG, "initReceiver() 开始初始化广播接收器");
mGlobalReceiver = new GlobalApplicationReceiver(this);
mGlobalReceiver.registerAction();
LogUtils.d(TAG, "initReceiver() 广播接收器注册完成");
}
/**
* 初始化定时任务(全局唯一实例)
*/
private void initTimerTask() {
LogUtils.d(TAG, "initTimerTask() 开始初始化定时任务,当前运行状态:" + sIsTimerRunning);
// 已运行则直接返回
if (sIsTimerRunning) {
LogUtils.d(TAG, "initTimerTask() 定时任务已在运行,无需重复启动");
return;
}
// 初始化Handler
if (sTimerHandler == null) {
sTimerHandler = new Handler(Looper.getMainLooper());
LogUtils.d(TAG, "initTimerTask() 定时任务Handler已初始化");
}
// 初始化Runnable
if (sTimerRunnable == null) {
sTimerRunnable = new Runnable() {
@Override
public void run() {
try {
LogUtils.d(TAG, "定时任务执行,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
sBitmapCacheUtils = BitmapCacheUtils.getInstance();
LogUtils.d(TAG, "定时任务Bitmap缓存已重新初始化");
} catch (Exception e) {
LogUtils.e(TAG, "定时任务执行异常:" + e.getMessage());
} finally {
if (sIsTimerRunning) {
long delayMillis = TimeUnit.MINUTES.toMillis(TIMER_INTERVAL_MINUTES);
sTimerHandler.postDelayed(this, delayMillis);
LogUtils.d(TAG, "定时任务已预约下次执行,延迟:" + delayMillis + "ms");
}
}
}
};
LogUtils.d(TAG, "initTimerTask() 定时任务Runnable已初始化");
}
// 启动任务
sTimerHandler.post(sTimerRunnable);
sIsTimerRunning = true;
LogUtils.d(TAG, "initTimerTask() 定时任务已启动,间隔:" + TIMER_INTERVAL_MINUTES + "分钟");
}
// ===================== 私有工具方法区 =====================
/**
* 停止定时任务
*/
private void stopTimerTask() {
LogUtils.d(TAG, "stopTimerTask() 开始停止定时任务");
if (sTimerHandler != null && sTimerRunnable != null) {
sTimerHandler.removeCallbacks(sTimerRunnable);
sIsTimerRunning = false;
LogUtils.d(TAG, "stopTimerTask() 定时任务已停止运行状态重置为false");
} else {
LogUtils.d(TAG, "stopTimerTask() 定时任务未初始化,无需停止");
}
}
/**
* 释放通知管理工具资源
*/
private void releaseNotificationManager() {
LogUtils.d(TAG, "releaseNotificationManager() 开始释放通知工具");
if (mNotificationManager != null) {
mNotificationManager.release();
mNotificationManager = null;
LogUtils.d(TAG, "releaseNotificationManager() 通知工具资源已释放");
} else {
LogUtils.d(TAG, "releaseNotificationManager() 通知工具未初始化,无需释放");
}
}
/**
* 发送内存紧张通知
*/
private void sendTrimMemoryNotification(int level) {
LogUtils.d(TAG, "sendTrimMemoryNotification() 调用内存等级level" + level);
NotificationMessage message = new NotificationMessage();
message.setTitle(TRIM_MEMORY_NOTIFY_TITLE);
String content = String.format("%s [ 缓存紧张级别描述: Level %d | %s ]",
TRIM_MEMORY_NOTIFY_CONTENT, level, getTrimMemoryLevelDesc(level));
message.setContent(content);
mNotificationManager.showConfigNotification(this, message);
LogUtils.d(TAG, "sendTrimMemoryNotification() 内存紧张通知已发送,内容:" + content);
}
/**
* 转换内存等级为可读描述
*/
private String getTrimMemoryLevelDesc(int level) {
LogUtils.d(TAG, "getTrimMemoryLevelDesc() 调用传入level" + level);
String desc;
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
desc = "TRIM_MEMORY_COMPLETE应用内存完全紧张";
break;
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
desc = "MODERATE中等内存紧张";
break;
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
desc = "BACKGROUND应用进入后台";
break;
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
desc = "BACKGROUND应用UI隐藏";
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
desc = "RUNNING_CRITICAL应用运行关键级紧张";
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
desc = "RUNNING_LOW应用运行低内存";
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
desc = "RUNNING_MODERATE应用运行中等内存紧张";
break;
default:
desc = "UNKNOWN(" + level + ")";
break;
}
LogUtils.d(TAG, "getTrimMemoryLevelDesc() 内存等级描述结果:" + desc);
return desc;
}
} }

View File

@@ -41,14 +41,11 @@ import cc.winboll.studio.powerbell.views.MainContentView;
* 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步 * 适配Java7 | API30 | 内存泄漏防护 | UI与服务状态实时同步
*/ */
public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener { public class MainActivity extends WinBoLLActivity implements MainContentView.OnViewActionListener {
// ======================== 静态常量(置顶统一,抽离魔法值,便于维护)========================
public static final String TAG = "MainActivity";
// 请求码常量 // ======================== 静态常量(置顶统一,抽离魔法值)========================
public static final String TAG = "MainActivity";
private static final int REQUEST_READ_MEDIA_IMAGES = 1001; private static final int REQUEST_READ_MEDIA_IMAGES = 1001;
// 延迟加载常量(非核心视图延迟加载时长)
private static final long DELAY_LOAD_NON_CRITICAL = 500L; private static final long DELAY_LOAD_NON_CRITICAL = 500L;
// Handler消息标识按业务优先级排序
public static final int MSG_RELOAD_APPCONFIG = 0; public static final int MSG_RELOAD_APPCONFIG = 0;
public static final int MSG_CURRENTVALUEBATTERY = 1; public static final int MSG_CURRENTVALUEBATTERY = 1;
public static final int MSG_LOAD_BACKGROUND = 2; public static final int MSG_LOAD_BACKGROUND = 2;
@@ -75,7 +72,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
private Drawable mFrameDrawable; private Drawable mFrameDrawable;
private Menu mMenu; private Menu mMenu;
// ======================== 生命周期方法(按系统调用顺序排列,逻辑闭环======================== // ======================== 生命周期方法(按系统调用顺序排列)========================
@Override @Override
public Activity getActivity() { public Activity getActivity() {
return this; return this;
@@ -88,12 +85,10 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreate: 页面启动,开始初始化流程 | savedInstanceState=" + savedInstanceState);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate() | savedInstanceState=" + savedInstanceState);
// 优先初始化全局Handler避免消息丢失
initGlobalHandler(); initGlobalHandler();
// 布局与核心流程初始化
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
initPermissionUtils(); initPermissionUtils();
initMainContentView(); initMainContentView();
@@ -105,62 +100,56 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
protected void onPostCreate(Bundle savedInstanceState) { protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState); super.onPostCreate(savedInstanceState);
LogUtils.d(TAG, "onPostCreate: 发起权限申请"); LogUtils.d(TAG, "onPostCreate() | savedInstanceState=" + savedInstanceState);
mPermissionUtils.startPermissionRequest(this); mPermissionUtils.startPermissionRequest(this);
LogUtils.d(TAG, "onPostCreate: 发起权限申请");
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
LogUtils.d(TAG, "onResume: 恢复页面状态"); LogUtils.d(TAG, "onResume()");
// 恢复背景与服务开关UI
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
LogUtils.d(TAG, "onResume: 发送背景加载与服务开关更新消息");
} }
// 恢复广告
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.resumeADs(this); mADsBannerView.resumeADs(this);
LogUtils.d(TAG, "onResume: 广告视图恢复展示");
} }
} }
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
LogUtils.d(TAG, "onPause: 页面暂停"); LogUtils.d(TAG, "onPause()");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
LogUtils.d(TAG, "onDestroy: 开始释放资源"); LogUtils.d(TAG, "onDestroy()");
// 释放广告资源 // 释放广告资源
if (mADsBannerView != null) { if (mADsBannerView != null) {
mADsBannerView.releaseAdResources(); mADsBannerView.releaseAdResources();
mADsBannerView = null; mADsBannerView = null;
LogUtils.d(TAG, "onDestroy: 广告资源已释放");
} }
// 释放核心视图 // 释放核心视图
if (mMainContentView != null) { if (mMainContentView != null) {
mMainContentView.releaseResources(); mMainContentView.releaseResources();
mMainContentView = null; mMainContentView = null;
LogUtils.d(TAG, "onDestroy: 核心视图资源已释放");
} }
// 销毁Handler防止内存泄漏 // 销毁Handler防止内存泄漏
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.removeCallbacksAndMessages(null); sGlobalHandler.removeCallbacksAndMessages(null);
sGlobalHandler = null; sGlobalHandler = null;
LogUtils.d(TAG, "onDestroy: 全局Handler已销毁");
} }
// 释放Drawable,清空回调 // 释放Drawable
if (mFrameDrawable != null) { if (mFrameDrawable != null) {
mFrameDrawable.setCallback(null); mFrameDrawable.setCallback(null);
mFrameDrawable = null; mFrameDrawable = null;
LogUtils.d(TAG, "onDestroy: 框架背景Drawable已释放");
} }
// 置空所有引用帮助GC回收 // 置空所有引用
sMainActivity = null; sMainActivity = null;
mPermissionUtils = null; mPermissionUtils = null;
mAppConfigUtils = null; mAppConfigUtils = null;
@@ -170,31 +159,27 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
mApplication = null; mApplication = null;
mToolbar = null; mToolbar = null;
mAdsViewStub = null; mAdsViewStub = null;
LogUtils.d(TAG, "onDestroy: 所有资源释放完成");
} }
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
LogUtils.d(TAG, "onActivityResult: requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data); LogUtils.d(TAG, "onActivityResult() | requestCode=" + requestCode + " | resultCode=" + resultCode + " | data=" + data);
mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data); mPermissionUtils.handlePermissionRequest(this, requestCode, resultCode, data);
// 背景设置完成后重新加载
if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) { if (requestCode == REQUEST_READ_MEDIA_IMAGES && sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND); sGlobalHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
LogUtils.d(TAG, "onActivityResult: 背景设置完成,发送重新加载消息");
} }
} }
// ======================== 菜单与导航方法 ======================== // ======================== 菜单与导航方法 ========================
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
LogUtils.d(TAG, "onCreateOptionsMenu: 初始化菜单"); LogUtils.d(TAG, "onCreateOptionsMenu() | menu=" + menu);
mMenu = menu; mMenu = menu;
AESThemeUtil.inflateMenu(this, menu); AESThemeUtil.inflateMenu(this, menu);
if (App.isDebugging()) { if (App.isDebugging()) {
DevelopUtils.inflateMenu(this, menu); DevelopUtils.inflateMenu(this, menu);
getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu); getMenuInflater().inflate(R.menu.toolbar_unittest, mMenu);
LogUtils.d(TAG, "onCreateOptionsMenu: 调试模式,加载单元测试菜单");
} }
getMenuInflater().inflate(R.menu.toolbar_main, mMenu); getMenuInflater().inflate(R.menu.toolbar_main, mMenu);
return true; return true;
@@ -202,7 +187,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
LogUtils.d(TAG, "onOptionsItemSelected: 菜单点击 | itemId=" + item.getItemId()); LogUtils.d(TAG, "onOptionsItemSelected() | itemId=" + item.getItemId());
if (AESThemeUtil.onAppThemeItemSelected(this, item)) { if (AESThemeUtil.onAppThemeItemSelected(this, item)) {
recreate(); recreate();
return true; return true;
@@ -213,27 +198,21 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_settings: case R.id.action_settings:
startActivity(new Intent(this, SettingsActivity.class)); startActivity(new Intent(this, SettingsActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转设置页面");
break; break;
case R.id.action_battery_report: case R.id.action_battery_report:
startActivity(new Intent(this, BatteryReportActivity.class)); startActivity(new Intent(this, BatteryReportActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转电池报告页面");
break; break;
case R.id.action_clearrecord: case R.id.action_clearrecord:
startActivity(new Intent(this, ClearRecordActivity.class)); startActivity(new Intent(this, ClearRecordActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转记录清理页面");
break; break;
case R.id.action_changepicture: case R.id.action_changepicture:
startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES); startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES);
LogUtils.d(TAG, "onOptionsItemSelected: 跳转背景设置页面 | requestCode=" + REQUEST_READ_MEDIA_IMAGES);
break; break;
case R.id.action_unittestactivity: case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class)); startActivity(new Intent(this, MainUnitTestActivity.class));
LogUtils.d(TAG, "onOptionsItemSelected: 跳转单元测试页面");
break; break;
case R.id.action_about: case R.id.action_about:
startAboutActivity(); startAboutActivity();
LogUtils.d(TAG, "onOptionsItemSelected: 跳转关于页面");
break; break;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@@ -244,41 +223,41 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void setupToolbar() { public void setupToolbar() {
super.setupToolbar(); super.setupToolbar();
LogUtils.d(TAG, "setupToolbar()");
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
LogUtils.d(TAG, "setupToolbar: 隐藏返回按钮");
} }
} }
@Override @Override
public void onBackPressed() { public void onBackPressed() {
LogUtils.d(TAG, "onBackPressed()");
moveTaskToBack(true); moveTaskToBack(true);
LogUtils.d(TAG, "onBackPressed: 应用退至后台");
} }
@Override @Override
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
LogUtils.d(TAG, "dispatchKeyEvent() | event=" + event);
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
// ======================== 核心初始化方法 ======================== // ======================== 核心初始化方法 ========================
private void initPermissionUtils() { private void initPermissionUtils() {
LogUtils.d(TAG, "initPermissionUtils: 初始化权限工具类"); LogUtils.d(TAG, "initPermissionUtils()");
mPermissionUtils = PermissionUtils.getInstance(); mPermissionUtils = PermissionUtils.getInstance();
} }
private void initGlobalHandler() { private void initGlobalHandler() {
LogUtils.d(TAG, "initGlobalHandler: 初始化全局Handler"); LogUtils.d(TAG, "initGlobalHandler()");
if (sGlobalHandler == null) { if (sGlobalHandler == null) {
sGlobalHandler = new Handler() { sGlobalHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
// 校验Activity状态避免销毁后操作UI
if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) { if (sMainActivity == null || sMainActivity.isFinishing() || sMainActivity.isDestroyed()) {
LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what=" + msg.what); LogUtils.w(TAG, "handleMessage: Activity已销毁跳过消息 | what=" + msg.what);
return; return;
} }
LogUtils.d(TAG, "handleMessage: 处理消息 | what=" + msg.what); LogUtils.d(TAG, "handleMessage() | what=" + msg.what);
switch (msg.what) { switch (msg.what) {
case MSG_RELOAD_APPCONFIG: case MSG_RELOAD_APPCONFIG:
sMainActivity.updateViewData(); sMainActivity.updateViewData();
@@ -299,30 +278,28 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
} }
}; };
LogUtils.d(TAG, "initGlobalHandler: 全局Handler创建成功");
} }
} }
private void initMainContentView() { private void initMainContentView() {
LogUtils.d(TAG, "initMainContentView: 初始化核心视图"); LogUtils.d(TAG, "initMainContentView()");
View rootView = findViewById(android.R.id.content); View rootView = findViewById(android.R.id.content);
mMainContentView = new MainContentView(this, rootView, this); mMainContentView = new MainContentView(this, rootView, this);
} }
private void initCriticalView() { private void initCriticalView() {
LogUtils.d(TAG, "initCriticalView: 初始化关键视图组件"); LogUtils.d(TAG, "initCriticalView()");
sMainActivity = this; sMainActivity = this;
mToolbar = findViewById(R.id.toolbar); mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar); setSupportActionBar(mToolbar);
if (mToolbar != null) { if (mToolbar != null) {
mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
LogUtils.d(TAG, "initCriticalView: Toolbar样式设置完成");
} }
mAdsViewStub = findViewById(R.id.stub_ads_banner); mAdsViewStub = findViewById(R.id.stub_ads_banner);
} }
private void initCoreUtilsAsync() { private void initCoreUtilsAsync() {
LogUtils.d(TAG, "initCoreUtilsAsync: 异步初始化核心工具类"); LogUtils.d(TAG, "initCoreUtilsAsync()");
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -336,7 +313,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
mServiceControlBean = new ControlCenterServiceBean(false); mServiceControlBean = new ControlCenterServiceBean(false);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "initCoreUtilsAsync: 本地无配置,创建默认禁用配置");
} }
// 根据配置启停服务 // 根据配置启停服务
@@ -348,7 +324,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void run() { public void run() {
ControlCenterService.startControlCenterService(getApplicationContext()); ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 配置启用服务,启动服务");
} }
}); });
} else if (!isServiceEnable && isServiceAlive) { } else if (!isServiceEnable && isServiceAlive) {
@@ -356,7 +331,6 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
@Override @Override
public void run() { public void run() {
ControlCenterService.stopControlCenterService(getApplicationContext()); ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "initCoreUtilsAsync: 配置禁用服务,停止服务");
} }
}); });
} }
@@ -380,13 +354,12 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
} }
}); });
LogUtils.d(TAG, "initCoreUtilsAsync: 异步线程执行完成");
} }
}).start(); }).start();
} }
private void loadNonCriticalViewDelayed() { private void loadNonCriticalViewDelayed() {
LogUtils.d(TAG, "loadNonCriticalViewDelayed: 延迟加载非核心视图 | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms"); LogUtils.d(TAG, "loadNonCriticalViewDelayed() | 延迟时长=" + DELAY_LOAD_NON_CRITICAL + "ms");
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -401,7 +374,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 视图操作方法 ======================== // ======================== 视图操作方法 ========================
private void loadAdsView() { private void loadAdsView() {
LogUtils.d(TAG, "loadAdsView: 加载广告视图"); LogUtils.d(TAG, "loadAdsView()");
if (mAdsViewStub == null) { if (mAdsViewStub == null) {
LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空加载失败"); LogUtils.e(TAG, "loadAdsView: 广告ViewStub为空加载失败");
return; return;
@@ -409,22 +382,20 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
if (mADsBannerView == null) { if (mADsBannerView == null) {
View adsView = mAdsViewStub.inflate(); View adsView = mAdsViewStub.inflate();
mADsBannerView = adsView.findViewById(R.id.adsbanner); mADsBannerView = adsView.findViewById(R.id.adsbanner);
LogUtils.d(TAG, "loadAdsView: 广告视图创建成功");
} }
} }
private void updateViewData() { private void updateViewData() {
LogUtils.d(TAG, "updateViewData: 更新视图数据"); LogUtils.d(TAG, "updateViewData()");
if (mMainContentView == null || mFrameDrawable == null) { if (mMainContentView == null || mFrameDrawable == null) {
LogUtils.e(TAG, "updateViewData: 核心视图或框架背景为空,更新失败"); LogUtils.e(TAG, "updateViewData: 核心视图或框架背景为空,更新失败");
return; return;
} }
mMainContentView.updateViewData(mFrameDrawable); mMainContentView.updateViewData(mFrameDrawable);
LogUtils.d(TAG, "updateViewData: 视图数据更新完成");
} }
private void reloadBackground() { private void reloadBackground() {
LogUtils.d(TAG, "reloadBackground: 重新加载背景"); LogUtils.d(TAG, "reloadBackground()");
if (mMainContentView == null || mBgSourceUtils == null) { if (mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "reloadBackground: 核心视图或背景工具类为空,加载失败"); LogUtils.e(TAG, "reloadBackground: 核心视图或背景工具类为空,加载失败");
return; return;
@@ -432,15 +403,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean(); BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) { if (currentBgBean != null) {
mMainContentView.backgroundView.loadBackgroundBean(currentBgBean); mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
LogUtils.d(TAG, "reloadBackground: 加载自定义背景成功");
} else { } else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background); mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
LogUtils.w(TAG, "reloadBackground: 无自定义背景,使用默认背景");
} }
} }
private void setMainLayoutBackgroundColor() { private void setMainLayoutBackgroundColor() {
LogUtils.d(TAG, "setMainLayoutBackgroundColor: 设置主布局背景色"); LogUtils.d(TAG, "setMainLayoutBackgroundColor()");
if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) { if (isFinishing() || isDestroyed() || mMainContentView == null || mBgSourceUtils == null) {
LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败"); LogUtils.e(TAG, "setMainLayoutBackgroundColor: 上下文无效,设置失败");
return; return;
@@ -453,41 +422,34 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
private void updateServiceSwitchUI() { private void updateServiceSwitchUI() {
LogUtils.d(TAG, "updateServiceSwitchUI: 更新服务开关UI状态"); LogUtils.d(TAG, "updateServiceSwitchUI()");
if (mMainContentView == null || mServiceControlBean == null) { if (mMainContentView == null || mServiceControlBean == null) {
LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图或服务配置为空,更新失败"); LogUtils.e(TAG, "updateServiceSwitchUI: 核心视图或服务配置为空,更新失败");
return; return;
} }
boolean configEnabled = mServiceControlBean.isEnableService(); boolean configEnabled = mServiceControlBean.isEnableService();
LogUtils.d(TAG, "updateServiceSwitchUI: 服务配置启用状态=" + configEnabled);
mMainContentView.setServiceSwitchEnabled(false); mMainContentView.setServiceSwitchEnabled(false);
mMainContentView.setServiceSwitchChecked(configEnabled); mMainContentView.setServiceSwitchChecked(configEnabled);
mMainContentView.setServiceSwitchEnabled(true); mMainContentView.setServiceSwitchEnabled(true);
LogUtils.d(TAG, "updateServiceSwitchUI: 服务开关UI状态更新完成");
} }
// ======================== 服务与线程管理方法 ======================== // ======================== 服务与线程管理方法 ========================
private void toggleServiceEnableState(boolean isEnable) { private void toggleServiceEnableState(boolean isEnable) {
LogUtils.d(TAG, "toggleServiceEnableState: 切换服务状态 | 目标状态=" + isEnable); LogUtils.d(TAG, "toggleServiceEnableState() | 目标状态=" + isEnable);
if (mServiceControlBean == null) { if (mServiceControlBean == null) {
LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败"); LogUtils.e(TAG, "toggleServiceEnableState: 服务配置为空,切换失败");
return; return;
} }
mServiceControlBean.setIsEnableService(isEnable); mServiceControlBean.setIsEnableService(isEnable);
ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean); ControlCenterServiceBean.saveBean(getApplicationContext(), mServiceControlBean);
LogUtils.d(TAG, "toggleServiceEnableState: 服务配置已保存");
// UI开关联动服务启停 // UI开关联动服务启停
if (isEnable) { if (isEnable) {
// 开启:启动服务
if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) { if (!ServiceUtils.isServiceAlive(getApplicationContext(), ControlCenterService.class.getName())) {
ControlCenterService.startControlCenterService(getApplicationContext()); ControlCenterService.startControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已启动");
} }
} else { } else {
// 关闭:停止服务
ControlCenterService.stopControlCenterService(getApplicationContext()); ControlCenterService.stopControlCenterService(getApplicationContext());
LogUtils.d(TAG, "toggleServiceEnableState: 服务已停止");
} }
sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH); sGlobalHandler.sendEmptyMessage(MSG_UPDATE_SERVICE_SWITCH);
@@ -495,7 +457,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 页面跳转方法 ======================== // ======================== 页面跳转方法 ========================
private void startAboutActivity() { private void startAboutActivity() {
LogUtils.d(TAG, "startAboutActivity: 启动关于页面"); LogUtils.d(TAG, "startAboutActivity()");
Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class); Intent aboutIntent = new Intent(getApplicationContext(), AboutActivity.class);
APPInfo appInfo = genDefaultAppInfo(); APPInfo appInfo = genDefaultAppInfo();
aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo); aboutIntent.putExtra(AboutActivity.EXTRA_APPINFO, appInfo);
@@ -504,14 +466,13 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 消息发送方法 ======================== // ======================== 消息发送方法 ========================
private void notifyServiceAppConfigChange() { private void notifyServiceAppConfigChange() {
LogUtils.d(TAG, "notifyServiceAppConfigChange: 通知服务配置变更"); LogUtils.d(TAG, "notifyServiceAppConfigChange()");
ControlCenterService.sendAppConfigStatusUpdateMessage(this); ControlCenterService.sendAppConfigStatusUpdateMessage(this);
reloadAppConfig(); reloadAppConfig();
} }
// ======================== 静态工具方法 ========================
public static void reloadAppConfig() { public static void reloadAppConfig() {
LogUtils.d(TAG, "reloadAppConfig: 发送配置重载消息"); LogUtils.d(TAG, "reloadAppConfig()");
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG); sGlobalHandler.sendEmptyMessage(MSG_RELOAD_APPCONFIG);
} else { } else {
@@ -520,7 +481,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
} }
public static void sendCurrentBatteryValueMessage(int value) { public static void sendCurrentBatteryValueMessage(int value) {
LogUtils.d(TAG, "sendCurrentBatteryValueMessage: 发送当前电量消息 | 电量=" + value); LogUtils.d(TAG, "sendCurrentBatteryValueMessage() | 电量=" + value);
if (sGlobalHandler != null) { if (sGlobalHandler != null) {
Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY); Message msg = sGlobalHandler.obtainMessage(MSG_CURRENTVALUEBATTERY);
msg.arg1 = value; msg.arg1 = value;
@@ -532,7 +493,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== 辅助工具方法 ======================== // ======================== 辅助工具方法 ========================
private APPInfo genDefaultAppInfo() { private APPInfo genDefaultAppInfo() {
LogUtils.d(TAG, "genDefaultAppInfo: 生成默认应用信息"); LogUtils.d(TAG, "genDefaultAppInfo()");
String branchName = "powerbell"; String branchName = "powerbell";
APPInfo appInfo = new APPInfo(); APPInfo appInfo = new APPInfo();
appInfo.setAppName(getString(R.string.app_name)); appInfo.setAppName(getString(R.string.app_name));
@@ -551,31 +512,31 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
// ======================== MainContentView 事件回调 ======================== // ======================== MainContentView 事件回调 ========================
@Override @Override
public void onChargeReminderSwitchChanged(boolean isChecked) { public void onChargeReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onChargeReminderSwitchChanged: 充电提醒开关状态变更 | isChecked=" + isChecked); LogUtils.d(TAG, "onChargeReminderSwitchChanged() | isChecked=" + isChecked);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderSwitchChanged(boolean isChecked) { public void onUsageReminderSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onUsageReminderSwitchChanged: 耗电提醒开关状态变更 | isChecked=" + isChecked); LogUtils.d(TAG, "onUsageReminderSwitchChanged() | isChecked=" + isChecked);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onServiceSwitchChanged(boolean isChecked) { public void onServiceSwitchChanged(boolean isChecked) {
LogUtils.d(TAG, "onServiceSwitchChanged: 服务总开关状态变更 | isChecked=" + isChecked); LogUtils.d(TAG, "onServiceSwitchChanged() | isChecked=" + isChecked);
toggleServiceEnableState(isChecked); toggleServiceEnableState(isChecked);
} }
@Override @Override
public void onChargeReminderProgressChanged(int progress) { public void onChargeReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onChargeReminderProgressChanged: 充电提醒阈值变更 | progress=" + progress); LogUtils.d(TAG, "onChargeReminderProgressChanged() | progress=" + progress);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
@Override @Override
public void onUsageReminderProgressChanged(int progress) { public void onUsageReminderProgressChanged(int progress) {
LogUtils.d(TAG, "onUsageReminderProgressChanged: 耗电提醒阈值变更 | progress=" + progress); LogUtils.d(TAG, "onUsageReminderProgressChanged() | progress=" + progress);
notifyServiceAppConfigChange(); notifyServiceAppConfigChange();
} }
} }

View File

@@ -21,6 +21,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import cc.winboll.studio.powerbell.utils.ImageDownloader; import cc.winboll.studio.powerbell.utils.ImageDownloader;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import android.text.TextUtils;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
@@ -52,7 +53,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
// 按钮点击回调接口Java7 接口实现) // 按钮点击回调接口Java7 接口实现)
public interface OnDialogClickListener { public interface OnDialogClickListener {
void onConfirm(String szConfirmFilePath, String previewFileUrl); // 确认按钮点击 void onConfirm(String szConfirmFilePath); // 确认按钮点击
void onCancel(); // 取消按钮点击 void onCancel(); // 取消按钮点击
} }
@@ -91,7 +92,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
case MSG_IMAGE_LOAD_SUCCESS: case MSG_IMAGE_LOAD_SUCCESS:
// 图片加载成功,获取文件路径并设置背景 // 图片加载成功,获取文件路径并设置背景
mDownloadSavedPath = (String) msg.obj; mDownloadSavedPath = (String) msg.obj;
previewBackground(mDownloadSavedPath); mBackgroundView.loadImage(mDownloadSavedPath);
break; break;
case MSG_IMAGE_LOAD_FAILED: case MSG_IMAGE_LOAD_FAILED:
// 图片加载失败,设置默认背景 // 图片加载失败,设置默认背景
@@ -139,7 +140,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
etURL = (EditText) dialogView.findViewById(R.id.et_url); etURL = (EditText) dialogView.findViewById(R.id.et_url);
mBackgroundView = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview); mBackgroundView = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview);
// 加载初始图片 // 加载初始图片
mBackgroundView.setBackgroundResource(R.drawable.ic_launcher); mBackgroundView.setBackgroundResource(R.drawable.blank100x100);
// 设置按钮点击事件 // 设置按钮点击事件
setButtonClickListeners(); setButtonClickListeners();
} }
@@ -168,13 +169,13 @@ public class NetworkBackgroundDialog extends AlertDialog {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认按钮点击"); LogUtils.d("NetworkBackgroundDialog", "确认按钮点击");
// 确定预览背景资源
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
dismiss(); // 关闭对话框 dismiss(); // 关闭对话框
if(TextUtils.isEmpty(mDownloadSavedPath)) {
ToastUtils.show("未下载图片。");
return;
}
if (listener != null) { if (listener != null) {
listener.onConfirm(mPreviewFilePath, mPreviewFileUrl); listener.onConfirm(mDownloadSavedPath);
} }
} }
}); });
@@ -258,6 +259,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
// 发送消息到主线程,携带图片路径 // 发送消息到主线程,携带图片路径
Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath); Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath);
mUiHandler.sendMessage(successMsg); mUiHandler.sendMessage(successMsg);
} }
@Override @Override

View File

@@ -222,10 +222,14 @@ public class RemindThread extends Thread {
} else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) { } else if (!isCharging && isEnableUsageReminder && quantityOfElectricity <= usageReminderValue) {
LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + " ≤ 阈值=" + usageReminderValue + " | threadId=" + getId()); LogUtils.d(TAG, "触发耗电提醒 | 当前电量=" + quantityOfElectricity + " ≤ 阈值=" + usageReminderValue + " | threadId=" + getId());
sendNotificationMessageInternal(REMIND_TYPE_USAGE, quantityOfElectricity, isCharging); sendNotificationMessageInternal(REMIND_TYPE_USAGE, quantityOfElectricity, isCharging);
} } else {
// 未有合适类型提醒,退出提醒线程
// 安全休眠,保留中断标记 LogUtils.d(TAG, "未有合适类型提醒,退出提醒线程");
break;
}
// 安全休眠,保留中断标记
safeSleepInternal(sleepTime); safeSleepInternal(sleepTime);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "循环运行异常,退出电量提醒线程 | 当前电量=" + quantityOfElectricity + " | threadId=" + getId(), e); LogUtils.e(TAG, "循环运行异常,退出电量提醒线程 | 当前电量=" + quantityOfElectricity + " | threadId=" + getId(), e);
break; break;

View File

@@ -1,6 +1,7 @@
package cc.winboll.studio.powerbell.utils; package cc.winboll.studio.powerbell.utils;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.media.ExifInterface; import android.media.ExifInterface;
import android.net.Uri; import android.net.Uri;
@@ -11,6 +12,7 @@ import androidx.core.content.FileProvider;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.BuildConfig; import cc.winboll.studio.powerbell.BuildConfig;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.BackgroundBean;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
@@ -181,37 +183,42 @@ public class BackgroundSourceUtils {
/** /**
* 检查背景是否为空并创建空白背景Bean * 检查背景是否为空并创建空白背景Bean
*/ */
boolean checkEmptyBackgroundAndCreateBlankBackgroundBean(BackgroundBean checkBackgroundBean) { public boolean checkEmptyBackgroundAndCreateBlankBackgroundBean(BackgroundBean checkBackgroundBean) {
LogUtils.d(TAG, "【checkEmptyBackgroundAndCreateBlankBackgroundBean调用】开始检查背景Bean"); LogUtils.d(TAG, "【checkEmptyBackgroundAndCreateBlankBackgroundBean调用】开始检查背景Bean");
File fCheckBackgroundFile = new File(checkBackgroundBean.getBackgroundFilePath()); File fCheckBackgroundFile = new File(checkBackgroundBean.getBackgroundFilePath());
if (!fCheckBackgroundFile.exists()) { if (!fCheckBackgroundFile.exists()) {
String newCropFileName = genNewCropFileName(); return createBlankBackgroundBean(checkBackgroundBean.getPixelColor());
String fileSuffix = "png";
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
AssetsCopyUtils.copyAssetsFileToDir(mContext, "images/blank10x10.png", mCropSourceFile.getAbsolutePath());
try {
mCropResultFile.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
loadSettings();
previewBackgroundBean.setIsUseBackgroundFile(true);
previewBackgroundBean.setIsUseBackgroundScaledCompressFile(false);
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
previewBackgroundBean.setBackgroundFilePath(mCropSourceFile.getAbsolutePath());
previewBackgroundBean.setBackgroundScaledCompressFileName(mCropResultFile.getName());
previewBackgroundBean.setBackgroundScaledCompressFilePath(mCropResultFile.getAbsolutePath());
saveSettings();
LogUtils.d(TAG, "背景Bean为空已创建空白背景并更新配置");
return true;
} }
LogUtils.d(TAG, "背景Bean文件存在无需创建空白背景"); LogUtils.d(TAG, "背景Bean文件存在无需创建空白背景");
return false; return false;
} }
public boolean createBlankBackgroundBean(int nBackgroundPixelColor) {
String newCropFileName = genNewCropFileName();
String fileSuffix = "png";
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
AssetsCopyUtils.copyAssetsFileToDir(mContext, "images/blank100x100.png", mCropSourceFile.getAbsolutePath());
try {
mCropResultFile.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
loadSettings();
previewBackgroundBean.setPixelColor(nBackgroundPixelColor);
previewBackgroundBean.setIsUseBackgroundFile(true);
previewBackgroundBean.setIsUseBackgroundScaledCompressFile(false);
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
previewBackgroundBean.setBackgroundFilePath(mCropSourceFile.getAbsolutePath());
previewBackgroundBean.setBackgroundScaledCompressFileName(mCropResultFile.getName());
previewBackgroundBean.setBackgroundScaledCompressFilePath(mCropResultFile.getAbsolutePath());
saveSettings();
LogUtils.d(TAG, "背景Bean为空已创建空白背景并更新配置");
return true;
}
String genNewCropFileName() { String genNewCropFileName() {
return UUID.randomUUID().toString() + System.currentTimeMillis(); return UUID.randomUUID().toString() + System.currentTimeMillis();
} }

View File

@@ -20,9 +20,9 @@ import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.models.NotificationMessage; import cc.winboll.studio.powerbell.models.NotificationMessage;
/** /**
* 通知工具类:统一管理前台服务/电池提醒通知 * 通知工具类:统一管理前台服务/电池提醒/应用配置信息通知
* 适配API19-30 | Java7 | 小米手机 * 适配API19-30 | Java7 | 小米手机
* 特性前台服务无铃声、提醒通知系统默认铃声、API分级适配、内存泄漏防护 * 特性:前台服务无铃声、提醒通知系统默认铃声、配置通知低优先级无打扰、API分级适配、内存泄漏防护
*/ */
public class NotificationManagerUtils { public class NotificationManagerUtils {
// ================================== 静态常量(置顶统一管理,杜绝魔法值)================================= // ================================== 静态常量(置顶统一管理,杜绝魔法值)=================================
@@ -30,9 +30,11 @@ public class NotificationManagerUtils {
// 通知渠道IDAPI26+ 必需,区分通知类型) // 通知渠道IDAPI26+ 必需,区分通知类型)
public static final String CHANNEL_ID_FOREGROUND = "cc.winboll.studio.powerbell.channel.foreground"; public static final String CHANNEL_ID_FOREGROUND = "cc.winboll.studio.powerbell.channel.foreground";
public static final String CHANNEL_ID_REMIND = "cc.winboll.studio.powerbell.channel.remind"; public static final String CHANNEL_ID_REMIND = "cc.winboll.studio.powerbell.channel.remind";
public static final String CHANNEL_ID_CONFIG = "cc.winboll.studio.powerbell.channel.config"; // 新增:应用配置信息渠道
// 通知ID唯一标识避免重复 // 通知ID唯一标识避免重复
public static final int NOTIFY_ID_FOREGROUND_SERVICE = 1001; public static final int NOTIFY_ID_FOREGROUND_SERVICE = 1001;
public static final int NOTIFY_ID_REMIND = 1002; public static final int NOTIFY_ID_REMIND = 1002;
public static final int NOTIFY_ID_CONFIG = 1003; // 新增应用配置信息通知ID
// 低版本兼容默认通知图标API<21 避免显示异常) // 低版本兼容默认通知图标API<21 避免显示异常)
private static final int NOTIFICATION_DEFAULT_ICON = R.drawable.ic_launcher; private static final int NOTIFICATION_DEFAULT_ICON = R.drawable.ic_launcher;
// 通知内容兜底常量 // 通知内容兜底常量
@@ -40,9 +42,12 @@ public class NotificationManagerUtils {
private static final String FOREGROUND_NOTIFY_CONTENT_DEFAULT = "后台监测电池状态"; private static final String FOREGROUND_NOTIFY_CONTENT_DEFAULT = "后台监测电池状态";
private static final String REMIND_NOTIFY_TITLE_DEFAULT = "电池状态提醒"; private static final String REMIND_NOTIFY_TITLE_DEFAULT = "电池状态提醒";
private static final String REMIND_NOTIFY_CONTENT_DEFAULT = "电池状态异常,请及时处理"; private static final String REMIND_NOTIFY_CONTENT_DEFAULT = "电池状态异常,请及时处理";
private static final String CONFIG_NOTIFY_TITLE_DEFAULT = "应用配置更新"; // 新增:配置通知默认标题
private static final String CONFIG_NOTIFY_CONTENT_DEFAULT = "配置信息已更新,生效中"; // 新增:配置通知默认内容
// PendingIntent请求码 // PendingIntent请求码
private static final int PENDING_INTENT_REQUEST_CODE_FOREGROUND = 0; 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_REMIND = 1;
private static final int PENDING_INTENT_REQUEST_CODE_CONFIG = 2; // 新增:配置通知请求码
// ================================== 成员变量(私有封装,按依赖优先级排序)================================= // ================================== 成员变量(私有封装,按依赖优先级排序)=================================
// 核心上下文(应用级,避免内存泄漏) // 核心上下文(应用级,避免内存泄漏)
@@ -54,33 +59,35 @@ public class NotificationManagerUtils {
// ================================== 构造方法(初始化核心资源,前置校验)================================= // ================================== 构造方法(初始化核心资源,前置校验)=================================
public NotificationManagerUtils(Context context) { public NotificationManagerUtils(Context context) {
LogUtils.d(TAG, "构造方法执行"); LogUtils.d(TAG, "NotificationManagerUtils: 构造方法执行 | context=" + context);
// 前置校验Context非空 // 前置校验Context非空
if (context == null) { if (context == null) {
LogUtils.e(TAG, "构造失败context is null"); LogUtils.e(TAG, "NotificationManagerUtils: 构造失败context is null");
return; return;
} }
// 初始化核心资源 // 初始化核心资源
this.mContext = context.getApplicationContext(); this.mContext = context.getApplicationContext();
this.mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); this.mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
LogUtils.d(TAG, "NotificationManagerUtils: 核心资源初始化完成 | mContext=" + mContext + " | mNotificationManager=" + mNotificationManager);
// 初始化通知渠道API26+ 必需) // 初始化通知渠道API26+ 必需)
initNotificationChannels(); initNotificationChannels();
LogUtils.d(TAG, "构造完成:核心资源初始化成功"); LogUtils.d(TAG, "NotificationManagerUtils: 构造完成");
} }
// ================================== 核心初始化方法通知渠道API分级适配================================= // ================================== 核心初始化方法通知渠道API分级适配=================================
/** /**
* 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动) * 初始化通知渠道:前台服务渠道(无铃声+无振动)、提醒渠道(系统默认铃声+无振动)、配置信息渠道(低优先级无打扰)
*/ */
private void initNotificationChannels() { private void initNotificationChannels() {
LogUtils.d(TAG, "initNotificationChannels: 执行通知渠道初始化");
// API<26 无渠道机制,直接返回 // API<26 无渠道机制,直接返回
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
LogUtils.d(TAG, "initNotificationChannelsAPI<26无需创建渠道"); LogUtils.d(TAG, "initNotificationChannels: API<26无需创建渠道");
return; return;
} }
// 通知服务为空,避免空指针 // 通知服务为空,避免空指针
if (mNotificationManager == null) { if (mNotificationManager == null) {
LogUtils.e(TAG, "initNotificationChannels失败NotificationManager is null"); LogUtils.e(TAG, "initNotificationChannels: 失败NotificationManager is null");
return; return;
} }
@@ -96,6 +103,7 @@ public class NotificationManagerUtils {
foregroundChannel.setSound(null, null); // 强制无铃声 foregroundChannel.setSound(null, null); // 强制无铃声
foregroundChannel.setShowBadge(false); foregroundChannel.setShowBadge(false);
foregroundChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); foregroundChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
LogUtils.d(TAG, "initNotificationChannels: 前台服务渠道配置完成");
// 2. 电池提醒渠道(中优先级,系统默认铃声,无振动) // 2. 电池提醒渠道(中优先级,系统默认铃声,无振动)
NotificationChannel remindChannel = new NotificationChannel( NotificationChannel remindChannel = new NotificationChannel(
@@ -109,11 +117,27 @@ public class NotificationManagerUtils {
remindChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT); remindChannel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), Notification.AUDIO_ATTRIBUTES_DEFAULT);
remindChannel.setShowBadge(false); remindChannel.setShowBadge(false);
remindChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); remindChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
LogUtils.d(TAG, "initNotificationChannels: 电池提醒渠道配置完成");
// 3. 应用配置信息渠道(新增:最低优先级,无铃声无振动,仅提示不打扰)
NotificationChannel configChannel = new NotificationChannel(
CHANNEL_ID_CONFIG,
"应用配置信息",
NotificationManager.IMPORTANCE_MIN
);
configChannel.setDescription("应用配置更新、参数变更等提示,无声音、无振动");
configChannel.enableLights(false);
configChannel.enableVibration(false);
configChannel.setSound(null, null);
configChannel.setShowBadge(false);
configChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
LogUtils.d(TAG, "initNotificationChannels: 应用配置信息渠道配置完成");
// 注册渠道到系统 // 注册渠道到系统
mNotificationManager.createNotificationChannel(foregroundChannel); mNotificationManager.createNotificationChannel(foregroundChannel);
mNotificationManager.createNotificationChannel(remindChannel); mNotificationManager.createNotificationChannel(remindChannel);
LogUtils.d(TAG, "initNotificationChannels成功创建前台服务+电池提醒渠道"); mNotificationManager.createNotificationChannel(configChannel); // 注册新增渠道
LogUtils.d(TAG, "initNotificationChannels: 成功:创建前台服务+电池提醒+应用配置信息渠道");
} }
// ================================== 对外核心方法(前台服务通知:启动/更新/取消)================================= // ================================== 对外核心方法(前台服务通知:启动/更新/取消)=================================
@@ -121,26 +145,26 @@ public class NotificationManagerUtils {
* 启动前台服务通知API30适配无铃声 * 启动前台服务通知API30适配无铃声
*/ */
public void startForegroundServiceNotify(Service service, NotificationMessage message) { public void startForegroundServiceNotify(Service service, NotificationMessage message) {
LogUtils.d(TAG, "startForegroundServiceNotify执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE); LogUtils.d(TAG, "startForegroundServiceNotify: 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | service=" + service + " | message=" + message);
// 前置校验:参数非空 // 前置校验:参数非空
if (service == null || message == null || mNotificationManager == null) { 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; return;
} }
// 构建前台通知 // 构建前台通知
mForegroundServiceNotify = buildForegroundNotification(message); mForegroundServiceNotify = buildForegroundNotification(message);
if (mForegroundServiceNotify == null) { if (mForegroundServiceNotify == null) {
LogUtils.e(TAG, "startForegroundServiceNotify失败构建通知为空"); LogUtils.e(TAG, "startForegroundServiceNotify: 失败:构建通知为空");
return; return;
} }
// 启动前台服务API30无FOREGROUND_SERVICE_TYPE限制全版本通用 // 启动前台服务API30无FOREGROUND_SERVICE_TYPE限制全版本通用
try { try {
service.startForeground(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify); service.startForeground(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
LogUtils.d(TAG, "startForegroundServiceNotify成功"); LogUtils.d(TAG, "startForegroundServiceNotify: 成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "startForegroundServiceNotify异常", e); LogUtils.e(TAG, "startForegroundServiceNotify: 异常", e);
} }
} }
@@ -148,23 +172,23 @@ public class NotificationManagerUtils {
* 更新前台服务通知内容复用通知ID保持无铃声 * 更新前台服务通知内容复用通知ID保持无铃声
*/ */
public void updateForegroundServiceNotify(NotificationMessage message) { public void updateForegroundServiceNotify(NotificationMessage message) {
LogUtils.d(TAG, "updateForegroundServiceNotify执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE); LogUtils.d(TAG, "updateForegroundServiceNotify: 执行 | notifyId=" + NOTIFY_ID_FOREGROUND_SERVICE + " | message=" + message);
if (message == null || mNotificationManager == null) { 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; return;
} }
mForegroundServiceNotify = buildForegroundNotification(message); mForegroundServiceNotify = buildForegroundNotification(message);
if (mForegroundServiceNotify == null) { if (mForegroundServiceNotify == null) {
LogUtils.e(TAG, "updateForegroundServiceNotify失败构建通知为空"); LogUtils.e(TAG, "updateForegroundServiceNotify: 失败:构建通知为空");
return; return;
} }
try { try {
mNotificationManager.notify(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify); mNotificationManager.notify(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
LogUtils.d(TAG, "updateForegroundServiceNotify成功"); LogUtils.d(TAG, "updateForegroundServiceNotify: 成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "updateForegroundServiceNotify异常", e); LogUtils.e(TAG, "updateForegroundServiceNotify: 异常", e);
} }
} }
@@ -172,10 +196,10 @@ public class NotificationManagerUtils {
* 取消前台服务通知Service销毁时调用 * 取消前台服务通知Service销毁时调用
*/ */
public void cancelForegroundServiceNotify() { 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); cancelNotification(NOTIFY_ID_FOREGROUND_SERVICE);
mForegroundServiceNotify = null; // 置空释放 mForegroundServiceNotify = null; // 置空释放
LogUtils.d(TAG, "cancelForegroundServiceNotify成功"); LogUtils.d(TAG, "cancelForegroundServiceNotify: 成功");
} }
// ================================== 对外核心方法(电池提醒通知:发送)================================= // ================================== 对外核心方法(电池提醒通知:发送)=================================
@@ -183,23 +207,48 @@ public class NotificationManagerUtils {
* 发送电池提醒通知(系统默认铃声,无振动) * 发送电池提醒通知(系统默认铃声,无振动)
*/ */
public void showRemindNotification(Context context, NotificationMessage message) { public void showRemindNotification(Context context, NotificationMessage message) {
LogUtils.d(TAG, "showRemindNotification执行 | notifyId=" + NOTIFY_ID_REMIND); LogUtils.d(TAG, "showRemindNotification: 执行 | notifyId=" + NOTIFY_ID_REMIND + " | context=" + context + " | message=" + message);
if (context == null || message == null || mNotificationManager == null) { 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; return;
} }
Notification remindNotify = buildRemindNotification(context, message); Notification remindNotify = buildRemindNotification(context, message);
if (remindNotify == null) { if (remindNotify == null) {
LogUtils.e(TAG, "showRemindNotification失败构建通知为空"); LogUtils.e(TAG, "showRemindNotification: 失败:构建通知为空");
return; return;
} }
try { try {
mNotificationManager.notify(NOTIFY_ID_REMIND, remindNotify); mNotificationManager.notify(NOTIFY_ID_REMIND, remindNotify);
LogUtils.d(TAG, "showRemindNotification成功"); LogUtils.d(TAG, "showRemindNotification: 成功");
} catch (Exception e) { } 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);
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: 成功");
} catch (Exception e) {
LogUtils.e(TAG, "showConfigNotification: 异常", e);
} }
} }
@@ -208,16 +257,16 @@ public class NotificationManagerUtils {
* 取消指定ID的通知 * 取消指定ID的通知
*/ */
public void cancelNotification(int notifyId) { public void cancelNotification(int notifyId) {
LogUtils.d(TAG, "cancelNotification执行 | notifyId=" + notifyId); LogUtils.d(TAG, "cancelNotification: 执行 | notifyId=" + notifyId);
if (mNotificationManager == null) { if (mNotificationManager == null) {
LogUtils.e(TAG, "cancelNotification失败NotificationManager is null"); LogUtils.e(TAG, "cancelNotification: 失败NotificationManager is null");
return; return;
} }
try { try {
mNotificationManager.cancel(notifyId); mNotificationManager.cancel(notifyId);
LogUtils.d(TAG, "cancelNotification成功 | notifyId=" + notifyId); LogUtils.d(TAG, "cancelNotification: 成功 | notifyId=" + notifyId);
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "cancelNotification异常 | notifyId=" + notifyId, e); LogUtils.e(TAG, "cancelNotification: 异常 | notifyId=" + notifyId, e);
} }
} }
@@ -225,16 +274,16 @@ public class NotificationManagerUtils {
* 取消所有通知(兜底场景使用) * 取消所有通知(兜底场景使用)
*/ */
public void cancelAllNotifications() { public void cancelAllNotifications() {
LogUtils.d(TAG, "cancelAllNotifications执行"); LogUtils.d(TAG, "cancelAllNotifications: 执行");
if (mNotificationManager == null) { if (mNotificationManager == null) {
LogUtils.e(TAG, "cancelAllNotifications失败NotificationManager is null"); LogUtils.e(TAG, "cancelAllNotifications: 失败NotificationManager is null");
return; return;
} }
try { try {
mNotificationManager.cancelAll(); mNotificationManager.cancelAll();
LogUtils.d(TAG, "cancelAllNotifications成功"); LogUtils.d(TAG, "cancelAllNotifications: 成功");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "cancelAllNotifications异常", e); LogUtils.e(TAG, "cancelAllNotifications: 异常", e);
} }
} }
@@ -243,28 +292,30 @@ public class NotificationManagerUtils {
* 构建前台服务通知(全版本无铃声+无振动) * 构建前台服务通知(全版本无铃声+无振动)
*/ */
private Notification buildForegroundNotification(NotificationMessage message) { private Notification buildForegroundNotification(NotificationMessage message) {
LogUtils.d(TAG, "buildForegroundNotification执行"); LogUtils.d(TAG, "buildForegroundNotification: 执行 | message=" + message);
if (message == null || mContext == null) { 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; return null;
} }
// 内容兜底 // 内容兜底
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : FOREGROUND_NOTIFY_TITLE_DEFAULT; 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; String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : FOREGROUND_NOTIFY_CONTENT_DEFAULT;
LogUtils.d(TAG, "buildForegroundNotificationtitle=" + title + " | content=" + content); LogUtils.d(TAG, "buildForegroundNotification: 内容兜底完成 | title=" + title + " | content=" + content);
Notification.Builder builder; Notification.Builder builder;
// API分级构建 // API分级构建
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// API26+:绑定前台渠道(渠道已配置无铃声) // API26+:绑定前台渠道(渠道已配置无铃声)
builder = new Notification.Builder(mContext, CHANNEL_ID_FOREGROUND); builder = new Notification.Builder(mContext, CHANNEL_ID_FOREGROUND);
LogUtils.d(TAG, "buildForegroundNotification: 使用API26+渠道构建");
} else { } else {
// API<26直接构建手动禁用铃声振动 // API<26直接构建手动禁用铃声振动
builder = new Notification.Builder(mContext); builder = new Notification.Builder(mContext);
builder.setSound(null); builder.setSound(null);
builder.setVibrate(new long[]{0}); builder.setVibrate(new long[]{0});
builder.setDefaults(0); builder.setDefaults(0);
LogUtils.d(TAG, "buildForegroundNotification: 使用API<26手动配置");
} }
// 通用配置 // 通用配置
@@ -281,9 +332,12 @@ public class NotificationManagerUtils {
builder.setLargeIcon(getAppIcon(mContext)) builder.setLargeIcon(getAppIcon(mContext))
.setColor(mContext.getResources().getColor(R.color.colorPrimary)) .setColor(mContext.getResources().getColor(R.color.colorPrimary))
.setPriority(Notification.PRIORITY_LOW); .setPriority(Notification.PRIORITY_LOW);
LogUtils.d(TAG, "buildForegroundNotification: 补充API21+配置");
} }
return builder.build(); Notification notification = builder.build();
LogUtils.d(TAG, "buildForegroundNotification: 成功构建前台通知");
return notification;
} }
// ================================== 内部辅助方法(通知构建:电池提醒通知)================================= // ================================== 内部辅助方法(通知构建:电池提醒通知)=================================
@@ -291,28 +345,30 @@ public class NotificationManagerUtils {
* 构建电池提醒通知(全版本系统默认铃声+无振动) * 构建电池提醒通知(全版本系统默认铃声+无振动)
*/ */
private Notification buildRemindNotification(Context context, NotificationMessage message) { private Notification buildRemindNotification(Context context, NotificationMessage message) {
LogUtils.d(TAG, "buildRemindNotification执行"); LogUtils.d(TAG, "buildRemindNotification: 执行 | context=" + context + " | message=" + message);
if (context == null || message == null) { 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; return null;
} }
// 内容兜底 // 内容兜底
String title = message.getTitle() != null && !message.getTitle().isEmpty() ? message.getTitle() : REMIND_NOTIFY_TITLE_DEFAULT; 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; String content = message.getContent() != null && !message.getContent().isEmpty() ? message.getContent() : REMIND_NOTIFY_CONTENT_DEFAULT;
LogUtils.d(TAG, "buildRemindNotificationtitle=" + title + " | content=" + content); LogUtils.d(TAG, "buildRemindNotification: 内容兜底完成 | title=" + title + " | content=" + content);
Notification.Builder builder; Notification.Builder builder;
// API分级构建 // API分级构建
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// API26+:绑定提醒渠道(渠道已配置默认铃声) // API26+:绑定提醒渠道(渠道已配置默认铃声)
builder = new Notification.Builder(context, CHANNEL_ID_REMIND); builder = new Notification.Builder(context, CHANNEL_ID_REMIND);
LogUtils.d(TAG, "buildRemindNotification: 使用API26+渠道构建");
} else { } else {
// API<26手动配置默认铃声关闭振动 // API<26手动配置默认铃声关闭振动
builder = new Notification.Builder(context); builder = new Notification.Builder(context);
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI) // 显式默认铃声 builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI) // 显式默认铃声
.setVibrate(new long[]{0}) .setVibrate(new long[]{0})
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND); .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND);
LogUtils.d(TAG, "buildRemindNotification: 使用API<26手动配置");
} }
// 通用配置 // 通用配置
@@ -330,9 +386,65 @@ public class NotificationManagerUtils {
builder.setLargeIcon(getAppIcon(context)) builder.setLargeIcon(getAppIcon(context))
.setColor(context.getResources().getColor(R.color.colorPrimary)) .setColor(context.getResources().getColor(R.color.colorPrimary))
.setPriority(Notification.PRIORITY_DEFAULT); .setPriority(Notification.PRIORITY_DEFAULT);
LogUtils.d(TAG, "buildRemindNotification: 补充API21+配置");
} }
return builder.build(); Notification notification = builder.build();
LogUtils.d(TAG, "buildRemindNotification: 成功构建提醒通知");
return notification;
}
// ================================== 内部辅助方法(通知构建:应用配置信息通知)=================================
/**
* 构建应用配置信息通知(新增:全版本无铃声+无振动,低优先级)
*/
private Notification buildConfigNotification(Context context, NotificationMessage 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);
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);
Notification.Builder builder;
// API分级构建
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// API26+:绑定配置渠道(渠道已配置无铃声)
builder = new Notification.Builder(context, CHANNEL_ID_CONFIG);
LogUtils.d(TAG, "buildConfigNotification: 使用API26+渠道构建");
} else {
// API<26直接构建手动禁用铃声振动
builder = new Notification.Builder(context);
builder.setSound(null);
builder.setVibrate(new long[]{0});
builder.setDefaults(0);
LogUtils.d(TAG, "buildConfigNotification: 使用API<26手动配置");
}
// 通用配置
builder.setSmallIcon(NOTIFICATION_DEFAULT_ICON)
.setContentTitle(title)
.setContentText(content)
.setAutoCancel(true) // 点击关闭
.setOngoing(false)
.setWhen(System.currentTimeMillis())
.setContentIntent(createJumpPendingIntent(context, PENDING_INTENT_REQUEST_CODE_CONFIG));
// API21+ 新增大图标+主题色
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+配置");
}
Notification notification = builder.build();
LogUtils.d(TAG, "buildConfigNotification: 成功构建配置信息通知");
return notification;
} }
// ================================== 内部辅助方法创建跳转PendingIntentAPI30安全适配================================= // ================================== 内部辅助方法创建跳转PendingIntentAPI30安全适配=================================
@@ -340,19 +452,20 @@ public class NotificationManagerUtils {
* 创建跳转MainActivity的PendingIntentAPI23+ 添加IMMUTABLE标记避免安全异常 * 创建跳转MainActivity的PendingIntentAPI23+ 添加IMMUTABLE标记避免安全异常
*/ */
private PendingIntent createJumpPendingIntent(Context context, int requestCode) { private PendingIntent createJumpPendingIntent(Context context, int requestCode) {
LogUtils.d(TAG, "createJumpPendingIntent执行 | requestCode=" + requestCode); LogUtils.d(TAG, "createJumpPendingIntent: 执行 | requestCode=" + requestCode + " | context=" + context);
Intent intent = new Intent(context, MainActivity.class); Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
LogUtils.d(TAG, "createJumpPendingIntent: 跳转Intent配置完成");
// API23+ 必需添加IMMUTABLE适配API30安全规范 // API23+ 必需添加IMMUTABLE适配API30安全规范
int flags = PendingIntent.FLAG_UPDATE_CURRENT; int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
flags |= PendingIntent.FLAG_IMMUTABLE; flags |= PendingIntent.FLAG_IMMUTABLE;
LogUtils.d(TAG, "createJumpPendingIntent添加FLAG_IMMUTABLE标记"); LogUtils.d(TAG, "createJumpPendingIntent: 添加FLAG_IMMUTABLE标记API23+");
} }
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, flags); PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, flags);
LogUtils.d(TAG, "createJumpPendingIntent成功 | requestCode=" + requestCode); LogUtils.d(TAG, "createJumpPendingIntent: 成功 | requestCode=" + requestCode);
return pendingIntent; return pendingIntent;
} }
@@ -361,33 +474,33 @@ public class NotificationManagerUtils {
* 获取APP图标失败返回默认图标 * 获取APP图标失败返回默认图标
*/ */
private Bitmap getAppIcon(Context context) { private Bitmap getAppIcon(Context context) {
LogUtils.d(TAG, "getAppIcon执行"); LogUtils.d(TAG, "getAppIcon: 执行 | context=" + context);
try { try {
PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); PackageInfo pkgInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
Bitmap appIcon = BitmapFactory.decodeResource(context.getResources(), pkgInfo.applicationInfo.icon); Bitmap appIcon = BitmapFactory.decodeResource(context.getResources(), pkgInfo.applicationInfo.icon);
LogUtils.d(TAG, "getAppIcon成功获取应用图标"); LogUtils.d(TAG, "getAppIcon: 成功:获取应用图标");
return appIcon; return appIcon;
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
LogUtils.e(TAG, "getAppIcon异常获取应用图标失败使用默认图标", e); LogUtils.e(TAG, "getAppIcon: 异常:获取应用图标失败,使用默认图标", e);
return BitmapFactory.decodeResource(context.getResources(), NOTIFICATION_DEFAULT_ICON); return BitmapFactory.decodeResource(context.getResources(), NOTIFICATION_DEFAULT_ICON);
} }
} }
// ================================== 对外 getter 方法(仅前台通知实例,只读)=================================
public Notification getForegroundServiceNotify() {
return mForegroundServiceNotify;
}
// ================================== 资源释放方法(避免内存泄漏)================================= // ================================== 资源释放方法(避免内存泄漏)=================================
/** /**
* 释放资源,销毁时调用 * 释放资源,销毁时调用
*/ */
public void release() { public void release() {
LogUtils.d(TAG, "release执行"); LogUtils.d(TAG, "release: 执行资源释放");
cancelForegroundServiceNotify(); cancelForegroundServiceNotify();
mNotificationManager = null; mNotificationManager = null;
mContext = null; mContext = null;
LogUtils.d(TAG, "release成功所有资源已释放"); LogUtils.d(TAG, "release: 成功:所有资源已释放");
}
// ================================== 对外 getter 方法(仅前台通知实例,只读)=================================
public Notification getForegroundServiceNotify() {
return mForegroundServiceNotify;
} }
} }

View File

@@ -15,6 +15,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.models.BackgroundBean; import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import java.io.File; import java.io.File;
/** /**
@@ -123,8 +124,8 @@ public class BackgroundView extends RelativeLayout {
// 调用带路径判断的loadImage方法 // 调用带路径判断的loadImage方法
if (isRefresh) { if (isRefresh) {
App._mBitmapCacheUtils.removeCachedBitmap(targetPath); App.sBitmapCacheUtils.removeCachedBitmap(targetPath);
App._mBitmapCacheUtils.cacheBitmap(targetPath); App.sBitmapCacheUtils.cacheBitmap(targetPath);
} }
loadImage(targetPath); loadImage(targetPath);
} }
@@ -153,7 +154,7 @@ public class BackgroundView extends RelativeLayout {
// ======================== 新增:路径判断逻辑 ======================== // ======================== 新增:路径判断逻辑 ========================
// 1. 路径未变化:直接使用缓存 // 1. 路径未变化:直接使用缓存
if (imagePath.equals(mCurrentCachedPath)) { if (imagePath.equals(mCurrentCachedPath)) {
Bitmap cachedBitmap = App._mBitmapCacheUtils.getCachedBitmap(imagePath); Bitmap cachedBitmap = App.sBitmapCacheUtils.getCachedBitmap(imagePath);
// 核心修改判断缓存Bitmap是否为null // 核心修改判断缓存Bitmap是否为null
if (cachedBitmap != null && !cachedBitmap.isRecycled()) { if (cachedBitmap != null && !cachedBitmap.isRecycled()) {
LogUtils.d(TAG, "loadImage: 路径未变,使用缓存 Bitmap"); LogUtils.d(TAG, "loadImage: 路径未变,使用缓存 Bitmap");
@@ -173,7 +174,7 @@ public class BackgroundView extends RelativeLayout {
// 2. 路径已更新:移除旧缓存,加载新图片并更新缓存 // 2. 路径已更新:移除旧缓存,加载新图片并更新缓存
if (!TextUtils.isEmpty(mCurrentCachedPath)) { if (!TextUtils.isEmpty(mCurrentCachedPath)) {
App._mBitmapCacheUtils.removeCachedBitmap(mCurrentCachedPath); App.sBitmapCacheUtils.removeCachedBitmap(mCurrentCachedPath);
LogUtils.d(TAG, "loadImage: 路径已更新,移除旧缓存 - " + mCurrentCachedPath); LogUtils.d(TAG, "loadImage: 路径已更新,移除旧缓存 - " + mCurrentCachedPath);
} }
// ======================== 路径判断逻辑结束 ======================== // ======================== 路径判断逻辑结束 ========================
@@ -193,7 +194,7 @@ public class BackgroundView extends RelativeLayout {
} }
// 缓存新图片,并更新当前缓存路径记录 // 缓存新图片,并更新当前缓存路径记录
App._mBitmapCacheUtils.cacheBitmap(imagePath); App.sBitmapCacheUtils.cacheBitmap(imagePath);
mCurrentCachedPath = imagePath; mCurrentCachedPath = imagePath;
LogUtils.d(TAG, "loadImage: 加载新图片并更新缓存 - " + imagePath); LogUtils.d(TAG, "loadImage: 加载新图片并更新缓存 - " + imagePath);
@@ -289,5 +290,6 @@ public class BackgroundView extends RelativeLayout {
super.onSizeChanged(w, h, oldw, oldh); super.onSizeChanged(w, h, oldw, oldh);
adjustImageViewSize(); // 尺寸变化时重新调整 adjustImageViewSize(); // 尺寸变化时重新调整
} }
} }

View File

@@ -24,12 +24,55 @@ import cc.winboll.studio.powerbell.utils.AppConfigUtils;
* @Date 2025/12/17 13:14 * @Date 2025/12/17 13:14
* @Describe 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑 * @Describe 主页面核心视图封装类:统一管理视图绑定、数据更新、事件监听,解耦 Activity 逻辑
* 适配Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏,配置变更确认对话框 * 适配Java7 | API30 | 小米手机,优化性能与资源回收,杜绝内存泄漏,配置变更确认对话框
* 新增:拖动进度条时实时预览 sbUsageReminder 与 sbChargeReminder 比值
*/ */
public class MainContentView { public class MainContentView {
// ======================== 静态常量(置顶,唯一标识)======================== // ======================== 静态常量(置顶,唯一标识)========================
public static final String TAG = "MainContentView"; public static final String TAG = "MainContentView";
// ======================== 核心成员变量(按「依赖→视图→内部资源→对话框」排序)======================== // 变更类型常量(区分不同控件,精准处理逻辑)
private static final int CHANGE_TYPE_CHARGE_SWITCH = 1;
private static final int CHANGE_TYPE_USAGE_SWITCH = 2;
private static final int CHANGE_TYPE_SERVICE_SWITCH = 3;
private static final int CHANGE_TYPE_CHARGE_SEEKBAR = 4;
private static final int CHANGE_TYPE_USAGE_SEEKBAR = 5;
// ======================== 内部静态类(临时数据载体,避免外部依赖)========================
/**
* 临时配置数据实体(缓存变更信息,取消时恢复)
*/
private static class TempConfigData {
int changeType;
boolean originalBooleanValue;
int originalIntValue;
boolean newBooleanValue;
int newIntValue;
// 构造方法(开关类型)
TempConfigData(int changeType, boolean originalValue, boolean newValue) {
this.changeType = changeType;
this.originalBooleanValue = originalValue;
this.newBooleanValue = newValue;
}
// 构造方法(进度条类型)
TempConfigData(int changeType, int originalValue, int newValue) {
this.changeType = changeType;
this.originalIntValue = originalValue;
this.newIntValue = newValue;
}
}
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)========================
public interface OnViewActionListener {
void onChargeReminderSwitchChanged(boolean isChecked);
void onUsageReminderSwitchChanged(boolean isChecked);
void onServiceSwitchChanged(boolean isChecked);
void onChargeReminderProgressChanged(int progress);
void onUsageReminderProgressChanged(int progress);
}
// ======================== 成员变量(按功能分类,避免混乱)========================
// 外部依赖实例(生命周期关联,优先声明) // 外部依赖实例(生命周期关联,优先声明)
private Context mContext; private Context mContext;
private AppConfigUtils mAppConfigUtils; private AppConfigUtils mAppConfigUtils;
@@ -59,6 +102,10 @@ public class MainContentView {
public ImageView ivChargeReminderBattery; public ImageView ivChargeReminderBattery;
public ImageView ivUsageReminderBattery; public ImageView ivUsageReminderBattery;
// 进度缓存(用于实时计算比值,避免频繁调用 getProgress()
private int mCurrentChargeProgress;
private int mCurrentUsageProgress;
// 内部复用资源(避免重复创建,优化性能) // 内部复用资源(避免重复创建,优化性能)
private BatteryDrawable mCurrentBatteryDrawable; private BatteryDrawable mCurrentBatteryDrawable;
private BatteryDrawable mChargeReminderBatteryDrawable; private BatteryDrawable mChargeReminderBatteryDrawable;
@@ -66,62 +113,27 @@ public class MainContentView {
// 配置变更确认对话框(单例复用,避免重复创建) // 配置变更确认对话框(单例复用,避免重复创建)
private AlertDialog mConfigConfirmDialog; private AlertDialog mConfigConfirmDialog;
// 对话框 Builder核心新增解决 setMessage 不生效问题)
private AlertDialog.Builder mDialogBuilder; private AlertDialog.Builder mDialogBuilder;
// 临时存储变更数据(对话框确认前缓存,取消时恢复) // 临时存储变更数据(对话框确认前缓存,取消时恢复)
private TempConfigData mTempConfigData; private TempConfigData mTempConfigData;
// 对话框状态锁(避免快速点击重复弹窗) // 对话框状态锁(避免快速点击重复弹窗)
private boolean isDialogShowing = false; private boolean isDialogShowing = false;
// ======================== 临时配置数据实体(缓存变更信息,取消时恢复)========================
private static class TempConfigData {
// 变更类型(区分开关/进度条,避免混淆)
int changeType;
// 原始值(取消时恢复用)
boolean originalBooleanValue;
int originalIntValue;
// 变更后的值(确认时保存用)
boolean newBooleanValue;
int newIntValue;
// 构造方法(开关类型)
TempConfigData(int changeType, boolean originalValue, boolean newValue) {
this.changeType = changeType;
this.originalBooleanValue = originalValue;
this.newBooleanValue = newValue;
}
// 构造方法(进度条类型)
TempConfigData(int changeType, int originalValue, int newValue) {
this.changeType = changeType;
this.originalIntValue = originalValue;
this.newIntValue = newValue;
}
}
// 变更类型常量(区分不同控件,精准处理逻辑)
private static final int CHANGE_TYPE_CHARGE_SWITCH = 1;
private static final int CHANGE_TYPE_USAGE_SWITCH = 2;
private static final int CHANGE_TYPE_SERVICE_SWITCH = 3;
private static final int CHANGE_TYPE_CHARGE_SEEKBAR = 4;
private static final int CHANGE_TYPE_USAGE_SEEKBAR = 5;
// ======================== 构造方法(初始化入口,逻辑闭环)======================== // ======================== 构造方法(初始化入口,逻辑闭环)========================
public MainContentView(Context context, View rootView, OnViewActionListener actionListener) { public MainContentView(Context context, View rootView, OnViewActionListener actionListener) {
LogUtils.d(TAG, "constructor: 开始初始化"); LogUtils.d(TAG, "MainContentView() | context=" + context + " | rootView=" + rootView + " | actionListener=" + actionListener);
// 初始化外部依赖 // 初始化外部依赖
this.mContext = context; this.mContext = context;
this.mActionListener = actionListener; this.mActionListener = actionListener;
this.mAppConfigUtils = AppConfigUtils.getInstance(context.getApplicationContext()); this.mAppConfigUtils = AppConfigUtils.getInstance(context.getApplicationContext());
LogUtils.d(TAG, "constructor: 外部依赖初始化完成");
// 执行核心初始化流程(按顺序执行,避免依赖空指针) // 执行核心初始化流程(按顺序执行,避免依赖空指针)
bindViews(rootView); bindViews(rootView);
initBatteryDrawables(); initBatteryDrawables();
initConfirmDialog(); // 先初始化对话框,再绑定监听 initConfirmDialog();
bindViewListeners(); bindViewListeners();
LogUtils.d(TAG, "constructor: 整体初始化完成"); LogUtils.d(TAG, "MainContentView 初始化完成");
} }
// ======================== 私有初始化方法(封装内部逻辑,仅暴露入口)======================== // ======================== 私有初始化方法(封装内部逻辑,仅暴露入口)========================
@@ -129,7 +141,7 @@ public class MainContentView {
* 绑定视图控件(显式强转适配 Java7适配 API30 视图加载机制) * 绑定视图控件(显式强转适配 Java7适配 API30 视图加载机制)
*/ */
private void bindViews(View rootView) { private void bindViews(View rootView) {
LogUtils.d(TAG, "bindViews: 开始绑定视图"); LogUtils.d(TAG, "bindViews() | rootView=" + rootView);
// 基础布局绑定 // 基础布局绑定
mainLayout = (RelativeLayout) rootView.findViewById(R.id.activitymainRelativeLayout1); mainLayout = (RelativeLayout) rootView.findViewById(R.id.activitymainRelativeLayout1);
backgroundView = (BackgroundView) rootView.findViewById(R.id.fragmentmainviewBackgroundView1); backgroundView = (BackgroundView) rootView.findViewById(R.id.fragmentmainviewBackgroundView1);
@@ -153,17 +165,20 @@ public class MainContentView {
ivChargeReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView3); ivChargeReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView3);
ivUsageReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView2); ivUsageReminderBattery = (ImageView) rootView.findViewById(R.id.fragmentandroidviewImageView2);
// 初始化进度缓存(从配置读取初始值)
mCurrentChargeProgress = mAppConfigUtils.getChargeReminderValue();
mCurrentUsageProgress = mAppConfigUtils.getUsageReminderValue();
// 关键视图绑定校验(仅保留核心控件错误日志,精简冗余) // 关键视图绑定校验(仅保留核心控件错误日志,精简冗余)
if (mainLayout == null) LogUtils.e(TAG, "bindViews: mainLayout 绑定失败"); if (mainLayout == null) LogUtils.e(TAG, "mainLayout 绑定失败");
if (backgroundView == null) LogUtils.e(TAG, "bindViews: backgroundView 绑定失败"); if (backgroundView == null) LogUtils.e(TAG, "backgroundView 绑定失败");
LogUtils.d(TAG, "bindViews: 视图绑定完成");
} }
/** /**
* 初始化电池 Drawable集成 BatteryDrawable默认能量风格适配小米机型渲染 * 初始化电池 Drawable集成 BatteryDrawable默认能量风格适配小米机型渲染
*/ */
private void initBatteryDrawables() { private void initBatteryDrawables() {
LogUtils.d(TAG, "initBatteryDrawables: 开始初始化电池 Drawable"); LogUtils.d(TAG, "initBatteryDrawables()");
// 当前电量 Drawable颜色从资源读取适配 API30 主题) // 当前电量 Drawable颜色从资源读取适配 API30 主题)
int colorCurrent = getResourceColor(R.color.colorCurrent); int colorCurrent = getResourceColor(R.color.colorCurrent);
mCurrentBatteryDrawable = new BatteryDrawable(colorCurrent); mCurrentBatteryDrawable = new BatteryDrawable(colorCurrent);
@@ -173,17 +188,15 @@ public class MainContentView {
// 耗电提醒 Drawable // 耗电提醒 Drawable
int colorUsage = getResourceColor(R.color.colorUsege); int colorUsage = getResourceColor(R.color.colorUsege);
mUsageReminderBatteryDrawable = new BatteryDrawable(colorUsage); mUsageReminderBatteryDrawable = new BatteryDrawable(colorUsage);
LogUtils.d(TAG, "initBatteryDrawables: 电池 Drawable 初始化完成");
} }
/** /**
* 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题) * 初始化配置变更确认对话框(核心优化:保存 Builder 实例,解决消息不生效问题)
*/ */
private void initConfirmDialog() { private void initConfirmDialog() {
LogUtils.d(TAG, "initConfirmDialog: 开始初始化确认对话框"); LogUtils.d(TAG, "initConfirmDialog()");
if (mContext == null) { if (mContext == null) {
LogUtils.e(TAG, "initConfirmDialog: Context 为空,初始化失败"); LogUtils.e(TAG, "Context 为空,初始化失败");
return; return;
} }
@@ -196,7 +209,7 @@ public class MainContentView {
mDialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { mDialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
confirmConfigChange(); // 确认变更,保存配置 confirmConfigChange();
dialog.dismiss(); dialog.dismiss();
} }
}); });
@@ -205,7 +218,7 @@ public class MainContentView {
mDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() { mDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
cancelConfigChange(); // 取消变更,恢复原始值 cancelConfigChange();
dialog.dismiss(); dialog.dismiss();
} }
}); });
@@ -214,7 +227,7 @@ public class MainContentView {
mDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() { mDialogBuilder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override @Override
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
cancelConfigChange(); // 取消变更,恢复原始值 cancelConfigChange();
dialog.dismiss(); dialog.dismiss();
} }
}); });
@@ -223,22 +236,22 @@ public class MainContentView {
mConfigConfirmDialog = mDialogBuilder.create(); mConfigConfirmDialog = mDialogBuilder.create();
mConfigConfirmDialog.setCancelable(true); mConfigConfirmDialog.setCancelable(true);
mConfigConfirmDialog.setCanceledOnTouchOutside(true); mConfigConfirmDialog.setCanceledOnTouchOutside(true);
LogUtils.d(TAG, "initConfirmDialog: 确认对话框初始化完成");
} }
/** /**
* 绑定视图事件监听Java7 显式实现接口,适配 API30 事件分发,修复进度条弹窗失效) * 绑定视图事件监听Java7 显式实现接口,适配 API30 事件分发,修复进度条弹窗失效)
*/ */
private void bindViewListeners() { private void bindViewListeners() {
LogUtils.d(TAG, "bindViewListeners: 开始绑定事件监听"); LogUtils.d(TAG, "bindViewListeners()");
// 依赖校验,避免空指针 // 依赖校验,避免空指针
if (mAppConfigUtils == null || mActionListener == null || mConfigConfirmDialog == null) { if (mAppConfigUtils == null || mActionListener == null || mConfigConfirmDialog == null) {
LogUtils.e(TAG, "bindViewListeners: 依赖实例为空,跳过监听绑定"); LogUtils.e(TAG, "依赖实例为空,跳过监听绑定");
return; return;
} }
// 充电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发) // 充电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发)
if (sbChargeReminder != null) { if (sbChargeReminder != null) {
// 原有:触摸抬起/取消监听(用于配置确认)
sbChargeReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() { sbChargeReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
@Override @Override
public void onTouchUp(VerticalSeekBar seekBar, int progress) { public void onTouchUp(VerticalSeekBar seekBar, int progress) {
@@ -250,9 +263,9 @@ public class MainContentView {
} }
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress); mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语 updateDialogMessageByChangeType();
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress); LogUtils.d(TAG, "ChargeReminderSeekBar触摸抬起 | 原始值=" + originalValue + " | 新进度=" + progress);
} }
@Override @Override
@@ -265,10 +278,34 @@ public class MainContentView {
tvChargeReminderValue.setText(originalValue + "%"); tvChargeReminderValue.setText(originalValue + "%");
} }
seekBar.setProgress(originalValue); seekBar.setProgress(originalValue);
LogUtils.d(TAG, "ChargeReminderSeekBar: 触摸取消,进度回滚至=" + originalValue); // 恢复进度缓存
mCurrentChargeProgress = originalValue;
LogUtils.d(TAG, "ChargeReminderSeekBar触摸取消 | 进度回滚至=" + originalValue);
} }
}); });
LogUtils.d(TAG, "bindViewListeners: 充电提醒进度条专属监听绑定完成");
// 新增:实时进度变化监听(用于比值预览)
sbChargeReminder.setOnVerticalSeekBarChangeListener(new VerticalSeekBar.OnVerticalSeekBarChangeListener() {
@Override
public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mCurrentChargeProgress = progress;
// 同步更新进度文本和电池图标保持UI一致性
if (tvChargeReminderValue != null && mChargeReminderBatteryDrawable != null && ivChargeReminderBattery != null) {
mChargeReminderBatteryDrawable.setBatteryValue(progress);
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
tvChargeReminderValue.setText(progress + "%");
}
}
}
@Override
public void onStartTrackingTouch(VerticalSeekBar seekBar) {}
@Override
public void onStopTrackingTouch(VerticalSeekBar seekBar) {}
});
LogUtils.d(TAG, "充电提醒进度条专属监听绑定完成");
} }
// 充电提醒开关监听 // 充电提醒开关监听
@@ -282,16 +319,17 @@ public class MainContentView {
if (originalValue == newValue) return; if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue); mTempConfigData = new TempConfigData(CHANGE_TYPE_CHARGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语 updateDialogMessageByChangeType();
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableChargeReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "cbEnableChargeReminder点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
} }
}); });
LogUtils.d(TAG, "bindViewListeners: 充电提醒开关监听绑定完成"); LogUtils.d(TAG, "充电提醒开关监听绑定完成");
} }
// 耗电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发) // 耗电提醒进度条监听(使用 VerticalSeekBar 专属接口确保弹窗100%触发)
if (sbUsageReminder != null) { if (sbUsageReminder != null) {
// 原有:触摸抬起/取消监听(用于配置确认)
sbUsageReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() { sbUsageReminder.setOnVerticalSeekBarTouchListener(new VerticalSeekBar.OnVerticalSeekBarTouchListener() {
@Override @Override
public void onTouchUp(VerticalSeekBar seekBar, int progress) { public void onTouchUp(VerticalSeekBar seekBar, int progress) {
@@ -303,9 +341,9 @@ public class MainContentView {
} }
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress); mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SEEKBAR, originalValue, progress);
updateDialogMessageByChangeType(); // 更新提示语 updateDialogMessageByChangeType();
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸抬起触发变更,原始值=" + originalValue + ", 新进度=" + progress); LogUtils.d(TAG, "UsageReminderSeekBar触摸抬起 | 原始值=" + originalValue + " | 新进度=" + progress);
} }
@Override @Override
@@ -318,10 +356,34 @@ public class MainContentView {
tvUsageReminderValue.setText(originalValue + "%"); tvUsageReminderValue.setText(originalValue + "%");
} }
seekBar.setProgress(originalValue); seekBar.setProgress(originalValue);
LogUtils.d(TAG, "UsageReminderSeekBar: 触摸取消,进度回滚至=" + originalValue); // 恢复进度缓存
mCurrentUsageProgress = originalValue;
LogUtils.d(TAG, "UsageReminderSeekBar触摸取消 | 进度回滚至=" + originalValue);
} }
}); });
LogUtils.d(TAG, "bindViewListeners: 耗电提醒进度条专属监听绑定完成");
// 新增:实时进度变化监听(用于比值预览)
sbUsageReminder.setOnVerticalSeekBarChangeListener(new VerticalSeekBar.OnVerticalSeekBarChangeListener() {
@Override
public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
mCurrentUsageProgress = progress;
// 同步更新进度文本和电池图标保持UI一致性
if (tvUsageReminderValue != null && mUsageReminderBatteryDrawable != null && ivUsageReminderBattery != null) {
mUsageReminderBatteryDrawable.setBatteryValue(progress);
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
tvUsageReminderValue.setText(progress + "%");
}
}
}
@Override
public void onStartTrackingTouch(VerticalSeekBar seekBar) {}
@Override
public void onStopTrackingTouch(VerticalSeekBar seekBar) {}
});
LogUtils.d(TAG, "耗电提醒进度条专属监听绑定完成");
} }
// 耗电提醒开关监听 // 耗电提醒开关监听
@@ -335,12 +397,12 @@ public class MainContentView {
if (originalValue == newValue) return; if (originalValue == newValue) return;
// 缓存变更数据,显示确认对话框 // 缓存变更数据,显示确认对话框
mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue); mTempConfigData = new TempConfigData(CHANGE_TYPE_USAGE_SWITCH, originalValue, newValue);
updateDialogMessageByChangeType(); // 更新提示语 updateDialogMessageByChangeType();
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "cbEnableUsageReminder: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "cbEnableUsageReminder点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
} }
}); });
LogUtils.d(TAG, "bindViewListeners: 耗电提醒开关监听绑定完成"); LogUtils.d(TAG, "耗电提醒开关监听绑定完成");
} }
// 服务总开关监听(核心优化:逻辑与其他控件完全对齐) // 服务总开关监听(核心优化:逻辑与其他控件完全对齐)
@@ -359,13 +421,13 @@ public class MainContentView {
updateDialogMessageByChangeType(); updateDialogMessageByChangeType();
// 显示确认对话框 // 显示确认对话框
showConfigConfirmDialog(); showConfigConfirmDialog();
LogUtils.d(TAG, "swEnableService: 触发变更,原始值=" + originalValue + ", 变更后=" + newValue); LogUtils.d(TAG, "swEnableService点击 | 原始值=" + originalValue + " | 变更后=" + newValue);
} }
}); });
LogUtils.d(TAG, "bindViewListeners: 服务总开关监听绑定完成"); LogUtils.d(TAG, "服务总开关监听绑定完成");
} }
LogUtils.d(TAG, "bindViewListeners: 所有事件监听绑定完成"); LogUtils.d(TAG, "所有事件监听绑定完成");
} }
// ======================== 对外暴露核心方法(业务入口,精简参数,明确职责)======================== // ======================== 对外暴露核心方法(业务入口,精简参数,明确职责)========================
@@ -374,9 +436,9 @@ public class MainContentView {
* @param frameDrawable 进度条背景 Drawable外部传入适配主题切换 * @param frameDrawable 进度条背景 Drawable外部传入适配主题切换
*/ */
public void updateViewData(Drawable frameDrawable) { public void updateViewData(Drawable frameDrawable) {
LogUtils.d(TAG, "updateViewData: 开始更新视图数据"); LogUtils.d(TAG, "updateViewData() | frameDrawable=" + frameDrawable);
if (mAppConfigUtils == null) { if (mAppConfigUtils == null) {
LogUtils.e(TAG, "updateViewData: AppConfigUtils 为空,跳过更新"); LogUtils.e(TAG, "AppConfigUtils 为空,跳过更新");
return; return;
} }
@@ -388,13 +450,15 @@ public class MainContentView {
boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled(); boolean usageEnable = mAppConfigUtils.isUsageReminderEnabled();
// 从服务控制Bean读取状态确保UI与实际一致 // 从服务控制Bean读取状态确保UI与实际一致
boolean serviceEnable = getServiceEnableState(); boolean serviceEnable = getServiceEnableState();
LogUtils.d(TAG, "updateViewData: 配置数据读取完成charge=" + chargeVal + ", usage=" + usageVal + ", current=" + currentVal + ", serviceEnable=" + serviceEnable); // 更新进度缓存
mCurrentChargeProgress = chargeVal;
mCurrentUsageProgress = usageVal;
LogUtils.d(TAG, "配置数据读取完成 | charge=" + chargeVal + " | usage=" + usageVal + " | current=" + currentVal + " | serviceEnable=" + serviceEnable);
// 进度条背景更新 // 进度条背景更新
if (frameDrawable != null) { if (frameDrawable != null) {
if (llLeftSeekBar != null) llLeftSeekBar.setBackground(frameDrawable); if (llLeftSeekBar != null) llLeftSeekBar.setBackground(frameDrawable);
if (llRightSeekBar != null) llRightSeekBar.setBackground(frameDrawable); if (llRightSeekBar != null) llRightSeekBar.setBackground(frameDrawable);
LogUtils.d(TAG, "updateViewData: 进度条背景更新完成");
} }
// 当前电量更新(联动 BatteryDrawable实时刷新图标 // 当前电量更新(联动 BatteryDrawable实时刷新图标
@@ -406,7 +470,6 @@ public class MainContentView {
tvCurrentBatteryValue.setTextColor(getResourceColor(R.color.colorCurrent)); tvCurrentBatteryValue.setTextColor(getResourceColor(R.color.colorCurrent));
tvCurrentBatteryValue.setText(currentVal + "%"); tvCurrentBatteryValue.setText(currentVal + "%");
} }
LogUtils.d(TAG, "updateViewData: 当前电量视图更新完成");
// 充电提醒视图更新 // 充电提醒视图更新
if (ivChargeReminderBattery != null && mChargeReminderBatteryDrawable != null) { if (ivChargeReminderBattery != null && mChargeReminderBatteryDrawable != null) {
@@ -419,7 +482,6 @@ public class MainContentView {
} }
if (sbChargeReminder != null) sbChargeReminder.setProgress(chargeVal); if (sbChargeReminder != null) sbChargeReminder.setProgress(chargeVal);
if (cbEnableChargeReminder != null) cbEnableChargeReminder.setChecked(chargeEnable); if (cbEnableChargeReminder != null) cbEnableChargeReminder.setChecked(chargeEnable);
LogUtils.d(TAG, "updateViewData: 充电提醒视图更新完成");
// 耗电提醒视图更新 // 耗电提醒视图更新
if (ivUsageReminderBattery != null && mUsageReminderBatteryDrawable != null) { if (ivUsageReminderBattery != null && mUsageReminderBatteryDrawable != null) {
@@ -432,7 +494,6 @@ public class MainContentView {
} }
if (sbUsageReminder != null) sbUsageReminder.setProgress(usageVal); if (sbUsageReminder != null) sbUsageReminder.setProgress(usageVal);
if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable); if (cbEnableUsageReminder != null) cbEnableUsageReminder.setChecked(usageEnable);
LogUtils.d(TAG, "updateViewData: 耗电提醒视图更新完成");
// 服务开关+提示文本更新(确保状态准确) // 服务开关+提示文本更新(确保状态准确)
if (swEnableService != null) { if (swEnableService != null) {
@@ -440,9 +501,8 @@ public class MainContentView {
swEnableService.setText(mContext.getString(R.string.txt_aboveswitch)); swEnableService.setText(mContext.getString(R.string.txt_aboveswitch));
} }
if (tvTips != null) tvTips.setText(mContext.getString(R.string.txt_aboveswitchtips)); if (tvTips != null) tvTips.setText(mContext.getString(R.string.txt_aboveswitchtips));
LogUtils.d(TAG, "updateViewData: 服务开关及提示文本更新完成");
LogUtils.d(TAG, "updateViewData: 所有视图数据更新完成"); LogUtils.d(TAG, "所有视图数据更新完成");
} }
/** /**
@@ -450,10 +510,10 @@ public class MainContentView {
* @param value 电量值(自动校准 0-100避免异常值 * @param value 电量值(自动校准 0-100避免异常值
*/ */
public void updateCurrentBattery(int value) { public void updateCurrentBattery(int value) {
LogUtils.d(TAG, "updateCurrentBattery: 开始更新,原始值=" + value); LogUtils.d(TAG, "updateCurrentBattery() | 原始值=" + value);
// 核心依赖校验 // 核心依赖校验
if (tvCurrentBatteryValue == null || mCurrentBatteryDrawable == null || ivCurrentBattery == null) { if (tvCurrentBatteryValue == null || mCurrentBatteryDrawable == null || ivCurrentBattery == null) {
LogUtils.e(TAG, "updateCurrentBattery: 视图/Drawable 为空,跳过更新"); LogUtils.e(TAG, "视图/Drawable 为空,跳过更新");
return; return;
} }
@@ -464,14 +524,14 @@ public class MainContentView {
ivCurrentBattery.setImageDrawable(mCurrentBatteryDrawable); ivCurrentBattery.setImageDrawable(mCurrentBatteryDrawable);
tvCurrentBatteryValue.setText(validValue + "%"); tvCurrentBatteryValue.setText(validValue + "%");
LogUtils.d(TAG, "updateCurrentBattery: 更新完成校准后值=" + validValue); LogUtils.d(TAG, "更新完成 | 校准后值=" + validValue);
} }
/** /**
* 释放资源(主动回收,适配 API30 资源管控机制,优化小米手机内存占用) * 释放资源(主动回收,适配 API30 资源管控机制,优化小米手机内存占用)
*/ */
public void releaseResources() { public void releaseResources() {
LogUtils.d(TAG, "releaseResources: 开始释放资源"); LogUtils.d(TAG, "releaseResources()");
// 释放对话框资源(安全销毁,避免内存泄漏) // 释放对话框资源(安全销毁,避免内存泄漏)
if (mConfigConfirmDialog != null) { if (mConfigConfirmDialog != null) {
if (mConfigConfirmDialog.isShowing()) { if (mConfigConfirmDialog.isShowing()) {
@@ -514,7 +574,7 @@ public class MainContentView {
mAppConfigUtils = null; mAppConfigUtils = null;
mActionListener = null; mActionListener = null;
LogUtils.d(TAG, "releaseResources: 所有资源释放完成"); LogUtils.d(TAG, "所有资源释放完成");
} }
/** /**
@@ -522,9 +582,9 @@ public class MainContentView {
* @param enabled 服务启用状态 * @param enabled 服务启用状态
*/ */
public void setServiceSwitchChecked(boolean enabled) { public void setServiceSwitchChecked(boolean enabled) {
LogUtils.d(TAG, "setServiceSwitchChecked() | enabled=" + enabled);
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setChecked(enabled); swEnableService.setChecked(enabled);
LogUtils.d(TAG, "setServiceSwitchChecked: 服务开关UI更新为=" + enabled);
} }
} }
@@ -533,9 +593,9 @@ public class MainContentView {
* @param enabled 是否允许点击 * @param enabled 是否允许点击
*/ */
public void setServiceSwitchEnabled(boolean enabled) { public void setServiceSwitchEnabled(boolean enabled) {
LogUtils.d(TAG, "setServiceSwitchEnabled() | enabled=" + enabled);
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setEnabled(enabled); swEnableService.setEnabled(enabled);
LogUtils.d(TAG, "setServiceSwitchEnabled: 服务开关点击状态更新为=" + enabled);
} }
} }
@@ -544,21 +604,22 @@ public class MainContentView {
* 显示配置变更确认对话框(确保 Activity 处于前台,避免异常,防止重复弹窗) * 显示配置变更确认对话框(确保 Activity 处于前台,避免异常,防止重复弹窗)
*/ */
private void showConfigConfirmDialog() { private void showConfigConfirmDialog() {
LogUtils.d(TAG, "showConfigConfirmDialog() | isDialogShowing=" + isDialogShowing);
// 对话框状态锁:正在显示则跳过,避免重复触发 // 对话框状态锁:正在显示则跳过,避免重复触发
if (isDialogShowing) { if (isDialogShowing) {
LogUtils.d(TAG, "showConfigConfirmDialog: 对话框已显示,跳过重复调用"); LogUtils.d(TAG, "对话框已显示,跳过重复调用");
return; return;
} }
// 基础校验:对话框/上下文/Builder 为空 // 基础校验:对话框/上下文/Builder 为空
if (mDialogBuilder == null || mContext == null) { if (mDialogBuilder == null || mContext == null) {
LogUtils.e(TAG, "showConfigConfirmDialog: 对话框Builder/上下文异常,无法显示"); LogUtils.e(TAG, "对话框Builder/上下文异常,无法显示");
if (mTempConfigData != null) cancelConfigChange(); if (mTempConfigData != null) cancelConfigChange();
return; return;
} }
// Activity 状态校验:避免销毁后弹窗崩溃(适配 API30 // Activity 状态校验:避免销毁后弹窗崩溃(适配 API30
Activity activity = (Activity) mContext; Activity activity = (Activity) mContext;
if (activity.isFinishing() || activity.isDestroyed()) { if (activity.isFinishing() || activity.isDestroyed()) {
LogUtils.e(TAG, "showConfigConfirmDialog: Activity 已销毁,无法显示对话框"); LogUtils.e(TAG, "Activity 已销毁,无法显示对话框");
if (mTempConfigData != null) cancelConfigChange(); if (mTempConfigData != null) cancelConfigChange();
return; return;
} }
@@ -575,15 +636,16 @@ public class MainContentView {
mConfigConfirmDialog.setOnDismissListener(null); mConfigConfirmDialog.setOnDismissListener(null);
} }
}); });
LogUtils.d(TAG, "showConfigConfirmDialog: 确认对话框显示成功"); LogUtils.d(TAG, "确认对话框显示成功");
} }
/** /**
* 确认配置变更(保存数据+回调监听+更新视图) * 确认配置变更(保存数据+回调监听+更新视图)
*/ */
private void confirmConfigChange() { private void confirmConfigChange() {
LogUtils.d(TAG, "confirmConfigChange() | mTempConfigData=" + mTempConfigData);
if (mTempConfigData == null || mAppConfigUtils == null || mActionListener == null) { if (mTempConfigData == null || mAppConfigUtils == null || mActionListener == null) {
LogUtils.e(TAG, "confirmConfigChange: 依赖数据为空,确认失败"); LogUtils.e(TAG, "依赖数据为空,确认失败");
return; return;
} }
@@ -592,40 +654,40 @@ public class MainContentView {
case CHANGE_TYPE_CHARGE_SWITCH: case CHANGE_TYPE_CHARGE_SWITCH:
mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue); mAppConfigUtils.setChargeReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onChargeReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒开关确认值=" + mTempConfigData.newBooleanValue); LogUtils.d(TAG, "充电提醒开关确认 | 值=" + mTempConfigData.newBooleanValue);
break; break;
// 耗电提醒开关 // 耗电提醒开关
case CHANGE_TYPE_USAGE_SWITCH: case CHANGE_TYPE_USAGE_SWITCH:
mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue); mAppConfigUtils.setUsageReminderEnabled(mTempConfigData.newBooleanValue);
mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onUsageReminderSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒开关确认值=" + mTempConfigData.newBooleanValue); LogUtils.d(TAG, "耗电提醒开关确认 | 值=" + mTempConfigData.newBooleanValue);
break; break;
// 服务总开关(核心:持久化配置+触发 Activity 回调) // 服务总开关(核心:持久化配置+触发 Activity 回调)
case CHANGE_TYPE_SERVICE_SWITCH: case CHANGE_TYPE_SERVICE_SWITCH:
// 1. 设置服务启停 // 1. 设置服务启停
if (mTempConfigData.newBooleanValue) { if (mTempConfigData.newBooleanValue) {
ControlCenterService.startControlCenterService(mContext); ControlCenterService.startControlCenterService(mContext);
} else { } else {
ControlCenterService.stopControlCenterService(mContext); ControlCenterService.stopControlCenterService(mContext);
} }
// 2. 强制触发 Activity 回调,执行服务启停逻辑 // 2. 强制触发 Activity 回调,执行服务启停逻辑
mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue); mActionListener.onServiceSwitchChanged(mTempConfigData.newBooleanValue);
LogUtils.d(TAG, "confirmConfigChange: 服务开关确认值=" + mTempConfigData.newBooleanValue + ",已持久化配置"); LogUtils.d(TAG, "服务开关确认 | 值=" + mTempConfigData.newBooleanValue + ",已持久化配置");
break; break;
// 充电提醒进度条 // 充电提醒进度条
case CHANGE_TYPE_CHARGE_SEEKBAR: case CHANGE_TYPE_CHARGE_SEEKBAR:
mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue); mAppConfigUtils.setChargeReminderValue(mTempConfigData.newIntValue);
mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue); mActionListener.onChargeReminderProgressChanged(mTempConfigData.newIntValue);
LogUtils.d(TAG, "confirmConfigChange: 充电提醒进度确认值=" + mTempConfigData.newIntValue); LogUtils.d(TAG, "充电提醒进度确认 | 值=" + mTempConfigData.newIntValue);
break; break;
// 耗电提醒进度条 // 耗电提醒进度条
case CHANGE_TYPE_USAGE_SEEKBAR: case CHANGE_TYPE_USAGE_SEEKBAR:
mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue); mAppConfigUtils.setUsageReminderValue(mTempConfigData.newIntValue);
mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue); mActionListener.onUsageReminderProgressChanged(mTempConfigData.newIntValue);
LogUtils.d(TAG, "confirmConfigChange: 耗电提醒进度确认值=" + mTempConfigData.newIntValue); LogUtils.d(TAG, "耗电提醒进度确认 | 值=" + mTempConfigData.newIntValue);
break; break;
default: default:
LogUtils.w(TAG, "confirmConfigChange: 未知变更类型,跳过"); LogUtils.w(TAG, "未知变更类型,跳过");
break; break;
} }
@@ -637,8 +699,9 @@ public class MainContentView {
* 取消配置变更(恢复原始值+刷新视图,确保 UI 与配置一致) * 取消配置变更(恢复原始值+刷新视图,确保 UI 与配置一致)
*/ */
private void cancelConfigChange() { private void cancelConfigChange() {
LogUtils.d(TAG, "cancelConfigChange() | mTempConfigData=" + mTempConfigData);
if (mTempConfigData == null || mAppConfigUtils == null) { if (mTempConfigData == null || mAppConfigUtils == null) {
LogUtils.e(TAG, "cancelConfigChange: 依赖数据为空,取消失败"); LogUtils.e(TAG, "依赖数据为空,取消失败");
return; return;
} }
@@ -647,19 +710,19 @@ public class MainContentView {
if (cbEnableChargeReminder != null) { if (cbEnableChargeReminder != null) {
cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue); cbEnableChargeReminder.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 充电提醒开关取消恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "充电提醒开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
case CHANGE_TYPE_USAGE_SWITCH: case CHANGE_TYPE_USAGE_SWITCH:
if (cbEnableUsageReminder != null) { if (cbEnableUsageReminder != null) {
cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue); cbEnableUsageReminder.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒开关取消恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "耗电提醒开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
case CHANGE_TYPE_SERVICE_SWITCH: case CHANGE_TYPE_SERVICE_SWITCH:
if (swEnableService != null) { if (swEnableService != null) {
swEnableService.setChecked(mTempConfigData.originalBooleanValue); swEnableService.setChecked(mTempConfigData.originalBooleanValue);
} }
LogUtils.d(TAG, "cancelConfigChange: 服务开关取消恢复值=" + mTempConfigData.originalBooleanValue); LogUtils.d(TAG, "服务开关取消 | 恢复值=" + mTempConfigData.originalBooleanValue);
break; break;
case CHANGE_TYPE_CHARGE_SEEKBAR: case CHANGE_TYPE_CHARGE_SEEKBAR:
if (sbChargeReminder != null) { if (sbChargeReminder != null) {
@@ -670,7 +733,7 @@ public class MainContentView {
ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable); ivChargeReminderBattery.setImageDrawable(mChargeReminderBatteryDrawable);
tvChargeReminderValue.setText(mTempConfigData.originalIntValue + "%"); tvChargeReminderValue.setText(mTempConfigData.originalIntValue + "%");
} }
LogUtils.d(TAG, "cancelConfigChange: 充电提醒进度取消恢复值=" + mTempConfigData.originalIntValue); LogUtils.d(TAG, "充电提醒进度取消 | 恢复值=" + mTempConfigData.originalIntValue);
break; break;
case CHANGE_TYPE_USAGE_SEEKBAR: case CHANGE_TYPE_USAGE_SEEKBAR:
if (sbUsageReminder != null) { if (sbUsageReminder != null) {
@@ -681,10 +744,10 @@ public class MainContentView {
ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable); ivUsageReminderBattery.setImageDrawable(mUsageReminderBatteryDrawable);
tvUsageReminderValue.setText(mTempConfigData.originalIntValue + "%"); tvUsageReminderValue.setText(mTempConfigData.originalIntValue + "%");
} }
LogUtils.d(TAG, "cancelConfigChange: 耗电提醒进度取消恢复值=" + mTempConfigData.originalIntValue); LogUtils.d(TAG, "耗电提醒进度取消 | 恢复值=" + mTempConfigData.originalIntValue);
break; break;
default: default:
LogUtils.w(TAG, "cancelConfigChange: 未知变更类型,跳过"); LogUtils.w(TAG, "未知变更类型,跳过");
break; break;
} }
@@ -692,40 +755,11 @@ public class MainContentView {
mTempConfigData = null; mTempConfigData = null;
} }
// ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
/**
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示,防御空指针)
* @param colorResId 颜色资源 ID
* @return 校准后的颜色值
*/
private int getResourceColor(int colorResId) {
// 空指针防御Context 为空返回默认黑色
if (mContext == null) {
LogUtils.e(TAG, "getResourceColor: Context 为空,返回默认黑色");
return 0xFF000000;
}
// 适配 API30 主题颜色读取
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return mContext.getResources().getColor(colorResId, mContext.getTheme());
} else {
return mContext.getResources().getColor(colorResId);
}
}
/**
* 获取服务启用状态统一从服务控制Bean读取确保全链路状态一致
* @return 服务启用状态true=启用false=禁用)
*/
private boolean getServiceEnableState() {
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
// 本地无配置时,默认禁用服务(与服务初始化逻辑对齐)
return serviceBean != null && serviceBean.isEnableService();
}
/** /**
* 根据变更类型更新对话框提示语(核心优化:通过 Builder 更新,确保生效) * 根据变更类型更新对话框提示语(核心优化:通过 Builder 更新,确保生效)
*/ */
private void updateDialogMessageByChangeType() { private void updateDialogMessageByChangeType() {
LogUtils.d(TAG, "updateDialogMessageByChangeType() | mTempConfigData=" + mTempConfigData);
if (mDialogBuilder == null || mTempConfigData == null) return; if (mDialogBuilder == null || mTempConfigData == null) return;
String message; String message;
if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) { if (mTempConfigData.changeType == CHANGE_TYPE_SERVICE_SWITCH) {
@@ -741,13 +775,61 @@ public class MainContentView {
mDialogBuilder.setMessage(message); mDialogBuilder.setMessage(message);
} }
// ======================== 事件回调接口(解耦视图与业务,提升扩展性)======================== // ======================== 内部工具方法(封装重复逻辑,提升复用性)========================
public interface OnViewActionListener { /**
void onChargeReminderSwitchChanged(boolean isChecked); * 实时计算并更新比值预览sbUsageReminder / sbChargeReminder
void onUsageReminderSwitchChanged(boolean isChecked); * 处理除数为0的情况避免崩溃
void onServiceSwitchChanged(boolean isChecked); */
void onChargeReminderProgressChanged(int progress); // private void updateRatioPreview() {
void onUsageReminderProgressChanged(int progress); // if (mTvRatioPreview == null) return;
// float ratio;
// // 处理除数为0充电进度为0时显示0可根据需求改为“--”)
// if (mCurrentChargeProgress == 0) {
// ratio = 0.0f;
// } else {
// ratio = (float) mCurrentUsageProgress / mCurrentChargeProgress;
// }
// // 格式化比值保留1位小数适配本地化解决小米手机小数分隔符问题
// String ratioText = String.format(Locale.getDefault(), "比值:%.1f", ratio);
// mTvRatioPreview.setText(ratioText);
// // 触发比值变化回调
// if (mActionListener != null) {
// mActionListener.onRatioChanged(ratio);
// }
// LogUtils.d(TAG, "比值预览更新 | usage=" + mCurrentUsageProgress + " | charge=" + mCurrentChargeProgress + " | ratio=" + ratio);
// }
/**
* 获取资源颜色(适配 API30 主题颜色读取机制,兼容低版本,优化小米机型颜色显示,防御空指针)
* @param colorResId 颜色资源 ID
* @return 校准后的颜色值
*/
private int getResourceColor(int colorResId) {
LogUtils.d(TAG, "getResourceColor() | colorResId=" + colorResId);
// 空指针防御Context 为空返回默认黑色
if (mContext == null) {
LogUtils.e(TAG, "Context 为空,返回默认黑色");
return 0xFF000000;
}
// 适配 API30 主题颜色读取
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return mContext.getResources().getColor(colorResId, mContext.getTheme());
} else {
return mContext.getResources().getColor(colorResId);
}
}
/**
* 获取服务启用状态统一从服务控制Bean读取确保全链路状态一致
* @return 服务启用状态true=启用false=禁用)
*/
private boolean getServiceEnableState() {
LogUtils.d(TAG, "getServiceEnableState()");
ControlCenterServiceBean serviceBean = ControlCenterServiceBean.loadBean(mContext, ControlCenterServiceBean.class);
// 本地无配置时,默认禁用服务(与服务初始化逻辑对齐)
boolean state = serviceBean != null && serviceBean.isEnableService();
LogUtils.d(TAG, "服务启用状态获取完成 | state=" + state);
return state;
} }
} }

View File

@@ -5,49 +5,19 @@ import android.graphics.Canvas;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.SeekBar; import android.widget.SeekBar;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/12/17 14:11 * @Date 2025/12/17 14:11
* @Describe 垂直进度条控件,适配 API30支持逆时针旋转0在下100在上修复滑块同步+弹窗触发bug * @Describe 垂直进度条控件,适配 API30支持逆时针旋转0在下100在上修复滑块同步+弹窗触发bug
* 新增:实时进度变化监听接口,支持拖动时实时回调进度
*/ */
public class VerticalSeekBar extends SeekBar { public class VerticalSeekBar extends SeekBar {
// ======================== 静态常量 ========================= // ======================== 静态常量 =========================
private static final String TAG = VerticalSeekBar.class.getSimpleName(); private static final String TAG = VerticalSeekBar.class.getSimpleName();
// ======================== 成员变量 ========================= // ======================== 接口定义(前置,便于外部调用)========================
private volatile int mProgress = -1; // 当前进度缓存,修复滑块同步问题
private OnVerticalSeekBarTouchListener mTouchListener; // 触摸事件回调接口(核心新增)
// ======================== 构造方法 =========================
public VerticalSeekBar(Context context) {
super(context);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 单参数构造方法初始化完成");
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 双参数构造方法初始化完成");
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
LogUtils.d(TAG, "VerticalSeekBar: 三参数构造方法初始化完成");
}
// ======================== 初始化方法 =========================
private void initView() {
// 移除水平默认阴影,优化垂直显示效果,减少 API30 不必要的绘制开销
setBackgroundDrawable(null);
LogUtils.d(TAG, "initView: 视图初始化完成,移除默认背景阴影");
}
// ======================== 核心接口(新增,用于弹窗触发回调)========================
/** /**
* 垂直进度条触摸事件回调接口,解决原生 OnSeekBarChangeListener 回调失效问题 * 垂直进度条触摸事件回调接口,解决原生 OnSeekBarChangeListener 回调失效问题
* 直接在触摸抬起时回调确保配置变更对话框100%触发 * 直接在触摸抬起时回调确保配置变更对话框100%触发
@@ -68,6 +38,67 @@ public class VerticalSeekBar extends SeekBar {
void onTouchCancel(VerticalSeekBar seekBar, int progress); void onTouchCancel(VerticalSeekBar seekBar, int progress);
} }
/**
* 垂直进度条实时进度变化监听接口
* 支持拖动过程中实时回调进度用于比值预览等实时UI更新场景
*/
public interface OnVerticalSeekBarChangeListener {
/**
* 进度变化时回调
* @param seekBar 当前垂直进度条实例
* @param progress 当前进度0~100
* @param fromUser 是否是用户触摸导致的进度变化
*/
void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser);
/**
* 开始触摸进度条时回调
* @param seekBar 当前垂直进度条实例
*/
void onStartTrackingTouch(VerticalSeekBar seekBar);
/**
* 停止触摸进度条时回调
* @param seekBar 当前垂直进度条实例
*/
void onStopTrackingTouch(VerticalSeekBar seekBar);
}
// ======================== 成员变量 =========================
// 核心状态当前进度缓存修复滑块同步问题volatile 保证多线程可见性)
private volatile int mProgress = -1;
// 监听接口:触摸事件回调(原有,用于弹窗触发)
private OnVerticalSeekBarTouchListener mTouchListener;
// 监听接口:实时进度变化回调(新增,用于比值计算)
private OnVerticalSeekBarChangeListener mProgressChangeListener;
// ======================== 构造方法 =========================
public VerticalSeekBar(Context context) {
super(context);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context) 初始化");
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context, AttributeSet) 初始化");
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
LogUtils.d(TAG, "VerticalSeekBar(Context, AttributeSet, int) 初始化");
}
// ======================== 初始化方法 =========================
private void initView() {
// 移除水平默认阴影,优化垂直显示效果,减少 API30 不必要的绘制开销
setBackgroundDrawable(null);
LogUtils.d(TAG, "initView: 移除默认背景阴影,完成视图初始化");
}
// ======================== 对外设置方法(监听接口绑定)========================
/** /**
* 设置触摸事件监听器(给外部调用,如 MainContentView 绑定) * 设置触摸事件监听器(给外部调用,如 MainContentView 绑定)
* @param listener 触摸事件回调实例 * @param listener 触摸事件回调实例
@@ -77,7 +108,16 @@ public class VerticalSeekBar extends SeekBar {
LogUtils.d(TAG, "setOnVerticalSeekBarTouchListener: 触摸监听器绑定完成"); LogUtils.d(TAG, "setOnVerticalSeekBarTouchListener: 触摸监听器绑定完成");
} }
// ======================== 重写测量/布局/绘制方法 ========================= /**
* 设置实时进度变化监听器(给外部调用,如 MainContentView 绑定)
* @param listener 实时进度变化回调实例
*/
public void setOnVerticalSeekBarChangeListener(OnVerticalSeekBarChangeListener listener) {
this.mProgressChangeListener = listener;
LogUtils.d(TAG, "setOnVerticalSeekBarChangeListener: 实时进度监听器绑定完成");
}
// ======================== 重写系统方法(测量/布局/绘制)========================
@Override @Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec); super.onMeasure(heightMeasureSpec, widthMeasureSpec);
@@ -97,51 +137,13 @@ public class VerticalSeekBar extends SeekBar {
canvas.rotate(-90); canvas.rotate(-90);
canvas.translate(-getHeight(), 0); canvas.translate(-getHeight(), 0);
super.onDraw(canvas); super.onDraw(canvas);
LogUtils.v(TAG, "onDraw: 垂直绘制完成,旋转角度=-90°"); LogUtils.v(TAG, "onDraw: 完成垂直绘制,旋转角度=-90°");
} }
// ======================== 重写触摸事件(优化事件透传,新增接口回调)======================== // ======================== 重写进度设置方法(修复滑块同步+新增实时回调)========================
@Override
public boolean onTouchEvent(MotionEvent event) {
// 先调用父类方法,保留原生监听器兼容性,同时强制透传事件
super.onTouchEvent(event);
boolean handled = true; // 强制消费事件,避免事件被拦截导致回调丢失
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtils.d(TAG, "onTouchEvent: 触摸按下坐标Y=" + event.getY());
break;
case MotionEvent.ACTION_MOVE:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为=" + mProgress);
break;
case MotionEvent.ACTION_UP:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,触发弹窗回调,进度=" + mProgress);
// 核心:调用新增接口,直接通知外部触发配置变更对话框
if (mTouchListener != null) {
mTouchListener.onTouchUp(this, mProgress);
}
break;
case MotionEvent.ACTION_CANCEL:
LogUtils.d(TAG, "onTouchEvent: 触摸取消,进度保持=" + getProgress());
// 可选:触摸取消时回调,外部可做进度回滚处理
if (mTouchListener != null) {
mTouchListener.onTouchCancel(this, getProgress());
}
break;
}
return handled;
}
// ======================== 重写进度设置方法 =========================
/** /**
* 重写进度设置,调用尺寸变化方法强制刷新,解决 setProgress 滑块不跟随问题 * 重写进度设置,调用尺寸变化方法强制刷新,解决 setProgress 滑块不跟随问题
* 新增:支持外部调用 setProgress 时触发实时进度回调
*/ */
@Override @Override
public synchronized void setProgress(int progress) { public synchronized void setProgress(int progress) {
@@ -149,7 +151,68 @@ public class VerticalSeekBar extends SeekBar {
// 强制触发尺寸变化同步刷新滑块位置核心bug修复逻辑 // 强制触发尺寸变化同步刷新滑块位置核心bug修复逻辑
onSizeChanged(getWidth(), getHeight(), 0, 0); onSizeChanged(getWidth(), getHeight(), 0, 0);
mProgress = progress; mProgress = progress;
LogUtils.d(TAG, "setProgress: 进度设置完成,进度=" + progress + ", 滑块同步刷新"); LogUtils.d(TAG, "setProgress: 进度设置" + progress + "滑块同步刷新");
// 触发实时进度监听(外部调用 setProgress 时 fromUser 为 false
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, progress, false);
}
}
// ======================== 重写触摸事件(优化事件透传+实时进度回调)========================
@Override
public boolean onTouchEvent(MotionEvent event) {
// 先调用父类方法,保留原生监听器兼容性,同时强制透传事件
super.onTouchEvent(event);
boolean handled = true; // 强制消费事件,避免事件被拦截导致回调丢失
boolean fromUser = true; // 标记是否是用户触摸导致的进度变化
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
LogUtils.d(TAG, "onTouchEvent: 触摸按下Y坐标=" + event.getY());
// 触发实时进度监听:开始触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onStartTrackingTouch(this);
}
break;
case MotionEvent.ACTION_MOVE:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.v(TAG, "onTouchEvent: 触摸滑动,进度更新为" + mProgress);
// 触发实时进度监听:进度变化
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, mProgress, fromUser);
}
break;
case MotionEvent.ACTION_UP:
calculateProgress(event.getY());
setProgress(mProgress);
LogUtils.d(TAG, "onTouchEvent: 触摸抬起,进度=" + mProgress + ",触发弹窗回调");
// 触发实时进度监听:停止触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onProgressChanged(this, mProgress, fromUser);
mProgressChangeListener.onStopTrackingTouch(this);
}
// 核心:调用原有触摸接口,通知外部触发配置变更对话框
if (mTouchListener != null) {
mTouchListener.onTouchUp(this, mProgress);
}
break;
case MotionEvent.ACTION_CANCEL:
LogUtils.d(TAG, "onTouchEvent: 触摸取消,当前进度=" + getProgress());
// 触发实时进度监听:停止触摸
if (mProgressChangeListener != null) {
mProgressChangeListener.onStopTrackingTouch(this);
}
// 可选:触摸取消时回调,外部可做进度回滚处理
if (mTouchListener != null) {
mTouchListener.onTouchCancel(this, getProgress());
}
break;
}
return handled;
} }
// ======================== 内部工具方法 ========================= // ======================== 内部工具方法 =========================
@@ -162,7 +225,7 @@ public class VerticalSeekBar extends SeekBar {
mProgress = getMax() - (int) (getMax() * touchY / getHeight()); mProgress = getMax() - (int) (getMax() * touchY / getHeight());
// 校准进度范围,防止超出 0~100兼容 API30 进度边界校验) // 校准进度范围,防止超出 0~100兼容 API30 进度边界校验)
mProgress = Math.max(0, Math.min(mProgress, getMax())); mProgress = Math.max(0, Math.min(mProgress, getMax()));
LogUtils.v(TAG, "calculateProgress: 进度计算完成,触摸Y=" + touchY + ", 计算进度=" + mProgress); LogUtils.v(TAG, "calculateProgress: 触摸Y=" + touchY + "计算进度=" + mProgress);
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

View File

@@ -40,17 +40,17 @@
android:layout_width="160dp" android:layout_width="160dp"
android:layout_height="36dp" android:layout_height="36dp"
android:text="Origin BG" android:text="Origin BG"
android:id="@+id/activitybackgroundpictureAButton5"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_margin="5dp"/> android:layout_margin="5dp"
android:id="@+id/activitybackgroundsettingsAButton1"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="160dp" android:layout_width="160dp"
android:layout_height="36dp" android:layout_height="36dp"
android:text="Received BG" android:text="Received BG"
android:id="@+id/activitybackgroundpictureAButton4"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_margin="5dp"/> android:layout_margin="5dp"
android:id="@+id/activitybackgroundsettingsAButton2"/>
</RelativeLayout> </RelativeLayout>
@@ -66,7 +66,7 @@
android:text="◎" android:text="◎"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton1"/> android:id="@+id/activitybackgroundsettingsAButton3"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -74,7 +74,7 @@
android:text="☑" android:text="☑"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton2"/> android:id="@+id/activitybackgroundsettingsAButton4"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -82,8 +82,7 @@
android:text="♾" android:text="♾"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton9" android:id="@+id/activitybackgroundsettingsAButton5"/>
android:onClick="onNetworkBackgroundDialog"/>
</LinearLayout> </LinearLayout>
@@ -99,7 +98,7 @@
android:text="[+]" android:text="[+]"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton3"/> android:id="@+id/activitybackgroundsettingsAButton6"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -107,7 +106,7 @@
android:text="[+~]" android:text="[+~]"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton6"/> android:id="@+id/activitybackgroundsettingsAButton7"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -115,7 +114,7 @@
android:text="[◐]" android:text="[◐]"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton7"/> android:id="@+id/activitybackgroundsettingsAButton8"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -123,8 +122,8 @@
android:text="[©]" android:text="[©]"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundsettingsAButton1" android:onClick="onColorPaletteDialog"
android:onClick="onColorPaletteDialog"/> android:id="@+id/activitybackgroundsettingsAButton9"/>
<cc.winboll.studio.libaes.views.AButton <cc.winboll.studio.libaes.views.AButton
android:layout_width="50dp" android:layout_width="50dp"
@@ -132,7 +131,7 @@
android:text="[○]" android:text="[○]"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_margin="5dp" android:layout_margin="5dp"
android:id="@+id/activitybackgroundpictureAButton8"/> android:id="@+id/activitybackgroundsettingsAButton10"/>
</LinearLayout> </LinearLayout>

View File

@@ -13,11 +13,20 @@
android:id="@+id/tv_dialog_title" android:id="@+id/tv_dialog_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="网络后台提示" android:text="网络图片资源下载"
android:textSize="18sp" android:textSize="18sp"
android:textColor="@android:color/black" android:textColor="@android:color/black"
android:textStyle="bold"/> android:textStyle="bold"/>
<TextView
android:id="@+id/tv_dialog_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="请输入网络图片地址:"
android:textSize="15sp"
android:textColor="@android:color/darker_gray"/>
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -54,15 +63,6 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tv_dialog_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="应用正在后台使用网络,是否继续允许?"
android:textSize="15sp"
android:textColor="@android:color/darker_gray"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -74,7 +74,7 @@
android:id="@+id/btn_cancel" android:id="@+id/btn_cancel"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="取消" android:text="关闭返回"
android:textSize="14sp" android:textSize="14sp"
android:background="@android:drawable/btn_default_small" android:background="@android:drawable/btn_default_small"
android:layout_marginRight="8dp"/> android:layout_marginRight="8dp"/>
@@ -83,7 +83,7 @@
android:id="@+id/btn_confirm" android:id="@+id/btn_confirm"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="允许" android:text="使用图片"
android:textSize="14sp" android:textSize="14sp"
android:background="@android:drawable/btn_default_small"/> android:background="@android:drawable/btn_default_small"/>