diff --git a/powerbell/build.properties b/powerbell/build.properties index 1dda429..d49f89b 100644 --- a/powerbell/build.properties +++ b/powerbell/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Dec 21 01:45:57 GMT 2025 +#Sun Dec 21 03:13:26 GMT 2025 stageCount=14 libraryProject= baseVersion=15.14 publishVersion=15.14.13 -buildCount=6 +buildCount=18 baseBetaVersion=15.14.14 diff --git a/powerbell/src/main/AndroidManifest.xml b/powerbell/src/main/AndroidManifest.xml index c8ea92e..ebac690 100644 --- a/powerbell/src/main/AndroidManifest.xml +++ b/powerbell/src/main/AndroidManifest.xml @@ -4,54 +4,73 @@ xmlns:tools="http://schemas.android.com/tools" package="cc.winboll.studio.powerbell"> - - + - - + + + + - + - + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - + - - + + + + + - - - - - + @@ -68,17 +87,17 @@ android:supportsRtl="true" tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"> - + - + android:exported="false"/> + + + + + + + + + + + + + + + + + + + android:exported="false"/> + + + + + + + + + + - - + + + - + + + + - - - + + android:value="后台核心功能运行、持续保活"/> + - + android:process=".assistantservice"> + + android:value="辅助核心功能运行"/> + - - - - - - - - - + + - + - - + \ No newline at end of file diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java index 3c6fdf8..d1d5957 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/activities/BackgroundSettingsActivity.java @@ -1,22 +1,26 @@ package cc.winboll.studio.powerbell.activities; +import android.Manifest; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.provider.MediaStore; +import android.provider.Settings; import android.text.TextUtils; import android.view.View; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.ToastUtils; @@ -32,35 +36,38 @@ import cc.winboll.studio.powerbell.utils.FileUtils; import cc.winboll.studio.powerbell.utils.ImageCropUtils; import cc.winboll.studio.powerbell.utils.UriUtils; import cc.winboll.studio.powerbell.views.BackgroundView; -import com.a4455jkjh.colorpicker.ColorPickerDialog; -import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; +import cc.winboll.studio.powerbell.dialogs.NetworkBackgroundDialog; public class BackgroundSettingsActivity extends WinBoLLActivity { - // ====================== 常量定义 ====================== + // ====================== 常量定义(按功能分类置顶)====================== public static final String TAG = "BackgroundSettingsActivity"; + // 系统版本常量 private static final int SDK_VERSION_TIRAMISU = 33; - + // 请求码(按功能分组) public static final int REQUEST_SELECT_PICTURE = 0; public static final int REQUEST_TAKE_PHOTO = 1; public static final int REQUEST_CROP_IMAGE = 2; - private static final int REQUEST_PIXELPICKER = 1001; + private static final int REQUEST_PIXELPICKER = 1001; + private static final int REQUEST_CAMERA_PERMISSION = 1004; + // Bitmap解析常量 + private static final int BITMAP_MAX_SIZE = 2048; + private static final int BITMAP_MAX_SAMPLE_SIZE = 16; - // ====================== 成员变量 ====================== + // ====================== 成员变量(按依赖优先级+功能分类)====================== + // 工具类实例 private BackgroundSourceUtils mBgSourceUtils; private BitmapCacheUtils mBitmapCache; - + // 视图组件 private Toolbar mToolbar; private BackgroundView mBackgroundView; - private File mfTakePhoto; - volatile boolean isCommitSettings = false; - volatile boolean isPreviewBackgroundChanged = false; + // 状态标记(volatile保证多线程可见性) + private volatile boolean isCommitSettings = false; + private volatile boolean isPreviewBackgroundChanged = false; - // ====================== 生命周期方法 ====================== + // ====================== 生命周期方法(按执行顺序排列)====================== @Override public Activity getActivity() { return this; @@ -74,49 +81,29 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_background_settings); LogUtils.d(TAG, "【生命周期】onCreate 开始初始化"); + setContentView(R.layout.activity_background_settings); - // 初始化视图与工具类 - mBackgroundView = findViewById(R.id.background_view); - mBgSourceUtils = BackgroundSourceUtils.getInstance(this); - mBgSourceUtils.loadSettings(); - mBitmapCache = BitmapCacheUtils.getInstance(); - - // 初始化临时文件与目录 - File tempDir = new File(App.getTempDirPath()); - if (!tempDir.exists()) { - tempDir.mkdirs(); - } - mfTakePhoto = new File(tempDir, "TakePhoto.jpg"); - -// File selectTempDir = new File(mBgSourceUtils.getBackgroundSourceDirPath(), "SelectTemp"); -// if (!selectTempDir.exists()) { -// selectTempDir.mkdirs(); -// LogUtils.d(TAG, "【目录初始化】选图临时目录创建完成:" + selectTempDir.getAbsolutePath()); -// } - + // 初始化核心组件 + initCoreComponents(); // 初始化界面与事件 initToolbar(); initClickListeners(); + LogUtils.d(TAG, "【初始化】界面与事件绑定完成"); // 处理分享意图或初始化预览 - if (handleShareIntent()) { - ToastUtils.show("handleShareIntent"); - } else { - mBgSourceUtils.setCurrentSourceToPreview(); - } + handleIntentOrPreview(); - mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(mBgSourceUtils.getPreviewBackgroundBean()); - doubleRefreshPreview(); + // 初始化预览环境并刷新 + initPreviewEnvironment(); LogUtils.d(TAG, "【生命周期】onCreate 初始化完成"); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); + LogUtils.d(TAG, "【生命周期】onPostCreate 执行双重刷新预览"); doubleRefreshPreview(); - LogUtils.d(TAG, "【生命周期】onPostCreate 执行双重刷新"); } @Override @@ -126,29 +113,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { try { if (resultCode != RESULT_OK) { + LogUtils.d(TAG, "【回调处理】结果非RESULT_OK,执行取消逻辑"); handleOperationCancelOrFail(); return; } - - switch (requestCode) { - case REQUEST_SELECT_PICTURE: - handleSelectPictureResult(resultCode, data); - break; - case REQUEST_TAKE_PHOTO: - handleTakePhotoResult(resultCode, data); - break; - case REQUEST_CROP_IMAGE: - handleCropImageResult(requestCode, resultCode, data); - break; - case REQUEST_PIXELPICKER: - handlePixelPickerResult(requestCode, resultCode, data); - break; - default: - LogUtils.d(TAG, "【回调忽略】未知requestCode"); - break; - } + handleActivityResult(requestCode, data); } catch (Exception e) { - LogUtils.e(TAG, "【回调异常】" + e.getMessage()); + LogUtils.e(TAG, "【回调异常】requestCode:" + requestCode + ",异常信息:" + e.getMessage()); ToastUtils.show("操作失败"); } } @@ -159,32 +130,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { if (isCommitSettings) { super.finish(); } else { - if (isPreviewBackgroundChanged) { - YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener() { - @Override - public void onYes() { - //ToastUtils.show("onYes"); - mBgSourceUtils.commitPreviewSourceToCurrent(); - isCommitSettings = true; - finish(); - } - - @Override - public void onNo() { - isCommitSettings = true; - finish(); - } - }); - } else { - isCommitSettings = true; - finish(); - } + handleFinishConfirmation(); } } - // ====================== 界面初始化方法 ====================== + // ====================== 权限回调方法(单独分类)====================== + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + LogUtils.d(TAG, "【权限回调】requestCode:" + requestCode + ",权限数量:" + permissions.length); + if (requestCode == REQUEST_CAMERA_PERMISSION) { + handleCameraPermissionResult(grantResults); + } + } + + // ====================== 界面初始化方法(Toolbar + 点击事件)====================== private void initToolbar() { mToolbar = findViewById(R.id.toolbar); + if (mToolbar == null) { + LogUtils.e(TAG, "【初始化异常】Toolbar未找到"); + return; + } setSupportActionBar(mToolbar); mToolbar.setSubtitle(getTag()); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); @@ -192,34 +158,53 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - LogUtils.d(TAG, "【导航栏】点击返回"); + LogUtils.d(TAG, "【导航栏】点击返回按钮"); finish(); } }); + LogUtils.d(TAG, "【界面初始化】Toolbar 配置完成"); } private void initClickListeners() { - LogUtils.d(TAG, "【界面初始化】绑定按钮点击事件"); - findViewById(R.id.activitybackgroundpictureAButton5).setOnClickListener(onOriginNullClickListener); - findViewById(R.id.activitybackgroundpictureAButton4).setOnClickListener(onReceivedPictureClickListener); - findViewById(R.id.activitybackgroundpictureAButton1).setOnClickListener(onTakePhotoClickListener); - findViewById(R.id.activitybackgroundpictureAButton2).setOnClickListener(onSelectPictureClickListener); - findViewById(R.id.activitybackgroundpictureAButton3).setOnClickListener(onCropPictureClickListener); - findViewById(R.id.activitybackgroundpictureAButton6).setOnClickListener(onCropFreePictureClickListener); - findViewById(R.id.activitybackgroundpictureAButton7).setOnClickListener(onPixelPickerClickListener); - findViewById(R.id.activitybackgroundpictureAButton8).setOnClickListener(onCleanPixelClickListener); - findViewById(R.id.activitybackgroundsettingsAButton1).setOnClickListener(onColorPaletteClickListener); + LogUtils.d(TAG, "【界面初始化】开始绑定按钮点击事件"); + // 绑定所有按钮点击事件 + bindClickListener(R.id.activitybackgroundsettingsAButton1, onOriginNullClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton2, onReceivedPictureClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton3, onTakePhotoClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton4, onSelectPictureClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton5, onNetworkBackgroundDialog); + bindClickListener(R.id.activitybackgroundsettingsAButton6, onCropPictureClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton7, onCropFreePictureClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton8, onPixelPickerClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton9, onColorPaletteClickListener); + bindClickListener(R.id.activitybackgroundsettingsAButton10, onCleanPixelClickListener); + LogUtils.d(TAG, "【界面初始化】按钮点击事件绑定完成"); } - // ====================== 按钮点击事件 ====================== + // 通用按钮绑定工具方法 + private void bindClickListener(int resId, View.OnClickListener listener) { + View view = findViewById(resId); + if (view != null) { + view.setOnClickListener(listener); + } else { + LogUtils.e(TAG, "【绑定异常】未找到视图:" + resId); + } + } + + // ====================== 按钮点击事件(按功能分类)====================== private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】取消背景图片"); - mBgSourceUtils.getPreviewBackgroundBean().setIsUseBackgroundFile(false); - mBgSourceUtils.saveSettings(); - doubleRefreshPreview(); - isPreviewBackgroundChanged = true; + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【操作异常】预览Bean为空"); + return; + } + previewBean.setIsUseBackgroundFile(false); + mBgSourceUtils.saveSettings(); + doubleRefreshPreview(); + isPreviewBackgroundChanged = true; } }; @@ -227,7 +212,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】选择图片"); - launchImageSelector(); + launchImageSelector(); + } + }; + + private View.OnClickListener onNetworkBackgroundDialog = new View.OnClickListener() { + @Override + public void onClick(View v) { + NetworkBackgroundDialog networkBackgroundDialog = new NetworkBackgroundDialog(BackgroundSettingsActivity.this, new NetworkBackgroundDialog.OnDialogClickListener(){ + @Override + public void onConfirm(String szConfirmFilePath) { + // 拷贝文件到预览数据并启动裁剪 + if (putUriFileToPreviewSource(new File(szConfirmFilePath))) { + startImageCrop(false); + } + } + + @Override + public void onCancel() { + } + }); + networkBackgroundDialog.show(); } }; @@ -235,13 +240,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】固定比例裁剪"); - ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this, - mBgSourceUtils.getPreviewBackgroundBean(), - mBackgroundView.getWidth(), - mBackgroundView.getHeight(), - false, - REQUEST_CROP_IMAGE - ); + startImageCrop(false); } }; @@ -249,13 +248,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】自由裁剪"); - ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this, - mBgSourceUtils.getPreviewBackgroundBean(), - 0, - 0, - true, - REQUEST_CROP_IMAGE - ); + startImageCrop(true); } }; @@ -263,50 +256,47 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】拍照"); - // 移除:旧文件删除逻辑 - try { - boolean createSuccess = mfTakePhoto.createNewFile(); - LogUtils.d(TAG, "【拍照准备】创建新文件:" + (createSuccess ? "成功" : "失败")); - if (!createSuccess) { - ToastUtils.show("拍照文件创建失败"); - return; - } - } catch (IOException e) { - LogUtils.e(TAG, "【拍照异常】" + e.getMessage()); - ToastUtils.show("拍照文件创建失败"); + // 动态申请相机权限 + if (ContextCompat.checkSelfPermission(BackgroundSettingsActivity.this, Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) { + LogUtils.d(TAG, "【拍照准备】相机权限未授予,发起申请"); + ActivityCompat.requestPermissions( + BackgroundSettingsActivity.this, + new String[]{Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION); return; } - - Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - try { - Uri photoUri = getFileProviderUri(mfTakePhoto); - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); - startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); - LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString()); - } catch (Exception e) { - String errMsg = "拍照启动异常:" + e.getMessage(); - ToastUtils.show(errMsg.substring(0, 20)); - LogUtils.e(TAG, "【拍照失败】" + e.getMessage()); - } + handleTakePhoto(); } }; private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() { @Override public void onClick(View v) { - mBgSourceUtils.getPreviewBackgroundBean().setIsUseBackgroundFile(true); - mBgSourceUtils.saveSettings(); - doubleRefreshPreview(); - isPreviewBackgroundChanged = true; + LogUtils.d(TAG, "【按钮点击】恢复收到的图片"); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【操作异常】预览Bean为空"); + return; + } + previewBean.setIsUseBackgroundFile(true); + mBgSourceUtils.saveSettings(); + doubleRefreshPreview(); + isPreviewBackgroundChanged = true; } }; private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() { - @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】像素拾取"); - String targetImagePath = mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath(); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【操作异常】预览Bean为空"); + ToastUtils.show("无有效图片可拾取像素"); + return; + } + String targetImagePath = previewBean.getBackgroundFilePath(); File targetFile = new File(targetImagePath); if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) { ToastUtils.show("无有效图片可拾取像素"); @@ -324,48 +314,59 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】清空像素颜色"); - BackgroundBean bean = mBgSourceUtils.getPreviewBackgroundBean(); - int oldColor = bean.getPixelColor(); - bean.setPixelColor(0xFF000000); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【操作异常】预览Bean为空"); + return; + } + int oldColor = previewBean.getPixelColor(); + previewBean.setPixelColor(0xFF000000); mBgSourceUtils.saveSettings(); doubleRefreshPreview(); - isPreviewBackgroundChanged = true; + isPreviewBackgroundChanged = true; ToastUtils.show("像素颜色已清空"); - LogUtils.d(TAG, "【像素清空】旧颜色:" + oldColor); + LogUtils.d(TAG, "【像素清空】旧颜色:" + String.format("#%08X", oldColor)); } }; - private View.OnClickListener onColorPaletteClickListener = new View.OnClickListener() { + private View.OnClickListener onColorPaletteClickListener = new View.OnClickListener() { @Override public void onClick(View v) { LogUtils.d(TAG, "【按钮点击】调色板按钮"); - - // 初始颜色(白色,含透明度) - //int initialColor = 0xFFFFFFFF; - int initialColor = mBgSourceUtils.getPreviewBackgroundBean().getPixelColor(); - // 显示对话框 - ColorPaletteDialog dialog = new ColorPaletteDialog(BackgroundSettingsActivity.this, initialColor, new ColorPaletteDialog.OnColorSelectedListener() { + final BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【操作异常】预览Bean为空"); + return; + } + int initialColor = previewBean.getPixelColor(); + LogUtils.d(TAG, "【调色板】初始颜色:" + String.format("#%08X", initialColor)); + ColorPaletteDialog dialog = new ColorPaletteDialog(BackgroundSettingsActivity.this, initialColor, new ColorPaletteDialog.OnColorSelectedListener() { @Override public void onColorSelected(int color) { - // 回调返回 0xAARRGGBB 格式颜色,直接使用 - mBgSourceUtils.getPreviewBackgroundBean().setPixelColor(color); + previewBean.setPixelColor(color); mBgSourceUtils.saveSettings(); doubleRefreshPreview(); isPreviewBackgroundChanged = true; - LogUtils.d("选择颜色", String.format("#%08X", color)); + LogUtils.d(TAG, "【颜色选择】选中颜色:" + String.format("#%08X", color)); } }); - dialog.show(); - - LogUtils.d(TAG, "调色板按钮响应完成。"); + dialog.show(); + LogUtils.d(TAG, "【调色板】对话框已显示"); } }; - // ====================== 工具方法 ====================== + // ====================== 工具方法(通用工具 + 视图工具)====================== /** * 生成 FileProvider Uri,适配 Android 7.0+ + * @param file 目标文件 + * @return 适配后的Uri,失败返回null */ public Uri getFileProviderUri(File file) { + LogUtils.d(TAG, "【工具方法】生成FileProvider Uri,文件路径:" + (file != null ? file.getAbsolutePath() : "null")); + if (file == null) { + LogUtils.e(TAG, "【工具异常】文件为空"); + return null; + } try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { String FILE_PROVIDER_AUTHORITY = getPackageName() + ".fileprovider"; @@ -374,24 +375,27 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { return Uri.fromFile(file); } } catch (Exception e) { - LogUtils.e(TAG, "getFileProviderUri: 生成Uri失败:" + e.getMessage()); + LogUtils.e(TAG, "【工具异常】生成Uri失败:" + e.getMessage()); return null; } } /** * 校验 Bitmap 是否有效(未被回收且不为空) + * @param bitmap 目标Bitmap + * @return 有效返回true,否则false */ private boolean isBitmapValid(Bitmap bitmap) { - return bitmap != null && !bitmap.isRecycled(); + boolean isValid = bitmap != null && !bitmap.isRecycled(); + LogUtils.d(TAG, "【工具方法】Bitmap有效性校验:" + isValid); + return isValid; } /** * 双重刷新预览,确保背景加载最新数据 - * 移除:缓存清空逻辑 */ private void doubleRefreshPreview() { - LogUtils.d(TAG, "【工具方法】doubleRefreshPreview 开始执行"); + LogUtils.d(TAG, "【工具方法】开始双重刷新预览"); if (mBgSourceUtils == null || mBackgroundView == null || isFinishing()) { LogUtils.w(TAG, "【双重刷新】跳过:对象为空或Activity已结束"); return; @@ -400,8 +404,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { // 第一重刷新 try { mBgSourceUtils.loadSettings(); - mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true); - mBackgroundView.setBackgroundColor(mBgSourceUtils.getPreviewBackgroundBean().getPixelColor()); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + mBackgroundView.loadBackgroundBean(previewBean, true); + mBackgroundView.setBackgroundColor(previewBean.getPixelColor()); LogUtils.d(TAG, "【双重刷新】第一重完成"); } catch (Exception e) { LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage()); @@ -415,8 +420,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { if (mBackgroundView != null && !isFinishing() && mBgSourceUtils != null) { try { mBgSourceUtils.loadSettings(); - mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true); - mBackgroundView.setBackgroundColor(mBgSourceUtils.getPreviewBackgroundBean().getPixelColor()); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + mBackgroundView.loadBackgroundBean(previewBean, true); + mBackgroundView.setBackgroundColor(previewBean.getPixelColor()); LogUtils.d(TAG, "【双重刷新】第二重完成"); } catch (Exception e) { LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage()); @@ -428,26 +434,25 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { /** * 解析裁剪临时文件为 Bitmap,带采样率优化 + * @param cropTempFile 裁剪临时文件 + * @return 解析后的Bitmap,失败返回null */ private Bitmap parseCropTempFileToBitmap(File cropTempFile) { - LogUtils.d(TAG, "【工具方法】parseCropTempFileToBitmap 解析文件:" + (cropTempFile != null ? cropTempFile.getAbsolutePath() : "null")); + LogUtils.d(TAG, "【工具方法】解析裁剪文件:" + (cropTempFile != null ? cropTempFile.getAbsolutePath() : "null")); if (cropTempFile == null || !cropTempFile.exists() || !cropTempFile.isFile() || cropTempFile.length() <= 100) { LogUtils.e(TAG, "【Bitmap解析】文件无效"); return null; } + // 计算采样率 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(cropTempFile.getAbsolutePath(), options); - int maxSize = 2048; - int sampleSize = 1; - while (options.outWidth / sampleSize > maxSize || options.outHeight / sampleSize > maxSize) { - sampleSize *= 2; - } - sampleSize = Math.min(sampleSize, 16); + int sampleSize = calculateSampleSize(options.outWidth, options.outHeight); LogUtils.d(TAG, "【Bitmap解析】采样率:" + sampleSize); + // 解析Bitmap options.inJustDecodeBounds = false; options.inSampleSize = sampleSize; options.inPreferredConfig = Bitmap.Config.RGB_565; @@ -472,123 +477,69 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { } /** - * 调整 Bitmap 比例至目标比例 + * 计算Bitmap采样率 + * @param width 图片宽度 + * @param height 图片高度 + * @return 采样率 */ - private Bitmap adjustBitmapToFinalRatio(Bitmap originalBitmap, float finalCropRatio) { - LogUtils.d(TAG, "【工具方法】adjustBitmapToFinalRatio 调整比例,目标比例:" + finalCropRatio); - if (!isBitmapValid(originalBitmap) || finalCropRatio <= 0) { - LogUtils.e(TAG, "【比例调整】参数无效"); - return null; + private int calculateSampleSize(int width, int height) { + int sampleSize = 1; + while (width / sampleSize > BITMAP_MAX_SIZE || height / sampleSize > BITMAP_MAX_SIZE) { + sampleSize *= 2; } + return Math.min(sampleSize, BITMAP_MAX_SAMPLE_SIZE); + } - int originalWidth = originalBitmap.getWidth(); - int originalHeight = originalBitmap.getHeight(); - float originalRatio = (float) originalWidth / originalHeight; - - if (Math.abs(originalRatio - finalCropRatio) < 0.001f) { - LogUtils.d(TAG, "【比例调整】比例一致,生成副本"); - return originalBitmap.copy(originalBitmap.getConfig(), false); + // ====================== 业务逻辑方法(按功能分类)====================== + /** + * 初始化核心组件(工具类+视图) + */ + private void initCoreComponents() { + // 初始化视图 + mBackgroundView = findViewById(R.id.background_view); + if (mBackgroundView == null) { + LogUtils.e(TAG, "【初始化异常】BackgroundView未找到"); } + // 初始化工具类 + mBgSourceUtils = BackgroundSourceUtils.getInstance(this); + mBgSourceUtils.loadSettings(); + mBitmapCache = BitmapCacheUtils.getInstance(); + LogUtils.d(TAG, "【初始化】视图与工具类加载完成"); + } - int targetWidth, targetHeight; - targetHeight = originalHeight; - targetWidth = Math.round(targetHeight * finalCropRatio); - if (targetWidth > originalWidth) { - targetWidth = originalWidth; - targetHeight = Math.round(targetWidth / finalCropRatio); - } - targetWidth = Math.round(targetHeight * finalCropRatio); - LogUtils.d(TAG, "【比例调整】调整前:" + originalWidth + "x" + originalHeight + ",调整后:" + targetWidth + "x" + targetHeight); - - try { - Bitmap adjustedBitmap = Bitmap.createBitmap( - originalBitmap, - (originalWidth - targetWidth) / 2, - (originalHeight - targetHeight) / 2, - targetWidth, - targetHeight - ); - return adjustedBitmap; - } catch (OutOfMemoryError e) { - LogUtils.e(TAG, "【比例调整】OOM异常"); - return null; + /** + * 处理意图或初始化预览 + */ + private void handleIntentOrPreview() { + if (handleShareIntent()) { + ToastUtils.show("已接收分享图片"); + } else { + mBgSourceUtils.setCurrentSourceToPreview(); + LogUtils.d(TAG, "【预览初始化】加载当前背景配置"); } } /** - * 保存 Bitmap 到目标文件 - * 移除:原文件删除逻辑 + * 初始化预览环境 */ - private void saveScaledBitmapToFile(Bitmap bitmap, File targetFile) { - LogUtils.d(TAG, "【工具方法】saveScaledBitmapToFile 保存图片:" + targetFile.getAbsolutePath()); - if (!isBitmapValid(bitmap) || targetFile == null) { - LogUtils.e(TAG, "【图片保存】参数无效"); - return; - } - - OutputStream outputStream = null; - try { - outputStream = new BufferedOutputStream(new FileOutputStream(targetFile)); - bitmap.compress(CompressFormat.JPEG, 100, outputStream); - outputStream.flush(); - LogUtils.d(TAG, "【图片保存】成功,文件大小:" + targetFile.length() + " bytes"); - } catch (IOException e) { - LogUtils.e(TAG, "【图片保存】异常:" + e.getMessage()); - } finally { - if (outputStream != null) { - try { - outputStream.close(); - } catch (IOException e) { - LogUtils.e(TAG, "【图片保存】关闭流异常"); - } - } - } + private void initPreviewEnvironment() { + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + mBgSourceUtils.createAndUpdatePreviewEnvironmentForCropping(previewBean); + doubleRefreshPreview(); } - /** - * 从裁剪文件中读取比例 - */ - private float getRatioFromSystemCropFile(File systemCropFile) { - LogUtils.d(TAG, "【工具方法】getRatioFromSystemCropFile 读取比例:" + systemCropFile.getAbsolutePath()); - if (systemCropFile == null || !systemCropFile.exists() || !systemCropFile.isFile()) { - LogUtils.e(TAG, "【比例读取】文件无效"); - return -1; - } - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(systemCropFile.getAbsolutePath(), options); - - int cropWidth = options.outWidth; - int cropHeight = options.outHeight; - if (cropWidth <= 0 || cropHeight <= 0) { - LogUtils.e(TAG, "【比例读取】尺寸无效"); - return -1; - } - - float systemRatio = (float) cropWidth / cropHeight; - LogUtils.d(TAG, "【比例读取】成功,比例:" + systemRatio); - return systemRatio; - } - - // ====================== 业务逻辑方法 ====================== /** * 处理分享意图 + * @return 处理成功返回true,否则false */ private boolean handleShareIntent() { Intent intent = getIntent(); if (intent != null) { String action = intent.getAction(); String type = intent.getType(); + LogUtils.d(TAG, "【分享处理】action:" + action + ",type:" + type); if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) { - BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener(){ - @Override - public void onAcceptRecivedPicture(Uri uriRecivedPicture) { - ToastUtils.show(String.format("uriRecivedPicture %s", uriRecivedPicture)); - } - }); - dlg.show(); - LogUtils.d(TAG, "【分享处理】收到分享图片意图"); + showSharePreviewDialog(); return true; } } @@ -596,9 +547,30 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { } /** - * 判断是否为图片类型 + * 显示分享图片预览对话框 */ - boolean isImageType(String lowerMimeType) { + private void showSharePreviewDialog() { + BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener() { + @Override + public void onAcceptRecivedPicture(Uri uriRecivedPicture) { + ToastUtils.show("已接收图片:" + uriRecivedPicture); + LogUtils.d(TAG, "【分享处理】接收图片Uri:" + uriRecivedPicture); + } + }); + dlg.show(); + LogUtils.d(TAG, "【分享处理】显示图片预览对话框"); + } + + /** + * 判断是否为图片类型 + * @param mimeType MIME类型 + * @return 是图片返回true,否则false + */ + private boolean isImageType(String mimeType) { + if (mimeType == null) { + return false; + } + String lowerMimeType = mimeType.toLowerCase(); return lowerMimeType.equals("image/jpeg") || lowerMimeType.equals("image/png") || lowerMimeType.equals("image/tiff") @@ -610,19 +582,37 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { * 启动图片选择器 */ private void launchImageSelector() { - LogUtils.d(TAG, "【业务逻辑】launchImageSelector 启动选择器"); + LogUtils.d(TAG, "【业务逻辑】启动图片选择器"); + Intent[] intents = createImageSelectorIntents(); + Intent validIntent = findValidIntent(intents); + + if (validIntent != null) { + launchImageChooser(validIntent); + } else { + showNoGalleryDialog(); + } + } + + /** + * 创建图片选择器意图数组 + * @return 意图数组 + */ + private Intent[] createImageSelectorIntents() { Intent[] intents = new Intent[3]; + // 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; + // 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; + // ACTION_OPEN_DOCUMENT(API19+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { Intent openDocIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT); openDocIntent.setType("image/*"); @@ -630,58 +620,68 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { 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; - } - } - - if (validIntent != null) { - Intent chooser = Intent.createChooser(validIntent, "选择图片"); - chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); - startActivityForResult(chooser, REQUEST_SELECT_PICTURE); - LogUtils.d(TAG, "【选图意图】启动图片选择"); - } else { - LogUtils.d(TAG, "【选图意图】无相册应用"); - 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(); - } - }); - } + return intents; } /** - * 处理存储权限回调 + * 查找有效的意图 + * @param intents 意图数组 + * @return 有效意图,无则返回null */ - private void handleStoragePermissionCallback() { - if (Environment.isExternalStorageManager()) { - LogUtils.d(TAG, "【权限回调】已授予"); - ToastUtils.show("存储权限已获取"); + private Intent findValidIntent(Intent[] intents) { + for (Intent intent : intents) { + if (intent != null && intent.resolveActivity(getPackageManager()) != null) { + return intent; + } + } + return null; + } + + /** + * 启动图片选择器 + * @param validIntent 有效意图 + */ + private void launchImageChooser(Intent validIntent) { + Intent chooser = Intent.createChooser(validIntent, "选择图片"); + chooser.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); + startActivityForResult(chooser, REQUEST_SELECT_PICTURE); + LogUtils.d(TAG, "【选图意图】启动图片选择"); + } + + /** + * 显示无相册应用提示对话框 + */ + private void showNoGalleryDialog() { + LogUtils.d(TAG, "【选图意图】无相册应用"); + 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) { + launchGalleryMarket(); + } + }) + .setNegativeButton("取消", null) + .show(); + } + }); + } + + /** + * 启动应用商店下载相册 + */ + private void launchGalleryMarket() { + 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 { - LogUtils.d(TAG, "【权限回调】已拒绝"); - ToastUtils.show("存储权限不足"); + ToastUtils.show("无法打开应用商店"); } } @@ -696,115 +696,112 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { } /** - * 处理拍照结果 + * 处理拍照逻辑(权限通过后执行) */ - private void handleTakePhotoResult(int resultCode, Intent data) { - LogUtils.d(TAG, "【业务逻辑】handleTakePhotoResult 处理拍照结果"); - if (resultCode != RESULT_OK || data == null) { - handleOperationCancelOrFail(); + void handleTakePhoto() { + LogUtils.d(TAG, "【业务逻辑】开始处理拍照"); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【拍照失败】预览Bean为空"); + ToastUtils.show("拍照文件创建失败"); return; } - if (!mfTakePhoto.exists() || mfTakePhoto.length() <= 0) { - ToastUtils.show("拍照文件无效"); + File takePhotoFile = new File(previewBean.getBackgroundFilePath()); + if (!takePhotoFile.exists()) { + ToastUtils.show("拍照文件创建失败"); + LogUtils.e(TAG, "【拍照失败】文件不存在:" + takePhotoFile.getAbsolutePath()); return; } - Bitmap photoBitmap = getTakePhotoBitmap(data); - if (isBitmapValid(photoBitmap)) { - mBgSourceUtils.compressQualityToRecivedPicture(photoBitmap); - } else { - ToastUtils.show("拍照图片为空"); + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + try { + Uri photoUri = getFileProviderUri(takePhotoFile); + if (photoUri == null) { + throw new Exception("生成FileProvider Uri失败"); + } + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); + startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); + LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString()); + } catch (Exception e) { + String errMsg = "拍照启动异常:" + e.getMessage(); + ToastUtils.show(errMsg.substring(0, 20)); + LogUtils.e(TAG, "【拍照失败】" + e.getMessage()); + } + } + + /** + * 处理ActivityResult分发 + * @param requestCode 请求码 + * @param data 回调数据 + */ + private void handleActivityResult(int requestCode, Intent data) { + switch (requestCode) { + case REQUEST_SELECT_PICTURE: + handleSelectPictureResult(data); + break; + case REQUEST_TAKE_PHOTO: + handleTakePhotoResult(data); + break; + case REQUEST_CROP_IMAGE: + handleCropImageResult(data); + break; + case REQUEST_PIXELPICKER: + handlePixelPickerResult(); + break; + default: + LogUtils.d(TAG, "【回调忽略】未知requestCode:" + requestCode); + break; + } + } + + /** + * 处理拍照结果 + * @param data 回调数据 + */ + private void handleTakePhotoResult(Intent data) { + LogUtils.d(TAG, "【业务逻辑】处理拍照结果"); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【拍照结果处理】预览Bean为空"); return; } - mBgSourceUtils.saveFileToPreviewBean(mfTakePhoto, mfTakePhoto.getAbsolutePath()); + previewBean.setIsUseBackgroundFile(true); + previewBean.setIsUseBackgroundScaledCompressFile(false); + mBgSourceUtils.saveSettings(); doubleRefreshPreview(); - ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this, - mBgSourceUtils.getPreviewBackgroundBean(), - mBackgroundView.getWidth(), - mBackgroundView.getHeight(), - false, - REQUEST_CROP_IMAGE - ); + startImageCrop(false); LogUtils.d(TAG, "【拍照完成】已启动裁剪"); } - /** - * 解析拍照返回的 Bitmap - */ - private Bitmap getTakePhotoBitmap(Intent data) { - LogUtils.d(TAG, "【业务逻辑】getTakePhotoBitmap 解析拍照Bitmap"); - if (mfTakePhoto != null && mfTakePhoto.exists()) { - LogUtils.d(TAG, "【拍照Bitmap解析】从文件解析"); - Bitmap photoBitmap = parseCropTempFileToBitmap(mfTakePhoto); - if (isBitmapValid(photoBitmap)) { - LogUtils.d(TAG, "【拍照Bitmap解析】成功"); - return photoBitmap; - } else { - LogUtils.w(TAG, "【拍照Bitmap解析】文件解析失败,尝试Intent"); - } - } else { - LogUtils.w(TAG, "【拍照Bitmap解析】文件无效,尝试Intent"); - } - - if (data != null) { - try { - Bitmap thumbnailBitmap = data.getParcelableExtra("data"); - if (isBitmapValid(thumbnailBitmap)) { - LogUtils.d(TAG, "【拍照Bitmap解析】从Intent获取成功"); - return thumbnailBitmap; - } else { - LogUtils.e(TAG, "【拍照Bitmap解析】Intent解析失败"); - } - } catch (Exception e) { - LogUtils.e(TAG, "【拍照Bitmap解析】Intent异常:" + e.getMessage()); - } - } else { - LogUtils.e(TAG, "【拍照Bitmap解析】Intent为空"); - } - - LogUtils.e(TAG, "【拍照Bitmap解析】失败"); - ToastUtils.show("拍照图片解析失败"); - return null; - } - /** * 处理选图结果 - * 移除:缓存清空逻辑 + * @param data 回调数据 */ - private void handleSelectPictureResult(int resultCode, Intent data) { - LogUtils.d(TAG, "【业务逻辑】handleSelectPictureResult 处理选图结果"); - if (resultCode != RESULT_OK || data == null) { - handleOperationCancelOrFail(); - return; - } - + private void handleSelectPictureResult(Intent data) { + LogUtils.d(TAG, "【业务逻辑】处理选图结果"); Uri selectedImage = data.getData(); if (selectedImage == null) { ToastUtils.show("图片Uri为空"); + LogUtils.e(TAG, "【选图结果】Uri为空"); return; } LogUtils.d(TAG, "【选图回调】系统返回Uri : " + selectedImage.toString()); + // 申请持久化权限(API33+) if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) { getContentResolver().takePersistableUriPermission( selectedImage, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ); + Intent.FLAG_GRANT_READ_URI_PERMISSION); LogUtils.d(TAG, "【选图权限】已添加持久化权限"); } + // 同步文件并启动裁剪 if (putUriFileToPreviewSource(selectedImage)) { LogUtils.d(TAG, "【选图同步】路径绑定完成"); - ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this, - mBgSourceUtils.getPreviewBackgroundBean(), - mBackgroundView.getWidth(), - mBackgroundView.getHeight(), - false, - REQUEST_CROP_IMAGE - ); + startImageCrop(false); } else { ToastUtils.show("图片同步失败"); LogUtils.e(TAG, "【选图同步】文件复制失败"); @@ -813,11 +810,13 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { /** * 将 Uri 文件同步到预览 Bean + * @param srcUriFile 源Uri + * @return 同步成功返回true,否则false */ - boolean putUriFileToPreviewSource(Uri srcUriFile) { + private boolean putUriFileToPreviewSource(Uri srcUriFile) { String filePath = UriUtils.getFilePathFromUri(this, srcUriFile); if (TextUtils.isEmpty(filePath)) { - LogUtils.e(TAG, "putUriFileToPreviewSource: Uri解析路径为空"); + LogUtils.e(TAG, "【选图同步】Uri解析路径为空"); return false; } File srcFile = new File(filePath); @@ -826,74 +825,158 @@ public class BackgroundSettingsActivity extends WinBoLLActivity { /** * 将 File 同步到预览 Bean - * 保留:核心修复逻辑(更新预览Bean路径) + * @param srcFile 源文件 + * @return 同步成功返回true,否则false */ - boolean putUriFileToPreviewSource(File srcFile) { - LogUtils.d(TAG, String.format("putUriFileToPreviewSource(File srcFile) srcFile %s", srcFile)); - mBgSourceUtils.loadSettings(); - BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); - File dstFile = new File(previewBean.getBackgroundFilePath()); - LogUtils.d(TAG, String.format("putUriFileToPreviewSource(File srcFile) dstFile %s", dstFile)); + private boolean putUriFileToPreviewSource(File srcFile) { + LogUtils.d(TAG, "【选图同步】源文件:" + srcFile.getAbsolutePath()); + mBgSourceUtils.loadSettings(); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + File dstFile = new File(previewBean.getBackgroundFilePath()); + LogUtils.d(TAG, "【选图同步】目标文件:" + dstFile.getAbsolutePath()); if (FileUtils.copyFile(srcFile, dstFile)) { - LogUtils.d(TAG, "putUriFileToPreviewSource(File srcFile) 文件拷贝成功。 "); - return true; - } - LogUtils.d(TAG, "putUriFileToPreviewSource(File srcFile) 文件无法拷贝。 "); - return false; + LogUtils.d(TAG, "【选图同步】文件拷贝成功"); + return true; + } + LogUtils.d(TAG, "【选图同步】文件无法拷贝"); + return false; } /** * 处理裁剪结果 + * @param data 回调数据 */ - private void handleCropImageResult(int requestCode, int resultCode, Intent data) { - LogUtils.d(TAG, "【业务逻辑】handleCropImageResult 处理裁剪结果"); - File cropTempFile = new File(mBgSourceUtils.getPreviewBackgroundBean().getBackgroundScaledCompressFilePath()); + private void handleCropImageResult(Intent data) { + LogUtils.d(TAG, "【业务逻辑】处理裁剪结果"); + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【裁剪结果处理】预览Bean为空"); + handleOperationCancelOrFail(); + return; + } + + File cropTempFile = new File(previewBean.getBackgroundScaledCompressFilePath()); boolean isFileExist = cropTempFile.exists(); boolean isFileReadable = isFileExist ? cropTempFile.canRead() : false; long fileSize = isFileExist ? cropTempFile.length() : 0; - boolean isCropSuccess = (resultCode == RESULT_OK) && isFileExist && isFileReadable && fileSize > 100; + boolean isCropSuccess = isFileExist && isFileReadable && fileSize > 100; if (isCropSuccess) { - isPreviewBackgroundChanged = true; - LogUtils.d(TAG, "【裁剪结果】裁剪成功"); - final BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); - previewBean.setIsUseBackgroundFile(true); - previewBean.setIsUseBackgroundScaledCompressFile(true); - mBgSourceUtils.saveSettings(); - doubleRefreshPreview(); - -// float systemFileRatio = getRatioFromSystemCropFile(cropTempFile); -// if (systemFileRatio > 0) { -// Bitmap cropBitmap = parseCropTempFileToBitmap(cropTempFile); -// if (isBitmapValid(cropBitmap)) { -// Bitmap scaledCropBitmap = adjustBitmapToFinalRatio(cropBitmap, systemFileRatio); -// if (isBitmapValid(scaledCropBitmap)) { -// saveScaledBitmapToFile(scaledCropBitmap, cropTempFile); -// scaledCropBitmap.recycle(); -// } -// cropBitmap.recycle(); -// } else { -// LogUtils.e(TAG, "【裁剪结果】裁剪Bitmap解析无效"); -// } -// } -// -// new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { -// @Override -// public void run() { -// if (!isFinishing()) { -// doubleRefreshPreview(); -// LogUtils.d(TAG, "【裁剪结果】触发双重刷新"); -// } -// } -// }, 300); + handleCropSuccess(previewBean, fileSize); } else { - handleOperationCancelOrFail(); + handleCropFailure(isFileExist, isFileReadable, fileSize); } } - private void handlePixelPickerResult(int requestCode, int resultCode, Intent data) { - doubleRefreshPreview(); - isPreviewBackgroundChanged = true; - } + /** + * 处理裁剪成功 + * @param previewBean 预览Bean + * @param fileSize 文件大小 + */ + private void handleCropSuccess(BackgroundBean previewBean, long fileSize) { + isPreviewBackgroundChanged = true; + LogUtils.d(TAG, "【裁剪结果】裁剪成功,文件大小:" + fileSize); + previewBean.setIsUseBackgroundFile(true); + previewBean.setIsUseBackgroundScaledCompressFile(true); + mBgSourceUtils.saveSettings(); + doubleRefreshPreview(); + } + + /** + * 处理裁剪失败 + * @param isFileExist 文件是否存在 + * @param isFileReadable 文件是否可读 + * @param fileSize 文件大小 + */ + private void handleCropFailure(boolean isFileExist, boolean isFileReadable, long fileSize) { + handleOperationCancelOrFail(); + LogUtils.e(TAG, "【裁剪结果】裁剪失败,文件状态:存在=" + isFileExist + ",可读=" + isFileReadable + ",大小=" + fileSize); + } + + /** + * 处理像素拾取结果 + */ + private void handlePixelPickerResult() { + LogUtils.d(TAG, "【业务逻辑】处理像素拾取结果"); + doubleRefreshPreview(); + isPreviewBackgroundChanged = true; + } + + /** + * 处理相机权限申请结果 + * @param grantResults 权限结果数组 + */ + private void handleCameraPermissionResult(int[] grantResults) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + LogUtils.d(TAG, "【权限申请】相机权限授予成功"); + handleTakePhoto(); + } else { + LogUtils.d(TAG, "【权限申请】相机权限授予失败"); + ToastUtils.show("相机权限被拒绝,无法拍照"); + // 引导用户到设置页面开启权限(用户选择不再询问时) + if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { + launchAppSettings(); + } + } + } + + /** + * 启动应用设置页面 + */ + private void launchAppSettings() { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", getPackageName(), null); + intent.setData(uri); + startActivity(intent); + ToastUtils.show("请在设置中开启相机权限"); + LogUtils.d(TAG, "【权限引导】启动应用设置页面"); + } + + /** + * 处理Finish确认对话框 + */ + private void handleFinishConfirmation() { + if (isPreviewBackgroundChanged) { + YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener() { + @Override + public void onYes() { + mBgSourceUtils.commitPreviewSourceToCurrent(); + isCommitSettings = true; + finish(); + } + + @Override + public void onNo() { + isCommitSettings = true; + finish(); + } + }); + } else { + isCommitSettings = true; + finish(); + } + } + + /** + * 启动图片裁剪 + * @param isFreeCrop 是否自由裁剪 + */ + private void startImageCrop(boolean isFreeCrop) { + BackgroundBean previewBean = mBgSourceUtils.getPreviewBackgroundBean(); + if (previewBean == null) { + LogUtils.e(TAG, "【裁剪启动】预览Bean为空"); + ToastUtils.show("裁剪失败:无有效图片"); + return; + } + int width = isFreeCrop ? 0 : mBackgroundView.getWidth(); + int height = isFreeCrop ? 0 : mBackgroundView.getHeight(); + ImageCropUtils.startImageCrop(BackgroundSettingsActivity.this, + previewBean, + width, + height, + isFreeCrop, + REQUEST_CROP_IMAGE); + LogUtils.d(TAG, "【裁剪启动】是否自由裁剪:" + isFreeCrop + ",目标尺寸:" + width + "x" + height); + } } diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java index 1627d0b..1bcbd33 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/dialogs/NetworkBackgroundDialog.java @@ -21,6 +21,7 @@ import java.io.FileInputStream; import java.io.IOException; import cc.winboll.studio.powerbell.utils.ImageDownloader; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils; +import android.text.TextUtils; /** * @Author ZhanGSKen&豆包大模型 @@ -52,7 +53,7 @@ public class NetworkBackgroundDialog extends AlertDialog { // 按钮点击回调接口(Java7 接口实现) public interface OnDialogClickListener { - void onConfirm(String szConfirmFilePath, String previewFileUrl); // 确认按钮点击 + void onConfirm(String szConfirmFilePath); // 确认按钮点击 void onCancel(); // 取消按钮点击 } @@ -91,7 +92,7 @@ public class NetworkBackgroundDialog extends AlertDialog { case MSG_IMAGE_LOAD_SUCCESS: // 图片加载成功,获取文件路径并设置背景 mDownloadSavedPath = (String) msg.obj; - previewBackground(mDownloadSavedPath); + mBackgroundView.loadImage(mDownloadSavedPath); break; case MSG_IMAGE_LOAD_FAILED: // 图片加载失败,设置默认背景 @@ -139,7 +140,7 @@ public class NetworkBackgroundDialog extends AlertDialog { etURL = (EditText) dialogView.findViewById(R.id.et_url); mBackgroundView = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview); // 加载初始图片 - mBackgroundView.setBackgroundResource(R.drawable.ic_launcher); + mBackgroundView.setBackgroundResource(R.drawable.blank100x100); // 设置按钮点击事件 setButtonClickListeners(); } @@ -168,13 +169,13 @@ public class NetworkBackgroundDialog extends AlertDialog { @Override public void onClick(View v) { LogUtils.d("NetworkBackgroundDialog", "确认按钮点击"); - // 确定预览背景资源 - BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext); - utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl); - dismiss(); // 关闭对话框 + if(TextUtils.isEmpty(mDownloadSavedPath)) { + ToastUtils.show("未下载图片。"); + return; + } if (listener != null) { - listener.onConfirm(mPreviewFilePath, mPreviewFileUrl); + listener.onConfirm(mDownloadSavedPath); } } }); @@ -258,6 +259,7 @@ public class NetworkBackgroundDialog extends AlertDialog { // 发送消息到主线程,携带图片路径 Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath); mUiHandler.sendMessage(successMsg); + } @Override diff --git a/powerbell/src/main/res/drawable/blank100x100.png b/powerbell/src/main/res/drawable/blank100x100.png new file mode 100644 index 0000000..84e1003 Binary files /dev/null and b/powerbell/src/main/res/drawable/blank100x100.png differ diff --git a/powerbell/src/main/res/layout/activity_background_settings.xml b/powerbell/src/main/res/layout/activity_background_settings.xml index e8096d1..74d18c9 100644 --- a/powerbell/src/main/res/layout/activity_background_settings.xml +++ b/powerbell/src/main/res/layout/activity_background_settings.xml @@ -40,17 +40,17 @@ android:layout_width="160dp" android:layout_height="36dp" android:text="Origin BG" - android:id="@+id/activitybackgroundpictureAButton5" android:layout_alignParentLeft="true" - android:layout_margin="5dp"/> + android:layout_margin="5dp" + android:id="@+id/activitybackgroundsettingsAButton1"/> + android:layout_margin="5dp" + android:id="@+id/activitybackgroundsettingsAButton2"/> @@ -66,7 +66,7 @@ android:text="◎" android:layout_gravity="center_vertical" android:layout_margin="5dp" - android:id="@+id/activitybackgroundpictureAButton1"/> + android:id="@+id/activitybackgroundsettingsAButton3"/> + android:id="@+id/activitybackgroundsettingsAButton4"/> + android:id="@+id/activitybackgroundsettingsAButton5"/> @@ -99,7 +98,7 @@ android:text="[+]" android:layout_gravity="center_vertical" android:layout_margin="5dp" - android:id="@+id/activitybackgroundpictureAButton3"/> + android:id="@+id/activitybackgroundsettingsAButton6"/> + android:id="@+id/activitybackgroundsettingsAButton7"/> + android:id="@+id/activitybackgroundsettingsAButton8"/> + android:onClick="onColorPaletteDialog" + android:id="@+id/activitybackgroundsettingsAButton9"/> + android:id="@+id/activitybackgroundsettingsAButton10"/> diff --git a/powerbell/src/main/res/layout/dialog_networkbackground.xml b/powerbell/src/main/res/layout/dialog_networkbackground.xml index 34e7ea7..2b5cf40 100644 --- a/powerbell/src/main/res/layout/dialog_networkbackground.xml +++ b/powerbell/src/main/res/layout/dialog_networkbackground.xml @@ -13,11 +13,20 @@ android:id="@+id/tv_dialog_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="网络后台提示" + android:text="网络图片资源下载" android:textSize="18sp" android:textColor="@android:color/black" android:textStyle="bold"/> + + - - @@ -83,7 +83,7 @@ android:id="@+id/btn_confirm" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="允许" + android:text="使用图片" android:textSize="14sp" android:background="@android:drawable/btn_default_small"/>