Android 11 cropping photos and google photo album processing

      After Android 11, the storage permissions of the Android system are forced to be partitioned, so photo storage has become more and more troublesome, increasing the problems in development. The following is a demo written by me. There is a lot of code, so I will not delete it. , you can also see my debugging process through these

1. First, we need to authorize the application and apply for permission (this is nothing to explain, all developers understand)

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA" />
 String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};    
 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
//                ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
        ) {
            //6.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permission, 100);
            }
        }

2. After android11, file:// cannot be used to crop photos. It is recommended to use MediaStore.Images.Media for processing. However, the problem is that bitmap photos will be generated correspondingly in the album. My method of processing is to delete the generated ones after the logic is completed. Photos to avoid affecting user experience

   

    private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", true);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }

delete photo

                  getContentResolver().delete(cutUri, null);

3. But do you think that’s it? No, that’s too naive. We still have our Google phones. The Uri of Google Photos is different from that of our mobile phones and requires special processing, otherwise the media cannot be recognized.

The above is the path I printed out. Google Photos needs to be converted into regular media, which is to use bitmap to replace a photo, at least that's what I did. . .

    private Uri toUri(Uri uri) {
        // 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
        InputStream is = null;
        try {
            is = getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        Bitmap bitmap = BitmapFactory.decodeStream(is);

        // 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
        Log.e("clm", "path: " + path);
        // 能被正确解析的 uri
        Uri result = Uri.parse(path);
        return result;
    }
  private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
            //google相册里面的照片地址是需要转换的
            tempToUri = toUri(uri);
        } else {
            tempToUri = null;
        }
        intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }

 At this point, the key points of the project have been listed and can be developed or modified as needed. In addition, if you have a better method or there are mistakes in the article, I hope you will enlighten me, thank you! ! !

The following is all the code, you can copy it yourself if needed!

package com.u8.base_dialog;

import android.Manifest;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.core.content.PackageManagerCompat;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class SelectPhotoActivity extends AppCompatActivity {


    String permission[] = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.READ_EXTERNAL_STORAGE"};

    private ImageView iv_photo;

    private boolean cut_x = false;

    private Uri cutUri;
    private Uri tempToUri;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.select_photo_activity);
        iv_photo = findViewById(R.id.iv_photo);


        findViewById(R.id.btn_select_photo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                cut_x = false;
                selectPhoto();
            }
        });

        findViewById(R.id.btn_test_ac).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testActivity();
            }
        });

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
//                ||ContextCompat.checkSelfPermission(this,Manifest.permission.MANAGE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED
        ) {
            //6.0 以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permission, 100);
            }
        }


    }


    private ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
//            Log.e("clm","----action: "+result.getData().getAction());
//            Log.e("clm","----cate: "+result.getData().getCategories());
            Log.e("clm", "----: " + result.getResultCode());
            Log.e("clm", "----result ok: " + Activity.RESULT_OK);
            if (result.getData() != null) {
                Uri uri = result.getData().getData();
                Log.e("clm", "uri: " + uri);

                if (uri != null) {

                    if (!cut_x) {
                        cut(uri);
                        return;
                    }

                    Bitmap bitmap = null;
                    try {
                        bitmap = BitmapFactory.decodeStream(getContentResolver().
                                openInputStream(uri));
                        Log.e("clm", "bitmap: " + bitmap);
                    } catch (FileNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                    if (bitmap == null) {
                        Bundle bundle = result.getData().getExtras();
                        if (bundle != null) {
                            bitmap = (Bitmap) bundle.get("data");
                        }
                    }
                    saveImg(bitmap);
                    iv_photo.setImageBitmap(bitmap);


                    //删除临时保存在相册的文件
                    /**
                     * 轻轻的存 正如我轻轻的删   不留下一张照片
                     */
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                        getContentResolver().delete(cutUri, null);
                        if (tempToUri != null) {
                            getContentResolver().delete(tempToUri, null);
                        }
                    }
                    Log.e("clm", "走了这里111111");
                } else {
                    Bitmap bitmap;

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                        try {
                            bitmap = BitmapFactory.decodeStream(getContentResolver().
                                    openInputStream(cutUri));
                        } catch (FileNotFoundException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        bitmap = result.getData().getExtras().getParcelable("data");
                        saveImg(bitmap);

                    }
                    iv_photo.setImageBitmap(bitmap);
                    Log.e("clm", "走了这里2222");
                }
            }
        }
    });

    private void selectPhoto() {
        Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/*");
        launcher.launch(intent);

    }


    private void cut(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        if (uri.toString().contains("content://com.google.android.apps.photos.contentprovider")) {
            //google相册里面的照片地址是需要转换的
            tempToUri = toUri(uri);
        } else {
            tempToUri = null;
        }
        intent.setDataAndType(tempToUri == null ? uri : tempToUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale ", true);  //是否保留比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 300);
        intent.putExtra("outputY", 300);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            cutUri = createR(uri);
            Log.e("clm", "createR: " + cutUri);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, cutUri);
        }
        cut_x = true;
        launcher.launch(intent);
    }


    private Uri toUri(Uri uri) {
        // 1. 获取 Google Photos 照片 Uri 的输入流,并转为 Bitmap
        InputStream is = null;
        try {
            is = getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        Bitmap bitmap = BitmapFactory.decodeStream(is);

        // 2. 将 bitmap 保存到手机本地相册中获取返回的 uri
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "temp", null);
        Log.e("clm", "path: " + path);
        // 能被正确解析的 uri
        Uri result = Uri.parse(path);
        return result;
    }


    private Uri createR(Uri uri) {

        File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "clm.jpg");
        if (!file.getParentFile().exists())
        {
            file.getParentFile().mkdirs();
        }
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
        contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "clm.jpg");
        contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
        contentValues.put(MediaStore.Video.Media.DATE_MODIFIED, System.currentTimeMillis() / 1000);
        Uri newUrl = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
        return newUrl;
    }

    private void saveImg(Bitmap bitmap) {

        String testPath = Environment.getExternalStorageDirectory() + File.separator + "test.jpg";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            testPath = getExternalFilesDir("clm").getAbsolutePath() + File.separator + "test.jpg";
            File file = new File(testPath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdir();
            }

        }
        Log.e("clm", "testPath:  " + testPath);
        File file = new File(testPath);
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void testActivity() {
        launcher.launch(new Intent(this, MainActivity.class));
    }
}

Guess you like

Origin blog.csdn.net/chenluming210/article/details/132490589