20251204_134218_045

This commit is contained in:
2025-12-04 13:42:30 +08:00
parent 7f3c91fb1d
commit 19e6e276bd
5 changed files with 240 additions and 179 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Wed Dec 03 22:57:30 GMT 2025
#Thu Dec 04 05:39:23 GMT 2025
stageCount=13
libraryProject=
baseVersion=15.11
publishVersion=15.11.12
buildCount=195
buildCount=205
baseBetaVersion=15.11.13

View File

@@ -6,7 +6,6 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -14,10 +13,10 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import cc.winboll.studio.libaes.views.AToolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
@@ -236,9 +235,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
public void onClick(View v) {
LogUtils.d(TAG, "【按钮点击】固定比例裁剪");
// 调用裁剪工具类:传入上下文、预览图、固定比例(按视图宽高)、请求码
ImageCropUtils.startSystemCrop(
BackgroundSettingsActivity.this,
new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()),
startSystemCrop(
mBgSourceUtils.getPreviewBackgroundBean(),
mBackgroundView.getWidth(),
mBackgroundView.getHeight(),
false,
@@ -252,9 +250,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
public void onClick(View v) {
LogUtils.d(TAG, "【按钮点击】自由裁剪");
// 调用裁剪工具类传入上下文、预览图、自由裁剪比例参数传0、请求码
ImageCropUtils.startSystemCrop(
BackgroundSettingsActivity.this,
new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()),
startSystemCrop(
mBgSourceUtils.getPreviewBackgroundBean(),
0,
0,
true,
@@ -288,7 +285,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, "【拍照权限】已获取");
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
Uri photoUri = ImageCropUtils.getFileProviderUri(BackgroundSettingsActivity.this, mfTakePhoto);
Uri photoUri = getFileProviderUri(mfTakePhoto);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
LogUtils.d(TAG, "【拍照启动】Uri" + photoUri.toString());
@@ -412,9 +409,8 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
doubleRefreshPreview();
// 拍照后启动固定比例裁剪(调用工具类)
ImageCropUtils.startSystemCrop(
this,
mfTakePhoto,
startSystemCrop(
mBgSourceUtils.getPreviewBackgroundBean(),
mBackgroundView.getWidth(),
mBackgroundView.getHeight(),
false,
@@ -460,7 +456,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
}
private void handleCropImageResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "handleCropImageResult: 处理裁剪结果");
LogUtils.d(TAG, "handleCropImageResult: 处理裁剪结果");
File cropTempFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath());
boolean isFileExist = cropTempFile.exists();
boolean isFileReadable = isFileExist ? cropTempFile.canRead() : false;
@@ -468,7 +464,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
boolean isCropSuccess = (resultCode == RESULT_OK) && isFileExist && isFileReadable && fileSize > 100;
if (isCropSuccess) {
Log.d(TAG, "handleCropImageResult: 裁剪成功");
LogUtils.d(TAG, "handleCropImageResult: 裁剪成功");
BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean();
previewBean.setIsUseBackgroundFile(true);
previewBean.setIsUseBackgroundScaledCompressFile(true);
@@ -495,7 +491,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
public void run() {
if (mBackgroundView != null && !isFinishing()) {
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean());
Log.d(TAG, "handleCropImageResult: 裁剪图片加载完成");
LogUtils.d(TAG, "handleCropImageResult: 裁剪图片加载完成");
}
}
}, 50);
@@ -505,9 +501,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
}
private float getRatioFromSystemCropFile(File systemCropFile) {
Log.d(TAG, "getRatioFromSystemCropFile: 读取比例");
LogUtils.d(TAG, "getRatioFromSystemCropFile: 读取比例");
if (systemCropFile == null || !systemCropFile.exists() || !systemCropFile.isFile()) {
Log.e(TAG, "getRatioFromSystemCropFile: 文件无效");
LogUtils.e(TAG, "getRatioFromSystemCropFile: 文件无效");
return -1;
}
@@ -518,19 +514,19 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
int cropWidth = options.outWidth;
int cropHeight = options.outHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
Log.e(TAG, "getRatioFromSystemCropFile: 尺寸无效");
LogUtils.e(TAG, "getRatioFromSystemCropFile: 尺寸无效");
return -1;
}
float systemRatio = (float) cropWidth / cropHeight;
Log.d(TAG, "getRatioFromSystemCropFile: 比例:" + systemRatio);
LogUtils.d(TAG, "getRatioFromSystemCropFile: 比例:" + systemRatio);
return systemRatio;
}
private Bitmap adjustBitmapToFinalRatio(Bitmap originalBitmap, float finalCropRatio) {
Log.d(TAG, "adjustBitmapToFinalRatio: 调整比例");
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整比例");
if (originalBitmap == null || originalBitmap.isRecycled() || finalCropRatio <= 0) {
Log.e(TAG, "adjustBitmapToFinalRatio: 参数无效");
LogUtils.e(TAG, "adjustBitmapToFinalRatio: 参数无效");
return originalBitmap;
}
@@ -539,7 +535,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
float originalRatio = (float) originalWidth / originalHeight;
if (Math.abs(originalRatio - finalCropRatio) < 0.001f) {
Log.d(TAG, "adjustBitmapToFinalRatio: 比例一致");
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 比例一致");
return originalBitmap;
}
@@ -552,7 +548,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
}
targetWidth = Math.round(targetHeight * finalCropRatio);
Log.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight);
LogUtils.d(TAG, "adjustBitmapToFinalRatio: 调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight);
Bitmap adjustedBitmap = Bitmap.createBitmap(
originalBitmap,
@@ -566,15 +562,15 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
}
private void saveScaledBitmapToFile(Bitmap bitmap, File targetFile) {
Log.d(TAG, "saveScaledBitmapToFile: 保存图片");
LogUtils.d(TAG, "saveScaledBitmapToFile: 保存图片");
if (bitmap == null || bitmap.isRecycled() || targetFile == null) {
Log.e(TAG, "saveScaledBitmapToFile: 参数无效");
LogUtils.e(TAG, "saveScaledBitmapToFile: 参数无效");
return;
}
if (targetFile.exists()) {
boolean deleteSuccess = targetFile.delete();
Log.d(TAG, "saveScaledBitmapToFile: 删除原文件:" + (deleteSuccess ? "成功" : "失败"));
LogUtils.d(TAG, "saveScaledBitmapToFile: 删除原文件:" + (deleteSuccess ? "成功" : "失败"));
}
OutputStream outputStream = null;
@@ -582,24 +578,24 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));
bitmap.compress(CompressFormat.JPEG, 100, outputStream);
outputStream.flush();
Log.d(TAG, "saveScaledBitmapToFile: 保存成功");
LogUtils.d(TAG, "saveScaledBitmapToFile: 保存成功");
} catch (IOException e) {
Log.e(TAG, "saveScaledBitmapToFile: 异常:" + e.getMessage());
LogUtils.e(TAG, "saveScaledBitmapToFile: 异常:" + e.getMessage());
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Log.e(TAG, "saveScaledBitmapToFile: 关闭流异常");
LogUtils.e(TAG, "saveScaledBitmapToFile: 关闭流异常");
}
}
}
}
private Bitmap parseCropTempFileToBitmap(File cropTempFile) {
Log.d(TAG, "parseCropTempFileToBitmap: 解析文件");
LogUtils.d(TAG, "parseCropTempFileToBitmap: 解析文件");
if (cropTempFile == null || !cropTempFile.exists() || !cropTempFile.isFile() || cropTempFile.length() <= 100) {
Log.e(TAG, "parseCropTempFileToBitmap: 文件无效");
LogUtils.e(TAG, "parseCropTempFileToBitmap: 文件无效");
return null;
}
@@ -613,7 +609,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
sampleSize *= 2;
}
sampleSize = Math.min(sampleSize, 16);
Log.d(TAG, "parseCropTempFileToBitmap: 采样率:" + sampleSize);
LogUtils.d(TAG, "parseCropTempFileToBitmap: 采样率:" + sampleSize);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
@@ -625,16 +621,16 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
try {
cropBitmap = BitmapFactory.decodeFile(cropTempFile.getAbsolutePath(), options);
if (cropBitmap == null || cropBitmap.isRecycled()) {
Log.e(TAG, "parseCropTempFileToBitmap: 解析失败");
LogUtils.e(TAG, "parseCropTempFileToBitmap: 解析失败");
return null;
}
Log.d(TAG, "parseCropTempFileToBitmap: 解析成功");
LogUtils.d(TAG, "parseCropTempFileToBitmap: 解析成功");
} catch (OutOfMemoryError e) {
Log.e(TAG, "parseCropTempFileToBitmap: OOM");
LogUtils.e(TAG, "parseCropTempFileToBitmap: OOM");
Toast.makeText(this, "图片解析失败", Toast.LENGTH_SHORT).show();
return null;
} catch (Exception e) {
Log.e(TAG, "parseCropTempFileToBitmap: 异常:" + e.getMessage());
LogUtils.e(TAG, "parseCropTempFileToBitmap: 异常:" + e.getMessage());
return null;
}
@@ -683,14 +679,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, "【选图权限】已添加持久化权限");
}
mBgSourceUtils.createCropFileProviderPath(selectedImage);
String targetCompressPath = mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath();
BackgroundBean cropBean = mBgSourceUtils.createCropFileProviderBackgroundBean(selectedImage);
LogUtils.d(TAG, "【选图同步】路径绑定完成");
// 选图后启动固定比例裁剪(调用工具类)
ImageCropUtils.startSystemCrop(
this,
new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath()),
startSystemCrop(
cropBean,
mBackgroundView.getWidth(),
mBackgroundView.getHeight(),
false,
@@ -703,6 +697,87 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
LogUtils.d(TAG, "【操作回调】取消或失败");
ToastUtils.show("操作已取消");
}
/**
* 启动系统裁剪工具
* @param activity 上下文
* @param srcFile 裁剪原图
* @param aspectX 裁剪宽比例自由裁剪传0
* @param aspectY 裁剪高比例自由裁剪传0
* @param isFreeCrop 是否自由裁剪
* @param requestCode 裁剪请求码
*/
public void startSystemCrop(BackgroundBean cropBean, int aspectX, int aspectY, boolean isFreeCrop, int requestCode) {
LogUtils.d(TAG, "startSystemCrop: 启动系统裁剪,自由裁剪:" + isFreeCrop);
File srcFile = new File(cropBean.getBackgroundFilePath());
// 校验原图
if (srcFile == null || !srcFile.exists() || srcFile.length() <= 100) {
Toast.makeText(this, "无有效图片可裁剪", Toast.LENGTH_SHORT).show();
LogUtils.e(TAG, "startSystemCrop: 原图无效");
return;
}
// 生成输入Uri
Uri inputUri = getFileProviderUri(srcFile);
if (inputUri == null) {
Toast.makeText(this, "获取图片Uri失败", Toast.LENGTH_SHORT).show();
LogUtils.e(TAG, "startSystemCrop: 输入Uri生成失败");
return;
}
// 生成输出文件使用BackgroundSourceUtils的压缩路径
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(this);
File outputFile = new File(bgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath());
if (outputFile == null) {
Toast.makeText(this, "裁剪输出路径无效", Toast.LENGTH_SHORT).show();
LogUtils.e(TAG, "startSystemCrop: 输出文件为空");
return;
}
Uri outputUri = getFileProviderUri(outputFile);
Uri cropOutPutUri = outputUri;
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(inputUri, "image/*");
//intent.setDataAndType(inputUri, activity.getContentResolver().getType(inputUri));
intent.putExtra("crop", "true");
intent.putExtra("noFaceDetection", true);
if (!isFreeCrop) {
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
}
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, requestCode);
LogUtils.d(TAG, "startSystemCrop: 启动裁剪成功,输出路径:" + outputFile.getAbsolutePath());
}
/**
* 获取FileProvider Uri复用方法避免重复代码
*/
public Uri getFileProviderUri(File file) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String FILE_PROVIDER_AUTHORITY = getPackageName() + ".fileprovider";
return FileProvider.getUriForFile(this, FILE_PROVIDER_AUTHORITY, file);
} else {
return Uri.fromFile(file);
}
} catch (Exception e) {
LogUtils.e(TAG, "getFileProviderUri: 生成Uri失败" + e.getMessage());
return null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

View File

@@ -245,23 +245,15 @@ public class BackgroundSourceUtils {
return contentUri;
}
public boolean createCropFileProviderPath(Uri uri) {
public BackgroundBean createCropFileProviderBackgroundBean(Uri uri) {
InputStream is = null;
FileOutputStream fos = null;
try {
clearCropTempFiles();
String szType = mContext.getContentResolver().getType(uri);
//String szType = mContext.getContentResolver().getType(uri);
// 2. 截取MIME类型后缀如从image/jpeg中提取jpeg【核心新增逻辑】
String fileSuffix = "";
if (szType != null && szType.contains("/")) {
// 分割字符串,取"/"后面的部分(如"image/jpeg" → 分割后取索引1的"jpeg"
fileSuffix = szType.split("/")[1];
// 调试日志:打印截取后的文件后缀
} else {
// 异常处理若类型为空或格式错误默认后缀设为jpeg保留原逻辑兼容性
fileSuffix = "jpeg";
}
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
String newCropFileName = UUID.randomUUID().toString() + System.currentTimeMillis();
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
@@ -273,7 +265,7 @@ public class BackgroundSourceUtils {
is = mContext.getContentResolver().openInputStream(uri);
if (is == null) {
LogUtils.e(TAG, "【选图解析】ContentResolver打开Uri失败Uri" + uri.toString());
return false;
return null;
}
// 2. 初始化选图临时文件输出流Java7 手动创建流不依赖try-with-resources
@@ -310,14 +302,14 @@ public class BackgroundSourceUtils {
LogUtils.d(TAG, "→ 目标临时文件大小:" + mCropSourceFile.length() + " bytes");
LogUtils.d(TAG, "→ 目标剪裁临时文件:" + mCropResultFile.getAbsolutePath());
LogUtils.d(TAG, "→ 目标剪裁临时文件大小:" + mCropResultFile.length() + " bytes");
return true;
return previewBackgroundBean;
} catch (Exception e) {
// 捕获所有异常IO异常/空指针等),避免崩溃
LogUtils.e(TAG, "【选图解析】流复制异常:" + e.getMessage(), e);
// 异常时清理无效文件,防止残留
clearCropTempFiles();
return false;
return null;
} finally {
// 7. 手动关闭流资源Java7 标准写法,避免内存泄漏)

View File

@@ -11,6 +11,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import android.content.Context;
import android.net.Uri;
/**
* 文件操作工具类
@@ -260,6 +262,20 @@ public class FileUtils {
}
}
}
public static String getFileSuffix(Context context, Uri uri){
String szType = context.getContentResolver().getType(uri);
// 2. 截取MIME类型后缀如从image/jpeg中提取jpeg【核心新增逻辑】
String fileSuffix = "";
if (szType != null && szType.contains("/")) {
// 分割字符串,取"/"后面的部分(如"image/jpeg" → 分割后取索引1的"jpeg"
fileSuffix = szType.split("/")[1];
// 调试日志:打印截取后的文件后缀
} else {
// 异常处理若类型为空或格式错误默认后缀设为jpeg保留原逻辑兼容性
fileSuffix = "jpeg";
}
return fileSuffix;
}
}

View File

@@ -12,9 +12,14 @@ import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.model.BackgroundBean;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
@@ -22,127 +27,100 @@ import cc.winboll.studio.powerbell.App;
* @Describe 图片裁剪工具类(仅调用系统裁剪,传入比例/自由裁剪参数)
*/
public class ImageCropUtils {
private static final String TAG = "ImageCropUtils";
public static final String TAG = "ImageCropUtils";
// FileProvider授权与清单文件一致
/**
* 启动系统裁剪工具
* @param activity 上下文
* @param srcFile 裁剪原图
* @param aspectX 裁剪宽比例自由裁剪传0
* @param aspectY 裁剪高比例自由裁剪传0
* @param isFreeCrop 是否自由裁剪
* @param requestCode 裁剪请求码
*/
public static void startSystemCrop(Activity activity, File srcFile, int aspectX, int aspectY, boolean isFreeCrop, int requestCode) {
Log.d(TAG, "startSystemCrop: 启动系统裁剪,自由裁剪:" + isFreeCrop);
// 校验原图
if (srcFile == null || !srcFile.exists() || srcFile.length() <= 100) {
Toast.makeText(activity, "无有效图片可裁剪", Toast.LENGTH_SHORT).show();
Log.e(TAG, "startSystemCrop: 原图无效");
return;
}
// 生成输入Uri
Uri inputUri = getFileProviderUri(activity, srcFile);
if (inputUri == null) {
Toast.makeText(activity, "获取图片Uri失败", Toast.LENGTH_SHORT).show();
Log.e(TAG, "startSystemCrop: 输入Uri生成失败");
return;
}
// 生成输出文件使用BackgroundSourceUtils的压缩路径
BackgroundSourceUtils bgSourceUtils = BackgroundSourceUtils.getInstance(activity);
File outputFile = new File(bgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath());
if (outputFile == null) {
Toast.makeText(activity, "裁剪输出路径无效", Toast.LENGTH_SHORT).show();
Log.e(TAG, "startSystemCrop: 输出文件为空");
return;
}
Uri outputUri = getFileProviderUri(activity, outputFile);
// 构建裁剪意图
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(inputUri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("noFaceDetection", true);
// 设置裁剪比例(自由裁剪则不设置)
if (!isFreeCrop && aspectX > 0 && aspectY > 0) {
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
Log.d(TAG, "startSystemCrop: 裁剪比例:" + aspectX + ":" + aspectY);
}
// 输出配置
intent.putExtra("outputX", 2048);
intent.putExtra("outputY", 2048);
intent.putExtra("scale", true);
intent.putExtra("scaleUpIfNeeded", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("quality", 100);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
// 权限设置
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}
// 适配系统裁剪工具
try {
List<ResolveInfo> resolveInfos = activity.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (!resolveInfos.isEmpty()) {
ResolveInfo resolveInfo = resolveInfos.get(0);
String cropPackageName = resolveInfo.activityInfo.packageName;
String cropActivityName = resolveInfo.activityInfo.name;
// 授予MIUI裁剪权限
if (cropPackageName.equals("com.miui.gallery")) {
activity.grantUriPermission(cropPackageName, inputUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
activity.grantUriPermission(cropPackageName, outputUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
// 显式启动裁剪
Intent cropIntent = new Intent(intent);
cropIntent.setComponent(new ComponentName(cropPackageName, cropActivityName));
activity.startActivityForResult(cropIntent, requestCode);
Log.d(TAG, "startSystemCrop: 启动裁剪成功,输出路径:" + outputFile.getAbsolutePath());
} else {
// 兜底启动
Intent chooser = Intent.createChooser(intent, "选择裁剪工具");
chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (chooser.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooser, requestCode);
} else {
Toast.makeText(activity, "无可用裁剪工具", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Log.e(TAG, "startSystemCrop: 启动裁剪失败:" + e.getMessage());
Toast.makeText(activity, "裁剪工具启动失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 获取FileProvider Uri复用方法避免重复代码
*/
public static Uri getFileProviderUri(Activity activity, File file) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String FILE_PROVIDER_AUTHORITY = activity.getPackageName() + ".fileprovider";
return FileProvider.getUriForFile(activity, FILE_PROVIDER_AUTHORITY, file);
} else {
return Uri.fromFile(file);
}
} catch (Exception e) {
Log.e(TAG, "getFileProviderUri: 生成Uri失败" + e.getMessage());
return null;
}
}
//
// /**
// * 保存剪裁后的Bitmap优化版
// */
// private void saveCropBitmap(Bitmap bitmap) {
// if (bitmap == null) {
// ToastUtils.show("剪裁图片为空");
// 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(mBackgroundPictureUtils.getBackgroundDir());
// if (!backgroundDir.exists()) {
// if (!backgroundDir.mkdirs()) {
// ToastUtils.show("无法创建保存目录");
// if (scaledBitmap != bitmap) scaledBitmap.recycle();
// return;
// }
// }
//
// File saveFile = new File(backgroundDir, getBackgroundFileName());
//
// // 优化:检查文件是否可写
// if (saveFile.exists() && !saveFile.canWrite()) {
// if (!saveFile.delete()) {
// ToastUtils.show("无法删除旧文件");
// if (scaledBitmap != bitmap) scaledBitmap.recycle();
// return;
// }
// }
//
// FileOutputStream fos = null;
// try {
// fos = new FileOutputStream(saveFile);
// boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
// fos.flush();
// if (success) {
// ToastUtils.show("保存成功");
// // 更新数据
// mBackgroundPictureUtils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
// updatePreviewBackground();
// } else {
// ToastUtils.show("图片压缩保存失败");
// }
// } catch (FileNotFoundException e) {
// LogUtils.e(TAG, "文件未找到" + e);
// ToastUtils.show("保存失败:文件路径错误");
// } catch (IOException e) {
// LogUtils.e(TAG, "写入异常" + e);
// ToastUtils.show("保存失败:磁盘可能已满或路径错误");
// } finally {
// if (fos != null) {
// try {
// fos.close();
// } catch (IOException e) {
// LogUtils.e(TAG, "流关闭异常" + e);
// }
// }
// if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
// scaledBitmap.recycle();
// }
// }
// }
//
// /**
// * 缩放Bitmap
// */
// private Bitmap scaleBitmap(Bitmap original, float scale) {
// if (original == null) {
// return null;
// }
// int width = (int) (original.getWidth() * scale);
// int height = (int) (original.getHeight() * scale);
// return Bitmap.createScaledBitmap(original, width, height, true);
// }
}