Compare commits
3 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| e440943992 | |||
| 7c5f8c3cc2 | |||
| 016b3b5e48 |
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Sun Dec 07 15:19:14 HKT 2025
|
#Wed Dec 10 14:57:42 HKT 2025
|
||||||
stageCount=2
|
stageCount=3
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.12
|
baseVersion=15.12
|
||||||
publishVersion=15.12.1
|
publishVersion=15.12.2
|
||||||
buildCount=0
|
buildCount=0
|
||||||
baseBetaVersion=15.12.2
|
baseBetaVersion=15.12.3
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import cc.winboll.studio.powerbell.utils.UriUtil;
|
||||||
|
import cc.winboll.studio.powerbell.utils.FileUtils;
|
||||||
|
|
||||||
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
|
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
private BackgroundView mBackgroundView;
|
private BackgroundView mBackgroundView;
|
||||||
private File mfTakePhoto;
|
private File mfTakePhoto;
|
||||||
volatile boolean isCommitSettings = false;
|
volatile boolean isCommitSettings = false;
|
||||||
|
volatile boolean isPreviewBackgroundChanged = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivity() {
|
public Activity getActivity() {
|
||||||
@@ -68,34 +71,42 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
|
|
||||||
mBackgroundView = (BackgroundView) findViewById(R.id.background_view);
|
mBackgroundView = (BackgroundView) findViewById(R.id.background_view);
|
||||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
|
mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
|
||||||
|
mBgSourceUtils.loadSettings();
|
||||||
mPermissionUtils = PermissionUtils.getInstance();
|
mPermissionUtils = PermissionUtils.getInstance();
|
||||||
|
|
||||||
File tempDir = new File(App.getTempDirPath());
|
// File tempDir = new File(App.getTempDirPath());
|
||||||
if (!tempDir.exists()) {
|
// if (!tempDir.exists()) {
|
||||||
tempDir.mkdirs();
|
// tempDir.mkdirs();
|
||||||
}
|
// }
|
||||||
mfTakePhoto = new File(tempDir, "TakePhoto.jpg");
|
// mfTakePhoto = new File(tempDir, "TakePhoto.jpg");
|
||||||
|
//
|
||||||
File selectTempDir = new File(mBgSourceUtils.getBackgroundSourceDirPath(), "SelectTemp");
|
// File selectTempDir = new File(mBgSourceUtils.getBackgroundSourceDirPath(), "SelectTemp");
|
||||||
if (!selectTempDir.exists()) {
|
// if (!selectTempDir.exists()) {
|
||||||
selectTempDir.mkdirs();
|
// selectTempDir.mkdirs();
|
||||||
LogUtils.d(TAG, "【选图初始化】选图临时目录创建完成:" + selectTempDir.getAbsolutePath());
|
// LogUtils.d(TAG, "【选图初始化】选图临时目录创建完成:" + selectTempDir.getAbsolutePath());
|
||||||
}
|
// }
|
||||||
|
|
||||||
initToolbar();
|
initToolbar();
|
||||||
initClickListeners();
|
initClickListeners();
|
||||||
initBackgroundViewByPreviewBean();
|
|
||||||
handleShareIntent();
|
|
||||||
|
|
||||||
|
if (handleShareIntent()) {
|
||||||
|
ToastUtils.show("handleShareIntent");
|
||||||
|
} else {
|
||||||
|
mBgSourceUtils.setCurrentSourceToPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri uriSelectedImage = UriUtil.getUriForFile(this, new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()));
|
||||||
|
// 创建预览数据剪裁环境
|
||||||
|
mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(mBgSourceUtils.getPreviewBackgroundBean());
|
||||||
|
doubleRefreshPreview();
|
||||||
LogUtils.d(TAG, "【初始化】BackgroundSettingsActivity 初始化完成");
|
LogUtils.d(TAG, "【初始化】BackgroundSettingsActivity 初始化完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initBackgroundViewByPreviewBean() {
|
@Override
|
||||||
LogUtils.d(TAG, "【Bean初始化】正式Bean → 预览Bean");
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
mBgSourceUtils.setCurrentSourceToPreview();
|
super.onPostCreate(savedInstanceState);
|
||||||
doubleRefreshPreview();
|
doubleRefreshPreview();
|
||||||
LogUtils.d(TAG, "【Bean初始化】预览Bean初始化完成");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void initToolbar() {
|
private void initToolbar() {
|
||||||
mToolbar = findViewById(R.id.toolbar);
|
mToolbar = findViewById(R.id.toolbar);
|
||||||
@@ -123,7 +134,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
findViewById(R.id.activitybackgroundpictureAButton8).setOnClickListener(onCleanPixelClickListener);
|
findViewById(R.id.activitybackgroundpictureAButton8).setOnClickListener(onCleanPixelClickListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleShareIntent() {
|
private boolean handleShareIntent() {
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
@@ -132,8 +143,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this);
|
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this);
|
||||||
dlg.show();
|
dlg.show();
|
||||||
LogUtils.d(TAG, "【分享处理】收到分享图片意图");
|
LogUtils.d(TAG, "【分享处理】收到分享图片意图");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isImageType(String lowerMimeType) {
|
boolean isImageType(String lowerMimeType) {
|
||||||
@@ -478,11 +491,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
LogUtils.d(TAG, "【选图权限】已添加持久化权限");
|
LogUtils.d(TAG, "【选图权限】已添加持久化权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
mBgSourceUtils.createCropFileProviderBackgroundBean(selectedImage);
|
|
||||||
|
|
||||||
LogUtils.d(TAG, "【选图同步】路径绑定完成");
|
LogUtils.d(TAG, "【选图同步】路径绑定完成");
|
||||||
// 选图后启动固定比例裁剪(调用工具类)
|
// 选图后启动固定比例裁剪(调用工具类)
|
||||||
mBgSourceUtils.loadSettings();
|
putUriFileToPreviewSource(selectedImage);
|
||||||
ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this,
|
ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this,
|
||||||
mBgSourceUtils.getPreviewBackgroundBean(),
|
mBgSourceUtils.getPreviewBackgroundBean(),
|
||||||
mBackgroundView.getWidth(),
|
mBackgroundView.getWidth(),
|
||||||
@@ -492,6 +503,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean putUriFileToPreviewSource(Uri srcUriFile) {
|
||||||
|
File srcFile = new File(UriUtil.getFilePathFromUri(this, srcUriFile));
|
||||||
|
return putUriFileToPreviewSource(srcFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean putUriFileToPreviewSource(File srcFile) {
|
||||||
|
mBgSourceUtils.loadSettings();
|
||||||
|
File dstFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath());
|
||||||
|
return FileUtils.copyFile(srcFile, dstFile);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleCropImageResult(int requestCode, int resultCode, Intent data) {
|
private void handleCropImageResult(int requestCode, int resultCode, Intent data) {
|
||||||
LogUtils.d(TAG, "handleCropImageResult: 处理裁剪结果");
|
LogUtils.d(TAG, "handleCropImageResult: 处理裁剪结果");
|
||||||
File cropTempFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath());
|
File cropTempFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath());
|
||||||
@@ -501,6 +523,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
boolean isCropSuccess = (resultCode == RESULT_OK) && isFileExist && isFileReadable && fileSize > 100;
|
boolean isCropSuccess = (resultCode == RESULT_OK) && isFileExist && isFileReadable && fileSize > 100;
|
||||||
|
|
||||||
if (isCropSuccess) {
|
if (isCropSuccess) {
|
||||||
|
isPreviewBackgroundChanged = true;
|
||||||
LogUtils.d(TAG, "handleCropImageResult: 裁剪成功");
|
LogUtils.d(TAG, "handleCropImageResult: 裁剪成功");
|
||||||
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||||
previewBean.setIsUseBackgroundFile(true);
|
previewBean.setIsUseBackgroundFile(true);
|
||||||
@@ -677,6 +700,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
private void doubleRefreshPreview() {
|
private void doubleRefreshPreview() {
|
||||||
LogUtils.d(TAG, "【双重刷新】开始");
|
LogUtils.d(TAG, "【双重刷新】开始");
|
||||||
if (mBackgroundView != null && !isFinishing()) {
|
if (mBackgroundView != null && !isFinishing()) {
|
||||||
|
mBgSourceUtils.loadSettings();
|
||||||
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
|
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
|
||||||
LogUtils.d(TAG, "【双重刷新】第一重完成");
|
LogUtils.d(TAG, "【双重刷新】第一重完成");
|
||||||
} else {
|
} else {
|
||||||
@@ -688,6 +712,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (mBackgroundView != null && !isFinishing()) {
|
if (mBackgroundView != null && !isFinishing()) {
|
||||||
|
mBgSourceUtils.loadSettings();
|
||||||
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
|
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
|
||||||
LogUtils.d(TAG, "【双重刷新】第二重完成");
|
LogUtils.d(TAG, "【双重刷新】第二重完成");
|
||||||
}
|
}
|
||||||
@@ -697,9 +722,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
|
|
||||||
|
|
||||||
private void handleOperationCancelOrFail() {
|
private void handleOperationCancelOrFail() {
|
||||||
initBackgroundViewByPreviewBean();
|
mBgSourceUtils.setCurrentSourceToPreview();
|
||||||
LogUtils.d(TAG, "【操作回调】取消或失败");
|
LogUtils.d(TAG, "【操作回调】取消或失败");
|
||||||
ToastUtils.show("操作已取消");
|
ToastUtils.show("【操作回调】取消或失败");
|
||||||
|
doubleRefreshPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -753,20 +779,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
if (isCommitSettings) {
|
if (isCommitSettings) {
|
||||||
super.finish();
|
super.finish();
|
||||||
} else {
|
} else {
|
||||||
YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener(){
|
// 如果预览背景改变过就提示是否更换背景
|
||||||
@Override
|
if (isPreviewBackgroundChanged) {
|
||||||
public void onYes() {
|
YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener(){
|
||||||
mBgSourceUtils.commitPreviewSourceToCurrent();
|
@Override
|
||||||
isCommitSettings = true;
|
public void onYes() {
|
||||||
finish();
|
mBgSourceUtils.commitPreviewSourceToCurrent();
|
||||||
}
|
isCommitSettings = true;
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNo() {
|
public void onNo() {
|
||||||
isCommitSettings = true;
|
isCommitSettings = true;
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// 如果预览背景未改变就直接退出
|
||||||
|
isCommitSettings = true;
|
||||||
|
finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ public class BackgroundSourceUtils {
|
|||||||
clearCropTempFiles();
|
clearCropTempFiles();
|
||||||
LogUtils.d(TAG, "【文件初始化】完成。");
|
LogUtils.d(TAG, "【文件初始化】完成。");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 【核心实现】定义 getFileProviderUri 方法:将 File 转为 ContentUri(适配 FileProvider)
|
// 【核心实现】定义 getFileProviderUri 方法:将 File 转为 ContentUri(适配 FileProvider)
|
||||||
public Uri getFileProviderUri(File file) {
|
public Uri getFileProviderUri(File file) {
|
||||||
Log.d("BackgroundSourceUtils", "getFileProviderUri: 生成FileProvider Uri,文件路径:" + file.getAbsolutePath());
|
Log.d("BackgroundSourceUtils", "getFileProviderUri: 生成FileProvider Uri,文件路径:" + file.getAbsolutePath());
|
||||||
@@ -245,13 +245,16 @@ public class BackgroundSourceUtils {
|
|||||||
return contentUri;
|
return contentUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean createCropFileProviderBackgroundBean(Uri uri) {
|
/*
|
||||||
|
* 创建预览数据剪裁环境
|
||||||
|
*/
|
||||||
|
public boolean createAndUpdatePreviewEnvironmentForCropping(BackgroundBean oldPreviewBackgroundBean) {
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
FileOutputStream fos = null;
|
FileOutputStream fos = null;
|
||||||
loadSettings();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
clearCropTempFiles();
|
clearCropTempFiles();
|
||||||
|
Uri uri = UriUtil.getUriForFile(mContext, oldPreviewBackgroundBean.getBackgroundFilePath());
|
||||||
//String szType = mContext.getContentResolver().getType(uri);
|
//String szType = mContext.getContentResolver().getType(uri);
|
||||||
// 2. 截取MIME类型后缀(如从image/jpeg中提取jpeg)【核心新增逻辑】
|
// 2. 截取MIME类型后缀(如从image/jpeg中提取jpeg)【核心新增逻辑】
|
||||||
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
|
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
|
||||||
@@ -259,51 +262,63 @@ 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);
|
||||||
|
|
||||||
mCropSourceFile.createNewFile();
|
if (FileUtils.isFileExists(oldPreviewBackgroundBean.getBackgroundScaledCompressFilePath())) {
|
||||||
mCropResultFile.createNewFile();
|
FileUtils.copyFile(new File(oldPreviewBackgroundBean.getBackgroundScaledCompressFilePath()), mCropResultFile);
|
||||||
|
} else {
|
||||||
// 1. 打开Uri输入流(兼容content:///file:// 等多种Uri格式)
|
mCropResultFile.createNewFile();
|
||||||
is = mContext.getContentResolver().openInputStream(uri);
|
|
||||||
if (is == null) {
|
|
||||||
LogUtils.e(TAG, "【选图解析】ContentResolver打开Uri失败,Uri:" + uri.toString());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 初始化选图临时文件输出流(Java7 手动创建流,不依赖try-with-resources)
|
if (FileUtils.isFileExists(oldPreviewBackgroundBean.getBackgroundFilePath())) {
|
||||||
fos = new FileOutputStream(mCropSourceFile);
|
FileUtils.copyFile(new File(oldPreviewBackgroundBean.getBackgroundFilePath()), mCropSourceFile);
|
||||||
byte[] buffer = new byte[1024 * 8]; // 8KB缓冲区,平衡读写性能与内存占用
|
} else {
|
||||||
int readLen; // 每次读取的字节长度
|
mCropSourceFile.createNewFile();
|
||||||
|
// 1. 打开Uri输入流(兼容content:///file:// 等多种Uri格式)
|
||||||
|
is = mContext.getContentResolver().openInputStream(uri);
|
||||||
|
if (is == null) {
|
||||||
|
LogUtils.e(TAG, "【选图解析】ContentResolver打开Uri失败,Uri:" + uri.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 流复制(Java7 标准while循环,避免Java8+语法)
|
// 2. 初始化选图临时文件输出流(Java7 手动创建流,不依赖try-with-resources)
|
||||||
while ((readLen = is.read(buffer)) != -1) {
|
fos = new FileOutputStream(mCropSourceFile);
|
||||||
fos.write(buffer, 0, readLen); // 精准写入读取到的字节,避免空字节填充
|
byte[] buffer = new byte[1024 * 8]; // 8KB缓冲区,平衡读写性能与内存占用
|
||||||
}
|
int readLen; // 每次读取的字节长度
|
||||||
|
|
||||||
// 4. 强制同步写入磁盘(解决Android 10+ 异步写入导致的文件无效问题)
|
// 3. 流复制(Java7 标准while循环,避免Java8+语法)
|
||||||
fos.flush();
|
while ((readLen = is.read(buffer)) != -1) {
|
||||||
if (fos != null) {
|
fos.write(buffer, 0, readLen); // 精准写入读取到的字节,避免空字节填充
|
||||||
try {
|
}
|
||||||
fos.getFD().sync(); // 确保数据写入物理磁盘,而非缓存
|
|
||||||
} catch (IOException e) {
|
// 4. 强制同步写入磁盘(解决Android 10+ 异步写入导致的文件无效问题)
|
||||||
LogUtils.w(TAG, "【选图解析】文件同步到磁盘失败,用flush()兜底:" + e.getMessage());
|
fos.flush();
|
||||||
fos.flush();
|
if (fos != null) {
|
||||||
|
try {
|
||||||
|
fos.getFD().sync(); // 确保数据写入物理磁盘,而非缓存
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtils.w(TAG, "【选图解析】文件同步到磁盘失败,用flush()兜底:" + e.getMessage());
|
||||||
|
fos.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载图片数据模型数据
|
||||||
|
loadSettings();
|
||||||
|
// 修改预览数据模型
|
||||||
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
|
previewBackgroundBean.setBackgroundFileName(mCropSourceFile.getName());
|
||||||
previewBackgroundBean.setBackgroundFilePath(mCropSourceFile.getAbsolutePath());
|
previewBackgroundBean.setBackgroundFilePath(mCropSourceFile.getAbsolutePath());
|
||||||
|
|
||||||
previewBackgroundBean.setBackgroundScaledCompressFileName(mCropResultFile.getName());
|
previewBackgroundBean.setBackgroundScaledCompressFileName(mCropResultFile.getName());
|
||||||
previewBackgroundBean.setBackgroundScaledCompressFilePath(mCropResultFile.getAbsolutePath());
|
previewBackgroundBean.setBackgroundScaledCompressFilePath(mCropResultFile.getAbsolutePath());
|
||||||
|
// 保存数据模型数据更改
|
||||||
saveSettings();
|
saveSettings();
|
||||||
|
|
||||||
// 6. 解析成功日志(打印文件信息,便于问题排查)
|
// 6. 解析成功日志(打印文件信息,便于问题排查)
|
||||||
LogUtils.d(TAG, "【选图解析】Uri解析成功!");
|
LogUtils.d(TAG, "【选图解析】Uri解析成功!");
|
||||||
LogUtils.d(TAG, "→ 原Uri:" + uri.toString());
|
LogUtils.d(TAG, "→ 原Uri:" + uri.toString());
|
||||||
LogUtils.d(TAG, "→ 目标临时文件:" + mCropSourceFile.getAbsolutePath());
|
LogUtils.d(TAG, "→ 图片剪裁数据源:" + mCropSourceFile.getAbsolutePath());
|
||||||
LogUtils.d(TAG, "→ 目标临时文件大小:" + mCropSourceFile.length() + " bytes");
|
LogUtils.d(TAG, "→ 图片剪裁数据源文件大小:" + mCropSourceFile.length() + " bytes");
|
||||||
LogUtils.d(TAG, "→ 目标剪裁临时文件:" + mCropResultFile.getAbsolutePath());
|
LogUtils.d(TAG, "→ 剪裁结果数据文件:" + mCropResultFile.getAbsolutePath());
|
||||||
LogUtils.d(TAG, "→ 目标剪裁临时文件大小:" + mCropResultFile.length() + " bytes");
|
LogUtils.d(TAG, "→ 剪裁结果数据文件大小:" + mCropResultFile.length() + " bytes");
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -424,7 +439,7 @@ public class BackgroundSourceUtils {
|
|||||||
* 保存配置(核心:将两份独立Bean实例,分别写入各自的JSON文件)
|
* 保存配置(核心:将两份独立Bean实例,分别写入各自的JSON文件)
|
||||||
*/
|
*/
|
||||||
public void saveSettings() {
|
public void saveSettings() {
|
||||||
if(currentBackgroundBean != null && previewBackgroundBean != null) {
|
if (currentBackgroundBean != null && previewBackgroundBean != null) {
|
||||||
BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean); // 正式Bean→正式JSON
|
BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean); // 正式Bean→正式JSON
|
||||||
BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean); // 预览Bean→预览JSON
|
BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean); // 预览Bean→预览JSON
|
||||||
LogUtils.d(TAG, "【配置管理】两份配置保存成功:正式JSON=" + currentBackgroundBeanFile.getAbsolutePath() + ",预览JSON=" + previewBackgroundBeanFile.getAbsolutePath());
|
LogUtils.d(TAG, "【配置管理】两份配置保存成功:正式JSON=" + currentBackgroundBeanFile.getAbsolutePath() + ",预览JSON=" + previewBackgroundBeanFile.getAbsolutePath());
|
||||||
@@ -531,12 +546,12 @@ public class BackgroundSourceUtils {
|
|||||||
// 更新当前背景文件路径
|
// 更新当前背景文件路径
|
||||||
currentBackgroundBean.setBackgroundFilePath(currentFile.getAbsolutePath()); // 原图路径(BackgroundSource)
|
currentBackgroundBean.setBackgroundFilePath(currentFile.getAbsolutePath()); // 原图路径(BackgroundSource)
|
||||||
currentBackgroundBean.setBackgroundScaledCompressFilePath(currentCropFile.getAbsolutePath()); // 压缩图路径(BackgroundCrops)
|
currentBackgroundBean.setBackgroundScaledCompressFilePath(currentCropFile.getAbsolutePath()); // 压缩图路径(BackgroundCrops)
|
||||||
|
|
||||||
saveSettings(); // 分别保存:正式Bean→currentJSON,预览Bean→previewJSON(两份独立)
|
saveSettings(); // 分别保存:正式Bean→currentJSON,预览Bean→previewJSON(两份独立)
|
||||||
LogUtils.d(TAG, "【配置管理】预览背景深拷贝到正式Bean:两份实例独立,压缩图统一存储到BackgroundCrops");
|
LogUtils.d(TAG, "【配置管理】预览背景深拷贝到正式Bean:两份实例独立,压缩图统一存储到BackgroundCrops");
|
||||||
ToastUtils.show("背景图片应用成功");
|
ToastUtils.show("背景图片应用成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将正式背景同步到预览背景(正式Bean → 预览Bean:深拷贝,新建预览Bean实例+逐字段拷贝)
|
* 将正式背景同步到预览背景(正式Bean → 预览Bean:深拷贝,新建预览Bean实例+逐字段拷贝)
|
||||||
* 核心:深拷贝后,修改预览Bean不会影响正式Bean,两份实例完全独立,压缩图路径统一指向BackgroundCrops
|
* 核心:深拷贝后,修改预览Bean不会影响正式Bean,两份实例完全独立,压缩图路径统一指向BackgroundCrops
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package cc.winboll.studio.powerbell.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||||
|
* @Date 2025/12/08 21:11
|
||||||
|
* @Describe 把 R.drawable 中的图片保存为 File 对象的工具类
|
||||||
|
* 适配 PowerBell 项目:支持指定保存路径、自动创建目录、处理PNG图片压缩
|
||||||
|
*/
|
||||||
|
public class DrawableToFileUtils {
|
||||||
|
private static final String TAG = "DrawableToFileUtils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心方法:将 R.drawable 图片保存为 File 对象
|
||||||
|
* @param context 上下文(用于获取 Resources)
|
||||||
|
* @param drawableResId 图片资源ID(如 R.drawable.ic_test_png)
|
||||||
|
* @param fileName 保存的文件名(需带 .png 后缀,如 "test_drawable.png")
|
||||||
|
* @return 保存成功返回 File 对象,失败返回 null
|
||||||
|
*/
|
||||||
|
public static File saveDrawableToFile(Context context, int drawableResId, String filePath) {
|
||||||
|
// 1. 校验参数(避免空指针/无效参数)
|
||||||
|
if (context == null || drawableResId == 0 || filePath == null || filePath.isEmpty()) {
|
||||||
|
LogUtils.e(TAG, "【保存失败】参数无效(context为空/资源ID为0/文件名为空)");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!filePath.endsWith(".png")) {
|
||||||
|
filePath += ".png"; // 强制添加 .png 后缀,确保图片格式正确
|
||||||
|
LogUtils.d(TAG, "【格式适配】自动添加.png后缀,最终文件名:" + filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构建目标 File 对象(最终保存的文件路径)
|
||||||
|
File targetFile = new File(filePath);
|
||||||
|
LogUtils.d(TAG, "【保存路径】目标文件路径:" + targetFile.getAbsolutePath());
|
||||||
|
|
||||||
|
// 4. 读取 drawable 资源为 Bitmap(处理高清图/缩放问题)
|
||||||
|
Bitmap bitmap = null;
|
||||||
|
try {
|
||||||
|
// 读取 drawable 资源(适配不同分辨率的图片,避免变形)
|
||||||
|
bitmap = BitmapFactory.decodeResource(context.getResources(), drawableResId);
|
||||||
|
if (bitmap == null) {
|
||||||
|
LogUtils.e(TAG, "【读取失败】无法读取drawable资源(资源ID:" + drawableResId + ")");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LogUtils.d(TAG, "【读取成功】drawable资源转Bitmap成功(宽:" + bitmap.getWidth() + ",高:" + bitmap.getHeight() + ")");
|
||||||
|
|
||||||
|
// 5. 将 Bitmap 写入 File(PNG格式,无损保存)
|
||||||
|
FileOutputStream fos = new FileOutputStream(targetFile);
|
||||||
|
// 压缩参数:PNG格式,质量100(无损),写入输出流
|
||||||
|
boolean isSaved = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||||
|
fos.flush(); // 刷新输出流
|
||||||
|
fos.close(); // 关闭输出流
|
||||||
|
|
||||||
|
// 6. 校验保存结果(文件是否存在且有效)
|
||||||
|
if (isSaved && targetFile.exists() && targetFile.length() > 100) {
|
||||||
|
LogUtils.d(TAG, "【保存成功】drawable图片保存为File:" + targetFile.getAbsolutePath());
|
||||||
|
return targetFile; // 保存成功,返回File对象
|
||||||
|
} else {
|
||||||
|
LogUtils.e(TAG, "【保存失败】图片写入文件无效(文件大小:" + (targetFile.exists() ? targetFile.length() : 0) + "字节)");
|
||||||
|
// 保存失败,删除无效文件
|
||||||
|
if (targetFile.exists()) {
|
||||||
|
targetFile.delete();
|
||||||
|
LogUtils.d(TAG, "【清理无效文件】已删除无效文件:" + targetFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogUtils.e(TAG, "【保存异常】写入文件时出错:" + e.getMessage());
|
||||||
|
LogUtils.e(TAG, "【异常堆栈】" + Log.getStackTraceString(e));
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
// 回收Bitmap资源(避免内存溢出)
|
||||||
|
if (bitmap != null && !bitmap.isRecycled()) {
|
||||||
|
bitmap.recycle();
|
||||||
|
LogUtils.d(TAG, "【资源回收】Bitmap资源已回收");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重载方法:自定义保存路径(灵活适配不同场景)
|
||||||
|
* @param context 上下文
|
||||||
|
* @param drawableResId 图片资源ID
|
||||||
|
* @param saveDirPath 自定义保存目录路径(如 "/storage/emulated/0/PowerBell/custom/")
|
||||||
|
* @param fileName 保存的文件名(带.png后缀)
|
||||||
|
* @return 保存成功返回File对象,失败返回null
|
||||||
|
*/
|
||||||
|
public static File saveDrawableToFile(Context context, int drawableResId, String saveDirPath, String fileName) {
|
||||||
|
File filePath = new File(saveDirPath, fileName);
|
||||||
|
return saveDrawableToFile(context, drawableResId, filePath.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -277,5 +277,10 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
return fileSuffix;
|
return fileSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isFileExists(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ public class UriUtil {
|
|||||||
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Uri getUriForFile(Context context, String filePath) {
|
||||||
|
File file = new File(filePath);
|
||||||
|
return getUriForFile(context, file);
|
||||||
|
}
|
||||||
|
|
||||||
public static Uri getUriForFile(Context context, File file) {
|
public static Uri getUriForFile(Context context, File file) {
|
||||||
//Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
|
//Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
|
||||||
|
|||||||
Reference in New Issue
Block a user