Compare commits

...

18 Commits

Author SHA1 Message Date
13b6af6921 <powerbell>APK 15.11.11 release Publish. 2025-11-30 03:50:23 +08:00
e2703495ae 更新基础类库以改进应用崩溃处理方法 2025-11-30 03:47:36 +08:00
c9bc5c88d8 20251129_170510_937 2025-11-29 17:05:15 +08:00
34356b8116 20251129_163631_757 2025-11-29 16:36:37 +08:00
de189c3fb0 20251129_161627_420整体函数重构完成,待调试。。。 2025-11-29 16:17:12 +08:00
c4b2ecaecb 调试到下载图片,未调试图片存储管理。 2025-11-29 11:25:41 +08:00
1b53594086 更正基础类库,方便调试,继续调试。。。 2025-11-29 02:51:29 +08:00
6a2d011ceb 20251127_214905_683 Debugging ... 2025-11-27 21:49:29 +08:00
5aa54091e5 20251127_212052_680正在调试图片文件存储问题。 2025-11-27 21:21:25 +08:00
bc8a63867c <powerbell>APK 15.11.10 release Publish. 2025-11-27 19:24:29 +08:00
2a10cb493d 更新AES类库,更新广告控制UI界面。 2025-11-27 19:22:05 +08:00
ea7e2f8366 <powerbell>APK 15.11.9 release Publish. 2025-11-27 14:46:03 +08:00
d073a86b9b 添加应用设置与米盟广告SDK设置控件。 2025-11-27 14:43:53 +08:00
e76427eac8 修复背景图片右边有缝隙,以及像素背景设置的问题。 2025-11-27 14:25:37 +08:00
af53216af3 添加中文资源字符串 2025-11-27 13:34:55 +08:00
3ae56bb202 升级基础类库 2025-11-27 13:27:49 +08:00
09f1974c8e 更新类标签 2025-11-27 08:58:41 +08:00
721c93c4b2 更新应用快捷菜单提示 2025-11-27 08:51:06 +08:00
36 changed files with 1010 additions and 878 deletions

View File

