diff --git a/powerbell/build.properties b/powerbell/build.properties index dc4b9f6b..c39ec2ca 100644 --- a/powerbell/build.properties +++ b/powerbell/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Dec 03 09:19:24 GMT 2025 +#Wed Dec 03 10:59:39 GMT 2025 stageCount=13 libraryProject= baseVersion=15.11 publishVersion=15.11.12 -buildCount=122 +buildCount=129 baseBetaVersion=15.11.13 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 b40bc141..0e3dc82f 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 @@ -45,6 +45,7 @@ import java.util.List; import android.app.Activity; import android.os.Environment; import cc.winboll.studio.powerbell.utils.FileUtils; +import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog; /** * 背景设置Activity(图片选择/拍照/裁剪/预览/保存核心页面) @@ -77,9 +78,6 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg private File mfTakePhoto; // 配置标记(是否提交设置) boolean isCommitSettings = false; - // 预览图片信息(用于退出确认) - //private String preViewFilePath = ""; - //private String preViewFileUrl = ""; @Override public Activity getActivity() { @@ -969,4 +967,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg LogUtils.d(TAG, "【选图权限】已添加持久化读取权限"); } } + + @Override + public void finish() { + if(isCommitSettings) { + super.finish(); + } else{ + YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener(){ + + @Override + public void onYes() { + mBgSourceUtils.commitPreviewSourceToCurrent(); + isCommitSettings = true; + finish(); + } + + @Override + public void onNo() { + isCommitSettings = true; + finish(); + } + }); + } + } } diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/fragments/MainViewFragment.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/fragments/MainViewFragment.java index e75f285a..fe764fb5 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/fragments/MainViewFragment.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/fragments/MainViewFragment.java @@ -47,6 +47,8 @@ public class MainViewFragment extends Fragment { Switch mswIsEnableService; TextView mtvTips; + private BackgroundSourceUtils mBgSourceUtils; + // 背景布局 //LinearLayout mLinearLayoutloadBackground; @@ -79,14 +81,11 @@ public class MainViewFragment extends Fragment { mView = inflater.inflate(R.layout.fragment_mainview, container, false); _mMainViewFragment = MainViewFragment.this; mAppConfigUtils = App.getAppConfigUtils(getActivity()); - + mBgSourceUtils = BackgroundSourceUtils.getInstance(getActivity()); // 获取指定ID的View实例 mBackgroundView = mView.findViewById(R.id.fragmentmainviewBackgroundView1); - - BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(getActivity()); - BackgroundBean bean = utils.getCurrentBackgroundBean(); - int nPixelColor = bean.getPixelColor(); - mBackgroundView.setBackgroundColor(nPixelColor); + + loadBackground(); /*final View mainImageView = mView.findViewById(R.id.fragmentmainviewImageView1); // 注册OnGlobalLayoutListener @@ -149,16 +148,18 @@ public class MainViewFragment extends Fragment { return mView; } + void loadBackground() { + BackgroundBean bean = mBgSourceUtils.getCurrentBackgroundBean(); + mBackgroundView.loadBackground(bean); + } + @Override public void onResume() { super.onResume(); - BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(getActivity()); - BackgroundBean bean = utils.getCurrentBackgroundBean(); - int nPixelColor = bean.getPixelColor(); - mBackgroundView.setBackgroundColor(nPixelColor); + loadBackground(); } - - + + void setViewData() { int nChargeReminderValue = mAppConfigUtils.getChargeReminderValue(); diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java index 3d295193..37a3ad53 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/BackgroundSourceUtils.java @@ -311,49 +311,6 @@ public class BackgroundSourceUtils { } } - /** - * 核心优化函数:带原图参数的裁剪路径创建(优先使用原图,不复制) - * 替代原逻辑中"复制原图到BackgroundSource再裁剪"的流程 - */ -// File createFileProviderPath(File originalImageFile) { -// Log.d(TAG, "【裁剪优化】createCropFileProviderPath(原图) 触发,优先使用原图路径"); -// -// // 核心逻辑1:直接使用裁剪前的原图(不复制),仅校验合法性和权限 -// if (originalImageFile != null && originalImageFile.exists() -// && originalImageFile.isFile() && originalImageFile.length() > 0) { -// // 校验原图目录是否可写(系统裁剪工具需读写权限) -// if (isDirectoryWritable(originalImageFile.getParentFile())) { -// // 强制开放原图权限(解决跨进程访问问题) -// //setFileReadWritePermission(originalImageFile); -// Log.d(TAG, "【裁剪优化】直接使用原图启动裁剪(无复制):" + originalImageFile.getAbsolutePath()); -// return originalImageFile; // 直接返回原图,不做任何复制 -// } else { -// Log.w(TAG, "【裁剪优化】原图目录不可写,切换到临时文件兜底"); -// } -// } else { -// Log.w(TAG, "【裁剪优化】原图无效(空/不存在/0大小),切换到临时文件兜底"); -// } -// Log.e(TAG, "【裁剪优化】所有裁剪路径创建失败,裁剪功能不可用"); -// return null; -// } - - // 辅助方法:校验目录是否可写(新增,保障裁剪权限) -// private boolean isDirectoryWritable(File dir) { -// if (dir == null) return false; -// // 目录存在且可写,或目录不存在但能创建 -// return (dir.exists() && dir.isDirectory() && dir.canWrite()) -// || (!dir.exists() && dir.mkdirs()); -// } - - // 辅助方法:设置文件读写权限(新增,解决系统裁剪跨进程访问) -// private void setFileReadWritePermission(File file) { -// if (file == null || !file.exists()) return; -// // 开放读写权限(兼容Android 10+) -// file.setReadable(true, false); -// file.setWritable(true, false); -// file.setExecutable(true, false); -// } - /** * 加载背景图片配置数据(核心:确保current/preview是两份独立的BackgroundBean实例) */ @@ -453,9 +410,13 @@ public class BackgroundSourceUtils { * 保存配置(核心:将两份独立Bean实例,分别写入各自的JSON文件) */ public void saveSettings() { - BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean); // 正式Bean→正式JSON - BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean); // 预览Bean→预览JSON - LogUtils.d(TAG, "【配置管理】两份配置保存成功:正式JSON=" + currentBackgroundBeanFile.getAbsolutePath() + ",预览JSON=" + previewBackgroundBeanFile.getAbsolutePath()); + if(currentBackgroundBean != null && previewBackgroundBean != null) { + BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean); // 正式Bean→正式JSON + BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean); // 预览Bean→预览JSON + LogUtils.d(TAG, "【配置管理】两份配置保存成功:正式JSON=" + currentBackgroundBeanFile.getAbsolutePath() + ",预览JSON=" + previewBackgroundBeanFile.getAbsolutePath()); + return; + } + LogUtils.d(TAG, "【配置管理】两份配置保存失败。currentBackgroundBean 与 previewBackgroundBean 有空值。"); } /** @@ -544,11 +505,24 @@ public class BackgroundSourceUtils { currentBackgroundBean.setBackgroundHeight(previewBackgroundBean.getBackgroundHeight()); currentBackgroundBean.setPixelColor(previewBackgroundBean.getPixelColor()); + // 拷贝一份缓存图片文件到正式背景文件夹 + String previewFileName = previewBackgroundBean.getBackgroundFileName(); + String previewCropFileName = previewBackgroundBean.getBackgroundScaledCompressFileName(); + File previewFile = new File(previewBackgroundBean.getBackgroundFilePath()); + File previewCropFile = new File(previewBackgroundBean.getBackgroundScaledCompressFilePath()); + File currentFile = new File(fBackgroundSourceDir, previewFileName); + File currentCropFile = new File(fBackgroundCompressDir, previewCropFileName); + FileUtils.copyFile(previewFile, currentFile); + FileUtils.copyFile(previewCropFile, currentCropFile); + // 更新当前背景文件路径 + currentBackgroundBean.setBackgroundFilePath(currentFile.getAbsolutePath()); // 原图路径(BackgroundSource) + currentBackgroundBean.setBackgroundScaledCompressFilePath(currentCropFile.getAbsolutePath()); // 压缩图路径(BackgroundCrops) + saveSettings(); // 分别保存:正式Bean→currentJSON,预览Bean→previewJSON(两份独立) - LogUtils.d(TAG, "【配置管理】预览背景深拷贝到正式Bean:两份实例独立,压缩图统一存储到BackgroundCrops"); + LogUtils.d(TAG, "【配置管理】预览背景深拷贝到正式Bean:两份实例独立,压缩图统一存储到BackgroundCrops"); ToastUtils.show("背景图片应用成功"); } - + /** * 将正式背景同步到预览背景(正式Bean → 预览Bean:深拷贝,新建预览Bean实例+逐字段拷贝) * 核心:深拷贝后,修改预览Bean不会影响正式Bean,两份实例完全独立,压缩图路径统一指向BackgroundCrops @@ -572,75 +546,6 @@ public class BackgroundSourceUtils { LogUtils.d(TAG, "【配置管理】正式背景深拷贝到预览Bean:两份实例独立,压缩图统一存储到BackgroundCrops"); } - // ------------------------------ 必需保留的工具方法(与业务/权限强相关,无法复用FileUtils)------------------------------ - /** - * 工具方法:递归设置目录及子目录/文件的读写权限(适配系统公共目录/Pictures/PowerBell) - * @param dir 要设置权限的目录 - */ -// private void setDirPermissionsRecursively(File dir) { -// if (dir == null || !dir.exists()) { -// String dirPath = (dir != null) ? dir.getAbsolutePath() : "null"; -// LogUtils.d(TAG, "【权限管理】目录无效,无需设置权限:" + dirPath); -// return; -// } -// try { -// // 设置目录权限(允许所有用户读写,系统裁剪应用/预览功能必需) -// dir.setReadable(true, false); -// dir.setWritable(true, false); -// dir.setExecutable(false, false); -// -// LogUtils.d(TAG, "【权限管理】目录权限设置完成:路径=" + dir.getAbsolutePath() + ",可写=" + dir.canWrite() + ",可读=" + dir.canRead()); -// -// // 递归处理子目录和文件(Java7 普通for循环,兼容语法) -// File[] files = dir.listFiles(); -// if (files != null && files.length > 0) { -// for (int i = 0; i < files.length; i++) { -// File file = files[i]; -// if (file.isDirectory()) { -// setDirPermissionsRecursively(file); -// } else { -// // 设置文件权限(与目录一致,确保可读写) -// file.setReadable(true, false); -// file.setWritable(true, false); -// file.setExecutable(false, false); -// // 裁剪/压缩/预览相关文件单独打印日志 -// if (file.getName().contains(CROP_TEMP_FILE_NAME) || -// file.getName().contains(CROP_RESULT_FILE_NAME) || -// file.getName().startsWith("ScaledCompress_")) { -// LogUtils.d(TAG, "【权限管理】关键文件权限设置:文件名=" + file.getName() + ",可写=" + file.canWrite()); -// } -// } -// } -// } -// } catch (SecurityException e) { -// LogUtils.e(TAG, "【权限管理】设置目录权限失败(系统禁止):" + dir.getAbsolutePath() + ",错误:" + e.getMessage(), e); -// ToastUtils.show("目录权限设置失败,请授予应用存储权限"); -// } catch (Exception e) { -// LogUtils.e(TAG, "【权限管理】设置目录权限异常:" + dir.getAbsolutePath() + ",错误:" + e.getMessage(), e); -// } -// } - - /** - * 工具方法:设置单个文件权限(确保系统裁剪应用/预览功能可读写,适配/Pictures/PowerBell目录) - * 【关键调整】public修饰,适配BackgroundSettingsActivity的外部调用 - * @param file 要设置权限的文件 - */ -// public void setFilePermissions(File file) { -// if (file == null || !file.exists()) { -// LogUtils.d(TAG, "【权限管理】文件无效,无需设置权限:" + (file != null ? file.getAbsolutePath() : "null")); -// return; -// } -// try { -// // 核心:允许所有用户读写(系统裁剪应用非本应用进程,需开放权限) -// file.setReadable(true, false); -// file.setWritable(true, false); -// file.setExecutable(false, false); -// LogUtils.d(TAG, "【权限管理】文件权限设置完成(/Pictures/PowerBell下):路径=" + file.getAbsolutePath() + ",可写=" + file.canWrite() + ",可读=" + file.canRead()); -// } catch (Exception e) { -// LogUtils.e(TAG, "【权限管理】设置文件权限失败:" + file.getAbsolutePath() + ",错误:" + e.getMessage(), e); -// } -// } - /** * 工具方法:清理旧文件(避免文件锁定/残留,适配系统公共目录)【内部私有,不对外暴露】 * @param file 要清理的文件 @@ -667,45 +572,6 @@ public class BackgroundSourceUtils { mCropResultFile = null; } - /** - * 工具方法:验证目录实际写入能力(解决Android14+ canWrite()假阳性问题,适配/Pictures/PowerBell) - * 原理:通过创建临时空文件并删除,验证目录是否真的可写 - * @param dir 要验证的目录 - * @return true=实际可写,false=实际不可写 - */ -// private boolean isDirActuallyWritable(File dir) { -// if (dir == null || !dir.exists() || !dir.isDirectory()) { -// return false; -// } -// // 创建临时空文件(随机文件名,避免冲突) -// File testFile = new File(dir, "test_write_" + System.currentTimeMillis() + ".tmp"); -// try { -// boolean createSuccess = testFile.createNewFile(); -// if (createSuccess) { -// boolean canWrite = testFile.canWrite(); -// boolean canRead = testFile.canRead(); -// testFile.delete(); // 删除临时文件,不占用空间 -// LogUtils.d(TAG, "【权限校验】目录实际写入校验(/Pictures/PowerBell下):" + dir.getAbsolutePath() + ",创建成功=" + createSuccess + ",可写=" + canWrite + ",可读=" + canRead + ",结果=" + (canWrite ? "通过" : "失败")); -// return canWrite; -// } else { -// LogUtils.d(TAG, "【权限校验】目录实际写入校验失败:" + dir.getAbsolutePath() + ",创建临时文件失败(Permission denied)"); -// return false; -// } -// } catch (IOException e) { -// LogUtils.e(TAG, "【权限校验】目录实际写入校验异常:" + dir.getAbsolutePath() + ",错误:" + e.getMessage(), e); -// return false; -// } -// } - - /** - * 对外接口:清理指定旧文件(适配BackgroundSettingsActivity调用,支持/Pictures/PowerBell目录) - * @param file 要清理的文件 - * @param fileDesc 文件描述(用于日志打印) - */ -// public void clearOldFileByExternal(File file, String fileDesc) { -// clearOldFile(file, fileDesc); // 调用内部private方法,复用逻辑 -// } - /** * 适配原调用:mBgSourceUtils.copyFile(new File(""), parentDir) * 核心:复用FileUtils,支持「空源文件→仅创建目标目录」和「正常文件复制」两种场景