@@ -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 ( preview BackgroundBeanFile. getAbsolutePath ( ) , preview BackgroundBean) ; // 预览 Bean→预览 JSON
LogUtils . d ( TAG , " 【配置管理】两份配置保存成功: 正式JSON= " + currentBackgroundBeanFile . getAbsolutePath ( ) + " , 预览JSON=" + previewBackgroundBeanFile . getAbsolutePath ( ) ) ;
if ( currentBackgroundBean ! = null & & previewBackgroundBean ! = null ) {
BackgroundBean . saveBeanToFile ( current BackgroundBeanFile. getAbsolutePath ( ) , current BackgroundBean) ; // 正式 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, 支持「空源文件→仅创建目标目录」和「正常文件复制」两种场景