diff --git a/powerbell/build.properties b/powerbell/build.properties
index 5bdab7a..1e82604 100644
--- a/powerbell/build.properties
+++ b/powerbell/build.properties
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
-#Sun Dec 21 19:13:50 HKT 2025
+#Mon Dec 22 00:53:45 GMT 2025
stageCount=18
libraryProject=
baseVersion=15.14
publishVersion=15.14.17
-buildCount=0
+buildCount=7
baseBetaVersion=15.14.18
diff --git a/powerbell/src/main/AndroidManifest.xml b/powerbell/src/main/AndroidManifest.xml
index ebac690..76160eb 100644
--- a/powerbell/src/main/AndroidManifest.xml
+++ b/powerbell/src/main/AndroidManifest.xml
@@ -288,6 +288,8 @@
+
+
\ No newline at end of file
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java
index 10d1103..d2d62e2 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java
@@ -28,6 +28,7 @@ import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
import cc.winboll.studio.powerbell.models.BackgroundBean;
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
+import cc.winboll.studio.powerbell.unittest.MainUnitTest2Activity;
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
@@ -210,6 +211,9 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
break;
case R.id.action_unittestactivity:
startActivity(new Intent(this, MainUnitTestActivity.class));
+ break;
+ case R.id.action_unittest2activity:
+ startActivity(new Intent(this, MainUnitTest2Activity.class));
break;
case R.id.action_about:
startAboutActivity();
@@ -402,7 +406,7 @@ public class MainActivity extends WinBoLLActivity implements MainContentView.OnV
}
BackgroundBean currentBgBean = mBgSourceUtils.getCurrentBackgroundBean();
if (currentBgBean != null) {
- mMainContentView.backgroundView.loadBackgroundBean(currentBgBean);
+ mMainContentView.backgroundView.loadByBackgroundBean(currentBgBean);
} else {
mMainContentView.backgroundView.setBackgroundResource(R.drawable.default_background);
}
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java
index 44aae1c..f094eb4 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java
@@ -402,7 +402,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
try {
mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
- mBackgroundView.loadBackgroundBean(previewBean, true);
+ mBackgroundView.loadByBackgroundBean(previewBean, true);
mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) {
@@ -418,7 +418,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity {
try {
mBgSourceUtils.loadSettings();
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
- mBackgroundView.loadBackgroundBean(previewBean, true);
+ mBackgroundView.loadByBackgroundBean(previewBean, true);
mBackgroundView.setBackgroundColor(previewBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java
index 1bcbd33..0f94bb9 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java
@@ -208,7 +208,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
mPreviewFilePath = previewFilePath;
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
- mBackgroundView.loadBackgroundBean(utils.getPreviewBackgroundBean());
+ mBackgroundView.loadByBackgroundBean(utils.getPreviewBackgroundBean());
} catch (Exception e) {
e.printStackTrace();
mBackgroundView.setBackgroundResource(R.drawable.ic_launcher);
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTest2Activity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTest2Activity.java
new file mode 100644
index 0000000..a330e5d
--- /dev/null
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTest2Activity.java
@@ -0,0 +1,257 @@
+package cc.winboll.studio.powerbell.unittest;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import androidx.appcompat.app.AppCompatActivity;
+import cc.winboll.studio.libappbase.LogUtils;
+import cc.winboll.studio.libappbase.ToastUtils;
+import cc.winboll.studio.powerbell.MainActivity;
+import cc.winboll.studio.powerbell.R;
+import cc.winboll.studio.powerbell.models.BackgroundBean;
+import cc.winboll.studio.powerbell.utils.FileUtils;
+import cc.winboll.studio.powerbell.utils.ImageCropUtils;
+import cc.winboll.studio.powerbell.views.BackgroundView;
+import cc.winboll.studio.powerbell.views.MemoryCachedBackgroundView;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @Author ZhanGSKen&豆包大模型
+ * @Date 2025/12/22 08:31
+ * @Describe MainUnitTest2Activity
+ */
+public class MainUnitTest2Activity extends AppCompatActivity {
+ // ====================== 常量定义 ======================
+ public static final String TAG = "MainUnitTest2Activity";
+ public static final int REQUEST_CROP_IMAGE = 0;
+ private static final String ASSETS_TEST_IMAGE_PATH = "unittest/unittest-miku.png";
+
+ // ====================== 成员变量(移除所有Uri相关) ======================
+ private MemoryCachedBackgroundView mMemoryCachedBackgroundView;
+ private String mAppPrivateDirPath;
+ private File mPrivateTestImageFile; // 仅用File,不用Uri
+ private File mPrivateCropImageFile;
+ BackgroundBean mPreviewBackgroundBean;
+ LinearLayout mllBackgroundView;
+
+ // ====================== 生命周期方法 ======================
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LogUtils.d(TAG, "=== 页面 onCreate 启动 ===");
+
+ initBaseParams();
+ initViewAndEvent();
+ copyAssetsTestImageToPrivateDir();
+ //loadBackgroundByFile(); // 直接用File加载
+ mPreviewBackgroundBean = new BackgroundBean();
+ mPreviewBackgroundBean.setBackgroundFileName(mPrivateTestImageFile.getName());
+ mPreviewBackgroundBean.setBackgroundFilePath(mPrivateTestImageFile.getAbsolutePath());
+ mPreviewBackgroundBean.setBackgroundScaledCompressFileName(mPrivateCropImageFile.getName());
+ mPreviewBackgroundBean.setBackgroundScaledCompressFilePath(mPrivateCropImageFile.getAbsolutePath());
+ mPreviewBackgroundBean.setIsUseBackgroundFile(true);
+ doubleRefreshPreview();
+
+ ToastUtils.show("单元测试页面启动完成");
+ LogUtils.d(TAG, "=== 页面 onCreate 初始化结束 ===");
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ LogUtils.d(TAG, "=== onActivityResult 回调 ===");
+ if (requestCode == REQUEST_CROP_IMAGE) {
+ handleCropResult(resultCode);
+ }
+ }
+
+ // ====================== 初始化相关方法 ======================
+ private void initBaseParams() {
+ LogUtils.d(TAG, "初始化基础参数:工具类+私有目录+File");
+
+ // 私有目录(无需权限,无UID冲突)
+ mAppPrivateDirPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/PowerBellTest/";
+ File privateDir = new File(mAppPrivateDirPath);
+ if (!privateDir.exists()) {
+ privateDir.mkdirs();
+ LogUtils.d(TAG, "创建私有目录:" + mAppPrivateDirPath);
+ }
+
+ // 初始化File(无Uri)
+ File refFile = new File(ASSETS_TEST_IMAGE_PATH);
+ String uniqueTestName = FileUtils.createUniqueFileName(refFile) + ".png";
+ String uniqueCropName = uniqueTestName.replace(".png", "_crop.png");
+ mPrivateTestImageFile = new File(mAppPrivateDirPath, uniqueTestName);
+ mPrivateCropImageFile = new File(mAppPrivateDirPath, uniqueCropName);
+
+ LogUtils.d(TAG, "测试图File路径:" + mPrivateTestImageFile.getAbsolutePath());
+ }
+
+ private void initViewAndEvent() {
+ LogUtils.d(TAG, "初始化布局与控件事件");
+ setContentView(R.layout.activity_mainunittest2);
+ mllBackgroundView = (LinearLayout) findViewById(R.id.ll_backgroundview);
+ mMemoryCachedBackgroundView = MemoryCachedBackgroundView.getInstance(this, "", false);
+ mllBackgroundView.addView(mMemoryCachedBackgroundView);
+
+ //mMemoryCachedBackgroundView = (BackgroundView) findViewById(R.id.backgroundview);
+
+ // 跳转主页面按钮
+ Button btnMain = (Button) findViewById(R.id.btn_main_activity);
+ btnMain.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d(TAG, "点击按钮:跳转主页面");
+ startActivity(new Intent(MainUnitTest2Activity.this, MainActivity.class));
+ }
+ });
+
+ // 裁剪按钮(直接用File路径启动,无Uri)
+ Button btnCrop = (Button) findViewById(R.id.btn_test_cropimage);
+ btnCrop.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d(TAG, "点击按钮:启动裁剪(File路径版)");
+ ToastUtils.show("准备启动图片裁剪");
+
+ if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
+ startCropTestByFile(); // 直接传File
+ } else {
+ ToastUtils.show("测试图片未准备好,重新拷贝");
+ copyAssetsTestImageToPrivateDir();
+ }
+ }
+ });
+ }
+
+ // 从assets拷贝图片(不变,确保File存在)
+ private void copyAssetsTestImageToPrivateDir() {
+ LogUtils.d(TAG, "开始拷贝assets图片到私有目录");
+ if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
+ LogUtils.d(TAG, "图片已存在,无需拷贝");
+ return;
+ }
+
+ InputStream inputStream = null;
+ try {
+ inputStream = getAssets().open(ASSETS_TEST_IMAGE_PATH);
+ FileUtils.copyStreamToFile(inputStream, mPrivateTestImageFile);
+ LogUtils.d(TAG, "图片拷贝成功,大小:" + mPrivateTestImageFile.length() + "字节");
+ } catch (IOException e) {
+ LogUtils.e(TAG, "图片拷贝失败:" + e.getMessage(), e);
+ ToastUtils.show("图片准备失败");
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ LogUtils.e(TAG, "关闭流失败:" + e.getMessage());
+ }
+ }
+ }
+ }
+
+ // ====================== 核心业务方法(全改为File路径) ======================
+ /** 直接用File路径加载背景图(无Uri,无冲突) */
+// private void loadBackgroundByFile() {
+// LogUtils.d(TAG, "开始加载背景图(File路径版)");
+// if (mPrivateTestImageFile.exists() && mPrivateTestImageFile.length() > 100) {
+// mBackgroundView.loadImage(mPrivateTestImageFile.getAbsolutePath()); // 直接传路径
+// LogUtils.d(TAG, "背景图加载成功:" + mPrivateTestImageFile.getAbsolutePath());
+// ToastUtils.show("背景图加载成功");
+// } else {
+// LogUtils.e(TAG, "背景图加载失败:文件无效");
+// ToastUtils.show("背景图加载失败");
+// }
+// }
+
+ /** 直接用File启动裁剪(关键:调用ImageCropUtils的File重载方法) */
+ private void startCropTestByFile() {
+ LogUtils.d(TAG, "启动裁剪(File路径版),原图:" + mPrivateTestImageFile.getAbsolutePath());
+
+ // 确保输出目录存在
+ File cropParent = mPrivateCropImageFile.getParentFile();
+ if (!cropParent.exists()) {
+ cropParent.mkdirs();
+ }
+
+ // 调用ImageCropUtils的File参数方法(核心:绕开Uri)
+ ImageCropUtils.startImageCrop(
+ this,
+ mPrivateTestImageFile, // 原图File
+ mPrivateCropImageFile, // 输出File
+ 0,
+ 0,
+ true,
+ REQUEST_CROP_IMAGE
+ );
+
+ LogUtils.d(TAG, "裁剪请求已发送,输出路径:" + mPrivateCropImageFile.getAbsolutePath());
+ ToastUtils.show("已启动图片裁剪");
+ }
+
+ /** 处理裁剪结果(直接校验输出File) */
+ private void handleCropResult(int resultCode) {
+ LogUtils.d(TAG, "裁剪回调处理:resultCode=" + resultCode);
+ if (resultCode == RESULT_OK) {
+ if (mPrivateCropImageFile.exists() && mPrivateCropImageFile.length() > 100) {
+ mMemoryCachedBackgroundView.loadImage(mPrivateCropImageFile.getAbsolutePath());
+ LogUtils.d(TAG, "裁剪成功,加载裁剪图:" + mPrivateCropImageFile.getAbsolutePath());
+ ToastUtils.show("裁剪成功");
+ mPreviewBackgroundBean.setIsUseBackgroundScaledCompressFile(true);
+ doubleRefreshPreview();
+ } else {
+ LogUtils.e(TAG, "裁剪成功但输出文件无效");
+ ToastUtils.show("裁剪失败:输出文件无效");
+ }
+ } else if (resultCode == RESULT_CANCELED) {
+ LogUtils.d(TAG, "裁剪取消");
+ ToastUtils.show("裁剪已取消");
+ } else {
+ LogUtils.e(TAG, "裁剪失败:resultCode异常");
+ ToastUtils.show("裁剪失败");
+ }
+ }
+
+
+ /**
+ * 双重刷新预览,确保背景加载最新数据
+ * 移除:缓存清空逻辑
+ */
+ private void doubleRefreshPreview() {
+
+ // 第一重刷新
+ try {
+ mMemoryCachedBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
+ mMemoryCachedBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
+ LogUtils.d(TAG, "【双重刷新】第一重完成");
+ } catch (Exception e) {
+ LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
+ return;
+ }
+
+ // 第二重刷新(延迟执行)
+ new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mMemoryCachedBackgroundView != null && !isFinishing()) {
+ try {
+ mMemoryCachedBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
+ mMemoryCachedBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
+ LogUtils.d(TAG, "【双重刷新】第二重完成");
+ } catch (Exception e) {
+ LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
+ }
+ }
+ }
+ }, 200);
+ }
+}
+
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTestActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTestActivity.java
index 619465e..ab4b0de 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTestActivity.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/unittest/MainUnitTestActivity.java
@@ -221,7 +221,7 @@ public class MainUnitTestActivity extends AppCompatActivity {
// 第一重刷新
try {
- mBackgroundView.loadBackgroundBean(mPreviewBackgroundBean, true);
+ mBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第一重完成");
} catch (Exception e) {
@@ -235,7 +235,7 @@ public class MainUnitTestActivity extends AppCompatActivity {
public void run() {
if (mBackgroundView != null && !isFinishing()) {
try {
- mBackgroundView.loadBackgroundBean(mPreviewBackgroundBean, true);
+ mBackgroundView.loadByBackgroundBean(mPreviewBackgroundBean, true);
mBackgroundView.setBackgroundColor(mPreviewBackgroundBean.getPixelColor());
LogUtils.d(TAG, "【双重刷新】第二重完成");
} catch (Exception e) {
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/views/BackgroundView.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/views/BackgroundView.java
index d5b7780..89b6ef8 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/views/BackgroundView.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/views/BackgroundView.java
@@ -104,11 +104,11 @@ public class BackgroundView extends RelativeLayout {
LogUtils.d(TAG, "=== initImageView 完成 ===");
}
- public void loadBackgroundBean(BackgroundBean bean) {
- loadBackgroundBean(bean, false);
+ public void loadByBackgroundBean(BackgroundBean bean) {
+ loadByBackgroundBean(bean, false);
}
- public void loadBackgroundBean(BackgroundBean bean, boolean isRefresh) {
+ public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
if (!bean.isUseBackgroundFile()) {
setDefaultTransparentBackground();
return;
diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/views/MemoryCachedBackgroundView.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/views/MemoryCachedBackgroundView.java
index c65d14d..1acc66e 100644
--- a/powerbell/src/main/java/cc/winboll/studio/powerbell/views/MemoryCachedBackgroundView.java
+++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/views/MemoryCachedBackgroundView.java
@@ -20,17 +20,17 @@ public class MemoryCachedBackgroundView extends BackgroundView {
private static final Map sViewCacheMap = new HashMap();
// ====================================== 构造器(继承并兼容父类) ======================================
- public MemoryCachedBackgroundView(Context context) {
+ private MemoryCachedBackgroundView(Context context) {
super(context);
LogUtils.d(TAG, "构造器1:创建MemoryCachedBackgroundView实例");
}
- public MemoryCachedBackgroundView(Context context, AttributeSet attrs) {
+ private MemoryCachedBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
LogUtils.d(TAG, "构造器2:创建MemoryCachedBackgroundView实例");
}
- public MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
+ private MemoryCachedBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LogUtils.d(TAG, "构造器3:创建MemoryCachedBackgroundView实例");
}
@@ -113,15 +113,15 @@ public class MemoryCachedBackgroundView extends BackgroundView {
}
@Override
- public void loadBackgroundBean(BackgroundBean bean) {
+ public void loadByBackgroundBean(BackgroundBean bean) {
LogUtils.d(TAG, "loadBackgroundBean() 重载方法调用 | BackgroundBean:" + (bean == null ? "null" : bean.toString()));
- super.loadBackgroundBean(bean);
+ super.loadByBackgroundBean(bean);
}
@Override
- public void loadBackgroundBean(BackgroundBean bean, boolean isRefresh) {
+ public void loadByBackgroundBean(BackgroundBean bean, boolean isRefresh) {
LogUtils.d(TAG, "loadBackgroundBean() 重载方法调用 | BackgroundBean:" + (bean == null ? "null" : bean.toString()) + " | 是否刷新:" + isRefresh);
- super.loadBackgroundBean(bean, isRefresh);
+ super.loadByBackgroundBean(bean, isRefresh);
}
}
diff --git a/powerbell/src/main/res/layout/activity_mainunittest2.xml b/powerbell/src/main/res/layout/activity_mainunittest2.xml
new file mode 100644
index 0000000..04433e4
--- /dev/null
+++ b/powerbell/src/main/res/layout/activity_mainunittest2.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/powerbell/src/main/res/menu/toolbar_unittest.xml b/powerbell/src/main/res/menu/toolbar_unittest.xml
index 3bdd724..45e394e 100644
--- a/powerbell/src/main/res/menu/toolbar_unittest.xml
+++ b/powerbell/src/main/res/menu/toolbar_unittest.xml
@@ -4,6 +4,10 @@
-
+ android:title="MainUnitTestActivity"/>
+
+
+