@@ -77,8 +77,8 @@ dependencies {
//api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
//api 'androidx.fragment:fragment:1.1.0'
implementation 'cc.winboll.studio:libaes:15.11.6'
implementation 'cc.winboll.studio:libappbase:15.11.0'
implementation 'cc.winboll.studio:libaes:15.11.8'
implementation 'cc.winboll.studio:libappbase:15.11.4'
//api fileTree(dir: 'libs', include: ['*.aar'])
api fileTree(dir: 'libs', include: ['*.jar'])

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Wed Nov 26 16:27:33 HKT 2025
stageCount=9
#Sun Nov 30 03:50:22 HKT 2025
stageCount=12
libraryProject=
baseVersion=15.11
publishVersion=15.11.8
publishVersion=15.11.11
buildCount=0
baseBetaVersion=15.11.9
baseBetaVersion=15.11.12

View File

@@ -150,7 +150,7 @@
</activity>
<activity
android:name="cc.winboll.studio.powerbell.activities.BackgroundPictureActivity"
android:name="cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity"
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
android:exported="true"
android:launchMode="singleTask">
@@ -230,6 +230,8 @@
<activity android:name="cc.winboll.studio.powerbell.activities.ShortcutActionActivity"/>
<activity android:name="cc.winboll.studio.powerbell.activities.SettingsActivity"/>
</application>
</manifest>
</manifest>

View File

@@ -12,7 +12,7 @@ import java.io.File;
public class App extends GlobalApplication {
public static final String TAG = "GlobalApplication";
public static final String TAG = "App";
public static final String COMPONENT_EN1 = "cc.winboll.studio.powerbell.MainActivityEN1";
public static final String COMPONENT_CN1 = "cc.winboll.studio.powerbell.MainActivityCN1";

View File

@@ -17,14 +17,15 @@ import cc.winboll.studio.libaes.views.ADsBannerView;
import cc.winboll.studio.libappbase.LogActivity;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.activities.AboutActivity;
import cc.winboll.studio.powerbell.activities.BackgroundPictureActivity;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
import cc.winboll.studio.powerbell.activities.SettingsActivity;
import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean;
import cc.winboll.studio.powerbell.model.BackgroundBean;
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
/**
* 主活动类修复小米广告SDK空Context崩溃问题
@@ -198,7 +199,7 @@ public class MainActivity extends WinBoLLActivity {
reloadBackground();
setBackgroundColor();
if (mADsBannerView != null) {
mADsBannerView.resumeADs();
mADsBannerView.resumeADs(MainActivity.this);
}
// // 修复:优化广告请求逻辑(添加生命周期判断 + 主线程执行)
@@ -234,14 +235,16 @@ public class MainActivity extends WinBoLLActivity {
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
int menuItemId = item.getItemId();
if (menuItemId == R.id.action_about) {
if (menuItemId == R.id.action_settings) {
startActivity(new Intent(this, SettingsActivity.class));
} else if (menuItemId == R.id.action_about) {
startActivity(new Intent(this, AboutActivity.class));
} else if (menuItemId == R.id.action_battery_report) {
startActivity(new Intent(this, BatteryReportActivity.class));
} else if (menuItemId == R.id.action_clearrecord) {
startActivity(new Intent(this, ClearRecordActivity.class));
} else if (menuItemId == R.id.action_changepicture) {
startActivity(new Intent(this, BackgroundPictureActivity.class));
startActivity(new Intent(this, BackgroundSettingsActivity.class));
} else if (menuItemId == R.id.action_log) {
LogActivity.startLogActivity(this);
} else if (menuItemId == R.id.action_unittestactivity) {
@@ -278,8 +281,8 @@ public class MainActivity extends WinBoLLActivity {
if (isFinishing() || isDestroyed()) {
return;
}
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor();
RelativeLayout mainLayout = findViewById(R.id.activitymainRelativeLayout1);
if (mainLayout != null) {

View File

@@ -22,10 +22,10 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean;
import cc.winboll.studio.powerbell.model.BackgroundBean;
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
import cc.winboll.studio.powerbell.dialogs.NetworkBackgroundDialog;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.UriUtil;
import cc.winboll.studio.powerbell.views.BackgroundView;
@@ -35,11 +35,12 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import androidx.core.util.Preconditions;
public class BackgroundPictureActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
public static final String TAG = "BackgroundPictureActivity";
public BackgroundPictureUtils mBackgroundPictureUtils;
public static final String TAG = "BackgroundSettingsActivity";
public BackgroundSourceUtils mBackgroundSourceUtils;
// 图片选择请求码
public static final int REQUEST_SELECT_PICTURE = 0;
@@ -51,19 +52,28 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
private File mfBackgroundDir; // 背景图片存储文件夹
private File mfPictureDir; // 拍照与剪裁临时文件夹
private File mfTakePhoto; // 拍照文件
private File mfRecivedPicture; // 接收的图片文件
private File mfTempCropPicture; // 剪裁临时文件
private File mfRecivedCropPicture; // 剪裁后的目标文件
//private File mfRecivedPicture; // 接收的图片文件
private String preViewFileBackgroundView = "";
// 背景视图预览图片的文件名
private String preViewFilePath = "";
private String preViewFileUrl = "";
BackgroundView bvPreviewBackground;
boolean isCommitSettings = false;
// 静态变量
public static String _mszRecivedCropPicture = "RecivedCrop.jpg";
// 源文件的临时剪裁图片保存名称
private static String _mSourceCropTempFileName = "SourceCropTemp.jpg";
// 源文件的临时剪裁图片保存文件对象
private static File _mSourceCropTempFile;
// 源文件的剪裁图片保存名称
private static String _mSourceCroppedFileName = "SourceCropped.jpg";
// 源文件的剪裁图片保存文件对象
private static File _mSourceCroppedFile;
// 源文件的剪裁图片保存路径
private static String _mSourceCroppedFilePath;
private static String _mszCommonFileType = "jpeg";
private int mnPictureCompress = 100;
private static String _RecivedPictureFileName;
//private static String _RecivedBackgroundFileName;
@Override
public Activity getActivity() {
@@ -79,11 +89,13 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_backgroundpicture);
initEnv();
bvPreviewBackground = (BackgroundView) findViewById(R.id.activitybackgroundpictureBackgroundView1);
//initEnv();
// 初始化工具类和文件夹
mBackgroundPictureUtils = BackgroundPictureUtils.getInstance(this);
mfBackgroundDir = new File(mBackgroundPictureUtils.getBackgroundDir());
mBackgroundSourceUtils = BackgroundSourceUtils.getInstance(this);
mfBackgroundDir = new File(mBackgroundSourceUtils.getBackgroundSourceDirPath());
if (!mfBackgroundDir.exists()) {
mfBackgroundDir.mkdirs();
}
@@ -95,10 +107,13 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
// 初始化文件对象
mfTakePhoto = new File(mfPictureDir, "TakePhoto.jpg");
mfTempCropPicture = new File(mfPictureDir, "TempCrop.jpg");
//mfTempCropPicture = new File(mfPictureDir, "TempCrop.jpg");
mfRecivedPicture = getRecivedPictureFile(this);
mfRecivedCropPicture = new File(mfBackgroundDir, _mszRecivedCropPicture);
//mfRecivedPicture = getRecivedPictureFile();
_mSourceCropTempFile = new File(mfBackgroundDir, _mSourceCropTempFileName);
_mSourceCroppedFile = new File(mfBackgroundDir, _mSourceCroppedFileName);
_mSourceCroppedFilePath = _mSourceCroppedFile.getAbsolutePath().toString();
LogUtils.d(TAG, String.format("_mSourceCroppedFilePath : %s", _mSourceCroppedFilePath));
// 初始化工具栏
mAToolbar = (AToolbar) findViewById(R.id.toolbar);
@@ -122,7 +137,9 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
findViewById(R.id.activitybackgroundpictureAButton7).setOnClickListener(onPixelPickerClickListener);
findViewById(R.id.activitybackgroundpictureAButton8).setOnClickListener(onCleanPixelClickListener);
updatePreviewBackground();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
utils.setCurrentSourceToPreview();
bvPreviewBackground.reloadPreviewBackground();
// 处理分享的图片
Intent intent = getIntent();
@@ -135,76 +152,85 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
}
}
private void initEnv() {
LogUtils.d(TAG, "initEnv()");
_RecivedPictureFileName = "Recived.data";
}
// private void initEnv() {
// LogUtils.d(TAG, "initEnv()");
// _RecivedBackgroundFileName = "SourcePicture.data";
// }
public static String getBackgroundFileName() {
return _mszRecivedCropPicture;
return _mSourceCroppedFileName;
}
@Override
public void onAcceptRecivedPicture(String szPreRecivedPictureName) {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
utils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
utils.saveData();
File sourceFile = new File(utils.getBackgroundDir(), szPreRecivedPictureName);
if (FileUtils.copyFile(sourceFile, mfRecivedPicture)) {
startCropImageActivity(false);
} else {
ToastUtils.show("图片复制失败,请重试");
}
ToastUtils.show("onAcceptRecivedPicture not yet.");
// BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
// utils.getCurrentBackgroundBean().setIsUseBackgroundFile(true);
// utils.saveSettings();
//
// File sourceFile = new File(utils.getBackgroundSourceDirPath(), szPreRecivedPictureName);
// if (FileUtils.copyFile(sourceFile, mfRecivedPicture)) {
// startCropImageActivity(false);
// } else {
// ToastUtils.show("图片复制失败,请重试");
// }
}
/**
* 更新背景图片预览
* 更新背景图片预览
* 如果sourceFile参数为空则加载旧的背景图片资源
*/
public void updatePreviewBackground() {
public void updateBackgroundView(File sourceFile, String sourceFileInfo) {
LogUtils.d(TAG, "updatePreviewBackground");
//ImageView ivPreviewBackground = (ImageView) findViewById(R.id.activitybackgroundpictureImageView1);
bvPreviewBackground = (BackgroundView) findViewById(R.id.activitybackgroundpictureBackgroundView1);
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
utils.loadBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
if (sourceFile == null) {
bvPreviewBackground.reloadCurrentBackground();
} else {
utils.saveFileToPreviewBean(sourceFile, sourceFileInfo);
bvPreviewBackground.reloadPreviewBackground();
}
boolean isUseBackgroundFile = utils.getBackgroundPictureBean().isUseBackgroundFile();
if (isUseBackgroundFile && mfRecivedCropPicture.exists()) {
//try {
String filePath = utils.getBackgroundDir() + getBackgroundFileName();
preViewFileBackgroundView = filePath;
bvPreviewBackground.previewBackgroundImage(preViewFileBackgroundView);
/*Drawable drawable = FileUtils.getImageDrawable(filePath);
if (drawable != null) {
//drawable.setAlpha(120);
//bvPreviewBackground.setImageDrawable(drawable);
}*/
//ToastUtils.show("背景图片已更新");
// } catch (IOException e) {
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
// ToastUtils.show("背景图片加载失败");
// }
} else {
ToastUtils.show("未使用背景图片");
preViewFileBackgroundView = "";
bvPreviewBackground.previewBackgroundImage(preViewFileBackgroundView);
// Drawable drawable = getResources().getDrawable(R.drawable.blank10x10);
// if (drawable != null) {
// drawable.setAlpha(120);
// bvPreviewBackground.setImageDrawable(drawable);
// }
}
// boolean isUseBackgroundFile = utils.getCurrentBackgroundBean().isUseBackgroundFile();
// LogUtils.d(TAG, String.format("isUseBackgroundFile is %s, _mSourceCroppedFile.exists() is %s ", isUseBackgroundFile, _mSourceCroppedFile.exists()));
//
// //if (isUseBackgroundFile && _mSourceCroppedFile.exists()) {
// if (_mSourceCroppedFile.exists()) {
// //try {
// //String filePath = utils.getBackgroundDir() + getBackgroundFileName();
// preViewFilePath = _mSourceCroppedFilePath;
// LogUtils.d(TAG, String.format("preViewFilePathBackgroundView : %s", preViewFilePath));
// bvPreviewBackground.previewBackgroundImage(preViewFilePath);
// /*Drawable drawable = FileUtils.getImageDrawable(filePath);
// if (drawable != null) {
// //drawable.setAlpha(120);
// //bvPreviewBackground.setImageDrawable(drawable);
// }*/
// //ToastUtils.show("背景图片已更新");
//// } catch (IOException e) {
//// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//// ToastUtils.show("背景图片加载失败");
//// }
// } else {
// ToastUtils.show("未使用背景图片");
// preViewFilePath = "";
// bvPreviewBackground.previewBackgroundImage(preViewFilePath);
//// Drawable drawable = getResources().getDrawable(R.drawable.blank10x10);
//// if (drawable != null) {
//// drawable.setAlpha(120);
//// bvPreviewBackground.setImageDrawable(drawable);
//// }
// }
}
// 点击事件监听器
private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
bean.setIsUseBackgroundFile(false);
utils.saveData();
updatePreviewBackground();
utils.saveSettings();
bvPreviewBackground.reloadPreviewBackground();
}
};
@@ -269,10 +295,11 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
utils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
utils.saveData();
updatePreviewBackground();
ToastUtils.show("onReceivedPictureClickListener not yet.");
// BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
// utils.getCurrentBackgroundBean().setIsUseBackgroundFile(true);
// utils.saveSettings();
// updateBackgroundView();
}
};
@@ -281,7 +308,7 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
public void onClick(View v) {
// 从文件路径启动像素拾取活动
//String imagePath = "/storage/emulated/0/DCIM/Camera/sample.jpg";
String imagePath = mfRecivedCropPicture.toString();
String imagePath = _mSourceCroppedFile.toString();
Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class);
intent.putExtra("imagePath", imagePath);
startActivity(intent);
@@ -292,10 +319,10 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
private View.OnClickListener onCleanPixelClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
bean.setPixelColor(0);
utils.saveData();
utils.saveSettings();
setBackgroundColor();
}
};
@@ -306,12 +333,13 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
void compressQualityToRecivedPicture(Bitmap bitmap) {
OutputStream outStream = null;
try {
mfRecivedPicture = getRecivedPictureFile(this);
if (!mfRecivedPicture.exists()) {
mfRecivedPicture.createNewFile();
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
File fRecivedPicture = new File(utils.getPreviewBackgroundScaledCompressFilePath());
if (!fRecivedPicture.exists()) {
fRecivedPicture.createNewFile();
}
FileOutputStream fos = new FileOutputStream(mfRecivedPicture);
FileOutputStream fos = new FileOutputStream(fRecivedPicture);
outStream = new BufferedOutputStream(fos);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
@@ -338,24 +366,30 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
*/
public void startCropImageActivity(boolean isCropFree) {
LogUtils.d(TAG, "startCropImageActivity");
BackgroundPictureBean bean = mBackgroundPictureUtils.loadBackgroundPictureBean();
mfRecivedPicture = getRecivedPictureFile(this);
Uri uri = UriUtil.getUriForFile(this, mfRecivedPicture);
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
BackgroundBean bean = utils.getPreviewBackgroundBean();
bean.setIsUseScaledCompress(true);
utils.saveSettings();
File fRecivedPicture = new File(utils.getPreviewBackgroundFilePath());
Uri uri = UriUtil.getUriForFile(this, fRecivedPicture);
LogUtils.d(TAG, "uri : " + uri.toString());
if (mfTempCropPicture.exists()) {
mfTempCropPicture.delete();
if (_mSourceCropTempFile.exists()) {
_mSourceCropTempFile.delete();
}
try {
mfTempCropPicture.createNewFile();
_mSourceCropTempFile.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
ToastUtils.show("剪裁临时文件创建失败");
return;
}
Uri cropOutPutUri = Uri.fromFile(mfTempCropPicture);
LogUtils.d(TAG, "mfTempCropPicture : " + mfTempCropPicture.getPath());
Uri cropOutPutUri = Uri.fromFile(_mSourceCropTempFile);
LogUtils.d(TAG, "mfTempCropPicture : " + _mSourceCropTempFile.getPath());
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/" + _mszCommonFileType);
@@ -372,6 +406,7 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
intent.putExtra("scale", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_CROP_IMAGE);
}
@@ -399,7 +434,7 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
}
// 优化创建保存目录
File backgroundDir = new File(mBackgroundPictureUtils.getBackgroundDir());
File backgroundDir = new File(mBackgroundSourceUtils.getBackgroundSourceDirPath());
if (!backgroundDir.exists()) {
if (!backgroundDir.mkdirs()) {
ToastUtils.show("无法创建保存目录");
@@ -408,11 +443,12 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
}
}
File saveFile = new File(backgroundDir, getBackgroundFileName());
// 剪裁的图片的保存地址
File fScaledCompressBitmapFile = new File(backgroundDir, BackgroundSourceUtils.getInstance(this).getPreviewBackgroundScaledCompressFilePath());
// 优化检查文件是否可写
if (saveFile.exists() && !saveFile.canWrite()) {
if (!saveFile.delete()) {
if (fScaledCompressBitmapFile.exists() && !fScaledCompressBitmapFile.canWrite()) {
if (!fScaledCompressBitmapFile.delete()) {
ToastUtils.show("无法删除旧文件");
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
@@ -421,29 +457,34 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
FileOutputStream fos = null;
try {
fos = new FileOutputStream(saveFile);
fos = new FileOutputStream(fScaledCompressBitmapFile);
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
fos.flush();
if (success) {
ToastUtils.show("保存成功");
// 更新数据
mBackgroundPictureUtils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
updatePreviewBackground();
ToastUtils.show("图片压缩保存成功");
BackgroundSourceUtils.getInstance(this).getPreviewBackgroundBean().setIsUseScaledCompress(true);
BackgroundSourceUtils.getInstance(this).saveSettings();
bvPreviewBackground.reloadPreviewBackground();
} else {
ToastUtils.show("图片压缩保存失败");
BackgroundSourceUtils.getInstance(this).getPreviewBackgroundBean().setIsUseScaledCompress(false);
BackgroundSourceUtils.getInstance(this).saveSettings();
bvPreviewBackground.reloadPreviewBackground();
}
} catch (FileNotFoundException e) {
LogUtils.e(TAG, "文件未找到" + e);
ToastUtils.show("保存失败:文件路径错误");
ToastUtils.show("文件未找到" + e);
} catch (IOException e) {
LogUtils.e(TAG, "写入异常" + e);
ToastUtils.show("保存失败:磁盘可能已满或路径错误");
ToastUtils.show("写入异常" + e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogUtils.e(TAG, "流关闭异常" + e);
ToastUtils.show("流关闭异常" + e);
}
}
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
@@ -468,7 +509,9 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
* 分享图片
*/
void sharePicture() {
Uri uri = UriUtil.getUriForFile(this, mfRecivedPicture);
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
File fRecivedPicture = new File(utils.getCurrentBackgroundFilePath());
Uri uri = UriUtil.getUriForFile(this, fRecivedPicture);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("image/" + _mszCommonFileType);
@@ -476,11 +519,20 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
startActivity(Intent.createChooser(shareIntent, "Share Image"));
}
public static File getRecivedPictureFile(Context context) {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(context);
utils.loadBackgroundPictureBean();
return new File(utils.getBackgroundDir(), _RecivedPictureFileName);
}
// public File getRecivedPictureFile() {
// BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
// utils.loadSettings();
// return new File(utils.getBackgroundSourceDirPath(), _RecivedBackgroundFileName);
// }
// public void saveToRecivedBackground(String srcFilePath, String srcFillSourcePath) {
// BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(this);
// utils.loadSettings();
// File dstFile = new File(utils.getBackgroundSourceDirPath(), _RecivedBackgroundFileName);
// //compressQualityToRecivedPicture(srcFilePath);
// ToastUtils.show("compressQualityToRecivedPicture not yet.");
// FileUtils.copyFile(new File(srcFilePath), dstFile);
// }
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
@@ -490,12 +542,17 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
Uri selectedImage = data.getData();
LogUtils.d(TAG, "Uri is : " + selectedImage.toString());
File fSrcImage = new File(UriUtil.getFilePathFromUri(this, selectedImage));
mfRecivedPicture = getRecivedPictureFile(this);
if (FileUtils.copyFile(fSrcImage, mfRecivedPicture)) {
startCropImageActivity(false);
} else {
ToastUtils.show("图片复制失败,请重试");
}
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(this);
utils.saveFileToPreviewBean(fSrcImage, selectedImage.toString());
startCropImageActivity(false);
//mfRecivedPicture = getRecivedPictureFile();
// BackgroundBean bean = utils.getPreviewBackgroundBean();
// mfRecivedPicture = getRecivedPictureFile();
// if (FileUtils.copyFile(fSrcImage, mfRecivedPicture)) {
// startCropImageActivity(false);
// } else {
// ToastUtils.show("图片复制失败,请重试");
// }
} catch (Exception e) {
LogUtils.e(TAG, "选择图片异常" + e);
ToastUtils.show("选择图片失败:" + e.getMessage());
@@ -521,8 +578,9 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
// 方案1通过Intent获取剪裁后的Bitmap
if (data != null && data.hasExtra("data")) {
cropBitmap = data.getParcelableExtra("data");
} else if (mfTempCropPicture.exists()) {
cropBitmap = BitmapFactory.decodeFile(mfTempCropPicture.getPath());
} else if (_mSourceCropTempFile.exists()) {
LogUtils.d(TAG, String.format("_mSourceCropTempFile Exists, Path is %s ", _mSourceCropTempFile.getPath()));
cropBitmap = BitmapFactory.decodeFile(_mSourceCropTempFile.getPath());
} else {
ToastUtils.show("剪裁文件不存在");
return;
@@ -588,8 +646,8 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
}
void setBackgroundColor() {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor();
RelativeLayout mainLayout = findViewById(R.id.activitybackgroundpictureRelativeLayout1);
mainLayout.setBackgroundColor(nPixelColor);
@@ -605,19 +663,17 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
// 在需要显示对话框的地方如网络状态监听回调中
NetworkBackgroundDialog dialog = new NetworkBackgroundDialog(this, new NetworkBackgroundDialog.OnDialogClickListener() {
@Override
public void onConfirm() {
ToastUtils.show("onConfirm");
// 处理确认逻辑如允许后台网络使用
LogUtils.d("MainActivity", "用户允许后台网络使用");
// 执行具体业务如开启后台网络请求服务
public void onConfirm(String szConfirmFilePath, String szConfirmFileUrl) {
//ToastUtils.show("onConfirm");
// 保存预览资源信息
preViewFilePath = szConfirmFilePath;
preViewFileUrl = szConfirmFileUrl;
onRecivedPictureListener.onRecivedPicture(preViewFilePath, preViewFileUrl);
}
@Override
public void onCancel() {
ToastUtils.show("onCancel");
// 处理取消逻辑如禁止后台网络使用
LogUtils.d("MainActivity", "用户禁止后台网络使用");
// 执行具体业务如关闭后台网络请求
//ToastUtils.show("onCancel");
}
});
@@ -630,6 +686,19 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
}
interface OnRecivedPictureListener {
void onRecivedPicture(String srcFilePath, String srcFileUrl);
}
OnRecivedPictureListener onRecivedPictureListener = new OnRecivedPictureListener(){
@Override
public void onRecivedPicture(String srcFilePath, String srcFileUrl) {
BackgroundSourceUtils utils= BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
utils.saveFileToPreviewBean(new File(srcFilePath), srcFileUrl);
startCropImageActivity(true);
}
};
/**
* 重写finish方法确保所有退出场景都触发Toast
*/
@@ -641,12 +710,17 @@ public class BackgroundPictureActivity extends WinBoLLActivity implements Backgr
@Override
public void onNo() {
isCommitSettings = true;
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
bean.setIsUseBackgroundFile(!preViewFilePath.equals(""));
utils.saveSettings();
finish();
}
@Override
public void onYes() {
bvPreviewBackground.saveToBackgroundSources(preViewFileBackgroundView);
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(BackgroundSettingsActivity.this);
utils.commitPreviewSourceToCurrent();
isCommitSettings = true;
finish();
}

View File

@@ -12,7 +12,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.beans.BatteryInfoBean;
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
import cc.winboll.studio.powerbell.utils.StringUtils;

View File

@@ -24,10 +24,10 @@ import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libaes.views.AToolbar;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.activities.BackgroundPictureActivity;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils;
import cc.winboll.studio.powerbell.model.BackgroundBean;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -193,10 +193,10 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public void onClick(View v) {
dialog.dismiss();
// 可以在这里添加确定后的回调逻辑
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(PixelPickerActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
bean.setPixelColor(pixelColor);
utils.saveData();
utils.saveSettings();
Toast.makeText(PixelPickerActivity.this, "已记录像素值", Toast.LENGTH_SHORT).show();
setBackgroundColor();
}
@@ -217,8 +217,8 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
void setBackgroundColor() {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(PixelPickerActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor();
RelativeLayout mainLayout = findViewById(R.id.activitypixelpickerRelativeLayout1);
mainLayout.setBackgroundColor(nPixelColor);
@@ -235,7 +235,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent();
intent.setClass(this, BackgroundPictureActivity.class);
intent.setClass(this, BackgroundSettingsActivity.class);
startActivity(intent);
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), );
return true;
@@ -248,7 +248,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent();
intent.setClass(this, BackgroundPictureActivity.class);
intent.setClass(this, BackgroundSettingsActivity.class);
startActivity(intent);
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), BackgroundPictureActivity.class);
}

View File

@@ -0,0 +1,21 @@
package cc.winboll.studio.powerbell.activities;
import android.app.Activity;
import android.os.Bundle;
import cc.winboll.studio.powerbell.R;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/27 14:26
* @Describe 应用设置窗口
*/
public class SettingsActivity extends Activity {
public static final String TAG = "SettingsActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
}
}

View File

@@ -12,7 +12,7 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.adapters.BatteryAdapter;
import cc.winboll.studio.powerbell.beans.BatteryData;
import cc.winboll.studio.powerbell.model.BatteryData;
import java.util.ArrayList;
import java.util.List;

View File

@@ -1,99 +0,0 @@
package cc.winboll.studio.powerbell.beans;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/18 11:52:28
* @Describe 应用背景图片数据类
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class BackgroundPictureBean extends BaseBean {
public static final String TAG = "BackgroundPictureBean";
int backgroundWidth = 100;
int backgroundHeight = 100;
boolean isUseBackgroundFile = false;
// 图片拾取像素颜色
int pixelColor = 0;
public BackgroundPictureBean() {
}
public BackgroundPictureBean(String recivedFileName, boolean isUseBackgroundFile) {
this.isUseBackgroundFile = isUseBackgroundFile;
}
public void setPixelColor(int pixelColor) {
this.pixelColor = pixelColor;
}
public int getPixelColor() {
return pixelColor;
}
public void setBackgroundWidth(int backgroundWidth) {
this.backgroundWidth = backgroundWidth;
}
public int getBackgroundWidth() {
return backgroundWidth;
}
public void setBackgroundHeight(int backgroundHeight) {
this.backgroundHeight = backgroundHeight;
}
public int getBackgroundHeight() {
return backgroundHeight;
}
public void setIsUseBackgroundFile(boolean isUseBackgroundFile) {
this.isUseBackgroundFile = isUseBackgroundFile;
}
public boolean isUseBackgroundFile() {
return isUseBackgroundFile;
}
@Override
public String getName() {
return BackgroundPictureBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
BackgroundPictureBean bean = this;
jsonWriter.name("backgroundWidth").value(bean.getBackgroundWidth());
jsonWriter.name("backgroundHeight").value(bean.getBackgroundHeight());
jsonWriter.name("isUseBackgroundFile").value(bean.isUseBackgroundFile());
jsonWriter.name("pixelColor").value(bean.getPixelColor());
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
BackgroundPictureBean bean = new BackgroundPictureBean();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals("backgroundWidth")) {
bean.setBackgroundWidth(jsonReader.nextInt());
} else if (name.equals("backgroundHeight")) {
bean.setBackgroundHeight(jsonReader.nextInt());
} else if (name.equals("isUseBackgroundFile")) {
bean.setIsUseBackgroundFile(jsonReader.nextBoolean());
} else if (name.equals("pixelColor")) {
bean.setPixelColor(jsonReader.nextInt());
} else {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return bean;
}
}

View File

@@ -12,8 +12,8 @@ import android.widget.Toast;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.activities.BackgroundPictureActivity;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils;
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.UriUtil;
import java.io.File;
@@ -29,7 +29,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
public static final String TAG = "BackgroundPicturePreviewDialog";
Context mContext;
BackgroundPictureUtils mBackgroundPictureUtils;
BackgroundSourceUtils mBackgroundPictureUtils;
Button dialogbackgroundpicturepreviewButton1;
Button dialogbackgroundpicturepreviewButton2;
String mszPreReceivedFileName;
@@ -40,7 +40,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
initEnv();
mContext = context;
mBackgroundPictureUtils = ((BackgroundPictureActivity)context).mBackgroundPictureUtils;
mBackgroundPictureUtils = ((BackgroundSettingsActivity)context).mBackgroundSourceUtils;
ImageView imageView = findViewById(R.id.dialogbackgroundpicturepreviewImageView1);
copyAndViewRecivePicture(imageView);
@@ -78,7 +78,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
void copyAndViewRecivePicture(ImageView imageView) {
//AppConfigUtils appConfigUtils = AppConfigUtils.getInstance((GlobalApplication)mContext.getApplicationContext());
BackgroundPictureActivity activity = ((BackgroundPictureActivity)mContext);
BackgroundSettingsActivity activity = ((BackgroundSettingsActivity)mContext);
//取出文件uri
Uri uri = activity.getIntent().getData();
@@ -95,7 +95,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
File fSrcImage = new File(szSrcImage);
//mszPreReceivedFileName = DateUtils.getDateNowString() + "-" + fSrcImage.getName();
File mfPreReceivedPhoto = new File(activity.mBackgroundPictureUtils.getBackgroundDir(), mszPreReceivedFileName);
File mfPreReceivedPhoto = new File(activity.mBackgroundSourceUtils.getBackgroundSourceDirPath(), mszPreReceivedFileName);
// 复制源图片到剪裁文件
try {
FileUtils.copyFileUsingFileChannels(fSrcImage, mfPreReceivedPhoto);

View File

@@ -15,11 +15,12 @@ import androidx.appcompat.app.AlertDialog;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.utils.PictureUtils;
import cc.winboll.studio.powerbell.views.BackgroundView;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import cc.winboll.studio.powerbell.utils.ImageDownloader;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
@@ -45,11 +46,13 @@ public class NetworkBackgroundDialog extends AlertDialog {
Context mContext;
// 主线程 Handler用于接收子线程消息并更新 UI
private Handler mUiHandler;
String previewFilePath;
String mPreviewFilePath;
String mPreviewFileUrl;
String mDownloadSavedPath;
// 按钮点击回调接口Java7 接口实现)
public interface OnDialogClickListener {
void onConfirm(); // 确认按钮点击
void onConfirm(String szConfirmFilePath, String previewFileUrl); // 确认按钮点击
void onCancel(); // 取消按钮点击
}
@@ -87,8 +90,8 @@ public class NetworkBackgroundDialog extends AlertDialog {
switch (msg.what) {
case MSG_IMAGE_LOAD_SUCCESS:
// 图片加载成功,获取文件路径并设置背景
String filePath = (String) msg.obj;
setBackgroundFromPath(filePath);
mDownloadSavedPath = (String) msg.obj;
previewBackground(mDownloadSavedPath);
break;
case MSG_IMAGE_LOAD_FAILED:
// 图片加载失败,设置默认背景
@@ -135,7 +138,8 @@ public class NetworkBackgroundDialog extends AlertDialog {
btnPreview = (Button) dialogView.findViewById(R.id.btn_preview);
etURL = (EditText) dialogView.findViewById(R.id.et_url);
bvBackgroundPreview = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview);
// 加载初始图片
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
// 设置按钮点击事件
setButtonClickListeners();
}
@@ -149,6 +153,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
@Override
public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "取消按钮点击");
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.setCurrentSourceToPreview();
dismiss(); // 关闭对话框
if (listener != null) {
listener.onCancel();
@@ -162,11 +169,12 @@ public class NetworkBackgroundDialog extends AlertDialog {
public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认按钮点击");
// 确定预览背景资源
bvBackgroundPreview.saveToBackgroundSources(previewFilePath);
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
dismiss(); // 关闭对话框
if (listener != null) {
listener.onConfirm();
listener.onConfirm(mPreviewFilePath, mPreviewFileUrl);
}
}
});
@@ -175,14 +183,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
btnPreview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认预览点击");
downloadImageToAlbumAndPreview();
/*String url = etURL.getText().toString().trim();
if (url.isEmpty()) {
ToastUtils.show("请输入图片链接");
return;
}
ImageDownloader.getInstance(mContext).downloadImage(url, mDownloadCallback);*/
}
});
}
@@ -191,23 +192,24 @@ public class NetworkBackgroundDialog extends AlertDialog {
* 根据文件路径设置 BackgroundView 背景(主线程调用)
* @param filePath 图片文件路径
*/
private void setBackgroundFromPath(String filePath) {
private void previewBackground(String previewFilePath) {
FileInputStream fis = null;
try {
File imageFile = new File(filePath);
File imageFile = new File(previewFilePath);
if (!imageFile.exists()) {
LogUtils.e(TAG, "图片文件不存在:" + filePath);
ToastUtils.show("Test");
//bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
ToastUtils.show("图片文件不存在:" + previewFilePath);
LogUtils.e(TAG, "图片文件不存在:" + previewFilePath);
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
return;
}
// 预览背景
previewFilePath = filePath;
bvBackgroundPreview.previewBackgroundImage(previewFilePath);
LogUtils.d(TAG, "图片预览成功:" + filePath);
mPreviewFilePath = previewFilePath;
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
bvBackgroundPreview.reloadPreviewBackground();
//ToastUtils.show("预览背景中。。。");
} catch (Exception e) {
e.printStackTrace();
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
@@ -249,40 +251,20 @@ public class NetworkBackgroundDialog extends AlertDialog {
this.listener = listener;
}
/*ImageDownloader.DownloadCallback mDownloadCallback = new ImageDownloader.DownloadCallback() {
@Override
public void onSuccess(String filePath) {
ToastUtils.show("图片下载成功:" + filePath);
LogUtils.d(TAG, filePath);
// 发送消息到主线程,携带图片路径
Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, filePath);
mUiHandler.sendMessage(successMsg);
}
@Override
public void onFailure(String errorMsg) {
ToastUtils.show("下载失败:" + errorMsg);
LogUtils.e(TAG, errorMsg);
// 发送图片加载失败消息
mUiHandler.sendEmptyMessage(MSG_IMAGE_LOAD_FAILED);
}
};*/
void downloadImageToAlbumAndPreview() {
//String imgUrl = "https://example.com/test.jpg";
String imgUrl = etURL.getText().toString();
PictureUtils.downloadImageToAlbum(mContext, imgUrl, new PictureUtils.DownloadCallback(){
//String previewFileUrl = "https://example.com/test.jpg";
mPreviewFileUrl = etURL.getText().toString();
ImageDownloader.getInstance(mContext).downloadImage(mPreviewFileUrl, new ImageDownloader.DownloadCallback(){
@Override
public void onSuccess(String savePath) {
ToastUtils.show("下载成功:" + savePath);
// 发送消息到主线程,携带图片路径
Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath);
mUiHandler.sendMessage(successMsg);
}
@Override
public void onFailure(Exception e) {
ToastUtils.show("下载失败:" + e.getMessage());
public void onFailure(String errorMsg) {
ToastUtils.show("下载失败:" + errorMsg);
}
});

View File

@@ -19,8 +19,11 @@ import android.widget.TextView;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
import cc.winboll.studio.powerbell.model.BackgroundBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.ServiceUtils;
import cc.winboll.studio.powerbell.views.BackgroundView;
import cc.winboll.studio.powerbell.views.BatteryDrawable;
@@ -79,6 +82,11 @@ public class MainViewFragment extends Fragment {
// 获取指定ID的View实例
bvPreviewBackground = mView.findViewById(R.id.fragmentmainviewBackgroundView1);
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(getActivity());
BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor();
bvPreviewBackground.setBackgroundColor(nPixelColor);
/*final View mainImageView = mView.findViewById(R.id.fragmentmainviewImageView1);
// 注册OnGlobalLayoutListener
@@ -141,6 +149,17 @@ public class MainViewFragment extends Fragment {
return mView;
}
@Override
public void onResume() {
super.onResume();
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(getActivity());
BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor();
bvPreviewBackground.setBackgroundColor(nPixelColor);
}
void setViewData() {
int nChargeReminderValue = mAppConfigUtils.getChargeReminderValue();
int nUsegeReminderValue = mAppConfigUtils.getUsegeReminderValue();
@@ -301,7 +320,7 @@ public class MainViewFragment extends Fragment {
}
public void reloadBackground() {
bvPreviewBackground.reloadBackgroundImage();
bvPreviewBackground.reloadCurrentBackground();
// BackgroundPictureBean bean = BackgroundPictureUtils.getInstance(getActivity()).getBackgroundPictureBean();
// ImageView imageView = mView.findViewById(R.id.fragmentmainviewImageView1);
// String szBackgroundFilePath = BackgroundPictureUtils.getInstance(getActivity()).getBackgroundDir() + BackgroundPictureActivity.getBackgroundFileName();

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.powerbell.beans;
package cc.winboll.studio.powerbell.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>

View File

@@ -0,0 +1,143 @@
package cc.winboll.studio.powerbell.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/18 11:52:28
* @Describe 应用背景图片数据类
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class BackgroundBean extends BaseBean {
public static final String TAG = "BackgroundPictureBean";
String backgroundFileName = "";
String backgroundFileInfo = "";
boolean isUseBackgroundFile = false;
String backgroundScaledCompressFileName = "";
boolean isUseScaledCompress = false;
int backgroundWidth = 100;
int backgroundHeight = 100;
// 图片拾取像素颜色
int pixelColor = 0;
public BackgroundBean() {
}
public void setBackgroundScaledCompressFileName(String backgroundScaledCompressFileName) {
this.backgroundScaledCompressFileName = backgroundScaledCompressFileName;
}
public String getBackgroundScaledCompressFileName() {
return backgroundScaledCompressFileName;
}
public void setIsUseScaledCompress(boolean isUseScaledCompress) {
this.isUseScaledCompress = isUseScaledCompress;
}
public boolean isUseScaledCompress() {
return isUseScaledCompress;
}
public void setIsUseBackgroundFile(boolean isUseBackgroundFile) {
this.isUseBackgroundFile = isUseBackgroundFile;
}
public boolean isUseBackgroundFile() {
return isUseBackgroundFile;
}
public void setBackgroundFileInfo(String backgroundFileInfo) {
this.backgroundFileInfo = backgroundFileInfo;
}
public String getBackgroundFileInfo() {
return backgroundFileInfo;
}
public void setBackgroundFileName(String backgroundFileName) {
this.backgroundFileName = backgroundFileName;
}
public String getBackgroundFileName() {
return backgroundFileName;
}
public void setPixelColor(int pixelColor) {
this.pixelColor = pixelColor;
}
public int getPixelColor() {
return pixelColor;
}
public void setBackgroundWidth(int backgroundWidth) {
this.backgroundWidth = backgroundWidth;
}
public int getBackgroundWidth() {
return backgroundWidth;
}
public void setBackgroundHeight(int backgroundHeight) {
this.backgroundHeight = backgroundHeight;
}
public int getBackgroundHeight() {
return backgroundHeight;
}
@Override
public String getName() {
return BackgroundBean.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
BackgroundBean bean = this;
jsonWriter.name("backgroundFileName").value(bean.getBackgroundFileName());
jsonWriter.name("backgroundFileInfo").value(bean.getBackgroundFileInfo());
jsonWriter.name("isUseBackgroundFile").value(bean.isUseBackgroundFile());
jsonWriter.name("backgroundScaledCompressFileName").value(bean.getBackgroundScaledCompressFileName());
jsonWriter.name("isUseScaledCompress").value(bean.isUseScaledCompress());
jsonWriter.name("backgroundWidth").value(bean.getBackgroundWidth());
jsonWriter.name("backgroundHeight").value(bean.getBackgroundHeight());
jsonWriter.name("pixelColor").value(bean.getPixelColor());
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
BackgroundBean bean = new BackgroundBean();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
if (name.equals("backgroundFileName")) {
bean.setBackgroundFileName(jsonReader.nextString());
} else if (name.equals("backgroundFileInfo")) {
bean.setBackgroundFileInfo(jsonReader.nextString());
} else if (name.equals("isUseBackgroundFile")) {
bean.setIsUseBackgroundFile(jsonReader.nextBoolean());
} else if (name.equals("backgroundScaledCompressFileName")) {
bean.setBackgroundScaledCompressFileName(jsonReader.nextString());
} else if (name.equals("isUseScaledCompress")) {
bean.setIsUseScaledCompress(jsonReader.nextBoolean());
} else if (name.equals("backgroundWidth")) {
bean.setBackgroundWidth(jsonReader.nextInt());
} else if (name.equals("backgroundHeight")) {
bean.setBackgroundHeight(jsonReader.nextInt());
} else if (name.equals("pixelColor")) {
bean.setPixelColor(jsonReader.nextInt());
} else {
jsonReader.skipValue();
}
}
// 结束 JSON 对象
jsonReader.endObject();
return bean;
}
}

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.powerbell.beans;
package cc.winboll.studio.powerbell.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.powerbell.beans;
package cc.winboll.studio.powerbell.model;
import android.util.JsonReader;
import android.util.JsonWriter;

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.powerbell.beans;
package cc.winboll.studio.powerbell.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>

View File

@@ -1,4 +1,4 @@
package cc.winboll.studio.powerbell.beans;
package cc.winboll.studio.powerbell.model;
// 应用消息结构
//

View File

@@ -5,7 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.beans.AppConfigBean;
import cc.winboll.studio.powerbell.model.AppConfigBean;
import cc.winboll.studio.powerbell.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BatteryUtils;

View File

@@ -23,8 +23,8 @@ import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.beans.AppConfigBean;
import cc.winboll.studio.powerbell.beans.NotificationMessage;
import cc.winboll.studio.powerbell.model.AppConfigBean;
import cc.winboll.studio.powerbell.model.NotificationMessage;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
import cc.winboll.studio.powerbell.services.AssistantService;

View File

@@ -2,7 +2,7 @@ package cc.winboll.studio.powerbell.utils;
import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.beans.BatteryInfoBean;
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
import java.util.ArrayList;
public class AppCacheUtils {

View File

@@ -5,8 +5,8 @@ import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.beans.AppConfigBean;
import cc.winboll.studio.powerbell.beans.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.model.AppConfigBean;
import cc.winboll.studio.powerbell.model.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
import cc.winboll.studio.powerbell.services.ControlCenterService;

View File

@@ -1,64 +0,0 @@
package cc.winboll.studio.powerbell.utils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/18 12:07:20
* @Describe 背景图片工具集
*/
import android.content.Context;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean;
import java.io.File;
public class BackgroundPictureUtils {
public static final String TAG = "BackgroundPictureUtils";
static BackgroundPictureUtils _mBackgroundPictureUtils;
Context mContext;
BackgroundPictureBean mBackgroundPictureBean;
// 背景图片目录
String mszBackgroundDir;
BackgroundPictureUtils(Context context) {
mContext = context;
String szExternalFilesDir = mContext.getExternalFilesDir(TAG) + File.separator;
setBackgroundDir(szExternalFilesDir + "Background" + File.separator);
loadBackgroundPictureBean();
}
public static BackgroundPictureUtils getInstance(Context context) {
if (_mBackgroundPictureUtils == null) {
_mBackgroundPictureUtils = new BackgroundPictureUtils(context);
}
return _mBackgroundPictureUtils;
}
//
// 加载应用背景图片配置数据
//
public BackgroundPictureBean loadBackgroundPictureBean() {
mBackgroundPictureBean = BackgroundPictureBean.loadBean(mContext, BackgroundPictureBean.class);
if (mBackgroundPictureBean == null) {
mBackgroundPictureBean = new BackgroundPictureBean();
BackgroundPictureBean.saveBean(mContext, mBackgroundPictureBean);
}
return mBackgroundPictureBean;
}
void setBackgroundDir(String mszBackgroundDir) {
this.mszBackgroundDir = mszBackgroundDir;
}
public String getBackgroundDir() {
return mszBackgroundDir;
}
public BackgroundPictureBean getBackgroundPictureBean() {
return mBackgroundPictureBean;
}
public void saveData() {
BackgroundPictureBean.saveBean(mContext, mBackgroundPictureBean);
}
}

View File

@@ -0,0 +1,144 @@
package cc.winboll.studio.powerbell.utils;
import android.content.Context;
import cc.winboll.studio.powerbell.model.BackgroundBean;
import java.io.File;
import java.util.UUID;
import cc.winboll.studio.libappbase.ToastUtils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/18 12:07:20
* @Describe 背景图片工具集(修复单例模式,线程安全)
*/
public class BackgroundSourceUtils {
public static final String TAG = "BackgroundPictureUtils";
// 1. 静态实例加volatile禁止指令重排保证可见性
private static volatile BackgroundSourceUtils sInstance;
private Context mContext;
private File currentBackgroundBeanFile;
private BackgroundBean currentBackgroundBean;
private File previewBackgroundBeanFile;
private BackgroundBean previewBackgroundBean;
// 应用外部存储文件夹路径
private File fUtilsDir;
private File fModelDir;
// 背景图片目录
private File fBackgroundSourceDir;
// 2. 私有构造器(加防反射逻辑)
private BackgroundSourceUtils(Context context) {
// 防反射破坏:若已有实例,抛异常阻止创建
if (sInstance != null) {
throw new RuntimeException("BackgroundSourceUtils 是单例类,禁止重复创建!");
}
// 上下文建议用Application Context避免内存泄漏
this.mContext = context.getApplicationContext();
fUtilsDir = this.mContext.getExternalFilesDir(TAG);
fModelDir = new File(fUtilsDir, "ModelDir");
currentBackgroundBeanFile = new File(fModelDir, "currentBackgroundBean.json");
previewBackgroundBeanFile = new File(fModelDir, "previewBackgroundBean.json");
fBackgroundSourceDir = new File(fUtilsDir, "BackgroundSource");
// 加载配置
loadSettings();
}
// 3. 双重校验锁单例(线程安全,高效)
public static BackgroundSourceUtils getInstance(Context context) {
// 第一重校验:避免每次调用都加锁(提高效率)
if (sInstance == null) {
// 同步锁:保证同一时刻只有一个线程进入创建逻辑
synchronized (BackgroundSourceUtils.class) {
// 第二重校验:防止多线程并发时重复创建(核心)
if (sInstance == null) {
sInstance = new BackgroundSourceUtils(context);
}
}
}
return sInstance;
}
/*
* 加载背景图片配置数据
*/
void loadSettings() {
currentBackgroundBean = BackgroundBean.loadBeanFromFile(currentBackgroundBeanFile.getAbsolutePath(), BackgroundBean.class);
if (currentBackgroundBean == null) {
currentBackgroundBean = new BackgroundBean();
BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean);
}
previewBackgroundBean = BackgroundBean.loadBeanFromFile(previewBackgroundBeanFile.getAbsolutePath(), BackgroundBean.class);
if (previewBackgroundBean == null) {
previewBackgroundBean = new BackgroundBean();
BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean);
}
}
public BackgroundBean getCurrentBackgroundBean() {
return currentBackgroundBean;
}
public BackgroundBean getPreviewBackgroundBean() {
return previewBackgroundBean;
}
public String getCurrentBackgroundFilePath() {
loadSettings();
File file = new File(fBackgroundSourceDir, currentBackgroundBean.getBackgroundFileName());
return file.getAbsolutePath();
}
public String getPreviewBackgroundFilePath() {
loadSettings();
File file = new File(fBackgroundSourceDir, previewBackgroundBean.getBackgroundFileName());
return file.getAbsolutePath();
}
public String getPreviewBackgroundScaledCompressFilePath() {
loadSettings();
File file = new File(fBackgroundSourceDir, previewBackgroundBean.getBackgroundScaledCompressFileName());
return file.getAbsolutePath();
}
public void saveSettings() {
BackgroundBean.saveBeanToFile(currentBackgroundBeanFile.getAbsolutePath(), currentBackgroundBean);
BackgroundBean.saveBeanToFile(previewBackgroundBeanFile.getAbsolutePath(), previewBackgroundBean);
}
public String getBackgroundSourceDirPath() {
return fBackgroundSourceDir.getAbsolutePath();
}
/*
* 保存图片到预览模型, 并返回预览模型数据
*/
public BackgroundBean saveFileToPreviewBean(File sourceFile, String fileInfo) {
File previewBackgroundFile = new File(fBackgroundSourceDir, FileUtils.createUniqueFileName(sourceFile));
//ToastUtils.show(String.format("saveFileToPreviewBean previewBackgroundFile : %s", previewBackgroundFile.getAbsolutePath()));
FileUtils.copyFile(sourceFile, previewBackgroundFile);
previewBackgroundBean = new BackgroundBean();
previewBackgroundBean.setBackgroundFileName(previewBackgroundFile.getName());
previewBackgroundBean.setBackgroundScaledCompressFileName("ScaledCompress_"+previewBackgroundFile.getName());
previewBackgroundBean.setBackgroundFileName(fileInfo);
saveSettings();
ToastUtils.show(String.format("saveFileToPreviewBean getPreviewBackgroundFilePath() : %s", getPreviewBackgroundFilePath()));
return previewBackgroundBean;
}
public void commitPreviewSourceToCurrent() {
currentBackgroundBean = previewBackgroundBean;
saveSettings();
}
public void setCurrentSourceToPreview() {
previewBackgroundBean = currentBackgroundBean;
saveSettings();
}
}

View File

@@ -1,176 +1,236 @@
package cc.winboll.studio.powerbell.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
/**
* 文件读取工具类
* 文件操作工具类
* 功能:文件读写、复制、图片转换、文件名处理等常用文件操作
* 适配Java 7+支持Android全版本
* 注意调用文件操作前需确保已获取存储权限Android 6.0+ 需动态申请)
*/
public class FileUtils {
/** 日志标签 */
public static final String TAG = "FileUtils";
/** 读取文件默认缓冲区大小10KB */
private static final int BUFFER_SIZE = 10240;
/** 最大读取文件大小1GB防止OOM */
private static final long MAX_READ_FILE_SIZE = 1024 * 1024 * 1024;
//
// 读取文件内容,作为字符串返回
//
// ====================================== 文件读取相关 ======================================
/**
* 读取文件内容并转为字符串
* @param filePath 文件绝对路径(非空)
* @return 文件内容字符串
* @throws IOException 异常:文件不存在、文件过大、读取失败等
*/
public static String readFileAsString(String filePath) throws IOException {
// 1. 校验文件合法性
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
throw new FileNotFoundException("文件不存在:" + filePath);
}
if (file.length() > MAX_READ_FILE_SIZE) {
throw new IOException("文件过大超过1GB禁止读取" + filePath);
}
if (file.length() > 1024 * 1024 * 1024) {
throw new IOException("File is too large");
}
StringBuilder sb = new StringBuilder((int) (file.length()));
// 创建字节输入流
FileInputStream fis = new FileInputStream(filePath);
// 创建一个长度为10240的Buffer
byte[] bbuf = new byte[10240];
// 用于保存实际读取的字节数
int hasRead = 0;
while ((hasRead = fis.read(bbuf)) > 0) {
sb.append(new String(bbuf, 0, hasRead));
}
fis.close();
// 2. 读取文件内容使用StringBuilder高效拼接
StringBuilder sb = new StringBuilder((int) file.length());
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[BUFFER_SIZE];
int readLen;
// 循环读取缓冲区避免一次性读取大文件导致OOM
while ((readLen = fis.read(buffer)) > 0) {
sb.append(new String(buffer, 0, readLen));
}
}
return sb.toString();
}
//
// 根据文件路径读取byte[] 数组
//
/**
* 读取文件内容并转为byte数组适用于二进制文件图片、音频等
* @param filePath 文件绝对路径(非空)
* @return 文件内容byte数组
* @throws IOException 异常:文件不存在、读取失败等
*/
public static byte[] readFileByBytes(String filePath) throws IOException {
// 1. 校验文件合法性
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
BufferedInputStream in = null;
throw new FileNotFoundException("文件不存在:" + filePath);
}
try {
in = new BufferedInputStream(new FileInputStream(file));
short bufSize = 1024;
byte[] buffer = new byte[bufSize];
int len1;
while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
bos.write(buffer, 0, len1);
}
// 2. 缓冲流读取高效减少IO次数
try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
byte[] var7 = bos.toByteArray();
return var7;
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException var14) {
var14.printStackTrace();
}
bos.close();
byte[] buffer = new byte[BUFFER_SIZE];
int readLen;
while ((readLen = bis.read(buffer)) != -1) {
bos.write(buffer, 0, readLen);
}
bos.flush();
return bos.toByteArray();
}
}
//
// 文件复制函数
//
// ====================================== 文件复制相关 ======================================
/**
* 基于FileChannel复制文件高效适用于大文件复制
* @param source 源文件(非空,必须存在)
* @param dest 目标文件(非空,父目录会自动创建)
* @throws IOException 异常:源文件不存在、复制失败等
*/
public static void copyFileUsingFileChannels(File source, File dest) throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
// 1. 校验源文件合法性
if (!source.exists() || !source.isFile()) {
throw new FileNotFoundException("源文件不存在或不是文件:" + source.getAbsolutePath());
}
// 2. 创建目标文件父目录
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
// 3. 通道复制try-with-resources 自动关闭通道,无需手动关闭)
try (FileChannel inputChannel = new FileInputStream(source).getChannel();
FileChannel outputChannel = new FileOutputStream(dest).getChannel()) {
// 从输入通道复制到输出通道(高效,底层优化)
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
LogUtils.d(TAG, "文件复制成功FileChannel" + source.getAbsolutePath() + "" + dest.getAbsolutePath());
}
}
/**
* 将文件生成位图
* @param path
* @return
* @throws IOException
* 简化版文件复制基于NIO Files工具类代码简洁适用于中小文件
* @param oldFile 源文件(非空,必须存在)
* @param newFile 目标文件(非空,父目录会自动创建)
* @return 复制结果true-成功false-失败
*/
public static BitmapDrawable getImageDrawable(String path)
throws IOException {
//打开文件
File file = new File(path);
if (!file.exists()) {
return null;
}
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int BUFFER_SIZE = 1000;
byte[] bt = new byte[BUFFER_SIZE];
//得到文件的输入流
InputStream in = new FileInputStream(file);
//将文件读出到输出流中
int readLength = in.read(bt);
while (readLength != -1) {
outStream.write(bt, 0, readLength);
readLength = in.read(bt);
}
//转换成byte 后 再格式化成位图
byte[] data = outStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);// 生成位图
BitmapDrawable bd = new BitmapDrawable(bitmap);
return bd;
}
public static boolean copyFile(File oldFile, File newFile) {
//String oldPath = "path/to/original/file.txt";
//String newPath = "path/to/new-location/for/file.txt";
// 1. 校验源文件合法性
if (oldFile == null || !oldFile.exists() || !oldFile.isFile()) {
LogUtils.e(TAG, "源文件无效:" + (oldFile != null ? oldFile.getAbsolutePath() : "null"));
return false;
}
//File oldFile = new java.io.File(oldPath);
//File newFile = new java.io.File(newPath);
// 2. 创建目标文件父目录
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
if (!oldFile.exists()) {
//System.out.println("The original file does not exist.");
LogUtils.d(TAG, "The original file does not exist.");
} else {
try {
// 源文件路径
Path sourcePath = Paths.get(oldFile.getPath());
// 目标文件路径
Path destPath = Paths.get(newFile.getPath());
if(newFile.exists()) {
newFile.delete();
}
Files.copy(sourcePath, destPath);
LogUtils.d(TAG, "File copy successfully.");
//System.out.println("File moved successfully.");
return true;
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
//System.err.println("An error occurred while moving the file: " + e.getMessage());
// 3. 复制文件(覆盖已有目标文件)
try {
Path sourcePath = Paths.get(oldFile.getPath());
Path destPath = Paths.get(newFile.getPath());
// 先删除已有目标文件(避免覆盖失败)
if (newFile.exists()) {
newFile.delete();
}
Files.copy(sourcePath, destPath);
LogUtils.d(TAG, "文件复制成功Files" + oldFile.getAbsolutePath() + "" + newFile.getAbsolutePath());
return true;
} catch (Exception e) {
LogUtils.e(TAG, "文件复制失败:" + e.getMessage(), e);
return false;
}
return false;
}
// ====================================== 图片文件相关 ======================================
/**
* 从文件路径获取BitmapDrawable适用于Android图片显示
* @param path 图片文件绝对路径(非空)
* @return BitmapDrawable 图片对象(文件不存在/读取失败返回null
* @throws IOException 异常文件读取IO错误
*/
public static BitmapDrawable getImageDrawable(String path) throws IOException {
// 1. 校验文件合法性
File file = new File(path);
if (!file.exists() || !file.isFile()) {
LogUtils.e(TAG, "图片文件不存在:" + path);
return null;
}
// 2. 读取文件并转为BitmapDrawable缓冲流读取减少内存占用
try (InputStream is = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[BUFFER_SIZE];
int readLen;
while ((readLen = is.read(buffer)) != -1) {
bos.write(buffer, 0, readLen);
}
// 3. 生成Bitmap并包装为BitmapDrawable
byte[] imageBytes = bos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
return new BitmapDrawable(bitmap);
}
}
// ====================================== 文件名处理相关 ======================================
/**
* 截取文件后缀名(兼容多 "." 场景,如"image.2025.png" → ".png"
* @param file 目标文件可为null
* @return 文件后缀名:带点(如".jpg"),无后缀/文件无效返回空字符串
*/
public static String getFileSuffixWithMultiDot(File file) {
// 1. 校验文件合法性
if (file == null || !file.isFile()) {
return "";
}
// 2. 提取文件名并查找最后一个 "."
String fileName = file.getName();
int lastDotIndex = fileName.lastIndexOf(".");
// 3. 校验后缀合法性(排除无后缀、以点结尾、后缀过长的异常文件)
if (lastDotIndex == -1 // 无 "."
|| lastDotIndex == fileName.length() - 1 // 以 "." 结尾(如".gitignore"
|| (fileName.length() - lastDotIndex) > 5) { // 后缀长度超过5异常文件名
return "";
}
// 4. 返回小写后缀(统一格式,避免大小写不一致问题)
return fileName.substring(lastDotIndex).toLowerCase();
}
/**
* 生成唯一文件名(优化版:唯一、合法、简洁)
* 生成规则UUID(去掉"-") + "_" + 时间戳 + 原文件后缀
* @param refFile 参考文件用于提取后缀名可为null
* @return 唯一文件名(如"a1b2c3d4e5f6_1730000000000.jpg",无后缀则不带点)
*/
public static String createUniqueFileName(File refFile) {
// 1. 获取参考文件的后缀名自动容错null/无效文件)
String suffix = getFileSuffixWithMultiDot(refFile);
// 2. 生成唯一标识UUID确保全局唯一时间戳进一步降低重复概率
String uniqueId = UUID.randomUUID().toString().replace("-", ""); // 去掉"-"简化文件名
long timeStamp = System.currentTimeMillis();
// 3. 拼接文件名(分场景处理,避免多余点)
if (suffix.isEmpty()) {
// 无后缀唯一ID + 时间戳
return String.format("%s_%d", uniqueId, timeStamp);
} else {
// 有后缀唯一ID + 时间戳 + 后缀(无多余点)
return String.format("%s_%d%s", uniqueId, timeStamp, suffix);
}
}
}

View File

@@ -21,7 +21,7 @@ import android.widget.RemoteViews;
import androidx.annotation.RequiresApi;
import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.beans.NotificationMessage;
import cc.winboll.studio.powerbell.model.NotificationMessage;
import cc.winboll.studio.powerbell.services.ControlCenterService;
public class NotificationUtils2 {

View File

@@ -1,207 +0,0 @@
package cc.winboll.studio.powerbell.utils;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/21 18:55
* @Describe
* 图片下载工具类指定目录保存Pictures/PowerBell/BackgroundHistory
*/
public class PictureUtils {
private static final String TAG = "PictureUtils";
private static final String ROOT_DIR = "PowerBell/BackgroundHistory"; // 自定义目录结构
private static OkHttpClient sOkHttpClient;
static {
sOkHttpClient = new OkHttpClient();
}
/**
* 下载网络图片到指定目录(外部存储/Pictures/PowerBell/BackgroundHistory
* @param context 上下文(用于通知相册刷新)
* @param imgUrl 图片网络URL
* @param callback 下载结果回调(成功/失败)
*/
public static void downloadImageToAlbum(final Context context, final String imgUrl, final DownloadCallback callback) {
// 检查参数合法性
if (context == null) {
if (callback != null) {
callback.onFailure(new IllegalArgumentException("Context不能为空"));
}
return;
}
if (imgUrl == null || imgUrl.isEmpty()) {
if (callback != null) {
callback.onFailure(new IllegalArgumentException("图片URL为空"));
}
return;
}
startDownload(context, imgUrl, callback);
}
/**
* 执行实际的下载逻辑
*/
private static void startDownload(final Context context, final String imgUrl, final DownloadCallback callback) {
Request request = new Request.Builder().url(imgUrl).build();
sOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
if (callback != null) {
callback.onFailure(new IOException("请求失败,响应码:" + response.code()));
}
return;
}
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = response.body().byteStream();
// 1. 获取并创建指定保存目录(外部存储/Pictures/PowerBell/BackgroundHistory
File saveDir = getTargetSaveDir(context);
if (!saveDir.exists()) {
boolean isDirCreated = saveDir.mkdirs(); // 递归创建多级目录
if (!isDirCreated) {
if (callback != null) {
callback.onFailure(new IOException("创建目录失败:" + saveDir.getAbsolutePath()));
}
return;
}
}
// 2. 解析图片后缀
String fileSuffix = getImageSuffix(imgUrl, response);
// 3. 生成时间戳文件名
String fileName = generateTimeFileName() + fileSuffix;
// 4. 创建文件
final File saveFile = new File(saveDir, fileName);
// 5. 写入文件
outputStream = new FileOutputStream(saveFile);
byte[] buffer = new byte[1024 * 4];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.flush();
// 6. 通知相册刷新(使图片显示在系统相册中)
notifyAlbumRefresh(context, saveFile);
// 成功回调
if (callback != null) {
callback.onSuccess(saveFile.getAbsolutePath());
}
} catch (Exception e) {
Log.e(TAG, "下载图片异常", e);
if (callback != null) {
callback.onFailure(e);
}
} finally {
// 关闭资源
if (inputStream != null) inputStream.close();
if (outputStream != null) outputStream.close();
if (response.body() != null) response.body().close();
}
}
@Override
public void onFailure(Call call, final IOException e) {
Log.e(TAG, "下载图片失败", e);
if (callback != null) {
callback.onFailure(e);
}
}
});
}
/**
* 获取目标保存目录:外部存储/Pictures/PowerBell/BackgroundHistory
*/
private static File getTargetSaveDir(Context context) {
// 优先使用公共Pictures目录兼容多数设备
File publicPicturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (publicPicturesDir.exists()) {
return new File(publicPicturesDir, ROOT_DIR);
}
// 备选应用私有Pictures目录若公共目录不可用
File appPicturesDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (appPicturesDir != null) {
return new File(appPicturesDir, ROOT_DIR);
}
// 极端情况:外部存储根目录
return new File(Environment.getExternalStorageDirectory(), ROOT_DIR);
}
/**
* 解析图片后缀名
*/
private static String getImageSuffix(String imgUrl, Response response) {
// 优先从URL解析
if (imgUrl.lastIndexOf('.') != -1) {
String suffix = imgUrl.substring(imgUrl.lastIndexOf('.'));
if (suffix.length() <= 5 && (suffix.contains("png") || suffix.contains("jpg") || suffix.contains("jpeg") || suffix.contains("gif"))) {
return suffix.toLowerCase(Locale.getDefault());
}
}
// 从响应头解析
String contentType = response.header("Content-Type");
if (contentType != null) {
if (contentType.contains("png")) return ".png";
if (contentType.contains("jpeg") || contentType.contains("jpg")) return ".jpg";
if (contentType.contains("gif")) return ".gif";
}
return ".jpg"; // 默认后缀
}
/**
* 生成时间戳文件名
*/
private static String generateTimeFileName() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS", Locale.getDefault());
return sdf.format(new Date());
}
/**
* 通知相册刷新
*/
private static void notifyAlbumRefresh(Context context, File file) {
try {
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);
} catch (Exception e) {
Log.e(TAG, "通知相册刷新失败", e);
}
}
/**
* 下载结果回调接口
*/
public interface DownloadCallback {
void onSuccess(String savePath); // 下载成功(子线程回调)
void onFailure(Exception e); // 下载失败(子线程回调)
}
}

