diff --git a/app/src/main/java/com/luck/pictureselector/GlideEngine.java b/app/src/main/java/com/luck/pictureselector/GlideEngine.java index e908c9ab7..5dfbf65f7 100644 --- a/app/src/main/java/com/luck/pictureselector/GlideEngine.java +++ b/app/src/main/java/com/luck/pictureselector/GlideEngine.java @@ -20,21 +20,34 @@ */ public class GlideEngine implements ImageEngine { + /** + * 加载图片 + * + * @param context + * @param url + * @param imageView + */ @Override public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { Glide.with(context).load(url).into(imageView); } + /** + * 加载相册目录 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ @Override - public void loadFolderAsBitmapImage(@NonNull Context context, @NonNull String url, - @NonNull ImageView imageView, int placeholderId) { + public void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { Glide.with(context) .asBitmap() .override(180, 180) .centerCrop() .sizeMultiplier(0.5f) .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(placeholderId) + .placeholder(R.drawable.picture_icon_placeholder) .load(url) .into(new BitmapImageViewTarget(imageView) { @Override @@ -49,6 +62,13 @@ protected void setResource(Bitmap resource) { } + /** + * 加载gif + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ @Override public void loadAsGifImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { @@ -58,16 +78,21 @@ public void loadAsGifImage(@NonNull Context context, @NonNull String url, .into(imageView); } + /** + * 加载图片列表图片 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ @Override - public void loadAsBitmapGridImage(@NonNull Context context, @NonNull String url, - @NonNull ImageView imageView, int placeholderId) { + public void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { Glide.with(context) - .asBitmap() + .load(url) .override(200, 200) .centerCrop() .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(placeholderId) - .load(url) + .placeholder(R.drawable.picture_image_placeholder) .into(imageView); } diff --git a/app/src/main/java/com/luck/pictureselector/MainActivity.java b/app/src/main/java/com/luck/pictureselector/MainActivity.java index 620ac8644..53c2f4aca 100644 --- a/app/src/main/java/com/luck/pictureselector/MainActivity.java +++ b/app/src/main/java/com/luck/pictureselector/MainActivity.java @@ -149,8 +149,8 @@ protected void onCreate(Bundle savedInstanceState) { // animationStyle.activityPreviewEnterAnimation = R.anim.picture_anim_up_in; // animationStyle.activityPreviewExitAnimation = R.anim.picture_anim_down_out; PictureSelector.create(MainActivity.this) - //.themeStyle(themeId) // xml设置主题 - .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题 + .themeStyle(themeId) // xml设置主题 + //.setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题 //.setPictureWindowAnimationStyle(animationStyle)// 自定义页面启动动画 .isNotPreviewDownload(true)// 预览图片长按是否可以下载 .loadImageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项 @@ -192,6 +192,7 @@ public void onAddPicClick() { .maxSelectNum(maxSelectNum)// 最大图片选择数量 .minSelectNum(1)// 最小选择数量 .imageSpanCount(4)// 每行显示个数 + //.isAndroidQTransform(false)// 是否需要处理Android Q 拷贝至应用沙盒的操作,只针对compress(false); && enableCrop(false);有效,默认处理 .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)// 设置相册Activity方向,不设置默认使用系统 .isOriginalImageControl(cb_original.isChecked())// 是否显示原图控制按钮,如果设置为true则用户可以自由选择是否使用原图,压缩、裁剪功能将会失效 //.cameraFileName("test.png") // 重命名拍照文件名、注意这个只在使用相机时可以使用,如果使用相机又开启了压缩或裁剪 需要配合压缩和裁剪文件名api @@ -202,7 +203,7 @@ public void onAddPicClick() { .isSingleDirectReturn(cb_single_back.isChecked())// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效 .previewImage(cb_preview_img.isChecked())// 是否可预览图片 .previewVideo(cb_preview_video.isChecked())// 是否可预览视频 - //.querySpecifiedFormatSuffix(PictureMimeType.ofPNG())// 查询指定后缀格式资源 + //.querySpecifiedFormatSuffix(PictureMimeType.ofJPEG())// 查询指定后缀格式资源 .enablePreviewAudio(cb_preview_audio.isChecked()) // 是否可播放音频 .isCamera(cb_isCamera.isChecked())// 是否显示拍照按钮 .isZoomAnim(true)// 图片列表点击 缩放效果 默认true diff --git a/picture_library/src/main/java/com/luck/picture/lib/PictureBaseActivity.java b/picture_library/src/main/java/com/luck/picture/lib/PictureBaseActivity.java index a79a2b9d2..07944930e 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/PictureBaseActivity.java +++ b/picture_library/src/main/java/com/luck/picture/lib/PictureBaseActivity.java @@ -4,7 +4,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; @@ -310,12 +309,16 @@ protected void compressImage(final List result) { .loadMediaData(result) .setTargetDir(config.compressSavePath) .setCompressQuality(config.compressQuality) + .setFocusAlpha(config.focusAlpha) .setRenameListener(filePath -> config.renameCompressFileName) .ignoreBy(config.minimumCompressSize).get(); // 线程切换 mHandler.sendMessage(mHandler.obtainMessage(MSG_ASY_COMPRESSION_RESULT_SUCCESS, new Object[]{result, files})); } catch (Exception e) { + BroadcastManager.getInstance(getApplicationContext()) + .action(BroadcastAction.ACTION_CLOSE_PREVIEW).broadcast(); + onResult(result); e.printStackTrace(); } }); @@ -325,6 +328,7 @@ protected void compressImage(final List result) { .ignoreBy(config.minimumCompressSize) .setCompressQuality(config.compressQuality) .setTargetDir(config.compressSavePath) + .setFocusAlpha(config.focusAlpha) .setRenameListener(filePath -> config.renameCompressFileName) .setCompressListener(new OnCompressListener() { @Override @@ -615,7 +619,7 @@ protected void onResult(List images) { if (isAndroidQ && !isVideo) { showCompressDialog(); } - if (isAndroidQ) { + if (isAndroidQ && config.isAndroidQTransform) { onResultToAndroidAsy(images); } else { dismissCompressDialog(); diff --git a/picture_library/src/main/java/com/luck/picture/lib/PictureExternalPreviewActivity.java b/picture_library/src/main/java/com/luck/picture/lib/PictureExternalPreviewActivity.java index 11a8ae5b6..3b4ba4177 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/PictureExternalPreviewActivity.java +++ b/picture_library/src/main/java/com/luck/picture/lib/PictureExternalPreviewActivity.java @@ -1,13 +1,19 @@ package com.luck.picture.lib; import android.Manifest; -import android.content.Intent; +import android.content.ContentValues; import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.PointF; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.provider.MediaStore; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -28,12 +34,14 @@ import com.luck.picture.lib.entity.LocalMedia; import com.luck.picture.lib.permissions.PermissionChecker; import com.luck.picture.lib.photoview.PhotoView; +import com.luck.picture.lib.tools.AttrsUtils; import com.luck.picture.lib.tools.DateUtils; import com.luck.picture.lib.tools.MediaUtils; import com.luck.picture.lib.tools.PictureFileUtils; import com.luck.picture.lib.tools.ScreenUtils; import com.luck.picture.lib.tools.SdkVersionUtils; import com.luck.picture.lib.tools.ToastUtils; +import com.luck.picture.lib.tools.ValueOf; import com.luck.picture.lib.widget.PreviewViewPager; import com.luck.picture.lib.widget.longimage.ImageSource; import com.luck.picture.lib.widget.longimage.ImageViewState; @@ -44,6 +52,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -65,11 +74,14 @@ public class PictureExternalPreviewActivity extends PictureBaseActivity implemen private String downloadPath; private String mimeType; private ImageButton ibDelete; + private boolean isAndroidQ; + private View titleViewBg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); inflater = LayoutInflater.from(this); + isAndroidQ = SdkVersionUtils.checkedAndroid_Q(); } @Override @@ -80,6 +92,7 @@ public int getResourceId() { @Override protected void initWidgets() { super.initWidgets(); + titleViewBg = findViewById(R.id.titleViewBg); tvTitle = findViewById(R.id.picture_title); ibLeftBack = findViewById(R.id.left_back); ibDelete = findViewById(R.id.ib_delete); @@ -108,8 +121,20 @@ public void initPictureSelectorStyle() { if (config.style.pictureExternalPreviewDeleteStyle != 0) { ibDelete.setImageResource(config.style.pictureExternalPreviewDeleteStyle); } + if (config.style.pictureLeftBackIcon != 0) { + ibLeftBack.setImageResource(config.style.pictureLeftBackIcon); + } + if (config.style.pictureTitleBarBackgroundColor != 0) { + titleViewBg.setBackgroundColor(colorPrimary); + } + } else { + int previewBgColor = AttrsUtils.getTypeValueColor(this, R.attr.picture_ac_preview_title_bg); + if (previewBgColor != 0) { + titleViewBg.setBackgroundColor(previewBgColor); + } else { + titleViewBg.setBackgroundColor(colorPrimary); + } } - tvTitle.setBackgroundColor(colorPrimary); } private void initViewPageAdapterData() { @@ -206,7 +231,7 @@ public Object instantiateItem(ViewGroup container, int position) { // 压缩过,或者裁剪同时压缩过,以最终压缩过图片为准 path = media.getCompressPath(); } else { - path = SdkVersionUtils.checkedAndroid_Q() ? media.getAndroidQToPath() : media.getPath(); + path = media.getPath(); } boolean isGif = PictureMimeType.isGif(mimeType); final boolean eqLongImg = MediaUtils.isLongImg(media); @@ -222,7 +247,7 @@ public Object instantiateItem(ViewGroup container, int position) { } else { if (config != null && config.imageEngine != null) { if (eqLongImg) { - displayLongPic(SdkVersionUtils.checkedAndroid_Q() + displayLongPic(isAndroidQ ? Uri.parse(path) : Uri.fromFile(new File(path)), longImg); } else { config.imageEngine.loadImage(contentView.getContext(), path, imageView); @@ -298,19 +323,14 @@ private void showDownLoadDialog() { } else { // 有可能本地图片 try { - String suffix = PictureMimeType.getLastImgSuffix(mimeType); - String dirPath = PictureFileUtils.createDir(PictureExternalPreviewActivity.this, - DateUtils.getCreateFileName("IMG_") + suffix); - PictureFileUtils.copyFile(downloadPath, dirPath); - ToastUtils.s(getContext(), getString(R.string.picture_save_success) + "\n" + dirPath); - - Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); - Uri uri = Uri.fromFile(new File(dirPath)); - intent.setData(uri); - sendBroadcast(intent); - + if (isAndroidQ) { + savePictureAlbumAndroidQ(Uri.parse(downloadPath)); + } else { + // 把文件插入到系统图库 + savePictureAlbum(); + } dismissDialog(); - } catch (IOException e) { + } catch (Exception e) { ToastUtils.s(getContext(), getString(R.string.picture_save_error) + "\n" + e.getMessage()); dismissDialog(); e.printStackTrace(); @@ -321,6 +341,82 @@ private void showDownLoadDialog() { dialog.show(); } + /** + * 保存相片至本地相册 + * + * @throws Exception + */ + private void savePictureAlbum() throws Exception { + String suffix = PictureMimeType.getLastImgSuffix(mimeType); + String state = Environment.getExternalStorageState(); + File rootDir = isAndroidQ ? getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) : + state.equals(Environment.MEDIA_MOUNTED) + ? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + : getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES); + if (rootDir != null && !rootDir.exists() && rootDir.mkdirs()) { + } + File folderDir = new File(isAndroidQ || !state.equals(Environment.MEDIA_MOUNTED) + ? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + "Camera" + File.separator); + if (folderDir != null && !folderDir.exists() && folderDir.mkdirs()) { + } + String fileName = DateUtils.getCreateFileName("IMG_") + suffix; + File file = new File(folderDir, fileName); + PictureFileUtils.copyFile(downloadPath, file.getAbsolutePath()); + Message message = mHandler.obtainMessage(); + message.what = 200; + message.obj = file.getAbsolutePath(); + mHandler.sendMessage(message); + } + + /** + * 保存图片到picture 目录,Android Q适配,最简单的做法就是保存到公共目录,不用SAF存储 + * + * @param inputUri + */ + private void savePictureAlbumAndroidQ(Uri inputUri) { + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, DateUtils.getCreateFileName("IMG_")); + contentValues.put(MediaStore.Images.Media.DATE_TAKEN, ValueOf.toString(System.currentTimeMillis())); + contentValues.put(MediaStore.Images.Media.MIME_TYPE, PictureMimeType.MIME_TYPE_IMAGE); + contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM); + Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); + if (uri == null) { + mHandler.sendEmptyMessage(400); + return; + } + AsyncTask.SERIAL_EXECUTOR.execute(() -> { + OutputStream outputStream = null; + try { + outputStream = getContentResolver().openOutputStream(uri); + ParcelFileDescriptor inputDescriptor = getContentResolver().openFileDescriptor(inputUri, "r"); + Bitmap bitmap = BitmapFactory.decodeFileDescriptor(inputDescriptor.getFileDescriptor()); + if (bitmap != null) { + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); + outputStream.close(); + String path = PictureFileUtils.getPath(this, uri); + Message message = mHandler.obtainMessage(); + message.what = 200; + message.obj = path; + mHandler.sendMessage(message); + } else { + mHandler.sendEmptyMessage(400); + } + + } catch (Exception e) { + mHandler.sendEmptyMessage(400); + e.printStackTrace(); + } finally { + try { + if (outputStream != null) { + outputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + // 进度条线程 public class loadDataThread extends Thread { @@ -346,8 +442,20 @@ public void showLoadingImage(String urlPath) { try { URL u = new URL(urlPath); String suffix = PictureMimeType.getLastImgSuffix(mimeType); - String path = PictureFileUtils.createDir(PictureExternalPreviewActivity.this, - DateUtils.getCreateFileName("IMG_") + suffix); + String state = Environment.getExternalStorageState(); + File rootDir = isAndroidQ ? getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) : + state.equals(Environment.MEDIA_MOUNTED) + ? Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + : getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES); + if (rootDir != null && !rootDir.exists() && rootDir.mkdirs()) { + } + File folderDir = new File(isAndroidQ || !state.equals(Environment.MEDIA_MOUNTED) + ? rootDir.getAbsolutePath() : rootDir.getAbsolutePath() + File.separator + "Camera" + File.separator); + if (folderDir != null && !folderDir.exists() && folderDir.mkdirs()) { + } + String fileName = DateUtils.getCreateFileName("IMG_") + suffix; + File file = new File(folderDir, fileName); + String path = file.getAbsolutePath(); byte[] buffer = new byte[1024 * 8]; int read; int ava = 0; @@ -363,26 +471,44 @@ public void showLoadingImage(String urlPath) { } bout.flush(); bout.close(); - Message message = handler.obtainMessage(); + Message message = mHandler.obtainMessage(); message.what = 200; message.obj = path; - handler.sendMessage(message); + mHandler.sendMessage(message); } catch (IOException e) { - ToastUtils.s(getContext(), getString(R.string.picture_save_error) + "\n" + e.getMessage()); + Message message = mHandler.obtainMessage(); + message.what = 400; + mHandler.sendMessage(message); e.printStackTrace(); } } - private Handler handler = new Handler() { + private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 200: - String path = (String) msg.obj; - ToastUtils.s(getContext(), getString(R.string.picture_save_success) + "\n" + path); - dismissDialog(); + try { + String path = (String) msg.obj; + if (!TextUtils.isEmpty(path)) { + File file = new File(path); + MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), null); + new PictureMediaScannerConnection(getContext().getApplicationContext(), file.getAbsolutePath(), + () -> { + }); + ToastUtils.s(getContext(), getString(R.string.picture_save_success) + "\n" + file.getAbsolutePath()); + } + dismissDialog(); + } catch (Exception e) { + e.printStackTrace(); + } + break; + case 400: + ToastUtils.s(getContext(), getString(R.string.picture_save_error)); + break; + default: break; } } @@ -405,7 +531,7 @@ private void exitAnimation() { protected void onDestroy() { super.onDestroy(); if (loadDataThread != null) { - handler.removeCallbacks(loadDataThread); + mHandler.removeCallbacks(loadDataThread); loadDataThread = null; } } diff --git a/picture_library/src/main/java/com/luck/picture/lib/PictureSelectionModel.java b/picture_library/src/main/java/com/luck/picture/lib/PictureSelectionModel.java index 2d9138cc6..ba12d3ea0 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/PictureSelectionModel.java +++ b/picture_library/src/main/java/com/luck/picture/lib/PictureSelectionModel.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Locale; /** * @author:luck @@ -382,6 +381,14 @@ public PictureSelectionModel synOrAsy(boolean synOrAsy) { return this; } + /** + * @param focusAlpha After compression, the transparent channel is retained + * @return + */ + public PictureSelectionModel compressFocusAlpha(boolean focusAlpha) { + selectionConfig.focusAlpha = focusAlpha; + return this; + } /** * @param isOriginalControl Whether the original image is displayed @@ -717,9 +724,9 @@ public PictureSelectionModel setPictureStyle(PictureParameterStyle style) { } /** - * 动态设置相册启动退出动画 + * Dynamically set the album to start and exit the animation * - * @param style Activity启动退出动画主题 + * @param style Activity Launch exit animation theme * @return */ public PictureSelectionModel setPictureWindowAnimationStyle(PictureWindowAnimationStyle windowAnimationStyle) { @@ -727,6 +734,18 @@ public PictureSelectionModel setPictureWindowAnimationStyle(PictureWindowAnimati return this; } + /** + * # If you want to handle the Android Q path, if not, just return the uri, + * The getAndroidQToPath(); field will be empty + * + * @param isAndroidQTransform + * @return + */ + public PictureSelectionModel isAndroidQTransform(boolean isAndroidQTransform) { + selectionConfig.isAndroidQTransform = isAndroidQTransform; + return this; + } + /** * # 内部方法-要使用此方法时最好先咨询作者!!! * diff --git a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureAlbumDirectoryAdapter.java b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureAlbumDirectoryAdapter.java index f24c5e66b..d31a72db5 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureAlbumDirectoryAdapter.java +++ b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureAlbumDirectoryAdapter.java @@ -15,7 +15,6 @@ import com.luck.picture.lib.config.PictureSelectionConfig; import com.luck.picture.lib.entity.LocalMedia; import com.luck.picture.lib.entity.LocalMediaFolder; -import com.luck.picture.lib.tools.AttrsUtils; import java.util.ArrayList; import java.util.List; @@ -74,8 +73,8 @@ public void onBindViewHolder(final ViewHolder holder, int position) { } else { if (config != null && config.imageEngine != null) { config.imageEngine - .loadFolderAsBitmapImage(holder.itemView.getContext(), - imagePath, holder.ivFirstImage, R.drawable.picture_icon_placeholder); + .loadFolderImage(holder.itemView.getContext(), + imagePath, holder.ivFirstImage); } } Context context = holder.itemView.getContext(); diff --git a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureImageGridAdapter.java b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureImageGridAdapter.java index 897d18ab5..50d91fcbb 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureImageGridAdapter.java +++ b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureImageGridAdapter.java @@ -159,12 +159,22 @@ public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int pos contentHolder.tvCheck.setVisibility(isSingleDirectReturn ? View.GONE : View.VISIBLE); contentHolder.btnCheck.setVisibility(isSingleDirectReturn ? View.GONE : View.VISIBLE); contentHolder.tvIsGif.setVisibility(gif ? View.VISIBLE : View.GONE); + boolean eqImage = PictureMimeType.eqImage(image.getMimeType()); + if (eqImage) { + boolean eqLongImg = MediaUtils.isLongImg(image); + contentHolder.tvLongChart.setVisibility(eqLongImg ? View.VISIBLE : View.GONE); + } else { + contentHolder.tvLongChart.setVisibility(View.GONE); + } + contentHolder.tvDuration.setText(DateUtils.formatDurationTime(image.getDuration())); + if (chooseMode == PictureMimeType.ofAudio()) { contentHolder.tvDuration.setVisibility(View.VISIBLE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { contentHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds (R.drawable.picture_icon_audio, 0, 0, 0); } + contentHolder.ivPicture.setImageResource(R.drawable.picture_audio_placeholder); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { contentHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds @@ -172,25 +182,11 @@ public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int pos } contentHolder.tvDuration.setVisibility(PictureMimeType.eqVideo(mimeType) ? View.VISIBLE : View.GONE); - } - boolean eqImage = PictureMimeType.eqImage(image.getMimeType()); - if (eqImage) { - boolean eqLongImg = MediaUtils.isLongImg(image); - contentHolder.tvLongChart.setVisibility(eqLongImg ? View.VISIBLE : View.GONE); - } else { - contentHolder.tvLongChart.setVisibility(View.GONE); - } - long duration = image.getDuration(); - contentHolder.tvDuration.setText(DateUtils.formatDurationTime(duration)); - if (chooseMode == PictureMimeType.ofAudio()) { - contentHolder.ivPicture.setImageResource(R.drawable.picture_audio_placeholder); - } else { if (config != null && config.imageEngine != null) { - config.imageEngine - .loadAsBitmapGridImage(context, path, - contentHolder.ivPicture, R.drawable.picture_image_placeholder); + config.imageEngine.loadGridImage(context, path, contentHolder.ivPicture); } } + if (enablePreview || enablePreviewVideo || enablePreviewAudio) { contentHolder.btnCheck.setOnClickListener(v -> { // 如原图路径不存在或者路径存在但文件不存在 @@ -294,7 +290,9 @@ public boolean isSelected(LocalMedia image) { */ private void notifyCheckChanged(ViewHolder viewHolder, LocalMedia imageBean) { viewHolder.tvCheck.setText(""); - for (LocalMedia media : selectImages) { + int size = selectImages.size(); + for (int i = 0; i < size; i++) { + LocalMedia media = selectImages.get(i); if (media.getPath().equals(imageBean.getPath())) { imageBean.setNum(media.getNum()); media.setPosition(imageBean.getPosition()); diff --git a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureSimpleFragmentAdapter.java b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureSimpleFragmentAdapter.java index 5459d6577..52490bcf0 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureSimpleFragmentAdapter.java +++ b/picture_library/src/main/java/com/luck/picture/lib/adapter/PictureSimpleFragmentAdapter.java @@ -14,7 +14,6 @@ import com.luck.picture.lib.PictureVideoPlayActivity; import com.luck.picture.lib.R; -import com.luck.picture.lib.config.PictureConfig; import com.luck.picture.lib.config.PictureMimeType; import com.luck.picture.lib.config.PictureSelectionConfig; import com.luck.picture.lib.entity.LocalMedia; diff --git a/picture_library/src/main/java/com/luck/picture/lib/compress/Checker.java b/picture_library/src/main/java/com/luck/picture/lib/compress/Checker.java index afb06c37a..3329cf4b3 100755 --- a/picture_library/src/main/java/com/luck/picture/lib/compress/Checker.java +++ b/picture_library/src/main/java/com/luck/picture/lib/compress/Checker.java @@ -4,8 +4,6 @@ import android.text.TextUtils; import android.util.Log; -import com.luck.picture.lib.tools.PictureFileUtils; - import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -154,15 +152,14 @@ String extSuffix(InputStreamProvider input) { String extSuffix(String mimeType) { try { - return TextUtils.isEmpty(mimeType) ? "" - : mimeType.replace("image/", "."); + return TextUtils.isEmpty(mimeType) ? "" : mimeType.replace("image/", "."); } catch (Exception e) { - return ""; + return JPG; } } boolean needCompress(int leastCompressSize, String path) { - if (leastCompressSize > 0 && !TextUtils.isEmpty(path)) { + if (leastCompressSize > 0) { File source = new File(path); return source.exists() && source.length() > (leastCompressSize << 10); } diff --git a/picture_library/src/main/java/com/luck/picture/lib/compress/Engine.java b/picture_library/src/main/java/com/luck/picture/lib/compress/Engine.java index 5be1c2241..82e66b05b 100755 --- a/picture_library/src/main/java/com/luck/picture/lib/compress/Engine.java +++ b/picture_library/src/main/java/com/luck/picture/lib/compress/Engine.java @@ -14,19 +14,18 @@ */ class Engine { private static final int DEFAULT_QUALITY = 60; + private int compressQuality; private InputStreamProvider srcImg; private File tagImg; private int srcWidth; private int srcHeight; private boolean focusAlpha; - private int compressQuality; Engine(InputStreamProvider srcImg, File tagImg, boolean focusAlpha, int compressQuality) throws IOException { this.tagImg = tagImg; this.srcImg = srcImg; this.focusAlpha = focusAlpha; this.compressQuality = compressQuality <= 0 ? DEFAULT_QUALITY : compressQuality; - BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; options.inSampleSize = 1; diff --git a/picture_library/src/main/java/com/luck/picture/lib/compress/Luban.java b/picture_library/src/main/java/com/luck/picture/lib/compress/Luban.java index ba9237af1..2d572be85 100755 --- a/picture_library/src/main/java/com/luck/picture/lib/compress/Luban.java +++ b/picture_library/src/main/java/com/luck/picture/lib/compress/Luban.java @@ -32,7 +32,7 @@ public class Luban implements Handler.Callback { private static final int MSG_COMPRESS_SUCCESS = 0; private static final int MSG_COMPRESS_START = 1; private static final int MSG_COMPRESS_ERROR = 2; - private int compressQuality; + private String mTargetDir; private boolean focusAlpha; private int mLeastCompressSize; @@ -43,8 +43,9 @@ public class Luban implements Handler.Callback { private List mPaths; private List mediaList; private int index = -1; - private Handler mHandler; private boolean isAndroidQ; + private int compressQuality; + private Handler mHandler; private Luban(Builder builder) { this.mPaths = builder.mPaths; @@ -56,6 +57,7 @@ private Luban(Builder builder) { this.mLeastCompressSize = builder.mLeastCompressSize; this.mCompressionPredicate = builder.mCompressionPredicate; this.compressQuality = builder.compressQuality; + this.focusAlpha = builder.focusAlpha; this.mHandler = new Handler(Looper.getMainLooper(), this); this.isAndroidQ = builder.isAndroidQ; } @@ -95,8 +97,7 @@ private File getImageCustomFile(Context context, String filename) { * Returns a directory with the given name in the private cache directory of the application to * use to store retrieved media and thumbnails. * - * @param context A context. - * @param cacheName The name of the subdirectory in which to store the cache. + * @param context A context. * @see #getImageCacheDir(Context) */ private static File getImageCacheDir(Context context) { diff --git a/picture_library/src/main/java/com/luck/picture/lib/config/PictureMimeType.java b/picture_library/src/main/java/com/luck/picture/lib/config/PictureMimeType.java index dc71310ca..b98f4ce67 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/config/PictureMimeType.java +++ b/picture_library/src/main/java/com/luck/picture/lib/config/PictureMimeType.java @@ -381,7 +381,7 @@ public static String s(Context context, String mimeType) { public final static String PNG = ".png"; - + public final static String DCIM = "DCIM/Camera"; public final static String MIME_TYPE_IMAGE = "image/jpeg"; public final static String MIME_TYPE_VIDEO = "video/mp4"; public final static String MIME_TYPE_AUDIO = "audio/mpeg"; diff --git a/picture_library/src/main/java/com/luck/picture/lib/config/PictureSelectionConfig.java b/picture_library/src/main/java/com/luck/picture/lib/config/PictureSelectionConfig.java index 7341c66ac..eca96a657 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/config/PictureSelectionConfig.java +++ b/picture_library/src/main/java/com/luck/picture/lib/config/PictureSelectionConfig.java @@ -32,10 +32,12 @@ public final class PictureSelectionConfig implements Parcelable { public PictureWindowAnimationStyle windowAnimationStyle; public String compressSavePath; public String suffixType; + public boolean focusAlpha; public String renameCompressFileName; public String renameCropFileName; public String specifiedFormat; public int requestedOrientation; + public boolean isAndroidQTransform; @StyleRes public int themeStyleId; public int selectionMode; @@ -142,8 +144,10 @@ private void reset() { cropWidth = 0; cropHeight = 0; requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; + isAndroidQTransform = true; isCamera = true; isGif = false; + focusAlpha = false; isCheckOriginalImage = false; isSingleDirectReturn = false; enablePreview = true; diff --git a/picture_library/src/main/java/com/luck/picture/lib/engine/ImageEngine.java b/picture_library/src/main/java/com/luck/picture/lib/engine/ImageEngine.java index a9d987ce9..c2bc63920 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/engine/ImageEngine.java +++ b/picture_library/src/main/java/com/luck/picture/lib/engine/ImageEngine.java @@ -3,7 +3,6 @@ import android.content.Context; import android.widget.ImageView; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; /** @@ -22,15 +21,13 @@ public interface ImageEngine { void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView); /** - * 加载图片 + * 加载相册目录图片 * - * @param context 上下文 - * @param url 图片路径 - * @param imageView 承载图片ImageView - * @param placeholderId 占位图 + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView */ - void loadFolderAsBitmapImage(@NonNull Context context, @NonNull String url, - @NonNull ImageView imageView, @DrawableRes int placeholderId); + void loadFolderImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView); /** * 加载gif图片 @@ -42,13 +39,11 @@ void loadFolderAsBitmapImage(@NonNull Context context, @NonNull String url, void loadAsGifImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView); /** - * 加载图片 + * 加载图片列表图片 * - * @param context 上下文 - * @param url 图片路径 - * @param imageView 承载图片ImageView - * @param placeholderId 占位图 + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView */ - void loadAsBitmapGridImage(@NonNull Context context, @NonNull String url, - @NonNull ImageView imageView, @DrawableRes int placeholderId); + void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView); } diff --git a/picture_library/src/main/java/com/luck/picture/lib/model/LocalMediaLoader.java b/picture_library/src/main/java/com/luck/picture/lib/model/LocalMediaLoader.java index a9ba14963..de094e9dc 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/model/LocalMediaLoader.java +++ b/picture_library/src/main/java/com/luck/picture/lib/model/LocalMediaLoader.java @@ -18,7 +18,6 @@ import com.luck.picture.lib.config.PictureSelectionConfig; import com.luck.picture.lib.entity.LocalMedia; import com.luck.picture.lib.entity.LocalMediaFolder; -import com.luck.picture.lib.tools.MediaUtils; import com.luck.picture.lib.tools.SdkVersionUtils; import java.io.File; @@ -144,6 +143,7 @@ public LocalMediaLoader(Context context, PictureSelectionConfig config) { this.mHandler = new Handler(Looper.getMainLooper(), this); } + public void loadAllMedia() { AsyncTask.SERIAL_EXECUTOR.execute(() -> { Cursor data = mContext.getContentResolver().query(QUERY_URI, PROJECTION, getSelection(), getSelectionArgs(), ORDER_BY); @@ -179,23 +179,14 @@ public void loadAllMedia() { String folderName = data.getString (data.getColumnIndexOrThrow(PROJECTION[7])); + if (config.filterFileSize > 0) { if (size > config.filterFileSize * FILE_SIZE_UNIT) { continue; } } - if (width == 0 && height == 0) { - int[] newSize = isAndroidQ ? MediaUtils - .getLocalSizeToAndroidQ(mContext, path) - : MediaUtils.getLocalVideoSize(path); - width = newSize[0]; - height = newSize[1]; - } - if (PictureMimeType.eqVideo(mimeType)) { - if (duration == 0) { - duration = MediaUtils.extractDuration(mContext, isAndroidQ, path); - } + if (config.videoMinSecond > 0 && duration < config.videoMinSecond) { // 如果设置了最小显示多少秒的视频 continue; @@ -261,21 +252,21 @@ private String getSelection() { return getSelectionArgsForAllMediaCondition(getDurationCondition(0, 0), config.isGif); case PictureConfig.TYPE_IMAGE: if (!TextUtils.isEmpty(config.specifiedFormat)) { - // 获取指定的类型的图片 + // 获取指定类型的图片 return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'"; } return config.isGif ? SELECTION : SELECTION_NOT_GIF; case PictureConfig.TYPE_VIDEO: // 获取视频 if (!TextUtils.isEmpty(config.specifiedFormat)) { - // 获取指定的类型的图片 + // 获取指定类型的图片 return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'"; } return getSelectionArgsForSingleMediaCondition(); case PictureConfig.TYPE_AUDIO: // 获取音频 if (!TextUtils.isEmpty(config.specifiedFormat)) { - // 获取指定的类型的图片 + // 获取指定类型的图片 return SELECTION_SPECIFIED_FORMAT + "='" + config.specifiedFormat + "'"; } return getSelectionArgsForSingleMediaCondition(getDurationCondition(0, AUDIO_DURATION)); diff --git a/picture_library/src/main/java/com/luck/picture/lib/tools/MediaUtils.java b/picture_library/src/main/java/com/luck/picture/lib/tools/MediaUtils.java index 4e968a0e3..a5bab3659 100644 --- a/picture_library/src/main/java/com/luck/picture/lib/tools/MediaUtils.java +++ b/picture_library/src/main/java/com/luck/picture/lib/tools/MediaUtils.java @@ -12,13 +12,13 @@ import com.luck.picture.lib.config.PictureMimeType; import com.luck.picture.lib.entity.LocalMedia; + /** * @author:luck * @date:2019-10-21 17:10 * @describe:资源处理工具类 */ public class MediaUtils { - /** * 创建一条图片地址uri,用于保存拍照后的照片 * @@ -36,6 +36,7 @@ public static Uri createImageUri(final Context context) { values.put(MediaStore.Images.Media.MIME_TYPE, PictureMimeType.MIME_TYPE_IMAGE); // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储 if (status.equals(Environment.MEDIA_MOUNTED)) { + values.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM); imageFilePath[0] = context.getContentResolver() .insert(MediaStore.Images.Media.getContentUri("external"), values); } else { @@ -63,6 +64,7 @@ public static Uri createVideoUri(final Context context) { values.put(MediaStore.Video.Media.MIME_TYPE, PictureMimeType.MIME_TYPE_VIDEO); // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储 if (status.equals(Environment.MEDIA_MOUNTED)) { + values.put(MediaStore.Images.Media.RELATIVE_PATH, PictureMimeType.DCIM); imageFilePath[0] = context.getContentResolver() .insert(MediaStore.Video.Media.getContentUri("external"), values); } else { @@ -140,6 +142,7 @@ private static long getLocalDuration(String path) { * * @return */ + @Deprecated public static int[] getLocalSizeToAndroidQ(Context context, String videoPath) { int[] size = new int[2]; try { diff --git a/picture_library/src/main/res/layout/picture_activity_external_preview.xml b/picture_library/src/main/res/layout/picture_activity_external_preview.xml index 678298644..bca5d700c 100644 --- a/picture_library/src/main/res/layout/picture_activity_external_preview.xml +++ b/picture_library/src/main/res/layout/picture_activity_external_preview.xml @@ -6,29 +6,33 @@ android:fitsSystemWindows="true"> + + + + - - - + android:layout_below="@id/titleViewBg" /> \ No newline at end of file diff --git a/picture_library/src/main/res/values-ja-rJP/strings.xml b/picture_library/src/main/res/values-ja-rJP/strings.xml index b2b6071aa..97c1cf7d2 100644 --- a/picture_library/src/main/res/values-ja-rJP/strings.xml +++ b/picture_library/src/main/res/values-ja-rJP/strings.xml @@ -10,9 +10,9 @@ 最大で %1$s の音声を選択することができます プレビュー ちょっと待ってください... - %1$d/%2$d 完成 - 已完成 - 完成 + %1$d/%2$d 選べた + 選べた + 選べた 選んでください ビデオや写真はない\n オーディオなし\n