Compare commits
9 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| bf051dcc9f | |||
| b38a8df462 | |||
| a8dbe43d4b | |||
| 05a8dc5205 | |||
| 280fc1abd6 | |||
| fe2084f5ff | |||
| 2a75aa140e | |||
| 04b597cbe7 | |||
| 35d210c378 |
@@ -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 09:22:26 HKT 2025
|
||||||
stageCount=11
|
stageCount=14
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.14
|
baseVersion=15.14
|
||||||
publishVersion=15.14.10
|
publishVersion=15.14.13
|
||||||
buildCount=0
|
buildCount=0
|
||||||
baseBetaVersion=15.14.11
|
baseBetaVersion=15.14.14
|
||||||
|
|||||||
BIN
powerbell/src/main/assets/images/blank100x100.png
Normal file
BIN
powerbell/src/main/assets/images/blank100x100.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 517 B |
Binary file not shown.
|
Before Width: | Height: | Size: 100 B |
@@ -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;
|
||||||
@@ -9,11 +10,13 @@ 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.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.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;
|
||||||
|
|
||||||
public class App extends GlobalApplication {
|
public class App extends GlobalApplication {
|
||||||
@@ -26,14 +29,20 @@ public class App extends GlobalApplication {
|
|||||||
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";
|
||||||
|
|
||||||
|
// 内存紧张通知常量
|
||||||
|
private static final String TRIM_MEMORY_NOTIFY_TITLE = "应用使用时内存紧张提醒";
|
||||||
|
private static final String TRIM_MEMORY_NOTIFY_CONTENT = "由于本应用使用时,系统通知内存紧张程度级别较高,图片缓存功能暂时不启用。";
|
||||||
|
|
||||||
// 数据配置存储工具
|
// 数据配置存储工具
|
||||||
static AppConfigUtils _mAppConfigUtils;
|
static AppConfigUtils _mAppConfigUtils;
|
||||||
static AppCacheUtils _mAppCacheUtils;
|
static AppCacheUtils _mAppCacheUtils;
|
||||||
// 新增:全局 Bitmap 缓存工具(常驻内存)
|
// 全局 Bitmap 缓存工具(常驻内存)
|
||||||
public static BitmapCacheUtils _mBitmapCacheUtils;
|
public static BitmapCacheUtils _mBitmapCacheUtils;
|
||||||
|
|
||||||
GlobalApplicationReceiver mReceiver;
|
GlobalApplicationReceiver mReceiver;
|
||||||
static String szTempDir = "";
|
static String szTempDir = "";
|
||||||
|
// 通知工具类实例(用于发送内存紧张通知)
|
||||||
|
private NotificationManagerUtils mNotificationManager;
|
||||||
|
|
||||||
public static String getTempDirPath() {
|
public static String getTempDirPath() {
|
||||||
return szTempDir;
|
return szTempDir;
|
||||||
@@ -60,13 +69,17 @@ public class App extends GlobalApplication {
|
|||||||
// 设置数据配置存储工具
|
// 设置数据配置存储工具
|
||||||
_mAppConfigUtils = getAppConfigUtils(this);
|
_mAppConfigUtils = getAppConfigUtils(this);
|
||||||
_mAppCacheUtils = getAppCacheUtils(this);
|
_mAppCacheUtils = getAppCacheUtils(this);
|
||||||
// 初始化全局 Bitmap 缓存工具(关键:App 启动时初始化,常驻内存)
|
// 初始化全局 Bitmap 缓存工具
|
||||||
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||||
|
|
||||||
|
// 初始化通知工具类(使用整理后的 NotificationManagerUtils)
|
||||||
|
mNotificationManager = new NotificationManagerUtils(this);
|
||||||
|
LogUtils.d(TAG, "onCreate: 通知工具类初始化完成");
|
||||||
|
|
||||||
mReceiver = new GlobalApplicationReceiver(this);
|
mReceiver = new GlobalApplicationReceiver(this);
|
||||||
mReceiver.registerAction();
|
mReceiver.registerAction();
|
||||||
|
|
||||||
// ======================== 新增:异步预加载背景图 ========================
|
// 异步预加载背景图(保持原有逻辑)
|
||||||
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -74,23 +87,19 @@ public class App extends GlobalApplication {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// 1. 获取背景源工具类实例
|
|
||||||
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(App.this);
|
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(App.this);
|
||||||
if (bgSourceUtils == null) {
|
if (bgSourceUtils == null) {
|
||||||
LogUtils.e(TAG, "preloadBitmap: BackgroundSourceUtils 实例为空");
|
LogUtils.e(TAG, "preloadBitmap: BackgroundSourceUtils 实例为空");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 2. 获取当前背景Bean
|
|
||||||
BackgroundBean bgBean = bgSourceUtils.getCurrentBackgroundBean();
|
BackgroundBean bgBean = bgSourceUtils.getCurrentBackgroundBean();
|
||||||
if (bgBean == null || !bgBean.isUseBackgroundFile()) {
|
if (bgBean == null || !bgBean.isUseBackgroundFile()) {
|
||||||
LogUtils.d(TAG, "preloadBitmap: 无有效背景文件,跳过预加载");
|
LogUtils.d(TAG, "preloadBitmap: 无有效背景文件,跳过预加载");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 3. 获取背景图路径(优先取压缩图路径)
|
|
||||||
String bgPath = bgBean.isUseBackgroundScaledCompressFile()
|
String bgPath = bgBean.isUseBackgroundScaledCompressFile()
|
||||||
? bgBean.getBackgroundScaledCompressFilePath()
|
? bgBean.getBackgroundScaledCompressFilePath()
|
||||||
: bgBean.getBackgroundFilePath();
|
: bgBean.getBackgroundFilePath();
|
||||||
// 4. 预加载到全局缓存
|
|
||||||
if (_mBitmapCacheUtils != null) {
|
if (_mBitmapCacheUtils != null) {
|
||||||
_mBitmapCacheUtils.cacheBitmap(bgPath);
|
_mBitmapCacheUtils.cacheBitmap(bgPath);
|
||||||
LogUtils.d(TAG, "preloadBitmap: 应用启动时预加载成功 - " + bgPath);
|
LogUtils.d(TAG, "preloadBitmap: 应用启动时预加载成功 - " + bgPath);
|
||||||
@@ -103,8 +112,7 @@ public class App extends GlobalApplication {
|
|||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
}, 1000); // 延迟1秒执行,避免阻塞应用初始化
|
}, 1000);
|
||||||
// ======================== 预加载逻辑结束 ========================
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保持原有方法不变
|
// 保持原有方法不变
|
||||||
@@ -130,11 +138,91 @@ public class App extends GlobalApplication {
|
|||||||
public void onTerminate() {
|
public void onTerminate() {
|
||||||
super.onTerminate();
|
super.onTerminate();
|
||||||
ToastUtils.release();
|
ToastUtils.release();
|
||||||
|
// 释放通知工具类资源,避免内存泄漏
|
||||||
|
if (mNotificationManager != null) {
|
||||||
|
mNotificationManager.release();
|
||||||
|
mNotificationManager = null;
|
||||||
|
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=" + getTrimMemoryLevelDesc(level));
|
||||||
|
|
||||||
|
// 仅在中等及以上内存紧张等级发送通知,避免频繁打扰
|
||||||
|
if (mNotificationManager == null) {
|
||||||
|
mNotificationManager = new NotificationManagerUtils(this);
|
||||||
|
}
|
||||||
|
if (level > ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
|
||||||
|
sendTrimMemoryNotification(level);
|
||||||
|
} else {
|
||||||
|
// 再次缓存 Bitmap 缓存工具
|
||||||
|
_mBitmapCacheUtils = BitmapCacheUtils.getInstance();
|
||||||
|
LogUtils.d(TAG, "Bitmap 缓存启用中。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送内存紧张通知(完全复用 NotificationManagerUtils 的 showRemindNotification 方法)
|
||||||
|
*/
|
||||||
|
private void sendTrimMemoryNotification(int level) {
|
||||||
|
LogUtils.d(TAG, "sendTrimMemoryNotification: 准备发送内存紧张通知");
|
||||||
|
// 构建通知消息体
|
||||||
|
NotificationMessage message = new NotificationMessage();
|
||||||
|
message.setTitle(TRIM_MEMORY_NOTIFY_TITLE);
|
||||||
|
message.setContent(String.format("%s [ 缓存紧张级别描述: Level %d | %s ]",TRIM_MEMORY_NOTIFY_CONTENT, level, getTrimMemoryLevelDesc(level)));
|
||||||
|
// 使用整理后的 NotificationManagerUtils 发送通知(复用提醒渠道配置)
|
||||||
|
mNotificationManager.showConfigNotification(this, message);
|
||||||
|
LogUtils.d(TAG, "sendTrimMemoryNotification: 通知已通过 NotificationManagerUtils 发送");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换内存等级为可读描述,便于日志调试
|
||||||
|
* 排序规则:按 ComponentCallbacks2 枚举数值从高到低排列(数值越高,内存越紧张)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 转换内存等级为可读描述,便于日志调试
|
||||||
|
* 排序规则:按 ComponentCallbacks2 枚举实际数值(10进制)从高到低排列
|
||||||
|
* 数值来源:接口中定义的 16进制(注释10进制)数值
|
||||||
|
*/
|
||||||
|
private String getTrimMemoryLevelDesc(int level) {
|
||||||
|
switch (level) {
|
||||||
|
// 数值 80(0x50):应用内存完全紧张(补充接口中实际存在的枚举项)
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
|
||||||
|
return "TRIM_MEMORY_COMPLETE(应用内存完全紧张)";
|
||||||
|
// 数值 60(0x3c):中等内存紧张
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
|
||||||
|
return "MODERATE(中等内存紧张)";
|
||||||
|
// 数值 40(0x28):应用进入后台
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
|
||||||
|
return "BACKGROUND(应用进入后台)";
|
||||||
|
// 数值 20(0x14):应用UI隐藏
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
|
||||||
|
return "BACKGROUND(应用UI隐藏)";
|
||||||
|
// 数值 15(0xf):应用运行时关键级紧张
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
|
||||||
|
return "RUNNING_CRITICAL(应用运行关键级紧张)";
|
||||||
|
// 数值 10(0xa):应用运行时低内存
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
|
||||||
|
return "RUNNING_LOW(应用运行低内存)";
|
||||||
|
// 数值 5(0x5):应用运行时中等紧张
|
||||||
|
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
|
||||||
|
return "RUNNING_MODERATE(应用运行中等内存紧张)";
|
||||||
|
|
||||||
|
// 以下为注释备用项(接口中未提供,按你的原有注释保留)
|
||||||
|
// 数值 100:内存极度紧张(系统可能强制杀死应用)
|
||||||
|
// case ComponentCallbacks2.TRIM_MEMORY_URGENT:
|
||||||
|
// return "URGENT(内存极度紧张)";
|
||||||
|
// 数值 20:用户正在离开应用(如按Home键)
|
||||||
|
// case ComponentCallbacks2.TRIM_MEMORY_USER_LEAVING:
|
||||||
|
// return "USER_LEAVING(用户正在离开应用)";
|
||||||
|
|
||||||
|
// 未知等级
|
||||||
|
default:
|
||||||
|
return "UNKNOWN(" + level + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -190,7 +192,7 @@ public class BackgroundSourceUtils {
|
|||||||
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
||||||
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
||||||
|
|
||||||
AssetsCopyUtils.copyAssetsFileToDir(mContext, "images/blank10x10.png", mCropSourceFile.getAbsolutePath());
|
AssetsCopyUtils.copyAssetsFileToDir(mContext, "images/blank100x100.png", mCropSourceFile.getAbsolutePath());
|
||||||
try {
|
try {
|
||||||
mCropResultFile.createNewFile();
|
mCropResultFile.createNewFile();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -198,6 +200,7 @@ public class BackgroundSourceUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
previewBackgroundBean.setPixelColor(0xFFFFFFFF);
|
||||||
previewBackgroundBean.setIsUseBackgroundFile(true);
|
previewBackgroundBean.setIsUseBackgroundFile(true);
|
||||||
previewBackgroundBean.setIsUseBackgroundScaledCompressFile(false);
|
previewBackgroundBean.setIsUseBackgroundScaledCompressFile(false);
|
||||||
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
|
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
|
||||||
|
|||||||
@@ -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 {
|
|||||||
// 通知渠道ID(API26+ 必需,区分通知类型)
|
// 通知渠道ID(API26+ 必需,区分通知类型)
|
||||||
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, "initNotificationChannels:API<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, "buildForegroundNotification:title=" + 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, "buildRemindNotification:title=" + 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================== 内部辅助方法(创建跳转PendingIntent,API30安全适配)=================================
|
// ================================== 内部辅助方法(创建跳转PendingIntent,API30安全适配)=================================
|
||||||
@@ -340,19 +452,20 @@ public class NotificationManagerUtils {
|
|||||||
* 创建跳转MainActivity的PendingIntent,API23+ 添加IMMUTABLE标记(避免安全异常)
|
* 创建跳转MainActivity的PendingIntent,API23+ 添加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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,5 +290,6 @@ public class BackgroundView extends RelativeLayout {
|
|||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
adjustImageViewSize(); // 尺寸变化时重新调整
|
adjustImageViewSize(); // 尺寸变化时重新调整
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
Before Width: | Height: | Size: 100 B |
Reference in New Issue
Block a user