Compare commits

..

2 Commits

13 changed files with 353 additions and 192 deletions

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Thu Jun 19 20:42:40 HKT 2025
stageCount=2
#Mon Jun 09 01:44:28 HKT 2025
stageCount=1
libraryProject=libaes
baseVersion=15.9
publishVersion=15.9.1
publishVersion=15.9.0
buildCount=0
baseBetaVersion=15.9.2
baseBetaVersion=15.9.1

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Thu Jun 19 12:49:47 GMT 2025
#Sun Jun 01 08:03:56 GMT 2025
stageCount=0
libraryProject=
baseVersion=15.0
publishVersion=15.0.0
buildCount=26
buildCount=24
baseBetaVersion=15.0.1

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Jun 24 09:54:47 HKT 2025
stageCount=3
#Sun May 04 05:32:00 GMT 2025
stageCount=1
libraryProject=
baseVersion=15.2
publishVersion=15.2.2
buildCount=0
baseBetaVersion=15.2.3
publishVersion=15.2.0
buildCount=74
baseBetaVersion=15.2.1

View File

@ -42,24 +42,23 @@ android {
}
}
/*compileOptions {
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}*/
}
}
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
api project(':libjc')
api 'cc.winboll.studio:libaes:15.9.1'
api 'cc.winboll.studio:libapputils:15.8.4'
api 'cc.winboll.studio:libappbase:15.8.4'
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
//implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
implementation 'org.bouncycastle:bcprov-jdk15to18:1.69'
implementation 'org.bouncycastle:bcpkix-jdk15to18:1.69'
api project(':libjc')
api 'androidx.appcompat:appcompat:1.0.0'
api 'com.google.android.material:material:1.0.0'
api 'cc.winboll.studio:libapputils:9.1.0'
api 'cc.winboll.studio:libappbase:1.0.3'
api fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Jun 24 11:17:30 GMT 2025
#Fri Jan 10 22:03:57 GMT 2025
stageCount=0
libraryProject=libjc
baseVersion=1.0
publishVersion=1.0.0
buildCount=135
buildCount=133
baseBetaVersion=1.0.1

View File

