Estive a fazer um programa em Java, para Android, que permite o utilizador tirar uma foto e gravá-la no dispositivo.
Como em todos os projetos, surgiram muitos percalços, mas o mais complexo foi a dificuldade em gravar a foto.
O erro que surgia era o seguinte:
FileProvider - IllegalArgumentException: Failed to find configured root
E, aparentemente, tinha a ver com uma falta de permissões para escrever na diretoria pretendida, embora eu tenha feito tudo exatamente como estava indicado nos exemplos do Android developers.
Basicamente pode fazer-se tudo como está indicado no site do Android, exceto o conteúdo do ficheiro file_paths.xml, que deve ser alterado para o seguinte, conforme a resposta número seis desta página do stackoverflow.
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external" path="." /> <external-files-path name="external_files" path="." /> <cache-path name="cache" path="." /> <external-cache-path name="external_cache" path="." /> <files-path name="files" path="." /> </paths>
Quanto ao resto do código, aqui fica o código Java, incluindo o processo de pedir permissões ao utilizador para usar a câmara e o sd card. Basta chamar a função takePhoto().
public void takePhoto() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, REQUEST_PERMISSION_CAMERA); } else { takePhoto2(); } } public void takePhoto2() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_READ_EXTERNAL_STORAGE); } else { takePhoto3(); } } public void takePhoto3() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE); } else { takePhoto4(); } } public void takePhoto4() { if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) { Log.d("ERROR", "No permissions!!!"); //Toast.makeText(this, "No permission to take photos", Toast.LENGTH_LONG).show(); return; } else { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { photoFile = null; photoFile = getFile(); if (photoFile != null) { photoURI = FileProvider.getUriForFile(this,"pt.ulusofona.c3places.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } else { Toast.makeText(this, "Problems with the images folder", Toast.LENGTH_LONG).show(); } } } } String mCurrentPhotoPath; File photoFolder; String imageFileName; File photoFile; final static int REQUEST_TAKE_PHOTO = 121; final static int MAX_IMAGE_DIM = 480; private File getFile() { photoFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); if(!photoFolder.exists()) { photoFolder.mkdir(); } String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); imageFileName = "JPEG_"+ timeStamp; File image_file = null; try { image_file = File.createTempFile(imageFileName + "_",".jpg",photoFolder); mCurrentPhotoPath = image_file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return image_file; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); switch(requestCode) { case REQUEST_TAKE_PHOTO: try { Bitmap in = MediaStore.Images.Media.getBitmap(getContentResolver(),photoURI); int max = Math.max(in.getWidth(), in.getHeight()); max = (int)(max/MAX_IMAGE_DIM); int larg = (int)(in.getWidth()/max); int alt = (int)(in.getHeight()/max); Bitmap out = Bitmap.createScaledBitmap(in, larg, alt, false); File file = new File(photoFolder, imageFileName + ".png"); FileOutputStream fOut; fOut = new FileOutputStream(file); out.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); in.recycle(); out.recycle(); photoFile.delete(); }catch (Exception e){ e.printStackTrace(); } break; } }
Na função onActivityResult(), antes de gravar a foto, redimensiono-a.