Compare commits

...

21 Commits

Author SHA1 Message Date
5a9469317d <powerbell>APK 15.11.12 release Publish. 2025-11-30 18:48:20 +08:00
0d5f7f40cd 编译参数修复 2025-11-30 17:23:39 +08:00
64e5bc753a 提高应用崩溃信息UI友好性。 2025-11-30 17:21:58 +08:00
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 1011 additions and 878 deletions

View File

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

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed Nov 26 16:27:33 HKT 2025 #Sun Nov 30 18:48:20 HKT 2025
stageCount=9 stageCount=13
libraryProject= libraryProject=
baseVersion=15.11 baseVersion=15.11
publishVersion=15.11.8 publishVersion=15.11.12
buildCount=0 buildCount=0
baseBetaVersion=15.11.9 baseBetaVersion=15.11.13

View File

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

View File

@@ -12,7 +12,7 @@ import java.io.File;
public class App extends GlobalApplication { 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_EN1 = "cc.winboll.studio.powerbell.MainActivityEN1";
public static final String COMPONENT_CN1 = "cc.winboll.studio.powerbell.MainActivityCN1"; public static final String COMPONENT_CN1 = "cc.winboll.studio.powerbell.MainActivityCN1";
@@ -34,6 +34,7 @@ public class App extends GlobalApplication {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
//setIsDebugging(false);
setIsDebugging(BuildConfig.DEBUG); setIsDebugging(BuildConfig.DEBUG);
// 临时文件夹方案1 // 临时文件夹方案1

View File

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

View File

@@ -12,7 +12,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R; 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.receivers.ControlCenterServiceReceiver;
import cc.winboll.studio.powerbell.utils.AppCacheUtils; import cc.winboll.studio.powerbell.utils.AppCacheUtils;
import cc.winboll.studio.powerbell.utils.StringUtils; 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.libaes.views.AToolbar;
import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.powerbell.R; 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.activities.PixelPickerActivity;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean; import cc.winboll.studio.powerbell.model.BackgroundBean;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@@ -193,10 +193,10 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public void onClick(View v) { public void onClick(View v) {
dialog.dismiss(); dialog.dismiss();
// 可以在这里添加确定后的回调逻辑 // 可以在这里添加确定后的回调逻辑
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(PixelPickerActivity.this); BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean(); BackgroundBean bean = utils.getCurrentBackgroundBean();
bean.setPixelColor(pixelColor); bean.setPixelColor(pixelColor);
utils.saveData(); utils.saveSettings();
Toast.makeText(PixelPickerActivity.this, "已记录像素值", Toast.LENGTH_SHORT).show(); Toast.makeText(PixelPickerActivity.this, "已记录像素值", Toast.LENGTH_SHORT).show();
setBackgroundColor(); setBackgroundColor();
} }
@@ -217,8 +217,8 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
void setBackgroundColor() { void setBackgroundColor() {
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(PixelPickerActivity.this); BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean(); BackgroundBean bean = utils.getCurrentBackgroundBean();
int nPixelColor = bean.getPixelColor(); int nPixelColor = bean.getPixelColor();
RelativeLayout mainLayout = findViewById(R.id.activitypixelpickerRelativeLayout1); RelativeLayout mainLayout = findViewById(R.id.activitypixelpickerRelativeLayout1);
mainLayout.setBackgroundColor(nPixelColor); mainLayout.setBackgroundColor(nPixelColor);
@@ -235,7 +235,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) { if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(this, BackgroundPictureActivity.class); intent.setClass(this, BackgroundSettingsActivity.class);
startActivity(intent); startActivity(intent);
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), ); //GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), );
return true; return true;
@@ -248,7 +248,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
public void onBackPressed() { public void onBackPressed() {
super.onBackPressed(); super.onBackPressed();
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(this, BackgroundPictureActivity.class); intent.setClass(this, BackgroundSettingsActivity.class);
startActivity(intent); startActivity(intent);
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), BackgroundPictureActivity.class); //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 androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.adapters.BatteryAdapter; 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.ArrayList;
import java.util.List; 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.libappbase.LogUtils;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R; 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.utils.BackgroundPictureUtils; import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
import cc.winboll.studio.powerbell.utils.FileUtils; import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.UriUtil; import cc.winboll.studio.powerbell.utils.UriUtil;
import java.io.File; import java.io.File;
@@ -29,7 +29,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
public static final String TAG = "BackgroundPicturePreviewDialog"; public static final String TAG = "BackgroundPicturePreviewDialog";
Context mContext; Context mContext;
BackgroundPictureUtils mBackgroundPictureUtils; BackgroundSourceUtils mBackgroundPictureUtils;
Button dialogbackgroundpicturepreviewButton1; Button dialogbackgroundpicturepreviewButton1;
Button dialogbackgroundpicturepreviewButton2; Button dialogbackgroundpicturepreviewButton2;
String mszPreReceivedFileName; String mszPreReceivedFileName;
@@ -40,7 +40,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
initEnv(); initEnv();
mContext = context; mContext = context;
mBackgroundPictureUtils = ((BackgroundPictureActivity)context).mBackgroundPictureUtils; mBackgroundPictureUtils = ((BackgroundSettingsActivity)context).mBackgroundSourceUtils;
ImageView imageView = findViewById(R.id.dialogbackgroundpicturepreviewImageView1); ImageView imageView = findViewById(R.id.dialogbackgroundpicturepreviewImageView1);
copyAndViewRecivePicture(imageView); copyAndViewRecivePicture(imageView);
@@ -78,7 +78,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
void copyAndViewRecivePicture(ImageView imageView) { void copyAndViewRecivePicture(ImageView imageView) {
//AppConfigUtils appConfigUtils = AppConfigUtils.getInstance((GlobalApplication)mContext.getApplicationContext()); //AppConfigUtils appConfigUtils = AppConfigUtils.getInstance((GlobalApplication)mContext.getApplicationContext());
BackgroundPictureActivity activity = ((BackgroundPictureActivity)mContext); BackgroundSettingsActivity activity = ((BackgroundSettingsActivity)mContext);
//取出文件uri //取出文件uri
Uri uri = activity.getIntent().getData(); Uri uri = activity.getIntent().getData();
@@ -95,7 +95,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
File fSrcImage = new File(szSrcImage); File fSrcImage = new File(szSrcImage);
//mszPreReceivedFileName = DateUtils.getDateNowString() + "-" + fSrcImage.getName(); //mszPreReceivedFileName = DateUtils.getDateNowString() + "-" + fSrcImage.getName();
File mfPreReceivedPhoto = new File(activity.mBackgroundPictureUtils.getBackgroundDir(), mszPreReceivedFileName); File mfPreReceivedPhoto = new File(activity.mBackgroundSourceUtils.getBackgroundSourceDirPath(), mszPreReceivedFileName);
// 复制源图片到剪裁文件 // 复制源图片到剪裁文件
try { try {
FileUtils.copyFileUsingFileChannels(fSrcImage, mfPreReceivedPhoto); 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.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.utils.PictureUtils;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import cc.winboll.studio.powerbell.utils.ImageDownloader;
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
@@ -45,11 +46,13 @@ public class NetworkBackgroundDialog extends AlertDialog {
Context mContext; Context mContext;
// 主线程 Handler用于接收子线程消息并更新 UI // 主线程 Handler用于接收子线程消息并更新 UI
private Handler mUiHandler; private Handler mUiHandler;
String previewFilePath; String mPreviewFilePath;
String mPreviewFileUrl;
String mDownloadSavedPath;
// 按钮点击回调接口Java7 接口实现) // 按钮点击回调接口Java7 接口实现)
public interface OnDialogClickListener { public interface OnDialogClickListener {
void onConfirm(); // 确认按钮点击 void onConfirm(String szConfirmFilePath, String previewFileUrl); // 确认按钮点击
void onCancel(); // 取消按钮点击 void onCancel(); // 取消按钮点击
} }
@@ -87,8 +90,8 @@ public class NetworkBackgroundDialog extends AlertDialog {
switch (msg.what) { switch (msg.what) {
case MSG_IMAGE_LOAD_SUCCESS: case MSG_IMAGE_LOAD_SUCCESS:
// 图片加载成功,获取文件路径并设置背景 // 图片加载成功,获取文件路径并设置背景
String filePath = (String) msg.obj; mDownloadSavedPath = (String) msg.obj;
setBackgroundFromPath(filePath); previewBackground(mDownloadSavedPath);
break; break;
case MSG_IMAGE_LOAD_FAILED: case MSG_IMAGE_LOAD_FAILED:
// 图片加载失败,设置默认背景 // 图片加载失败,设置默认背景
@@ -135,7 +138,8 @@ public class NetworkBackgroundDialog extends AlertDialog {
btnPreview = (Button) dialogView.findViewById(R.id.btn_preview); btnPreview = (Button) dialogView.findViewById(R.id.btn_preview);
etURL = (EditText) dialogView.findViewById(R.id.et_url); etURL = (EditText) dialogView.findViewById(R.id.et_url);
bvBackgroundPreview = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview); bvBackgroundPreview = (BackgroundView) dialogView.findViewById(R.id.bv_background_preview);
// 加载初始图片
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
// 设置按钮点击事件 // 设置按钮点击事件
setButtonClickListeners(); setButtonClickListeners();
} }
@@ -149,6 +153,9 @@ public class NetworkBackgroundDialog extends AlertDialog {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "取消按钮点击"); LogUtils.d("NetworkBackgroundDialog", "取消按钮点击");
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.setCurrentSourceToPreview();
dismiss(); // 关闭对话框 dismiss(); // 关闭对话框
if (listener != null) { if (listener != null) {
listener.onCancel(); listener.onCancel();
@@ -162,11 +169,12 @@ public class NetworkBackgroundDialog extends AlertDialog {
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认按钮点击"); LogUtils.d("NetworkBackgroundDialog", "确认按钮点击");
// 确定预览背景资源 // 确定预览背景资源
bvBackgroundPreview.saveToBackgroundSources(previewFilePath); BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
dismiss(); // 关闭对话框 dismiss(); // 关闭对话框
if (listener != null) { if (listener != null) {
listener.onConfirm(); listener.onConfirm(mPreviewFilePath, mPreviewFileUrl);
} }
} }
}); });
@@ -175,14 +183,7 @@ public class NetworkBackgroundDialog extends AlertDialog {
btnPreview.setOnClickListener(new View.OnClickListener() { btnPreview.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("NetworkBackgroundDialog", "确认预览点击");
downloadImageToAlbumAndPreview(); 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 背景(主线程调用) * 根据文件路径设置 BackgroundView 背景(主线程调用)
* @param filePath 图片文件路径 * @param filePath 图片文件路径
*/ */
private void setBackgroundFromPath(String filePath) { private void previewBackground(String previewFilePath) {
FileInputStream fis = null; FileInputStream fis = null;
try { try {
File imageFile = new File(filePath); File imageFile = new File(previewFilePath);
if (!imageFile.exists()) { if (!imageFile.exists()) {
LogUtils.e(TAG, "图片文件不存在:" + filePath); ToastUtils.show("图片文件不存在:" + previewFilePath);
ToastUtils.show("Test"); LogUtils.e(TAG, "图片文件不存在:" + previewFilePath);
//bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher); bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
return; return;
} }
// 预览背景 // 预览背景
previewFilePath = filePath; mPreviewFilePath = previewFilePath;
bvBackgroundPreview.previewBackgroundImage(previewFilePath); BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(mContext);
utils.saveFileToPreviewBean(new File(mPreviewFilePath), mPreviewFileUrl);
LogUtils.d(TAG, "图片预览成功:" + filePath); bvBackgroundPreview.reloadPreviewBackground();
//ToastUtils.show("预览背景中。。。");
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher); bvBackgroundPreview.setBackgroundResource(R.drawable.ic_launcher);
@@ -249,40 +251,20 @@ public class NetworkBackgroundDialog extends AlertDialog {
this.listener = listener; 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() { void downloadImageToAlbumAndPreview() {
//String imgUrl = "https://example.com/test.jpg"; //String previewFileUrl = "https://example.com/test.jpg";
String imgUrl = etURL.getText().toString(); mPreviewFileUrl = etURL.getText().toString();
PictureUtils.downloadImageToAlbum(mContext, imgUrl, new PictureUtils.DownloadCallback(){ ImageDownloader.getInstance(mContext).downloadImage(mPreviewFileUrl, new ImageDownloader.DownloadCallback(){
@Override @Override
public void onSuccess(String savePath) { public void onSuccess(String savePath) {
ToastUtils.show("下载成功:" + savePath);
// 发送消息到主线程,携带图片路径 // 发送消息到主线程,携带图片路径
Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath); Message successMsg = mUiHandler.obtainMessage(MSG_IMAGE_LOAD_SUCCESS, savePath);
mUiHandler.sendMessage(successMsg); mUiHandler.sendMessage(successMsg);
} }
@Override @Override
public void onFailure(Exception e) { public void onFailure(String errorMsg) {
ToastUtils.show("下载失败:" + e.getMessage()); ToastUtils.show("下载失败:" + errorMsg);
} }
}); });

View File

@@ -19,8 +19,11 @@ import android.widget.TextView;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R; 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.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils; 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.utils.ServiceUtils;
import cc.winboll.studio.powerbell.views.BackgroundView; import cc.winboll.studio.powerbell.views.BackgroundView;
import cc.winboll.studio.powerbell.views.BatteryDrawable; import cc.winboll.studio.powerbell.views.BatteryDrawable;
@@ -79,6 +82,11 @@ public class MainViewFragment extends Fragment {
// 获取指定ID的View实例 // 获取指定ID的View实例
bvPreviewBackground = mView.findViewById(R.id.fragmentmainviewBackgroundView1); 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); /*final View mainImageView = mView.findViewById(R.id.fragmentmainviewImageView1);
// 注册OnGlobalLayoutListener // 注册OnGlobalLayoutListener
@@ -141,6 +149,17 @@ public class MainViewFragment extends Fragment {
return mView; 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() { void setViewData() {
int nChargeReminderValue = mAppConfigUtils.getChargeReminderValue(); int nChargeReminderValue = mAppConfigUtils.getChargeReminderValue();
int nUsegeReminderValue = mAppConfigUtils.getUsegeReminderValue(); int nUsegeReminderValue = mAppConfigUtils.getUsegeReminderValue();
@@ -301,7 +320,7 @@ public class MainViewFragment extends Fragment {
} }
public void reloadBackground() { public void reloadBackground() {
bvPreviewBackground.reloadBackgroundImage(); bvPreviewBackground.reloadCurrentBackground();
// BackgroundPictureBean bean = BackgroundPictureUtils.getInstance(getActivity()).getBackgroundPictureBean(); // BackgroundPictureBean bean = BackgroundPictureUtils.getInstance(getActivity()).getBackgroundPictureBean();
// ImageView imageView = mView.findViewById(R.id.fragmentmainviewImageView1); // ImageView imageView = mView.findViewById(R.id.fragmentmainviewImageView1);
// String szBackgroundFilePath = BackgroundPictureUtils.getInstance(getActivity()).getBackgroundDir() + BackgroundPictureActivity.getBackgroundFileName(); // 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> * @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> * @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.JsonReader;
import android.util.JsonWriter; 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> * @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.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import cc.winboll.studio.libappbase.LogUtils; 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.services.ControlCenterService;
import cc.winboll.studio.powerbell.utils.AppConfigUtils; import cc.winboll.studio.powerbell.utils.AppConfigUtils;
import cc.winboll.studio.powerbell.utils.BatteryUtils; 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.App;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.beans.AppConfigBean; import cc.winboll.studio.powerbell.model.AppConfigBean;
import cc.winboll.studio.powerbell.beans.NotificationMessage; import cc.winboll.studio.powerbell.model.NotificationMessage;
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler; import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver; import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
import cc.winboll.studio.powerbell.services.AssistantService; import cc.winboll.studio.powerbell.services.AssistantService;

View File

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

View File

@@ -5,8 +5,8 @@ import android.content.Context;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App; import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.beans.AppConfigBean; import cc.winboll.studio.powerbell.model.AppConfigBean;
import cc.winboll.studio.powerbell.beans.ControlCenterServiceBean; import cc.winboll.studio.powerbell.model.ControlCenterServiceBean;
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog; import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
import cc.winboll.studio.powerbell.fragments.MainViewFragment; import cc.winboll.studio.powerbell.fragments.MainViewFragment;
import cc.winboll.studio.powerbell.services.ControlCenterService; 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; package cc.winboll.studio.powerbell.utils;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream; import java.io.*;
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.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.UUID;
/** /**
* 文件读取工具类 * 文件操作工具类
* 功能:文件读写、复制、图片转换、文件名处理等常用文件操作
* 适配Java 7+支持Android全版本
* 注意调用文件操作前需确保已获取存储权限Android 6.0+ 需动态申请)
*/ */
public class FileUtils { public class FileUtils {
/** 日志标签 */
public static final String TAG = "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 { public static String readFileAsString(String filePath) throws IOException {
// 1. 校验文件合法性
File file = new File(filePath); File file = new File(filePath);
if (!file.exists()) { 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) { // 2. 读取文件内容使用StringBuilder高效拼接
throw new IOException("File is too large"); StringBuilder sb = new StringBuilder((int) file.length());
} try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[BUFFER_SIZE];
StringBuilder sb = new StringBuilder((int) (file.length())); int readLen;
// 创建字节输入流 // 循环读取缓冲区避免一次性读取大文件导致OOM
FileInputStream fis = new FileInputStream(filePath); while ((readLen = fis.read(buffer)) > 0) {
// 创建一个长度为10240的Buffer sb.append(new String(buffer, 0, readLen));
byte[] bbuf = new byte[10240]; }
// 用于保存实际读取的字节数 }
int hasRead = 0;
while ((hasRead = fis.read(bbuf)) > 0) {
sb.append(new String(bbuf, 0, hasRead));
}
fis.close();
return sb.toString(); return sb.toString();
} }
// /**
// 根据文件路径读取byte[] 数组 * 读取文件内容并转为byte数组适用于二进制文件图片、音频等
// * @param filePath 文件绝对路径(非空)
* @return 文件内容byte数组
* @throws IOException 异常:文件不存在、读取失败等
*/
public static byte[] readFileByBytes(String filePath) throws IOException { public static byte[] readFileByBytes(String filePath) throws IOException {
// 1. 校验文件合法性
File file = new File(filePath); File file = new File(filePath);
if (!file.exists()) { if (!file.exists()) {
throw new FileNotFoundException(filePath); throw new FileNotFoundException("文件不存在:" + filePath);
} else { }
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
BufferedInputStream in = null;
try { // 2. 缓冲流读取高效减少IO次数
in = new BufferedInputStream(new FileInputStream(file)); try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
short bufSize = 1024; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
byte[] buffer = new byte[bufSize];
int len1;
while (-1 != (len1 = in.read(buffer, 0, bufSize))) {
bos.write(buffer, 0, len1);
}
byte[] var7 = bos.toByteArray(); byte[] buffer = new byte[BUFFER_SIZE];
return var7; int readLen;
} finally { while ((readLen = bis.read(buffer)) != -1) {
try { bos.write(buffer, 0, readLen);
if (in != null) {
in.close();
}
} catch (IOException var14) {
var14.printStackTrace();
}
bos.close();
} }
bos.flush();
return bos.toByteArray();
} }
} }
// // ====================================== 文件复制相关 ======================================
// 文件复制函数
// /**
* 基于FileChannel复制文件高效适用于大文件复制
* @param source 源文件(非空,必须存在)
* @param dest 目标文件(非空,父目录会自动创建)
* @throws IOException 异常:源文件不存在、复制失败等
*/
public static void copyFileUsingFileChannels(File source, File dest) throws IOException { public static void copyFileUsingFileChannels(File source, File dest) throws IOException {
FileChannel inputChannel = null; // 1. 校验源文件合法性
FileChannel outputChannel = null; if (!source.exists() || !source.isFile()) {
try { throw new FileNotFoundException("源文件不存在或不是文件:" + source.getAbsolutePath());
inputChannel = new FileInputStream(source).getChannel(); }
outputChannel = new FileOutputStream(dest).getChannel();
// 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()); outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally { LogUtils.d(TAG, "文件复制成功FileChannel" + source.getAbsolutePath() + "" + dest.getAbsolutePath());
inputChannel.close();
outputChannel.close();
} }
} }
/** /**
* 将文件生成位图 * 简化版文件复制基于NIO Files工具类代码简洁适用于中小文件
* @param path * @param oldFile 源文件(非空,必须存在)
* @return * @param newFile 目标文件(非空,父目录会自动创建)
* @throws IOException * @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) { public static boolean copyFile(File oldFile, File newFile) {
//String oldPath = "path/to/original/file.txt"; // 1. 校验源文件合法性
//String newPath = "path/to/new-location/for/file.txt"; if (oldFile == null || !oldFile.exists() || !oldFile.isFile()) {
LogUtils.e(TAG, "源文件无效:" + (oldFile != null ? oldFile.getAbsolutePath() : "null"));
return false;
}
//File oldFile = new java.io.File(oldPath); // 2. 创建目标文件父目录
//File newFile = new java.io.File(newPath);
if (!newFile.getParentFile().exists()) { if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs(); newFile.getParentFile().mkdirs();
} }
if (!oldFile.exists()) { // 3. 复制文件(覆盖已有目标文件)
//System.out.println("The original file does not exist."); try {
LogUtils.d(TAG, "The original file does not exist."); Path sourcePath = Paths.get(oldFile.getPath());
} else { Path destPath = Paths.get(newFile.getPath());
try { // 先删除已有目标文件(避免覆盖失败)
// 源文件路径 if (newFile.exists()) {
Path sourcePath = Paths.get(oldFile.getPath()); newFile.delete();
// 目标文件路径
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());
} }
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 androidx.annotation.RequiresApi;
import cc.winboll.studio.powerbell.MainActivity; import cc.winboll.studio.powerbell.MainActivity;
import cc.winboll.studio.powerbell.R; 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; import cc.winboll.studio.powerbell.services.ControlCenterService;
public class NotificationUtils2 { 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; package cc.winboll.studio.powerbell.utils;
import cc.winboll.studio.powerbell.beans.BatteryInfoBean; import cc.winboll.studio.powerbell.model.BatteryInfoBean;
import java.util.ArrayList; import java.util.ArrayList;
public class StringUtils { public class StringUtils {

View File

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

View File

@@ -21,8 +21,7 @@
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/activitymainRelativeLayout1" android:id="@+id/activitymainRelativeLayout1"/>
android:background="#FFB7B7B7"/>
<FrameLayout <FrameLayout
android:layout_width="match_parent" 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 <item
android:id="@+id/action_changepicture" android:id="@+id/action_changepicture"
android:title="@string/item_changepicture"/> android:title="@string/item_changepicture"/>
<item
android:id="@+id/action_settings"
android:title="@string/item_settings"/>
<item <item
android:id="@+id/action_about" android:id="@+id/action_about"
android:title="@string/item_aboutview"/> android:title="@string/item_about"/>
</menu> </menu>

View File

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