调试到选择图片按钮到剪裁图片阶段
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sun Nov 30 17:13:20 GMT 2025
|
||||
#Sun Nov 30 18:04:35 GMT 2025
|
||||
stageCount=13
|
||||
libraryProject=
|
||||
baseVersion=15.11
|
||||
publishVersion=15.11.12
|
||||
buildCount=7
|
||||
buildCount=13
|
||||
baseBetaVersion=15.11.13
|
||||
|
||||
@@ -37,6 +37,11 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import androidx.core.util.Preconditions;
|
||||
import cc.winboll.studio.powerbell.BuildConfig;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
|
||||
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
|
||||
|
||||
@@ -50,7 +55,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
private static final int STORAGE_PERMISSION_REQUEST = 100;
|
||||
|
||||
// FileProvider 授权(必须与AndroidManifest.xml中配置一致)
|
||||
private static final String FILE_PROVIDER_AUTHORITY = "cc.winboll.studio.powerbell.fileprovider";
|
||||
private static final String FILE_PROVIDER_AUTHORITY = BuildConfig.APPLICATION_ID + ".fileprovider";
|
||||
|
||||
private AToolbar mAToolbar;
|
||||
private File mfBackgroundDir; // 背景图片存储文件夹
|
||||
@@ -184,14 +189,79 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
|
||||
// 修复:选择图片后添加视图刷新逻辑
|
||||
private View.OnClickListener onSelectPictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (checkAndRequestStoragePermission()) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
startActivityForResult(intent, REQUEST_SELECT_PICTURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (checkAndRequestStoragePermission()) {
|
||||
// 核心修复:创建多个意图作为兜底
|
||||
Intent[] intents = new Intent[3];
|
||||
|
||||
// 意图1:ACTION_GET_CONTENT(优先)
|
||||
Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
getContentIntent.setType("image/*");
|
||||
getContentIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
getContentIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intents[0] = getContentIntent;
|
||||
|
||||
// 意图2:ACTION_PICK(兜底)
|
||||
Intent pickIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||
pickIntent.setType("image/*");
|
||||
pickIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intents[1] = pickIntent;
|
||||
|
||||
// 意图3:ACTION_OPEN_DOCUMENT(Android 4.4+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
Intent openDocIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
openDocIntent.setType("image/*");
|
||||
openDocIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
openDocIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
intents[2] = openDocIntent;
|
||||
}
|
||||
|
||||
// 遍历意图,找到第一个能响应的
|
||||
Intent validIntent = null;
|
||||
for (Intent intent : intents) {
|
||||
if (intent != null && intent.resolveActivity(getPackageManager()) != null) {
|
||||
validIntent = intent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建chooser时添加flags
|
||||
if (validIntent != null) {
|
||||
Intent chooser = Intent.createChooser(validIntent, "选择图片");
|
||||
// 核心修复:传递持久化权限flag
|
||||
chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||
startActivityForResult(chooser, REQUEST_SELECT_PICTURE);
|
||||
} else {
|
||||
// 确保对话框能正常显示
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ToastUtils.show("请安装相册应用,或点击确定下载系统相册");
|
||||
new AlertDialog.Builder(BackgroundSettingsActivity.this)
|
||||
.setTitle("无图片选择应用")
|
||||
.setMessage("需要安装相册应用才能选择图片")
|
||||
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent marketIntent = new Intent(Intent.ACTION_VIEW);
|
||||
marketIntent.setData(Uri.parse("market://details?id=com.android.gallery3d"));
|
||||
// 确保市场意图能响应
|
||||
if (marketIntent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivity(marketIntent);
|
||||
} else {
|
||||
ToastUtils.show("无法打开应用商店");
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton("取消", null)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener onCropPictureClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
@@ -353,9 +423,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
_mSourceCropTempFile.createNewFile();
|
||||
// 核心优化:设置文件权限
|
||||
_mSourceCropTempFile.setReadable(true, false);
|
||||
_mSourceCropTempFile.setWritable(true, false);
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
ToastUtils.show("剪裁临时文件创建失败");
|
||||
@@ -375,7 +448,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
// 核心修复2:裁剪意图兼容(适配不同机型)
|
||||
Intent intent = new Intent("com.android.camera.action.CROP");
|
||||
// 兼容部分机型不支持隐式意图,添加包名过滤(可选,按需添加)
|
||||
intent.setPackage("com.android.camera");
|
||||
//intent.setPackage("com.android.camera");
|
||||
intent.setDataAndType(inputUri, "image/" + _mszCommonFileType);
|
||||
intent.putExtra("crop", "true");
|
||||
intent.putExtra("noFaceDetection", true);
|
||||
@@ -437,19 +510,25 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
* 工具方法:生成Content Uri(适配Android 7.0+),需在AndroidManifest.xml中配置FileProvider
|
||||
*/
|
||||
private Uri getUriForFile(Context context, File file) throws Exception {
|
||||
String targetPackage = getPackageName();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
try {
|
||||
// 与AndroidManifest.xml中配置的FileProvider授权一致
|
||||
return FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, file);
|
||||
Uri uri = FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, file);
|
||||
// 显式授予Uri权限给目标应用(如裁剪工具的包名)
|
||||
if (!TextUtils.isEmpty(targetPackage)) {
|
||||
context.grantUriPermission(targetPackage, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
}
|
||||
return uri;
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "FileProvider生成Uri失败:" + e.getMessage() + ",文件路径:" + file.getPath());
|
||||
throw e; // 抛出异常,让上层处理
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
return Uri.fromFile(file); // 低版本兼容
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存剪裁后的Bitmap(彻底修复:路径拼接+权限+解析异常)
|
||||
*/
|
||||
@@ -628,142 +707,143 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
}
|
||||
LogUtils.d(TAG, "选择图片Uri : " + selectedImage.toString());
|
||||
|
||||
// 核心修复1:替换路径解析方式,兼容UriUtil解析失败场景
|
||||
// 核心修复:对ACTION_GET_CONTENT返回的Uri,添加持久化权限(Android 4.4+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
getContentResolver().takePersistableUriPermission(
|
||||
selectedImage,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
);
|
||||
}
|
||||
|
||||
// 路径解析逻辑保持不变...
|
||||
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");
|
||||
// 检查拍照文件是否有效
|
||||
if (!mfTakePhoto.exists() || mfTakePhoto.length() <= 0) {
|
||||
ToastUtils.show("拍照文件不存在或损坏");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照文件无效,清理临时文件");
|
||||
}
|
||||
return;
|
||||
}
|
||||
LogUtils.d(TAG, "REQUEST_TAKE_PHOTO");
|
||||
// 检查拍照文件是否有效
|
||||
if (!mfTakePhoto.exists() || mfTakePhoto.length() <= 0) {
|
||||
ToastUtils.show("拍照文件不存在或损坏");
|
||||
// 清理临时文件
|
||||
if (_mSourceCropTempFile.exists()) {
|
||||
_mSourceCropTempFile.delete();
|
||||
LogUtils.d(TAG, "拍照文件无效,清理临时文件");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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",
|
||||
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解析选项(避免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());
|
||||
}
|
||||
}
|
||||
// 检查解析后的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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -782,37 +862,47 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
||||
* 检查并申请存储权限(修复:适配低版本API,移除Android13+依赖)
|
||||
*/
|
||||
private boolean checkAndRequestStoragePermission() {
|
||||
// 仅保留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},
|
||||
STORAGE_PERMISSION_REQUEST);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
if (!Environment.isExternalStorageManager()) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||
startActivity(intent);
|
||||
return false;
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// 核心修复:同时申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE
|
||||
String[] permissions = new String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
||||
|| ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this, permissions, STORAGE_PERMISSION_REQUEST);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == STORAGE_PERMISSION_REQUEST) {
|
||||
boolean isGranted = false;
|
||||
// 检查权限是否授予
|
||||
for (int result : grantResults) {
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
isGranted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isGranted) {
|
||||
ToastUtils.show("存储权限已获取");
|
||||
} else {
|
||||
ToastUtils.show("需要存储权限才能保存/选择图片");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == STORAGE_PERMISSION_REQUEST) {
|
||||
boolean isGranted = false;
|
||||
for (int result : grantResults) {
|
||||
if (result == PackageManager.PERMISSION_GRANTED) {
|
||||
isGranted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isGranted) {
|
||||
ToastUtils.show("存储权限已获取,正在打开图片选择器");
|
||||
// 核心优化:自动重试图片选择
|
||||
onSelectPictureClickListener.onClick(findViewById(R.id.activitybackgroundpictureAButton2));
|
||||
} else {
|
||||
ToastUtils.show("需要存储权限才能保存/选择图片");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setBackgroundColor() {
|
||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
|
||||
|
||||
@@ -238,22 +238,28 @@ public class FileUtils {
|
||||
*/
|
||||
public static void copyStreamToFile(InputStream inputStream, File file) throws IOException {
|
||||
if (inputStream == null || file == null) {
|
||||
return;
|
||||
throw new IllegalArgumentException("InputStream或File不能为空");
|
||||
}
|
||||
// 确保父目录存在
|
||||
File parentDir = file.getParentFile();
|
||||
if (!parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
if (!parentDir.exists() && !parentDir.mkdirs()) {
|
||||
throw new IOException("无法创建父目录:" + parentDir.getAbsolutePath());
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, len);
|
||||
try {
|
||||
OutputStream outputStream = new FileOutputStream(file);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, length);
|
||||
}
|
||||
outputStream.flush();
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.e("FileUtils", "关闭输入流失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
fos.flush();
|
||||
fos.close();
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user