Problems using camera, generate, edit and save image [duplicate]

3

I'm trying to create an app, and part of it is using the camera to take a picture, which will automatically be shortened and saved in folders separated by year / month / imgHora.jpg.

For older versions the code worked, but for newer versions it is giving error. I have seen several similar questions in English and Portuguese, but I could not solve it, if someone can give me a help thank you. I've tried using Provider, but I just added everything. The main error is this:

  

android.os.FileUriExposedException: file: ///storage/emulated/0/Pictures/CamMur/2018/October/28_182120.jpg exposed beyond app through ClipData.Item.getUri ()

Regarding:

mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(caminho)));

Another thing, I want you to click on the button again, it will generate a new image. If someone has a solution that is better than mine, welcome. Without it, the first time I enter the program and click the button it generates an image and saves it, but if I click again on the button it overlaps the previous photo.

            Intent intent = getIntent();
            finish();
            startActivity(intent);

Complete code:

package com.example.admin.camera;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class MainActivity extends AppCompatActivity {

    public static final int PROCESSO_TIRAR_FOTO = 10;

    private Context context;

    private ImageView iv_foto;
    private Button btn_tf;

    private int largura;
    private int altura;

    private String caminho;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.telainicial);

        iniciarVariaveis(savedInstanceState);
        iniciarAcoes();

    }

    @Override
    //se a tela morrer, faz cast e recria a tela;
    protected void onSaveInstanceState(Bundle outState) {

        outState.putInt("largura", largura);
        outState.putInt("altura", altura);
        outState.putString("caminho", caminho);

        super.onSaveInstanceState(outState);
    }

    private void iniciarVariaveis(Bundle savedInstanceState) {
        //bundle variavel de cache
        context = getBaseContext();
        //
        iv_foto = findViewById(R.id.iv_foto);
        btn_tf = findViewById(R.id.btn_tf);

        //Permissão para acessar camera
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.CAMERA}, 0);
        }

        //
        //Analisa savedInstance para recuperar os valores e inicializar as variaveis
        if (savedInstanceState != null) {
            altura = savedInstanceState.getInt("altura");
            largura = savedInstanceState.getInt("largura");
            //
            caminho = savedInstanceState.getString("caminho");


        } else {
            File path;
            File dir;

            String timeYear;
            String timeMoth;
            String timeDayHour;
            String timeAll;

            timeYear = new SimpleDateFormat("yyyy", Locale.getDefault()).format(new Date());
            timeMoth = new SimpleDateFormat("MMMM", Locale.getDefault()).format(new Date());
            timeDayHour ="/" + new SimpleDateFormat("dd_HHmmss", Locale.getDefault()).format(new Date()) + ".jpg";
            timeAll = "CamMur/" +timeYear + "/" + timeMoth ;


            //Cria pasta com nome CamMUR e um arquivo temporário foto.jpg
            path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
                        dir = new File(path, timeAll);


            if (!dir.exists()) {
                if (!dir.mkdirs()) {
                    Log.d("LabCamera", "Pasta não criada");

                }
            }

            caminho = dir.getPath() + timeDayHour ;
        }
    }

    private void iniciarAcoes() {
        btn_tf.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                Intent intent = getIntent();
                finish();
                startActivity(intent);

                largura = iv_foto.getWidth();
                altura = iv_foto.getHeight();
                //
                //chamar camera
                //não é de forma explicita, pois não sei a classe que chama a camera
                Intent mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                //saida da foto pro caminho criado;

                mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(caminho)));
                //
                startActivityForResult(mIntent, PROCESSO_TIRAR_FOTO);


            }


        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PROCESSO_TIRAR_FOTO && resultCode == RESULT_OK) {

                    configurarImagem(resultCode);
                } else {
                    Toast.makeText(context, "Operação Cancelada", Toast.LENGTH_SHORT).show();
                }

        }


    private void configurarImagem(int resultCode) {
        int larguraFOTO;
        int alturaFOTO;

        //Não gera um bitmap. Ele inicializa a variavel options com as informações
        // vindas da imagem: altura e largura;
        BitmapFactory.Options options = new BitmapFactory.Options();
        //não consome a foto
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(caminho, options);

        larguraFOTO = options.outWidth;
        alturaFOTO = options.outHeight;

        //Divide a largura da foto pela largura do ImageView
        int escala = Math.min(larguraFOTO /largura, alturaFOTO/altura);

        options.inJustDecodeBounds = false;
        options.inSampleSize = escala;

        //GERA O BITMAP
        Bitmap bm = BitmapFactory.decodeFile(caminho, options);

        iv_foto.setImageBitmap(bm);

    }
}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.admin.camera">

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
                android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:configChanges="orientation"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
    
asked by anonymous 28.10.2018 / 22:31

2 answers

3

Let's get right to the point, which is causing the error.

The File Provider statement is missing. Please enter Manifest.xml :

<application>
.
.
.
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths" />
    </provider>

</application>

And create the file provider_paths and directory xml (if it is not created). With the following code:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="." />
</paths>

You will need to modify the% s call of the Camera:

mIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileUtil.getUri(getApplicationContext(), new File(caminho)));

For intent do not get giant, create a new class containing Activity code, in order to separate the type of call, by the android version on the device:

public class FileUtil {
    public static Uri getUri(Context context, File file) {
        Uri uri;
        if (isAndroidMarshmallowOrSuperiorVersion()) {
            uri = getUriFrom(context, file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

    private static Uri getUriFrom(Context context, File file) {
        return FileProvider.getUriForFile(context, getAuthority(), file);
    }

    @NonNull
    private static String getAuthority() {
        return BuildConfig.APPLICATION_ID + ".provider";
    }

    private static boolean isAndroidMarshmallowOrSuperiorVersion() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }
}
    
29.10.2018 / 15:10
0

For part of clicking the button and generating a new image without overlapping the previous one that was taken. I just removed:

        Intent intent = getIntent();
        finish();
        startActivity(intent);

And I added the code that generates the image in:

 private void iniciarAcoes(final Bundle savedInstanceState) {
        btn_tf.setOnClickListener(new View.OnClickListener() {


        @Override
        public void onClick(View v) {
            //Analisa savedInstance para recuperar os valores e inicializar as variaveis
            if (savedInstanceState != null) {
                altura = savedInstanceState.getInt("altura");
                largura = savedInstanceState.getInt("largura");
                //
                caminho = savedInstanceState.getString("caminho");


            } else {
                File path;
                File dir;
                ...
    
30.10.2018 / 04:31