6
respostas

Erro ao testar em dispositivo físico

E aí, blz? Fui emular a aplicação, direto em meu celular físico, e tudo funcionou certinho, menos quando cliquei para tirar a foto. Quando faço isso, a aplicação fecha e aparece a seguinte mensagem de erro;

Process: alunoapp.com.miau, PID: 16240 android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/alunoapp.com.aluno/files/1549137072871.jpg exposed beyond app through ClipData.Item.getUri()

Até onde revisei o código, o que mando a seguir, está semelhante ao da aula, mas não funciona no dispositivo físico, mesmo funcionando no emulador virtual.

 public static final int CODIGO_CAMERA = 567;
    private AlunoHelper helper;
    private String caminhoFoto;

////outros codigos

Button botaoFoto = (Button) findViewById(R.id.formulario_botao_foto);
        botaoFoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intentcamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                caminhoFoto = getExternalFilesDir(null) + "/" + System.currentTimeMillis() + ".jpg";
                File arquivoFoto = new File(caminhoFoto);
                intentcamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivoFoto));
                startActivityForResult(intentcamera, CODIGO_CAMERA);
            }
        });

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode == Activity.RESULT_OK){
        if (requestCode == CODIGO_CAMERA){
            helper.carregaImagem(caminhoFoto);
            }
        }
    }
6 respostas

Ola Arthur

Da uma olhada nessa resposta do fórum, vê se te ajuda

Avisa aqui se foi útil ou não, beleza

Dei uma lida na pagina do link, alem de ler fóruns e assistir videos. Mas acabei por não entender direito, mesmo que tenha tentado...

<paths>
    <files-path name="caminhoFoto" path="arquivoFoto/"/>
</paths>

<provider            android:name="android.support.v4.content.FileProvider"
            android:authorities="$(applicationId).fileprovider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:ignore="ExtraText">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

foi o que tentei, mas continua dando o mesmo erro... não sei se é o cansaço, mas foi o que 'consegui' fazer

Consegue me mandar seu código no GitHub, é mais fácil para identificar o problema

Mas fica tranquila, essas coisas acontecem mesmo

insira seu código aqui `

public class FormularioActivity extends AppCompatActivity {

public static final int CODIGO_CAMERA = 567;
private AlunoHelper helper;
private String caminhoFoto;

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

    helper = new AlunoHelper(this);

    Intent intent = getIntent();
    Aluno aluno = (Aluno) intent.getSerializableExtra("aluno");
    if (aluno != null){
        helper.preencheFormulario(aluno);
    }

    Button botaoFoto = (Button) findViewById(R.id.formulario_botao_foto);
    botaoFoto.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            String caminhoFoto = getExternalFilesDir(null) + "/"+ System.currentTimeMillis() +".jpg";
            File arquivoFoto = new File(caminhoFoto);
            intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivoFoto));
            startActivity(intentCamera);
        }

        /*@Override
        public void onClick(View view) {
            Intent intentcamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            caminhoFoto = getExternalFilesDir(null) + "/" + System.currentTimeMillis() + ".jpg";
            File arquivoFoto = new File(caminhoFoto);
            intentcamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(arquivoFoto));
            startActivityForResult(intentcamera, CODIGO_CAMERA);
        }*/
    });
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if (resultCode == Activity.RESULT_OK){
    if (requestCode == CODIGO_CAMERA){
        helper.carregaImagem(caminhoFoto);
        }
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_salvar, menu);

    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()){
        case R.id.menu_salvar:
        Miau miau = helper.Pegaaluno();

        AlunoDAO dao = new AlunoDAO(this);

        if (aluno.getId() != null){
            dao.altera(aluno);
        }else {
            dao.insere(aluno);
        }
        dao.close();

        finish();
        break;
    }
    return super.onOptionsItemSelected(item);
}

}

provider_paths.xml

<files-path name="caminhoFoto" path="arquivoFoto/"/>

Acho mais fácil por aqui, para conferir a resposta depois

Manifest.xml

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="$(applicationId).fileprovider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:ignore="ExtraText">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>





AlunoAdapter

public class AlunoAdapter extends BaseAdapter{

    private final List<Aluno> alunos;
    private final Context context;

    public AlunoAdapter(Context context, List<Aluno> alunos) {
        this.context = context;
        this.alunos= alunos;
    }

    @Override
    public int getCount() {
        return alunos.size();
    }

    @Override
    public Object getItem(int position) {
        return alunos.get(position);
    }

    @Override
    public long getItemId(int position) {
        return alunos.get(position).getId();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Aluno aluno = alunos.get(position);

        LayoutInflater inflater = LayoutInflater.from(context);
        View view = convertView;
        if (view == null){
            view = inflater.inflate(R.layout.list_item, parent,false);
        }

        TextView Nome = (TextView) view.findViewById(R.id.item_nome);
        Nome.setText(aluno.getNome());

        TextView Idade = (TextView) view.findViewById(R.id.item_idade);
        Idade.setText(miau.getIdade());

        ImageView campoFoto = (ImageView) view.findViewById(R.id.item_foto);
        String caminhoFoto = aluno.getCaminhoFoto();
        if (caminhoFoto != null){
            Bitmap bitmap = BitmapFactory.decodeFile(caminhoFoto);
            Bitmap bitmapreduzido = Bitmap.createScaledBitmap(bitmap, 100,100, true);
            campoFoto.setImageBitmap(bitmapreduzido);
            campoFoto.setScaleType(ImageView.ScaleType.FIT_XY);
        }
        return view;
    }
}




AlunoHelper

private final ImageView campoFoto;

public void carregaImagem(String caminhoFoto) {
        if (caminhoFoto != null){
        Bitmap bitmap = Bitmap

Tudo bom Arthur, desculpe a demora

Cara, eu estava olhando aqui e acho que identifiquei o problema, neste treixo de código

intentCamera.putExtra(
    MediaStore.EXTRA_OUTPUT,
    Uri.fromFile(arquivoFoto));

Neste momento, resumidamente você esta compartilhando o arquivo da foto, com outra aplicação (que neste caso, é câmera do celular). Porém, a partir da API 24, este tipo de compartilhamento não é mais permitido por questões de segurança. Agora temos uma outra forma de fazer isto

intentCamera.putExtra(
    MediaStore.EXTRA_OUTPUT,
    FileProvider.getUriForFile(
        DetalheDoProdutoActivity.this,
        BuildConfig.APPLICATION_ID + ".provider", 
        arquivoFoto));

Repare que nós utilizamos um método da classe FileProvider.

"O principal objetivo dessa API é abrir temporariamente um arquivo privado em alguns aplicativos direcionados: você mantém o arquivo em sua pasta privada e permite que alguns outros aplicativos o leiam ou até mesmo o escrevam por meio de um arquivo protegido ContentProvider. As permissões são revogadas quando sua atividade é destruída."

Com esta alteração, seu código deve funcionar, faça a alteração e posta o resultado aqui.

Caso queira saber mais sobre o assunto, e entender os parâmetros que passamos para o método getUriForFile, vou deixar alguns links de referência

Documentação da Google

Medium, Lorenzo Quiroli

Post em um blog

abç