View File

@@ -1,6 +1,6 @@
package cc.winboll.studio.powerbell.utils;
import cc.winboll.studio.powerbell.beans.BatteryInfoBean;
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
import java.util.ArrayList;
public class StringUtils {

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
@@ -13,11 +14,13 @@ import cc.winboll.studio.powerbell.R;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.libappbase.ToastUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/19 18:01
* @Describe 背景图片视图控件(支持预览临时图片 + 外部刷新
* @Describe 背景图片视图控件(全透明背景 + 不拉伸居中平铺 + 完全填充父视图
*/
public class BackgroundView extends RelativeLayout {
@@ -30,8 +33,8 @@ public class BackgroundView extends RelativeLayout {
private static String BACKGROUND_IMAGE_FILENAME = "current.data";
private static String BACKGROUND_IMAGE_PREVIEW_FILENAME = "current_preview.data";
private static String backgroundSourceFilePath;
private float imageAspectRatio = 1.0f; // 默认 1:1
// 标记当前是否处于预览状态
private float imageAspectRatio = 1.0f; // 图片原始宽高比(控制不拉伸)
// 标记当前是否处于预览模式
private boolean isPreviewMode = false;
public BackgroundView(Context context) {
@@ -59,181 +62,199 @@ public class BackgroundView extends RelativeLayout {
}
void initView() {
initBackgroundImageView();
initBackgroundImagePath();
// 1. 控件本身:完全填充父视图 + 全透明背景 + 无内边距
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setPadding(0, 0, 0, 0); // 取消自身内边距
setBackgroundColor(0x00000000); // 全透明背景(#00000000
setBackground(new ColorDrawable(0x00000000)); // 双重保障同时设置Background为透明兼容低版本
initBackgroundImageView(); // 初始化内部ImageView全透明 + 不拉伸居中平铺)
backgroundSourceFilePath = BackgroundSourceUtils.getInstance(this.mContext).getCurrentBackgroundFilePath();
loadAndSetImageViewBackground();
}
private void initBackgroundImageView() {
ivBackground = new ImageView(mContext);
// 2. ImageView初始宽高WRAP_CONTENT + 居中 + 无内边距 + 全透明背景
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); // 居中显示
layoutParams.setMargins(0, 0, 0, 0); // 取消边距
ivBackground.setLayoutParams(layoutParams);
// 3. 缩放模式FIT_CENTER不拉伸按比例显示
ivBackground.setScaleType(ImageView.ScaleType.FIT_CENTER);
ivBackground.setPadding(0, 0, 0, 0); // 取消内部padding
ivBackground.setBackgroundColor(0x00000000); // ImageView背景全透明
ivBackground.setBackground(new ColorDrawable(0x00000000)); // 双重保障(兼容低版本)
this.addView(ivBackground);
}
private void initBackgroundImagePath() {
File externalFilesDir = mContext.getExternalFilesDir(null);
if (externalFilesDir == null) {
LogUtils.e(TAG, "外置存储不可用,无法初始化背景图片路径");
return;
}
File backgroundDir = new File(externalFilesDir, BACKGROUND_IMAGE_FOLDER);
if (!backgroundDir.exists()) {
backgroundDir.mkdirs();
}
backgroundSourceFilePath = new File(backgroundDir, BACKGROUND_IMAGE_FILENAME).getAbsolutePath();
}
// private void initBackgroundImagePath() {
// if (isPreviewMode) {
// backgroundSourceFilePath = BackgroundSourceUtils.getInstance(this.mContext).getPreviewBackgroundFilePath();
// } else {
// backgroundSourceFilePath = BackgroundSourceUtils.getInstance(this.mContext).getCurrentBackgroundFilePath();
// }
// }
/**
* 拷贝图片文件到背景资源目录(正式背景)
*/
public void saveToBackgroundSources(String srcBackgroundPath) {
initBackgroundImagePath();
if (backgroundSourceFilePath == null) {
LogUtils.e(TAG, "目标路径初始化失败,无法保存背景图片");
return;
}
File srcFile = new File(srcBackgroundPath);
if (!srcFile.exists() || !srcFile.isFile()) {
LogUtils.e(TAG, String.format("源文件不存在或不是文件:%s", srcBackgroundPath));
return;
}
File destFile = new File(backgroundSourceFilePath);
File destDir = destFile.getParentFile();
if (destDir != null && !destDir.exists()) {
boolean isDirCreated = destDir.mkdirs();
if (!isDirCreated) {
LogUtils.e(TAG, "目标目录创建失败:" + destDir.getAbsolutePath());
return;
}
}
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] buffer = new byte[4096];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.flush();
LogUtils.d(TAG, String.format("文件拷贝成功:%s -> %s", srcBackgroundPath, backgroundSourceFilePath));
// 拷贝成功后,若处于预览模式则退出预览,加载正式背景
if (isPreviewMode) {
exitPreviewMode();
} else {
loadAndSetImageViewBackground();
}
} catch (Exception e) {
LogUtils.e(TAG, String.format("文件拷贝失败:%s", e.getMessage()), e);
if (destFile.exists()) {
destFile.delete();
LogUtils.d(TAG, "已删除损坏的目标文件");
}
} finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
LogUtils.e(TAG, "输入流关闭失败:" + e.getMessage());
}
}
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
LogUtils.e(TAG, "输出流关闭失败:" + e.getMessage());
}
}
}
}
// public void setImageViewSource(String srcBackgroundPath) {
// initBackgroundImagePath();
// if (backgroundSourceFilePath == null) {
// LogUtils.e(TAG, "目标路径初始化失败,无法保存背景图片");
// return;
// }
//
// File srcFile = new File(srcBackgroundPath);
// if (!srcFile.exists() || !srcFile.isFile()) {
// LogUtils.e(TAG, String.format("源文件不存在或不是文件:%s", srcBackgroundPath));
// return;
// }
//
// File destFile = new File(backgroundSourceFilePath);
// File destDir = destFile.getParentFile();
// if (destDir != null && !destDir.exists()) {
// boolean isDirCreated = destDir.mkdirs();
// if (!isDirCreated) {
// LogUtils.e(TAG, "目标目录创建失败:" + destDir.getAbsolutePath());
// return;
// }
// }
//
// FileInputStream fis = null;
// FileOutputStream fos = null;
// try {
// fis = new FileInputStream(srcFile);
// fos = new FileOutputStream(destFile);
//
// byte[] buffer = new byte[4096];
// int len;
// while ((len = fis.read(buffer)) != -1) {
// fos.write(buffer, 0, len);
// }
// fos.flush();
//
// LogUtils.d(TAG, String.format("文件拷贝成功:%s -> %s", srcBackgroundPath, backgroundSourceFilePath));
// // 拷贝成功后,若处于预览模式则退出预览,加载正式背景
// if (isPreviewMode) {
// exitPreviewMode();
// } else {
// loadAndSetImageViewBackground();
// }
//
// } catch (Exception e) {
// LogUtils.e(TAG, String.format("文件拷贝失败:%s", e.getMessage()), e);
// if (destFile.exists()) {
// destFile.delete();
// LogUtils.d(TAG, "已删除损坏的目标文件");
// }
// } finally {
// if (fis != null) {
// try {
// fis.close();
// } catch (Exception e) {
// LogUtils.e(TAG, "输入流关闭失败:" + e.getMessage());
// }
// }
// if (fos != null) {
// try {
// fos.close();
// } catch (Exception e) {
// LogUtils.e(TAG, "输出流关闭失败:" + e.getMessage());
// }
// }
// }
// }
/**
* 【新增公共函数】预览临时图片(不修改正式背景文件
* 预览临时图片(全透明背景 + 不拉伸居中平铺
* @param previewImagePath 临时预览图片的路径
*/
public void previewBackgroundImage(String previewImagePath) {
if (previewImagePath == null || previewImagePath.isEmpty()) {
LogUtils.e(TAG, "预览图片路径为空");
return;
}
/*public void previewBackgroundImage(String previewImagePath) {
if (previewImagePath == null || previewImagePath.isEmpty()) {
LogUtils.e(TAG, "预览图片路径为空");
setDefaultImageViewBackground();
return;
}
File previewFile = new File(previewImagePath);
if (!previewFile.exists() || !previewFile.isFile()) {
LogUtils.e(TAG, "预览图片不存在或不是文件:" + previewImagePath);
return;
}
File previewFile = new File(previewImagePath);
if (!previewFile.exists() || !previewFile.isFile()) {
LogUtils.e(TAG, "预览图片不存在或不是文件:" + previewImagePath);
setDefaultImageViewBackground();
return;
}
// 计算预览图片宽高比
if (!calculateImageAspectRatio(previewFile)) {
LogUtils.e(TAG, "预览图片尺寸无效,无法预览");
return;
}
// 计算图片原始宽高比
if (!calculateImageAspectRatio(previewFile)) {
LogUtils.e(TAG, "预览图片尺寸无效,无法预览");
setDefaultImageViewBackground();
return;
}
// 压缩加载预览图片
Bitmap previewBitmap = decodeBitmapWithCompress(previewFile, 1080, 1920);
if (previewBitmap == null) {
LogUtils.e(TAG, "预览图片加载失败");
return;
}
// 压缩加载预览图片(保持比例)
Bitmap previewBitmap = decodeBitmapWithCompress(previewFile, 1080, 1920);
if (previewBitmap == null) {
LogUtils.e(TAG, "预览图片加载失败");
setDefaultImageViewBackground();
return;
}
// 设置预览图片ImageView
Drawable previewDrawable = new BitmapDrawable(mContext.getResources(), previewBitmap);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
ivBackground.setBackground(previewDrawable);
} else {
ivBackground.setBackgroundDrawable(previewDrawable);
}
// 设置预览图片(保持ImageView透明背景)
Drawable previewDrawable = new BitmapDrawable(mContext.getResources(), previewBitmap);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
ivBackground.setBackground(previewDrawable);
} else {
ivBackground.setBackgroundDrawable(previewDrawable);
}
// 调整 ImageView 尺寸以匹配预览图片宽高比
adjustImageViewSize();
isPreviewMode = true;
LogUtils.d(TAG, "进入预览模式,预览图片路径:" + previewImagePath);
}
// 调整ImageView尺寸(居中平铺,不拉伸)
adjustImageViewSize();
isPreviewMode = true;
LogUtils.d(TAG, "进入预览模式,预览图片路径:" + previewImagePath + ",宽高比:" + imageAspectRatio);
}
*/
/**
* 【新增公共函数】退出预览模式,恢复显示正式背景图片
* 退出预览模式,恢复显示正式背景图片
*/
public void exitPreviewMode() {
if (isPreviewMode) {
loadAndSetImageViewBackground();
isPreviewMode = false;
LogUtils.d(TAG, "退出预览模式,恢复正式背景");
}
}
/*public void exitPreviewMode() {
if (isPreviewMode) {
loadAndSetImageViewBackground();
isPreviewMode = false;
LogUtils.d(TAG, "退出预览模式,恢复正式背景");
}
}*/
/**
* 公共函数:供外部类调用,重新加载正式背景图片(刷新显示)
*/
public void reloadBackgroundImage() {
public void reloadCurrentBackground() {
LogUtils.d(TAG, "外部调用重新加载背景图片");
initBackgroundImagePath();
backgroundSourceFilePath = BackgroundSourceUtils.getInstance(this.mContext).getCurrentBackgroundFilePath();
loadAndSetImageViewBackground();
}
public void reloadPreviewBackground() {
LogUtils.d(TAG, "外部调用重新加载背景图片");
backgroundSourceFilePath = BackgroundSourceUtils.getInstance(this.mContext).getPreviewBackgroundFilePath();
loadAndSetImageViewBackground();
// 若处于预览模式,退出预览
if (isPreviewMode) {
isPreviewMode = false;
}
}
/**
* 加载正式背景图片并设置到 ImageView
* 加载正式背景图片并设置到 ImageView(全透明背景 + 不拉伸居中平铺)
*/
private void loadAndSetImageViewBackground() {
if (backgroundSourceFilePath == null) {
LogUtils.d(TAG, "backgroundSourceFilePath == null");
setDefaultImageViewBackground();
return;
}
//ToastUtils.show(String.format("backgroundSourceFilePath : %s", backgroundSourceFilePath));
File backgroundFile = new File(backgroundSourceFilePath);
if (!backgroundFile.exists() || !backgroundFile.isFile()) {
@@ -242,11 +263,13 @@ public class BackgroundView extends RelativeLayout {
return;
}
// 计算图片原始宽高比
if (!calculateImageAspectRatio(backgroundFile)) {
setDefaultImageViewBackground();
return;
}
// 压缩加载 Bitmap保持比例
Bitmap bitmap = decodeBitmapWithCompress(backgroundFile, 1080, 1920);
if (bitmap == null) {
LogUtils.e(TAG, "图片加载失败,无法解析为 Bitmap");
@@ -254,6 +277,7 @@ public class BackgroundView extends RelativeLayout {
return;
}
// 设置图片保持ImageView透明背景
Drawable backgroundDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
ivBackground.setBackground(backgroundDrawable);
@@ -261,12 +285,13 @@ public class BackgroundView extends RelativeLayout {
ivBackground.setBackgroundDrawable(backgroundDrawable);
}
// 调整ImageView尺寸居中平铺不拉伸
adjustImageViewSize();
LogUtils.d(TAG, "ImageView 背景加载成功,宽高比:" + imageAspectRatio);
LogUtils.d(TAG, "ImageView 背景加载成功(全透明+不拉伸),宽高比:" + imageAspectRatio);
}
/**
* 计算图片宽高比(宽/高)
* 计算图片原始宽高比(宽/高)
*/
private boolean calculateImageAspectRatio(File file) {
try {
@@ -291,11 +316,11 @@ public class BackgroundView extends RelativeLayout {
}
/**
* 动态调整 ImageView 尺寸以匹配图片宽高比
* 调整ImageView尺寸(不拉伸,居中平铺)
*/
private void adjustImageViewSize() {
int parentWidth = getWidth();
int parentHeight = getHeight();
int parentWidth = getWidth(); // 控件宽度(已填充父视图)
int parentHeight = getHeight(); // 控件高度(已填充父视图)
if (parentWidth == 0 || parentHeight == 0) {
post(new Runnable() {
@@ -316,14 +341,17 @@ public class BackgroundView extends RelativeLayout {
imageViewWidth = (int) (imageViewHeight * imageAspectRatio);
}
// 应用尺寸
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) ivBackground.getLayoutParams();
layoutParams.width = imageViewWidth;
layoutParams.height = imageViewHeight;
ivBackground.setLayoutParams(layoutParams);
LogUtils.d(TAG, "ImageView 尺寸调整完成:宽=" + imageViewWidth + ", 高=" + imageViewHeight);
}
/**
* 带压缩的 Bitmap 解码(避免 OOM
* 带压缩的 Bitmap 解码(保持比例,避免 OOM
*/
private Bitmap decodeBitmapWithCompress(File file, int maxWidth, int maxHeight) {
try {
@@ -349,13 +377,14 @@ public class BackgroundView extends RelativeLayout {
}
/**
* 设置默认背景(图片加载失败时兜底
* 设置默认背景(全透明兜底,避免空白
*/
private void setDefaultImageViewBackground() {
ivBackground.setBackgroundResource(R.drawable.default_background);
// 关键:默认背景设为全透明(而非默认图,避免遮挡下层视图)
ivBackground.setBackground(new ColorDrawable(0x00000000)); // 全透明背景
imageAspectRatio = 1.0f;
adjustImageViewSize();
LogUtils.d(TAG, "已设置 ImageView 默认背景");
LogUtils.d(TAG, "已设置默认透明背景");
}
@Override

View File

@@ -21,8 +21,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/activitymainRelativeLayout1"
android:background="#FFB7B7B7"/>
android:id="@+id/activitymainRelativeLayout1"/>
<FrameLayout
android:layout_width="match_parent"

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cc.winboll.studio.libaes.views.AToolbar
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:id="@+id/toolbar"
style="@style/DefaultAToolbar"/>
<cc.winboll.studio.libaes.views.ADsControlView
android:id="@+id/ads_control_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -9,7 +9,10 @@
<item
android:id="@+id/action_changepicture"
android:title="@string/item_changepicture"/>
<item
android:id="@+id/action_settings"
android:title="@string/item_settings"/>
<item
android:id="@+id/action_about"
android:title="@string/item_aboutview"/>
android:title="@string/item_about"/>
</menu>

View File

@@ -4,13 +4,16 @@
<string name="app_name_cn2">泡额呗额</string>
<string name="app_description">一个接收手机电量信息的应用,当电量值达到设定范围时会提醒用户。</string>
<string name="about_crashed">本应用崩溃了,作者水平有限,敬请谅解!</string>
<string name="item_mainview">Main View</string>
<string name="item_aboutview">About</string>
<string name="item_clearrecord">Clear Record</string>
<string name="item_changepicture">Change Picture</string>
<string name="item_devoloperoptionsview">Developer View</string>
<string name="item_logview">Log View</string>
<string name="item_sourceview">Source View</string>
<string name="item_main">主窗口</string>
<string name="item_about">关于</string>
<string name="item_settings">应用设置</string>
<string name="item_battery_report">应用耗电记录</string>
<string name="item_mainunittestactivity">开发调试窗口</string>
<string name="item_clearrecord">清理电量记录</string>
<string name="item_changepicture">更换背景图片</string>
<string name="item_devoloperoptionsview">开发调试窗口</string>
<string name="item_logview">日志窗口</string>
<string name="item_sourceview">源码窗口</string>
<string name="txt_aboveswitch">消息总开关</string>
<string name="txt_aboveswitchtips">当电量低于左边(放电状态)或高于右边(充电状态),就会发送一个提醒铃声。</string>
<string name="texthint_CustomSlideToCleanRecord">Slide Right To Clean Up APP Record.</string>

View File

@@ -9,11 +9,12 @@
<string name="switchto_en1">PowerBell</string>
<string name="switchto_cn1">能源钟</string>
<string name="switchto_cn2">泡额呗额</string>
<string name="en1_switch_disabled">PowerBell</string>
<string name="cn1_switch_disabled">能源钟</string>
<string name="cn2_switch_disabled">泡额呗额</string>
<string name="en1_switch_disabled">PowerBell X</string>
<string name="cn1_switch_disabled">能源钟 X</string>
<string name="cn2_switch_disabled">泡额呗额 X</string>
<string name="item_mainview">Main View</string>
<string name="item_aboutview">About</string>
<string name="item_about">About</string>
<string name="item_settings">Settings</string>
<string name="item_battery_report">Battery Report</string>
<string name="item_clearrecord">Clear Record</string>
<string name="item_changepicture">Change Picture</string>