20251201_011410_083
This commit is contained in:
@@ -16,6 +16,7 @@ import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
|
||||
import cc.winboll.studio.libaes.views.AToolbar;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
@@ -48,9 +49,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
public static final int REQUEST_CROP_IMAGE = 2;
|
||||
private static final int STORAGE_PERMISSION_REQUEST = 100;
|
||||
|
||||
// FileProvider 授权(必须与AndroidManifest.xml中配置一致)
|
||||
private static final String FILE_PROVIDER_AUTHORITY = "cc.winboll.studio.powerbell.fileprovider";
|
||||
|
||||
private AToolbar mAToolbar;
|
||||
private File mfBackgroundDir; // 背景图片存储文件夹
|
||||
private File mfPictureDir; // 拍照与剪裁临时文件夹
|
||||
private File mfPictureDir; // 拍照与剪裁临时文件夹(权限友好)
|
||||
private File mfTakePhoto; // 拍照文件
|
||||
|
||||
// 背景视图预览图片的文件名
|
||||
@@ -59,16 +63,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
BackgroundView bvPreviewBackground;
|
||||
boolean isCommitSettings = false;
|
||||
|
||||
// 静态变量
|
||||
// 源文件的临时剪裁图片保存名称
|
||||
// 静态变量(裁剪临时文件迁移到临时目录,解决权限冲突)
|
||||
private static String _mSourceCropTempFileName = "SourceCropTemp.jpg";
|
||||
// 源文件的临时剪裁图片保存文件对象
|
||||
private static File _mSourceCropTempFile;
|
||||
// 源文件的剪裁图片保存名称
|
||||
private static File _mSourceCropTempFile; // 存储在mfPictureDir(临时目录)
|
||||
private static String _mSourceCroppedFileName = "SourceCropped.jpg";
|
||||
// 源文件的剪裁图片保存文件对象
|
||||
private static File _mSourceCroppedFile;
|
||||
// 源文件的剪裁图片保存路径
|
||||
private static String _mSourceCroppedFilePath;
|
||||
private static String _mszCommonFileType = "jpeg";
|
||||
private int mnPictureCompress = 100;
|
||||
@@ -101,12 +100,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
mfPictureDir.mkdirs();
|
||||
}
|
||||
|
||||
// 初始化文件对象
|
||||
// 初始化文件对象(核心修复1:裁剪临时文件迁移到临时目录,避免私有目录权限冲突)
|
||||
mfTakePhoto = new File(mfPictureDir, "TakePhoto.jpg");
|
||||
_mSourceCropTempFile = new File(mfBackgroundDir, _mSourceCropTempFileName);
|
||||
_mSourceCropTempFile = new File(mfPictureDir, _mSourceCropTempFileName); // 迁移到mfPictureDir
|
||||
_mSourceCroppedFile = new File(mfBackgroundDir, _mSourceCroppedFileName);
|
||||
_mSourceCroppedFilePath = _mSourceCroppedFile.getAbsolutePath().toString();
|
||||
LogUtils.d(TAG, String.format("_mSourceCroppedFilePath : %s", _mSourceCroppedFilePath));
|
||||
LogUtils.d(TAG, String.format("裁剪临时文件路径 : %s", _mSourceCropTempFile.getAbsolutePath()));
|
||||
|
||||
// 初始化工具栏
|
||||
mAToolbar = (AToolbar) findViewById(R.id.toolbar);
|
||||
@@ -235,8 +235,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
}
|
||||
|
||||
if (checkAndRequestStoragePermission()) {
|
||||
// 适配Android 7.0+ 拍照Uri
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
|
||||
try {
|
||||
Uri photoUri = getUriForFile(BackgroundSettingsActivity.this, mfTakePhoto);
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
|
||||
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
|
||||
} catch (Exception e) {
|
||||
ToastUtils.show(String.format("sharePicture() Exception : %s", e));
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -277,7 +285,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
OutputStream outStream = null;
|
||||
try {
|
||||
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
|
||||
File fRecivedPicture = new File(utils.getPreviewBackgroundScaledCompressFilePath());
|
||||
String scaledCompressFilePath = utils.getPreviewBackgroundScaledCompressFilePath();
|
||||
File fRecivedPicture = new File(scaledCompressFilePath); // 直接使用完整路径,避免拼接错误
|
||||
|
||||
// 确保父目录存在
|
||||
File parentDir = fRecivedPicture.getParentFile();
|
||||
if (!parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
|
||||
if (!fRecivedPicture.exists()) {
|
||||
fRecivedPicture.createNewFile();
|
||||
}
|
||||
@@ -303,74 +319,106 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动图片裁剪活动(核心修复:传递BackgroundView实际宽高比例,替代Bean默认值)
|
||||
* @param isCropFree 是否自由裁剪
|
||||
*/
|
||||
public void startCropImageActivity(boolean isCropFree) {
|
||||
LogUtils.d(TAG, "startCropImageActivity");
|
||||
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
|
||||
BackgroundBean bean = utils.getPreviewBackgroundBean();
|
||||
bean.setIsUseScaledCompress(true);
|
||||
utils.saveSettings();
|
||||
/**
|
||||
* 启动图片裁剪活动(修复:FileProvider适配+意图兼容+异常捕获)
|
||||
* @param isCropFree 是否自由裁剪
|
||||
*/
|
||||
public void startCropImageActivity(boolean isCropFree) {
|
||||
LogUtils.d(TAG, "startCropImageActivity");
|
||||
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
|
||||
BackgroundBean bean = utils.getPreviewBackgroundBean();
|
||||
bean.setIsUseScaledCompress(true);
|
||||
utils.saveSettings();
|
||||
|
||||
File fRecivedPicture = new File(utils.getPreviewBackgroundFilePath());
|
||||
File fRecivedPicture = new File(utils.getPreviewBackgroundFilePath());
|
||||
if (!fRecivedPicture.exists() || fRecivedPicture.length() <= 0) {
|
||||
ToastUtils.show("预览图片不存在或损坏");
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = UriUtil.getUriForFile(this, fRecivedPicture);
|
||||
LogUtils.d(TAG, "uri : " + uri.toString());
|
||||
// 核心修复1:捕获Uri生成异常(避免FileProvider配置错误导致崩溃)
|
||||
Uri inputUri = null;
|
||||
Uri cropOutPutUri = null;
|
||||
try {
|
||||
// 适配Android7.0+,用FileProvider生成Content Uri(输入/输出)
|
||||
inputUri = getUriForFile(this, fRecivedPicture);
|
||||
LogUtils.d(TAG, "裁剪输入Uri : " + inputUri.toString());
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "生成裁剪输入Uri失败:" + e.getMessage());
|
||||
ToastUtils.show("图片裁剪失败:无法获取图片权限");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
// 清理旧临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
|
||||
try {
|
||||
_mSourceCropTempFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
ToastUtils.show("剪裁临时文件创建失败");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
_mSourceCropTempFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
ToastUtils.show("剪裁临时文件创建失败");
|
||||
return;
|
||||
}
|
||||
|
||||
Uri cropOutPutUri = Uri.fromFile(_mSourceCropTempFile);
|
||||
LogUtils.d(TAG, "mfTempCropPicture : " + _mSourceCropTempFile.getPath());
|
||||
// 生成裁剪输出Uri
|
||||
try {
|
||||
cropOutPutUri = getUriForFile(this, _mSourceCropTempFile);
|
||||
LogUtils.d(TAG, "裁剪输出Uri : " + cropOutPutUri.toString());
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "生成裁剪输出Uri失败:" + e.getMessage());
|
||||
ToastUtils.show("图片裁剪失败:无法创建临时文件");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent("com.android.camera.action.CROP");
|
||||
intent.setDataAndType(uri, "image/" + _mszCommonFileType);
|
||||
intent.putExtra("crop", "true");
|
||||
intent.putExtra("noFaceDetection", true);
|
||||
// 核心修复2:裁剪意图兼容(适配不同机型)
|
||||
Intent intent = new Intent("com.android.camera.action.CROP");
|
||||
// 兼容部分机型不支持隐式意图,添加包名过滤(可选,按需添加)
|
||||
intent.setPackage("com.android.camera");
|
||||
intent.setDataAndType(inputUri, "image/" + _mszCommonFileType);
|
||||
intent.putExtra("crop", "true");
|
||||
intent.putExtra("noFaceDetection", true);
|
||||
|
||||
// 修复核心:非自由裁剪时,传递bvPreviewBackground控件的实际宽高比例(确保裁剪与控件匹配)
|
||||
if (!isCropFree) {
|
||||
// 1. 优先获取BackgroundView的实际宽高(控件已填充父视图,宽高=父容器尺寸)
|
||||
int viewWidth = bvPreviewBackground.getWidth();
|
||||
int viewHeight = bvPreviewBackground.getHeight();
|
||||
// 裁剪比例逻辑保持不变...
|
||||
if (!isCropFree) {
|
||||
int viewWidth = bvPreviewBackground.getWidth();
|
||||
int viewHeight = bvPreviewBackground.getHeight();
|
||||
if (viewWidth <= 0 || viewHeight <= 0) {
|
||||
viewWidth = getResources().getDisplayMetrics().widthPixels;
|
||||
viewHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
LogUtils.d(TAG, "控件未测量完成,使用屏幕尺寸作为裁剪比例:" + viewWidth + "x" + viewHeight);
|
||||
}
|
||||
|
||||
// 2. 容错处理:若控件未测量完成(宽/高为0),使用屏幕尺寸兜底
|
||||
if (viewWidth <= 0 || viewHeight <= 0) {
|
||||
viewWidth = getResources().getDisplayMetrics().widthPixels;
|
||||
viewHeight = getResources().getDisplayMetrics().heightPixels;
|
||||
LogUtils.d(TAG, "控件未测量完成,使用屏幕尺寸作为裁剪比例:" + viewWidth + "x" + viewHeight);
|
||||
}
|
||||
int gcd = calculateGCD(viewWidth, viewHeight);
|
||||
int simplifiedWidth = viewWidth / gcd;
|
||||
int simplifiedHeight = viewHeight / gcd;
|
||||
|
||||
// 3. 计算宽高比的最大公约数,简化比例(避免过大数值导致裁剪工具不兼容,如1080:1920→9:16)
|
||||
int gcd = calculateGCD(viewWidth, viewHeight);
|
||||
int simplifiedWidth = viewWidth / gcd;
|
||||
int simplifiedHeight = viewHeight / gcd;
|
||||
intent.putExtra("aspectX", simplifiedWidth);
|
||||
intent.putExtra("aspectY", simplifiedHeight);
|
||||
LogUtils.d(TAG, "裁剪比例(控件实际比例/简化后):" + viewWidth + ":" + viewHeight + " → " + simplifiedWidth + ":" + simplifiedHeight);
|
||||
}
|
||||
|
||||
// 4. 传递简化后的宽高比例给裁剪意图(关键:确保裁剪比例与控件完全匹配)
|
||||
intent.putExtra("aspectX", simplifiedWidth);
|
||||
intent.putExtra("aspectY", simplifiedHeight);
|
||||
LogUtils.d(TAG, "裁剪比例(控件实际比例/简化后):" + viewWidth + ":" + viewHeight + " → " + simplifiedWidth + ":" + simplifiedHeight);
|
||||
}
|
||||
intent.putExtra("return-data", false);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropOutPutUri);
|
||||
intent.putExtra("scale", true);
|
||||
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
|
||||
// 授予裁剪工具读写权限(关键,避免权限不足)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
intent.putExtra("return-data", true);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropOutPutUri);
|
||||
intent.putExtra("scale", true);
|
||||
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
|
||||
startActivityForResult(intent, REQUEST_CROP_IMAGE);
|
||||
}
|
||||
// 核心修复3:添加意图启动校验(避免启动失败无响应)
|
||||
try {
|
||||
startActivityForResult(intent, REQUEST_CROP_IMAGE);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "启动裁剪窗口失败:" + e.getMessage());
|
||||
ToastUtils.show("无法启动裁剪工具,请安装系统相机");
|
||||
// 兼容方案:若系统相机不支持,使用第三方裁剪工具(可选)
|
||||
Intent chooserIntent = Intent.createChooser(intent, "选择裁剪工具");
|
||||
if (chooserIntent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivityForResult(chooserIntent, REQUEST_CROP_IMAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具方法:计算两个数的最大公约数(用于简化宽高比)
|
||||
@@ -386,134 +434,159 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存剪裁后的Bitmap(优化版,修复裁剪后加载不到图片问题)
|
||||
* 工具方法:生成Content Uri(适配Android 7.0+),需在AndroidManifest.xml中配置FileProvider
|
||||
*/
|
||||
private void saveCropBitmap(Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
ToastUtils.show("剪裁图片为空");
|
||||
// 修复:临时文件异常时也清理
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 内存优化:大图片自动缩放(保持原逻辑)
|
||||
Bitmap scaledBitmap = bitmap;
|
||||
if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB
|
||||
float scale = 1.0f;
|
||||
while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) {
|
||||
scale -= 0.2f; // 每次缩小20%
|
||||
if (scale < 0.2f) break; // 最小缩放到20%
|
||||
scaledBitmap = scaleBitmap(scaledBitmap, scale);
|
||||
}
|
||||
if (scaledBitmap != bitmap) {
|
||||
bitmap.recycle(); // 回收原Bitmap
|
||||
}
|
||||
}
|
||||
|
||||
// 优化:创建保存目录(保持原逻辑)
|
||||
File backgroundDir = new File(mBackgroundSourceUtils.getBackgroundSourceDirPath());
|
||||
if (!backgroundDir.exists()) {
|
||||
if (!backgroundDir.mkdirs()) {
|
||||
ToastUtils.show("无法创建保存目录");
|
||||
if (scaledBitmap != bitmap) scaledBitmap.recycle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 剪裁的图片的保存地址(保持原逻辑)
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
|
||||
String scaledCompressFileName = utils.getPreviewBackgroundScaledCompressFilePath();
|
||||
File fScaledCompressBitmapFile = new File(scaledCompressFileName);
|
||||
|
||||
// 优化:检查文件是否可写(保持原逻辑)
|
||||
if (fScaledCompressBitmapFile.exists() && !fScaledCompressBitmapFile.canWrite()) {
|
||||
if (!fScaledCompressBitmapFile.delete()) {
|
||||
ToastUtils.show("无法删除旧文件");
|
||||
if (scaledBitmap != bitmap) scaledBitmap.recycle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(fScaledCompressBitmapFile);
|
||||
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
|
||||
fos.flush();
|
||||
if (success) {
|
||||
ToastUtils.show("图片压缩保存成功");
|
||||
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
|
||||
// 修复1:同步裁剪后路径到预览Bean(关键!确保加载路径匹配)
|
||||
// 从压缩文件路径中提取文件名,更新到previewBean的backgroundFileName
|
||||
String cropFileName = fScaledCompressBitmapFile.getName();
|
||||
previewBean.setBackgroundFileName(cropFileName); // 重点:更新为裁剪后的压缩文件名
|
||||
// 修复2:强制设置isUseBackgroundFile=true(确保BackgroundView加载图片,而非透明背景)
|
||||
previewBean.setIsUseBackgroundFile(true);
|
||||
previewBean.setIsUseScaledCompress(true);
|
||||
utils.saveSettings(); // 持久化保存Bean,确保路径同步
|
||||
|
||||
// 修复3:裁剪成功后立即清理临时文件(避免残留冲突)
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪成功,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
|
||||
// 修复:裁剪成功后刷新预览视图(保持原逻辑,此时路径已同步)
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
|
||||
} else {
|
||||
ToastUtils.show("图片压缩保存失败");
|
||||
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
|
||||
previewBean.setIsUseScaledCompress(false);
|
||||
utils.saveSettings();
|
||||
// 修复:保存失败时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
// 修复:保存失败时刷新原始预览图
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
LogUtils.e(TAG, "文件未找到" + e);
|
||||
ToastUtils.show("文件未找到:" + e.getMessage());
|
||||
// 异常时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "写入异常" + e);
|
||||
ToastUtils.show("写入异常:" + e.getMessage());
|
||||
// 异常时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "流关闭异常" + e);
|
||||
ToastUtils.show("流关闭异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
|
||||
scaledBitmap.recycle(); // 回收缩放后的Bitmap,避免内存泄漏
|
||||
private Uri getUriForFile(Context context, File file) throws Exception {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
try {
|
||||
// 与AndroidManifest.xml中配置的FileProvider授权一致
|
||||
return FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, file);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "FileProvider生成Uri失败:" + e.getMessage() + ",文件路径:" + file.getPath());
|
||||
throw e; // 抛出异常,让上层处理
|
||||
}
|
||||
} else {
|
||||
return Uri.fromFile(file); // 低版本兼容
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存剪裁后的Bitmap(彻底修复:路径拼接+权限+解析异常)
|
||||
*/
|
||||
private void saveCropBitmap(Bitmap bitmap) {
|
||||
if (bitmap == null || bitmap.isRecycled()) {
|
||||
ToastUtils.show("剪裁图片为空或已回收");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 内存优化:大图片自动缩放(保持原逻辑)
|
||||
Bitmap scaledBitmap = bitmap;
|
||||
if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB
|
||||
float scale = 1.0f;
|
||||
while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) {
|
||||
scale -= 0.2f; // 每次缩小20%
|
||||
if (scale < 0.2f) break; // 最小缩放到20%
|
||||
scaledBitmap = scaleBitmap(scaledBitmap, scale);
|
||||
}
|
||||
if (scaledBitmap != bitmap) {
|
||||
bitmap.recycle(); // 回收原Bitmap
|
||||
}
|
||||
}
|
||||
|
||||
// 核心修复1:正确获取保存路径(直接使用完整路径,避免重复拼接)
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
|
||||
String scaledCompressFilePath = utils.getPreviewBackgroundScaledCompressFilePath(); // 完整路径(无嵌套)
|
||||
File fScaledCompressBitmapFile = new File(scaledCompressFilePath);
|
||||
|
||||
// 确保保存目录存在(避免路径无效)
|
||||
File parentDir = fScaledCompressBitmapFile.getParentFile();
|
||||
if (!parentDir.exists()) {
|
||||
if (!parentDir.mkdirs()) {
|
||||
ToastUtils.show("无法创建保存目录:" + parentDir.getAbsolutePath());
|
||||
if (scaledBitmap != bitmap) scaledBitmap.recycle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 优化:检查文件权限(确保可写)
|
||||
if (fScaledCompressBitmapFile.exists()) {
|
||||
if (!fScaledCompressBitmapFile.canWrite()) {
|
||||
if (!fScaledCompressBitmapFile.delete()) {
|
||||
ToastUtils.show("无法删除旧文件(权限不足):" + fScaledCompressBitmapFile.getPath());
|
||||
if (scaledBitmap != bitmap) scaledBitmap.recycle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
// 修复2:设置文件可写权限(避免写入失败)
|
||||
fScaledCompressBitmapFile.setWritable(true, false);
|
||||
fos = new FileOutputStream(fScaledCompressBitmapFile);
|
||||
// 压缩保存(80%质量,平衡清晰度和大小)
|
||||
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
|
||||
fos.flush();
|
||||
if (success) {
|
||||
ToastUtils.show("图片压缩保存成功");
|
||||
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
|
||||
// 修复3:同步裁剪后文件名到预览Bean(仅传文件名,避免路径污染)
|
||||
String cropFileName = fScaledCompressBitmapFile.getName();
|
||||
previewBean.setBackgroundFileName(cropFileName);
|
||||
previewBean.setIsUseBackgroundFile(true); // 强制启用背景图
|
||||
previewBean.setIsUseScaledCompress(true);
|
||||
utils.saveSettings(); // 持久化配置
|
||||
|
||||
// 清理临时文件(双重保障)
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪成功,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
|
||||
// 刷新预览视图(确保裁剪图实时显示)
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
|
||||
} else {
|
||||
ToastUtils.show("图片压缩保存失败(Bitmap压缩异常)");
|
||||
BackgroundBean previewBean = utils.getPreviewBackgroundBean();
|
||||
previewBean.setIsUseScaledCompress(false);
|
||||
utils.saveSettings();
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
// 刷新原始预览图
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
LogUtils.e(TAG, "文件未找到:" + e.getMessage() + ",保存路径:" + fScaledCompressBitmapFile.getPath());
|
||||
ToastUtils.show("保存失败:文件路径无效");
|
||||
// 异常时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "写入异常:" + e.getMessage());
|
||||
ToastUtils.show("保存失败:无写入权限或文件损坏");
|
||||
// 异常时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} finally {
|
||||
// 关闭流(避免资源泄漏)
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "流关闭异常" + e);
|
||||
ToastUtils.show("流关闭异常:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
// 回收Bitmap(避免内存泄漏)
|
||||
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
|
||||
scaledBitmap.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放Bitmap
|
||||
*/
|
||||
private Bitmap scaleBitmap(Bitmap original, float scale) {
|
||||
if (original == null) {
|
||||
if (original == null || original.isRecycled()) {
|
||||
return null;
|
||||
}
|
||||
int width = (int) (original.getWidth() * scale);
|
||||
int height = (int) (original.getHeight() * scale);
|
||||
// 确保宽高为正(避免缩放异常)
|
||||
width = Math.max(width, 1);
|
||||
height = Math.max(height, 1);
|
||||
return Bitmap.createScaledBitmap(original, width, height, true);
|
||||
}
|
||||
|
||||
@@ -522,124 +595,195 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
*/
|
||||
void sharePicture() {
|
||||
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
|
||||
File fRecivedPicture = new File(utils.getCurrentBackgroundFilePath());
|
||||
Uri uri = UriUtil.getUriForFile(this, fRecivedPicture);
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
shareIntent.setType("image/" + _mszCommonFileType);
|
||||
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(Intent.createChooser(shareIntent, "Share Image"));
|
||||
}
|
||||
String currentBgPath = utils.getCurrentBackgroundFilePath();
|
||||
File fRecivedPicture = new File(currentBgPath);
|
||||
if (!fRecivedPicture.exists() || fRecivedPicture.length() <= 0) {
|
||||
ToastUtils.show("分享的背景图片不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
// 适配Android7.0+ 分享Uri
|
||||
try {
|
||||
Uri uri = getUriForFile(this, fRecivedPicture);
|
||||
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
shareIntent.setType("image/" + _mszCommonFileType);
|
||||
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
startActivity(Intent.createChooser(shareIntent, "Share Image"));
|
||||
} catch (Exception e) {
|
||||
ToastUtils.show(String.format("sharePicture() Exception : %s", e));
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_SELECT_PICTURE && resultCode == RESULT_OK) {
|
||||
try {
|
||||
Uri selectedImage = data.getData();
|
||||
LogUtils.d(TAG, "Uri is : " + selectedImage.toString());
|
||||
File fSrcImage = new File(UriUtil.getFilePathFromUri(this, selectedImage));
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
|
||||
if (selectedImage == null) {
|
||||
ToastUtils.show("选择的图片Uri为空");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "选择图片Uri : " + selectedImage.toString());
|
||||
|
||||
// 修复:保存图片到预览Bean后,立即刷新BackgroundView显示预览图
|
||||
// 核心修复1:替换路径解析方式,兼容UriUtil解析失败场景
|
||||
File fSrcImage = null;
|
||||
String filePath = UriUtil.getFilePathFromUri(this, selectedImage);
|
||||
if (!TextUtils.isEmpty(filePath)) {
|
||||
fSrcImage = new File(filePath);
|
||||
} else {
|
||||
// 兼容方案:通过ContentResolver读取图片流,保存为临时文件
|
||||
fSrcImage = new File(mfPictureDir, "selected_temp.jpg");
|
||||
if (fSrcImage.exists()) {
|
||||
fSrcImage.delete();
|
||||
}
|
||||
// 复制图片流到临时文件
|
||||
FileUtils.copyStreamToFile(getContentResolver().openInputStream(selectedImage), fSrcImage);
|
||||
LogUtils.d(TAG, "Uri解析失败,通过流复制生成临时文件:" + fSrcImage.getPath());
|
||||
}
|
||||
|
||||
// 核心修复2:增强文件有效性校验
|
||||
if (fSrcImage == null || !fSrcImage.exists() || fSrcImage.length() <= 0) {
|
||||
ToastUtils.show("选择的图片文件不存在或损坏");
|
||||
return;
|
||||
}
|
||||
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
|
||||
// 保存图片到预览Bean并刷新
|
||||
utils.saveFileToPreviewBean(fSrcImage, selectedImage.toString());
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
|
||||
// 启动裁剪(保持原逻辑,裁剪比例已修复)
|
||||
// 启动裁剪(增加异常捕获)
|
||||
startCropImageActivity(false);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "选择图片异常" + e);
|
||||
ToastUtils.show("选择图片失败:" + e.getMessage());
|
||||
// 异常时清理临时文件(避免残留)
|
||||
// 异常时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "选择图片异常,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
|
||||
LogUtils.d(TAG, "REQUEST_TAKE_PHOTO");
|
||||
Bundle extras = data.getExtras();
|
||||
if (extras != null) {
|
||||
Bitmap imageBitmap = (Bitmap) extras.get("data");
|
||||
if (imageBitmap != null) {
|
||||
compressQualityToRecivedPicture(imageBitmap);
|
||||
// 修复:拍照压缩后,刷新预览图
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
startCropImageActivity(false);
|
||||
} else {
|
||||
ToastUtils.show("拍照图片为空");
|
||||
// 图片为空时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show("拍照数据获取失败");
|
||||
// 数据获取失败时清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照数据获取失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else if (requestCode == REQUEST_CROP_IMAGE && resultCode == RESULT_OK) {
|
||||
LogUtils.d(TAG, "CROP_IMAGE_REQUEST_CODE");
|
||||
try {
|
||||
Bitmap cropBitmap = null;
|
||||
// 方案1:通过Intent获取剪裁后的Bitmap
|
||||
if (data != null && data.hasExtra("data")) {
|
||||
cropBitmap = data.getParcelableExtra("data");
|
||||
} else if (_mSourceCropTempFile.exists()) {
|
||||
LogUtils.d(TAG, String.format("_mSourceCropTempFile Exists, Path is :%s ", _mSourceCropTempFile.getPath()));
|
||||
cropBitmap = BitmapFactory.decodeFile(_mSourceCropTempFile.getPath());
|
||||
} else {
|
||||
ToastUtils.show("剪裁文件不存在");
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "REQUEST_TAKE_PHOTO");
|
||||
// 检查拍照文件是否有效
|
||||
if (!mfTakePhoto.exists() || mfTakePhoto.length() <= 0) {
|
||||
ToastUtils.show("拍照文件不存在或损坏");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照文件无效,清理临时文件");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cropBitmap != null) {
|
||||
saveCropBitmap(cropBitmap); // 调用保存方法(内含预览刷新+临时文件清理)
|
||||
} else {
|
||||
ToastUtils.show("获取剪裁图片失败");
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
LogUtils.e(TAG, "内存溢出" + e);
|
||||
ToastUtils.show("保存失败:内存不足,请尝试裁剪更小的图片");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "剪裁保存异常" + e);
|
||||
ToastUtils.show("保存失败:" + e.getMessage());
|
||||
} finally {
|
||||
// 修复核心:裁剪流程结束后,强制清理临时文件(双重保障,避免残留冲突)
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪流程结束,强制清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else if (resultCode != RESULT_OK) {
|
||||
LogUtils.d(TAG, "操作取消或失败,requestCode: " + requestCode);
|
||||
ToastUtils.show("操作已取消");
|
||||
// 修复:操作取消/失败时,强制清理临时文件(避免影响下次裁剪)
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "操作取消/失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
Bundle extras = data.getExtras();
|
||||
if (extras != null) {
|
||||
Bitmap imageBitmap = (Bitmap) extras.get("data");
|
||||
if (imageBitmap != null && !imageBitmap.isRecycled()) {
|
||||
compressQualityToRecivedPicture(imageBitmap);
|
||||
// 拍照压缩后刷新预览
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
// 启动裁剪
|
||||
startCropImageActivity(false);
|
||||
} else {
|
||||
ToastUtils.show("拍照图片为空");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照图片为空,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show("拍照数据获取失败");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照数据获取失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else if (requestCode == REQUEST_CROP_IMAGE && resultCode == RESULT_OK) {
|
||||
LogUtils.d(TAG, "CROP_IMAGE_REQUEST_CODE");
|
||||
try {
|
||||
Bitmap cropBitmap = null;
|
||||
// 核心修复:优先读取裁剪临时文件(放弃data.getParcelableExtra,避免缩略图)
|
||||
if (_mSourceCropTempFile.exists() && _mSourceCropTempFile.length() > 0) {
|
||||
LogUtils.d(TAG, String.format("_mSourceCropTempFile 信息:路径=%s , 大小=%d bytes",
|
||||
_mSourceCropTempFile.getPath(), _mSourceCropTempFile.length()));
|
||||
// 优化Bitmap解析选项(避免OOM和损坏图片解析失败)
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inPreferredConfig = Bitmap.Config.RGB_565; // 省内存(仅RGB,无透明通道)
|
||||
options.inSampleSize = 1; // 不缩放(保证清晰度)
|
||||
options.inJustDecodeBounds = false;
|
||||
cropBitmap = BitmapFactory.decodeFile(_mSourceCropTempFile.getPath(), options);
|
||||
} else {
|
||||
ToastUtils.show("剪裁文件为空或损坏");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查解析后的Bitmap是否有效
|
||||
if (cropBitmap != null && !cropBitmap.isRecycled()) {
|
||||
saveCropBitmap(cropBitmap); // 调用保存方法(内含修复逻辑)
|
||||
} else {
|
||||
ToastUtils.show("获取剪裁图片失败(Bitmap解析异常)");
|
||||
// 清理无效临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "Bitmap解析失败,清理无效临时文件");
|
||||
}
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
LogUtils.e(TAG, "内存溢出" + e);
|
||||
ToastUtils.show("保存失败:内存不足,请尝试裁剪更小的图片");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "剪裁保存异常" + e);
|
||||
ToastUtils.show("保存失败:" + e.getMessage());
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
} finally {
|
||||
// 裁剪流程结束,强制清理临时文件(双重保障,避免残留)
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "裁剪流程结束,强制清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
} else if (resultCode != RESULT_OK) {
|
||||
LogUtils.d(TAG, "操作取消或失败,requestCode: " + requestCode);
|
||||
ToastUtils.show("操作已取消");
|
||||
// 操作取消/失败时,强制清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "操作取消/失败,清理临时文件:" + _mSourceCropTempFile.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类型是否为图片
|
||||
*/
|
||||
private boolean isImageType(String type) {
|
||||
if (TextUtils.isEmpty(type)) {
|
||||
return false;
|
||||
}
|
||||
return type.startsWith("image/") || "image/jpeg".equals(type) ||
|
||||
"image/jpg".equals(type) || "image/png".equals(type) ||
|
||||
"image/webp".equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并申请存储权限
|
||||
/**
|
||||
* 检查并申请存储权限(修复:适配低版本API,移除Android13+依赖)
|
||||
*/
|
||||
private boolean checkAndRequestStoragePermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// 仅保留Android 6.0+(API 23)的WRITE_EXTERNAL_STORAGE权限,兼容低版本
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // M = API 23,Android 6.0
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
@@ -654,10 +798,18 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == STORAGE_PERMISSION_REQUEST) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
boolean isGranted = false;
|
||||
// 检查权限是否授予
|
||||
for (int result : grantResults) {
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
isGranted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isGranted) {
|
||||
ToastUtils.show("存储权限已获取");
|
||||
} else {
|
||||
ToastUtils.show("需要存储权限才能保存图片");
|
||||
ToastUtils.show("需要存储权限才能保存/选择图片");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,13 +819,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
BackgroundBean bean = utils.getCurrentBackgroundBean();
|
||||
int nPixelColor = bean.getPixelColor();
|
||||
RelativeLayout mainLayout = findViewById(R.id.activitybackgroundpictureRelativeLayout1);
|
||||
mainLayout.setBackgroundColor(nPixelColor);
|
||||
if (mainLayout != null) {
|
||||
mainLayout.setBackgroundColor(nPixelColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
setBackgroundColor();
|
||||
// Resume时刷新预览(避免后台切换后视图异常)
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
}
|
||||
|
||||
public void onNetworkBackgroundDialog(View view) {
|
||||
@@ -709,16 +865,25 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
OnRecivedPictureListener onRecivedPictureListener = new OnRecivedPictureListener(){
|
||||
@Override
|
||||
public void onRecivedPicture(String srcFilePath, String srcFileUrl) {
|
||||
if (TextUtils.isEmpty(srcFilePath)) {
|
||||
ToastUtils.show("网络图片路径为空");
|
||||
return;
|
||||
}
|
||||
File srcFile = new File(srcFilePath);
|
||||
if (!srcFile.exists() || srcFile.length() <= 0) {
|
||||
ToastUtils.show("网络图片文件不存在或损坏");
|
||||
return;
|
||||
}
|
||||
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
|
||||
utils.saveFileToPreviewBean(new File(srcFilePath), srcFileUrl);
|
||||
utils.saveFileToPreviewBean(srcFile, srcFileUrl);
|
||||
// 修复:网络图片下载后刷新预览
|
||||
bvPreviewBackground.reloadPreviewBackground();
|
||||
startCropImageActivity(true);
|
||||
startCropImageActivity(true); // 自由裁剪
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重写finish方法,确保所有退出场景都触发Toast
|
||||
* 重写finish方法,确保所有退出场景都触发确认提示
|
||||
*/
|
||||
@Override
|
||||
public void finish() {
|
||||
@@ -730,7 +895,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
isCommitSettings = true;
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
|
||||
BackgroundBean bean = utils.getCurrentBackgroundBean();
|
||||
bean.setIsUseBackgroundFile(!preViewFilePath.equals(""));
|
||||
// 修复:根据预览路径是否为空,设置是否启用背景图
|
||||
bean.setIsUseBackgroundFile(!TextUtils.isEmpty(preViewFilePath));
|
||||
utils.saveSettings();
|
||||
finish();
|
||||
}
|
||||
@@ -738,7 +904,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
@Override
|
||||
public void onYes() {
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
|
||||
utils.commitPreviewSourceToCurrent();
|
||||
utils.commitPreviewSourceToCurrent(); // 提交预览到正式背景
|
||||
isCommitSettings = true;
|
||||
finish();
|
||||
}
|
||||
@@ -748,4 +914,3 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -232,5 +232,28 @@ public class FileUtils {
|
||||
return String.format("%s_%d%s", uniqueId, timeStamp, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制输入流到文件(兼容Uri解析失败场景)
|
||||
*/
|
||||
public static void copyStreamToFile(InputStream inputStream, File file) throws IOException {
|
||||
if (inputStream == null || file == null) {
|
||||
return;
|
||||
}
|
||||
// 确保父目录存在
|
||||
File parentDir = file.getParentFile();
|
||||
if (!parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
fos.flush();
|
||||
fos.close();
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<!-- 保留root-path适配特殊机型(如微信分身) -->
|
||||
<root-path
|
||||
name="root_path"
|
||||
path="" />
|
||||
|
||||
<!-- 核心修复1:替换files-path为external-files-path(对应外部存储应用目录) -->
|
||||
<!-- 适配mfBackgroundDir(BackgroundSource目录):对应BackgroundSourceUtils.getBackgroundSourceDirPath() -->
|
||||
<external-files-path
|
||||
name="background_source"
|
||||
path="BackgroundPictureUtils/BackgroundSource/" /> <!-- 与代码中目录完全一致 -->
|
||||
|
||||
<!-- 适配mfPictureDir(临时目录):对应App.getTempDirPath() -->
|
||||
<external-files-path
|
||||
name="temp"
|
||||
path="temp/" /> <!-- 与代码中App.getTempDirPath()的路径后缀一致 -->
|
||||
|
||||
<!-- 保留其他配置适配分享/拍照等场景 -->
|
||||
<external-path
|
||||
name="external_storage_root"
|
||||
path="." />
|
||||
<files-path
|
||||
name="files_path"
|
||||
path="." />
|
||||
<cache-path
|
||||
name="cache_path"
|
||||
path="." />
|
||||
<!--/storage/emulated/0/Android/data/...-->
|
||||
<external-files-path
|
||||
name="external_file_path"
|
||||
path="." />
|
||||
<external-files-path
|
||||
name="files_root"
|
||||
path="mimoDownload" />
|
||||
<!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的目录-->
|
||||
<external-files-path
|
||||
name="files_root"
|
||||
path="mimoDownload" />
|
||||
<external-cache-path
|
||||
name="external_cache_path"
|
||||
path="." />
|
||||
<!--配置root-path。这样子可以读取到sd卡和一些应用分身的目录,否则微信分身保存的图片,就会导致 java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/999/tencent/MicroMsg/WeiXin/export1544062754693.jpg,在小米6的手机上微信分身有这个crash,华为没有
|
||||
-->
|
||||
<root-path
|
||||
name="root_path"
|
||||
path="" />
|
||||
</paths>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user