博客

Android 14+ 适配图片权限选择

在Android14+以上,申请 Manifest.permission.READ_MEDIA_IMAGES 权限时,会弹出以下权限框。

权限申请

这是在Android 14新增的细化权限,参考链接:Google

当用户选择“选择照片和视频”而不是“全部允许”时,会丢失 READ_MEDIA_IMAGES 权限,因此在适配安卓14时,需要检测 READ_MEDIA_IMAGES READ_MEDIA_VISUAL_USER_SELECTED 权限,第二个是用户选择“选择照片和视频”时会授权的。

按照谷歌的建议,可以使用Photo Picker 来获取图片或视频文件Uri。

public void init(){
ActivityResultLauncher<PickVisualMediaRequest> launcher = ((AppCompatActivity) mContext).registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), new androidx.activity.result.ActivityResultCallback<Uri>() {
            @Override
            public void onActivityResult(Uri result) {
                LogUtils.e("result:" + result);
            }
        });
}
public void show(){
  PickVisualMediaRequest.Builder builder = new PickVisualMediaRequest.Builder()
                .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE);
        launcher.launch(builder.build());
}

如果需要解析成 Bitmap 或者 File ,可以参考以下代码

public void toBitmap(Uri uri){
  ImageDecoder.Source source = ImageDecoder.createSource(mContext.getContentResolver(), uri);
  Bitmap bitmap = ImageDecoder.decodeBitmap(source);
}

public boolean saveBitmap(Bitmap bitmap, File imageFile) {
        boolean success = false;
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(imageFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            saveImageInfo(imageFile);
            success = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }
   /**
     * 把视频保存到ContentProvider,在选择上传的时候能找到
     */
    private void saveImageInfo(File file) {
        try {
            String fileName = file.getName();
            long currentTimeMillis = System.currentTimeMillis();
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.TITLE, fileName);
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
            values.put(MediaStore.MediaColumns.DATE_MODIFIED, currentTimeMillis);
            values.put(MediaStore.MediaColumns.DATE_ADDED, currentTimeMillis);
            values.put(MediaStore.MediaColumns.DATA, file.getAbsolutePath());
            values.put(MediaStore.MediaColumns.SIZE, file.length());
            values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
            CommonAppContext.sInstance.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

参考文档:

https://developer.honor.com/cn/docs/11100/guides/google_u_compatibility_adaptation_guide#%E5%85%BC%E5%AE%B9%E6%80%A7%E5%BD%B1%E5%93%8D

https://developer.android.com/training/data-storage/shared/photopicker?hl=zh-cn

https://developer.android.com/about/versions/14/changes/partial-photo-video-access?hl=zh-cn

记录一次OMV的quota配额错误问题

不记得咋折腾的smb分享和重新格式化硬盘,导致新增硬盘提示500 quota配额错误:

Failed to execute command 'export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin; export LANG=C.UTF-8; export LANGUAGE=; omv-salt deploy run --no-color quota 2>&amp;1' with exit code '1': debian:

在尝试终端运行 omv-salt deploy run quota 后明显看到提示某块配额文件异常:

提示 create new quotafile /srv/dev-disk-by-uuid-331529a0-6814-4a25-81e8-e4da5a9bffdc/aquota.group.new: File exists

删除以上两个文件后重新运行 omv-salt deploy run quota 在GUI上重新应用即可生效