@ -15,10 +15,10 @@ import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import cc.winboll.studio.jc.R;
import cc.winboll.studio.libapputils.log.LogUtils;
import cc.winboll.studio.libjc.JAR_RUNNING_MODE;
import cc.winboll.studio.libjc.JCMainThread;
import cc.winboll.studio.libjc.net.JCSocketClient;
import cc.winboll.studio.libjc.util.LogUtils;
import cc.winboll.studio.libjc.Main;
final public class MainActivity extends Activity implements JCMainThread.OnMessageListener {
@ -77,7 +77,7 @@ final public class MainActivity extends Activity implements JCMainThread.OnMessa
// 启动主线程
_JCMainThread = JCMainThread.getInstance(getPackageName());
_JCMainThread.setOnLogListener(this);
//_JCMainThread.setRunningMode(Main.JAR_RUNNING_MODE.JC);
_JCMainThread.setRunningMode(JAR_RUNNING_MODE.JC);
_JCMainThread.start();
// 设置 WinBoll 应用 UI 类型

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Thu Jun 19 20:42:26 HKT 2025
stageCount=2
#Mon Jun 09 01:44:28 HKT 2025
stageCount=1
libraryProject=libaes
baseVersion=15.9
publishVersion=15.9.1
publishVersion=15.9.0
buildCount=0
baseBetaVersion=15.9.2
baseBetaVersion=15.9.1

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Jun 24 11:17:30 GMT 2025
#Fri Jan 10 22:03:57 GMT 2025
stageCount=0
libraryProject=libjc
baseVersion=1.0
publishVersion=1.0.0
buildCount=135
buildCount=133
baseBetaVersion=1.0.1

View File

@ -21,7 +21,7 @@ public class Main {
public final static int JAR_RUNNING_MODE_JCNDK_DEBUG = 4;
public final static int JAR_RUNNING_MODE_JC = 5;
public final static int JAR_RUNNING_MODE_JC_DEBUG = 6;
public static enum JAR_RUNNING_MODE {
public enum JAR_RUNNING_MODE {
UNKNOWN(JAR_RUNNING_MODE_UNKNOWN),
CONSOLE(JAR_RUNNING_MODE_CONSOLE),
CONSOLE_DEBUG(JAR_RUNNING_MODE_CONSOLE_DEBUG),

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Thu May 29 09:43:37 HKT 2025
stageCount=2
#Thu Jun 19 10:22:12 HKT 2025
stageCount=3
libraryProject=
baseVersion=15.4
publishVersion=15.4.1
publishVersion=15.4.2
buildCount=0
baseBetaVersion=15.4.2
baseBetaVersion=15.4.3

View File

@ -1,6 +1,7 @@
package cc.winboll.studio.powerbell;
import android.content.Context;
import android.os.Environment;
import android.view.Gravity;
import cc.winboll.studio.libappbase.GlobalApplication;
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
@ -27,12 +28,21 @@ public class App extends GlobalApplication {
public void onCreate() {
super.onCreate();
// 初始化临时文件夹目录
File fTempDir = new File(getExternalCacheDir(), "TempDir");
if(!fTempDir.exists()) {
fTempDir.mkdirs();
// 临时文件夹方案1
// 获取Pictures文件夹路径Android 10及以上推荐使用MediaStore此处为传统方式
File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
// 定义目标文件路径在Pictures目录下创建"PowerBell"子文件夹及文件
File powerBellDir = new File(picturesDir, "PowerBell");
// 临时文件夹方案2 <图片保存失败>
// 获取Pictures文件夹路径Android 10及以上推荐使用MediaStore此处为传统方式
//File powerBellDir = getExternalFilesDir("TempDir");
// 先创建文件夹如果不存在
if (!powerBellDir.exists()) {
powerBellDir.mkdirs();
}
szTempDir = fTempDir.getAbsolutePath();
szTempDir = powerBellDir.getAbsolutePath();
// 初始化 Toast 框架

View File

@ -1,22 +1,26 @@
package cc.winboll.studio.powerbell.activities;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import cc.winboll.studio.libaes.views.AToolbar;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.utils.ToastUtils;
import cc.winboll.studio.powerbell.App;
import cc.winboll.studio.powerbell.R;
import cc.winboll.studio.powerbell.activities.BackgroundPictureActivity;
import cc.winboll.studio.powerbell.beans.BackgroundPictureBean;
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
import cc.winboll.studio.powerbell.utils.BackgroundPictureUtils;
@ -24,42 +28,35 @@ import cc.winboll.studio.powerbell.utils.FileUtils;
import cc.winboll.studio.powerbell.utils.UriUtil;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class BackgroundPictureActivity extends Activity
implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
public class BackgroundPictureActivity extends Activity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
public static final String TAG = "BackgroundPictureActivity";
public BackgroundPictureUtils mBackgroundPictureUtils;
// 图片选择请求
// 图片选择请求
public static final int REQUEST_SELECT_PICTURE = 0;
// 照相选择请求
public static final int REQUEST_TAKE_PHOTO = 1;
// 图片裁剪选择请求
public static final int REQUEST_CROP_IMAGE = 2;
private static final int STORAGE_PERMISSION_REQUEST = 100;
AToolbar mAToolbar;
// 所有图片存储的文件夹
File mfBackgroundDir;
// 拍照与剪裁的文件夹
File mfPictureDir;
// 拍照文件类
File mfTakePhoto;
// 接收到的图片文件类
public File mfRecivedPicture;
// 剪裁文件类
File mfTempCropPicture;
// 剪裁接收后的文件的文件名
private AToolbar mAToolbar;
private File mfBackgroundDir; // 背景图片存储文件夹
private File mfPictureDir; // 拍照与剪裁临时文件夹
private File mfTakePhoto; // 拍照文件
private File mfRecivedPicture; // 接收的图片文件
private File mfTempCropPicture; // 剪裁临时文件
private File mfRecivedCropPicture; // 剪裁后的目标文件
// 静态变量
public static String _mszRecivedCropPicture = "RecivedCrop.jpg";
File mfRecivedCropPicture;
static String _mszCommonFileType = "jpeg";
// 背景图片的压缩比
int mnPictureCompress = 100;
static String _RecivedPictureFileName;
private static String _mszCommonFileType = "jpeg";
private int mnPictureCompress = 100;
private static String _RecivedPictureFileName;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -67,30 +64,29 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
setContentView(R.layout.activity_backgroundpicture);
initEnv();
// 初始化工具类和文件夹
mBackgroundPictureUtils = BackgroundPictureUtils.getInstance(this);
mfBackgroundDir = new File(mBackgroundPictureUtils.getBackgroundDir());
if (!mfBackgroundDir.exists()) {
mfBackgroundDir.mkdirs();
}
//mfPictureDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), getString(R.string.app_projectname));
mfPictureDir = new File(App.getTempDirPath());
if (!mfPictureDir.exists()) {
mfPictureDir.mkdirs();
}
// 初始化文件对象
mfTakePhoto = new File(mfPictureDir, "TakePhoto.jpg");
mfTempCropPicture = new File(mfPictureDir, "TempCrop.jpg");
mfRecivedPicture = getRecivedPictureFile(this);
mfRecivedCropPicture = new File(mfBackgroundDir, _mszRecivedCropPicture);
// 初始化工具栏
mAToolbar = (AToolbar) findViewById(R.id.toolbar);
setActionBar(mAToolbar);
//mAToolbar.setTitle(getTitle() + "-" + getString(R.string.subtitle_activity_backgroundpicture));
mAToolbar.setSubtitle(R.string.subtitle_activity_backgroundpicture);
//mAToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText);
//mAToolbar.setSubtitleTextAppearance(this, R.style.Toolbar_SubTitleText);
//mAToolbar.setBackgroundColor(getColor(R.color.colorPrimary));
setActionBar(mAToolbar);
getActionBar().setDisplayHomeAsUpEnabled(true);
mAToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
@ -99,7 +95,7 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
}
});
//给按钮设置点击事件
// 设置按钮点击事件
findViewById(R.id.activitybackgroundpictureAButton5).setOnClickListener(onOriginNullClickListener);
findViewById(R.id.activitybackgroundpictureAButton4).setOnClickListener(onReceivedPictureClickListener);
findViewById(R.id.activitybackgroundpictureAButton1).setOnClickListener(onTakePhotoClickListener);
@ -109,31 +105,18 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
updatePreviewBackground();
// 判断并且处理应用分享到的文件
//
//ToastUtils.show("Activity Opened.");
// 预备接收参数
// 处理分享的图片
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
//LogUtils.d(TAG, "action : " + action);
//LogUtils.d(TAG, "type : " + type);
// 判断是否进入图片分享状态
if (Intent.ACTION_SEND.equals(action)
&& type != null
&& ("image/*".equals(type) || "image/jpeg".equals(type) || "image/jpg".equals(type) || "image/png".equals(type) || "image/webp".equals(type))) {
// 预览图片
BackgroundPicturePreviewDialog dlg= new BackgroundPicturePreviewDialog(this);
if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) {
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this);
dlg.show();
}
}
void initEnv() {
private void initEnv() {
LogUtils.d(TAG, "initEnv()");
_RecivedPictureFileName = "Recived.data";
}
@ -144,47 +127,55 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
@Override
public void onAcceptRecivedPicture(String szPreRecivedPictureName) {
//ToastUtils.show("onAcceptRecivedPicture");
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
utils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
utils.saveData();
File fPreRecivedPictureName = new File(utils.getBackgroundDir(), szPreRecivedPictureName);
FileUtils.copyFile(fPreRecivedPictureName, mfRecivedPicture);
// 加载背景
startCropImageActivity(false);
}
//
// 更新预览背景
//
public void updatePreviewBackground() {
LogUtils.d(TAG, "updatePreviewBackground");
ImageView ivPreviewBackground = findViewById(R.id.activitybackgroundpictureImageView1);
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
utils.loadBackgroundPictureBean();
boolean isUseBackgroundFile = utils.getBackgroundPictureBean().isUseBackgroundFile();
if (isUseBackgroundFile && mfRecivedCropPicture.exists()) {
try {
String szBackgroundFilePath = utils.getBackgroundDir() + getBackgroundFileName();
Drawable drawableBackground = FileUtils.getImageDrawable(szBackgroundFilePath);
drawableBackground.setAlpha(120);
ivPreviewBackground.setImageDrawable(drawableBackground);
ToastUtils.show("Use acceptRecived background.");
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
File sourceFile = new File(utils.getBackgroundDir(), szPreRecivedPictureName);
if (FileUtils.copyFile(sourceFile, mfRecivedPicture)) {
startCropImageActivity(false);
} else {
ToastUtils.show(" No background.");
Drawable drawableBackground = getDrawable(R.drawable.blank10x10);
drawableBackground.setAlpha(120);
ivPreviewBackground.setImageDrawable(drawableBackground);
ToastUtils.show("图片复制失败,请重试");
}
}
/**
* 更新背景图片预览
*/
public void updatePreviewBackground() {
LogUtils.d(TAG, "updatePreviewBackground");
ImageView ivPreviewBackground = (ImageView) findViewById(R.id.activitybackgroundpictureImageView1);
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(this);
utils.loadBackgroundPictureBean();
boolean isUseBackgroundFile = utils.getBackgroundPictureBean().isUseBackgroundFile();
if (isUseBackgroundFile && mfRecivedCropPicture.exists()) {
try {
String filePath = utils.getBackgroundDir() + getBackgroundFileName();
Drawable drawable = FileUtils.getImageDrawable(filePath);
if (drawable != null) {
drawable.setAlpha(120);
ivPreviewBackground.setImageDrawable(drawable);
}
ToastUtils.show("背景图片已更新");
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
ToastUtils.show("背景图片加载失败");
}
} else {
ToastUtils.show("未使用背景图片");
Drawable drawable = getResources().getDrawable(R.drawable.blank10x10);
if (drawable != null) {
drawable.setAlpha(120);
ivPreviewBackground.setImageDrawable(drawable);
}
}
}
// 点击事件监听器
private View.OnClickListener onOriginNullClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// 选择原始空白背景
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
BackgroundPictureBean bean = utils.getBackgroundPictureBean();
bean.setIsUseBackgroundFile(false);
@ -196,11 +187,10 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
private View.OnClickListener onSelectPictureClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// 导入外部图片
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_SELECT_PICTURE);
if (checkAndRequestStoragePermission()) {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_SELECT_PICTURE);
}
}
};
@ -211,7 +201,7 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
if (fCheck.exists()) {
startCropImageActivity(false);
} else {
ToastUtils.show("There is not any picture to crop.");
ToastUtils.show("没有可剪裁的图片");
}
}
};
@ -223,7 +213,7 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
if (fCheck.exists()) {
startCropImageActivity(true);
} else {
ToastUtils.show("There is not any picture to crop.");
ToastUtils.show("没有可剪裁的图片");
}
}
};
@ -233,6 +223,7 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
public void onClick(View v) {
LogUtils.d(TAG, "onTakePhotoClickListener");
LogUtils.d(TAG, "mfTakePhoto : " + mfTakePhoto.getPath());
if (mfTakePhoto.exists()) {
mfTakePhoto.delete();
}
@ -240,56 +231,70 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
mfTakePhoto.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
ToastUtils.show("拍照文件创建失败");
return;
}
if (checkAndRequestStoragePermission()) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
};
private View.OnClickListener onReceivedPictureClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// 选择接收到的背景图片
BackgroundPictureUtils utils = BackgroundPictureUtils.getInstance(BackgroundPictureActivity.this);
utils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
utils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
utils.saveData();
updatePreviewBackground();
}
};
/**
* 压缩图片并保存到接收文件
*/
void compressQualityToRecivedPicture(Bitmap bitmap) {
// 设置输出流
OutputStream outStream = null;
try {
// 创建输出流对象准备写入压缩后的图片文件
mfRecivedPicture = getRecivedPictureFile(this);
// 创建新的接收文件
if (!mfRecivedPicture.exists()) {
mfRecivedPicture.createNewFile();
}
FileOutputStream fos = new FileOutputStream(mfRecivedPicture);
// 获取输出流对象
outStream = new BufferedOutputStream(fos);
// 使用默认的质量参数压缩图片
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); // 70% 的质量
// 关闭输出流以完成文件操作
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
ToastUtils.show("图片压缩失败");
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
}
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
}
}
/**
* 启动图片裁剪活动
* @param isCropFree 是否自由裁剪
*/
public void startCropImageActivity(boolean isCropFree) {
LogUtils.d(TAG, "startCropImageActivity");
BackgroundPictureBean bean = mBackgroundPictureUtils.loadBackgroundPictureBean();
mfRecivedPicture = getRecivedPictureFile(this);
Uri uri = UriUtil.getUriForFile(this, mfRecivedPicture);
LogUtils.d(TAG, "uri : " + uri.toString());
if (mfTempCropPicture.exists()) {
mfTempCropPicture.delete();
}
@ -297,27 +302,24 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
mfTempCropPicture.createNewFile();
} catch (IOException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
ToastUtils.show("剪裁临时文件创建失败");
return;
}
// 使用正确的文件路径构建 Uri
Uri cropOutPutUri = Uri.fromFile(mfTempCropPicture);
LogUtils.d(TAG, "mfTempCropPicture : " + mfTempCropPicture.getPath());
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/" + _mszCommonFileType);
// 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪
intent.putExtra("crop", "true");
intent.putExtra("noFaceDetection", true);
if (!isCropFree) {
// aspectX aspectY 是宽高的比例
intent.putExtra("aspectX", bean.getBackgroundWidth());
intent.putExtra("aspectY", bean.getBackgroundHeight());
}
// outputX outputY 是裁剪图片宽高
//intent.putExtra("outputX", 100);
//intent.putExtra("outputY", 100);
//return-data =false 意味着裁剪成功后不能在onActivityResult 的intent 中获得图片
//intent.putExtra("return-data", false);
intent.putExtra("return-data", true);
//裁剪后的图片输出至 cropOutPutUri
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropOutPutUri);
intent.putExtra("scale", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
@ -325,12 +327,101 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
startActivityForResult(intent, REQUEST_CROP_IMAGE);
}
// 启动裁剪窗口裁剪操作文件为 uirImage
//
/**
* 保存剪裁后的Bitmap优化版
*/
private void saveCropBitmap(Bitmap bitmap) {
if (bitmap == null) {
ToastUtils.show("剪裁图片为空");
return;
}
// 内存优化大图片自动缩放
Bitmap scaledBitmap = bitmap;
if (bitmap.getByteCount() > 10 * 1024 * 1024) { // 超过10MB
float scale = 1.0f;
while (scaledBitmap.getByteCount() > 5 * 1024 * 1024) {
scale -= 0.2f; // 每次缩小20%
if (scale < 0.2f) break; // 最小缩放到20%
scaledBitmap = scaleBitmap(scaledBitmap, scale);
}
if (scaledBitmap != bitmap) {
bitmap.recycle(); // 回收原Bitmap
}
}
// 优化创建保存目录
File backgroundDir = new File(mBackgroundPictureUtils.getBackgroundDir());
if (!backgroundDir.exists()) {
if (!backgroundDir.mkdirs()) {
ToastUtils.show("无法创建保存目录");
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
File saveFile = new File(backgroundDir, getBackgroundFileName());
// 优化检查文件是否可写
if (saveFile.exists() && !saveFile.canWrite()) {
if (!saveFile.delete()) {
ToastUtils.show("无法删除旧文件");
if (scaledBitmap != bitmap) scaledBitmap.recycle();
return;
}
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(saveFile);
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
fos.flush();
if (success) {
ToastUtils.show("保存成功");
// 更新数据
mBackgroundPictureUtils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
updatePreviewBackground();
} else {
ToastUtils.show("图片压缩保存失败");
}
} catch (FileNotFoundException e) {
LogUtils.e(TAG, "文件未找到" + e);
ToastUtils.show("保存失败:文件路径错误");
} catch (IOException e) {
LogUtils.e(TAG, "写入异常" + e);
ToastUtils.show("保存失败:磁盘可能已满或路径错误");
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
LogUtils.e(TAG, "流关闭异常" + e);
}
}
if (scaledBitmap != null && !scaledBitmap.isRecycled()) {
scaledBitmap.recycle();
}
}
}
/**
* 缩放Bitmap
*/
private Bitmap scaleBitmap(Bitmap original, float scale) {
if (original == null) {
return null;
}
int width = (int) (original.getWidth() * scale);
int height = (int) (original.getHeight() * scale);
return Bitmap.createScaledBitmap(original, width, height, true);
}
/**
* 分享图片
*/
void sharePicture() {
Uri uri = UriUtil.getUriForFile(this, mfRecivedPicture);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("image/" + _mszCommonFileType);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@ -345,45 +436,107 @@ implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_SELECT_PICTURE) {
// 处理选择后图片
if (resultCode == RESULT_OK) {
try {
Uri selectedImage = data.getData();
LogUtils.d(TAG, "Uri is : " + selectedImage.toString());
File fSrcImage = new File(UriUtil.getFilePathFromUri(this, selectedImage));
mfRecivedPicture = getRecivedPictureFile(this);
FileUtils.copyFile(fSrcImage, mfRecivedPicture);
// 启动剪裁文件窗口
if (requestCode == REQUEST_SELECT_PICTURE && resultCode == RESULT_OK) {
try {
Uri selectedImage = data.getData();
LogUtils.d(TAG, "Uri is : " + selectedImage.toString());
File fSrcImage = new File(UriUtil.getFilePathFromUri(this, selectedImage));
mfRecivedPicture = getRecivedPictureFile(this);
if (FileUtils.copyFile(fSrcImage, mfRecivedPicture)) {
startCropImageActivity(false);
} catch (Exception e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
} else {
ToastUtils.show("图片复制失败,请重试");
}
} catch (Exception e) {
LogUtils.e(TAG, "选择图片异常" + e);
ToastUtils.show("选择图片失败:" + e.getMessage());
}
} else if (requestCode == REQUEST_TAKE_PHOTO) {
if (resultCode == RESULT_OK) {
LogUtils.d(TAG, "REQUEST_TAKE_PHOTO");
Bundle extras = data.getExtras();
} else if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
LogUtils.d(TAG, "REQUEST_TAKE_PHOTO");
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap imageBitmap = (Bitmap) extras.get("data");
compressQualityToRecivedPicture(imageBitmap);
startCropImageActivity(false);
}
} else if (requestCode == REQUEST_CROP_IMAGE) {
if (resultCode == RESULT_OK) {
LogUtils.d(TAG, "CROP_IMAGE_REQUEST_CODE");
FileUtils.copyFile(mfTempCropPicture, mfRecivedCropPicture);
mfTempCropPicture.delete();
mBackgroundPictureUtils.getBackgroundPictureBean().setIsUseBackgroundFile(true);
updatePreviewBackground();
if (imageBitmap != null) {
compressQualityToRecivedPicture(imageBitmap);
startCropImageActivity(false);
} else {
ToastUtils.show("拍照图片为空");
}
} else {
ToastUtils.show("拍照数据获取失败");
}
} else if (requestCode == REQUEST_CROP_IMAGE && resultCode == RESULT_OK) {
LogUtils.d(TAG, "CROP_IMAGE_REQUEST_CODE");
try {
Bitmap cropBitmap = null;
// 方案1通过Intent获取剪裁后的Bitmap
if (data != null && data.hasExtra("data")) {
cropBitmap = data.getParcelableExtra("data");
} else if (mfTempCropPicture.exists()) {
cropBitmap = BitmapFactory.decodeFile(mfTempCropPicture.getPath());
} else {
ToastUtils.show("剪裁文件不存在");
return;
}
} else {
String sz = "Unsolved requestCode = " + Integer.toString(requestCode);
Toast.makeText(getApplication(), sz, Toast.LENGTH_SHORT).show();
LogUtils.d(TAG, sz);
if (cropBitmap != null) {
saveCropBitmap(cropBitmap);
} else {
ToastUtils.show("获取剪裁图片失败");
}
} catch (OutOfMemoryError e) {
LogUtils.e(TAG, "内存溢出" + e);
ToastUtils.show("保存失败:内存不足,请尝试裁剪更小的图片");
} catch (Exception e) {
LogUtils.e(TAG, "剪裁保存异常" + e);
ToastUtils.show("保存失败:" + e.getMessage());
}/* finally {
// 安全删除临时文件
if (mfTempCropPicture.exists()) {
mfTempCropPicture.delete();
}
}*/
} else if (resultCode != RESULT_OK) {
LogUtils.d(TAG, "操作取消或失败requestCode: " + requestCode);
ToastUtils.show("操作已取消");
}
}
/**
* 检查类型是否为图片
*/
private boolean isImageType(String type) {
return type.startsWith("image/") || "image/jpeg".equals(type) ||
"image/jpg".equals(type) || "image/png".equals(type) ||
"image/webp".equals(type);
}
/**
* 检查并申请存储权限
*/
private boolean checkAndRequestStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
STORAGE_PERMISSION_REQUEST);
return false;
}
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERMISSION_REQUEST) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ToastUtils.show("存储权限已获取");
} else {
ToastUtils.show("需要存储权限才能保存图片");
}
}
}
}

View File

@ -22,7 +22,6 @@
// JC 项目编译设置
//include ':jc'
//include ':libjc'
//rootProject.name = "jc"
// AES 项目编译设置