Roteiro para desenvolvimento de aplicativos para tirar fotos.
Direto ao assunto, alguns passos para desenvolver uma aplicação que tire/use fotos.
Pedindo permissão para usar a câmera
Se uma função essencial da sua aplicação é tirar fotos, restringir a sua visibilidade no Google Play a dispositivos que possuem uma câmera. Para anunciar que a sua aplicação depende de ter uma câmera, colocar uma tag <uses-feature> no seu arquivo de manifesto:
<manifest ... > <uses-feature android:name="android.hardware.camera" android:required="true" /> ...</manifest>
Se seu aplicativo usa, mas não exige uma câmera, a fim de função, em vez disso "set android:required to false". Ao fazê-lo, o Google Play permitirá que dispositivos sem uma câmera possam fazer o download do aplicativo. É então a sua responsabilidade de verificar a disponibilidade da câmara em tempo de execução chamando hasSystemFeature(PackageManager.FEATURE_CAMERA). Se a câmera não estiver disponível, então você deve desativar seus recursos de câmera.
Tirando uma foto com app da Câmera
A maneira Android de delegar ações para outras aplicações é invocar uma Intent que descreve o que você quer fazer. Este processo envolve três partes: O Intent em si, uma chamada para iniciar o externo Activity, e algum código para lidar com os dados da imagem quando o foco retorna para sua atividade.
Aqui está uma função que chama a intenção de capturar uma foto.
static final int REQUEST_IMAGE_CAPTURE = 1; private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } }
Obtendo o Thumbnail
Se o tirar uma foto não é o ambição principal da sua aplicação, então você provavelmente pode obter a imagem a partir do aplicativo de câmera e fazer algo com ela.
A aplicação Câmara Android codifica a foto no retorno Intent entregue a onActivityResult() como um pequeno Bitmap nos extras, sob a chave "data". O código a seguir recupera esta imagem e exibi-lo em um ImageView.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) { Bundle extras = data.getExtras(); Bitmap imageBitmap = (Bitmap) extras.get("data"); mImageView.setImageBitmap(imageBitmap); } }
Nota: Esta imagem é uma miniatura de "data" e pode ser bom para um ícone, mas não muito mais. Lidar uma imagem de tamanho normal pode demorar um pouco mais e demandar mais trabalho.
Salvando a foto em tamanho “normal”
A aplicação de Câmera do Android salva uma foto de tamanho “normal” em um arquivo. Você deve informar um nome de arquivo dentro dos padrões no qual o aplicativo da câmera deve salvar a foto.
Geralmente, as fotos que o usuário capta com a câmera do dispositivo são guardadas no dispositivo de armazenamento público acessíveis por todos os aplicativos. O diretório apropriado para fotos compartilhadas é fornecida por getExternalStoragePublicDirectory(), com o argumento DIRECTORY_PICTURES. Porque o diretório fornecido por este método é compartilhada entre todos os aplicativos, para ler e escrever exige a permissão READ_EXTERNAL_STORAGE e WRITE_EXTERNAL_STORAGE, respectivamente. A permissão de gravação permite implicitamente leitura, por isso, se você precisa escrever no armazenamento público, então você precisa solicitar apenas uma autorização:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...</manifest>
No entanto, se você gostaria que suas fotos para permanecessem no privado, só para o seu aplicativo, você pode passar a usar o diretório fornecido pela getExternalFilesDir(). No Android 4.3 e inferior, escrever neste diretório também exige a permissão WRITE_EXTERNAL_STORAGE. A partir do Android 4.4, a permissão não é mais necessária porque o diretório está acessível para outras aplicações, para que possa declarar a permissão deve ser solicitada apenas nas versões mais baixas do Android, adicionando o atributo maxSdkVersion:
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> ...</manifest>
Nota: Os arquivos que você salvar nos diretórios fornecidos pelo getExternalFilesDir() ou getFilesDir() serão apagados quando o usuário desinstalar a sua app.
Depois de decidir o diretório para o arquivo da foto, você precisa criar um nome de arquivo exclusivo e que não haja possibilidade de ser sobre-escrito. Você pode desejar também salvar o caminho em uma variável para uso posterior. Aqui está uma solução exemplo, em um método que retorna um nome de arquivo exclusivo para uma nova foto usando uma combinação de data e hora:
String mCurrentPhotoPath; private File createImageFile() throws IOException { // monta no nome para o arquivo de imagem String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); File image = File.createTempFile( imageFileName, /* prefixo */ ".jpg", /* sufixo*/ storageDir /* pasta*/ ); // salva o arquivo: caminho para usar com ACTION_VIEW mCurrentPhotoPath = "file:" + image.getAbsolutePath(); return image; }
Com este método disponível para criar um arquivo de foto, você pode agora criar e invocar um Intent como este:
static final int REQUEST_TAKE_PHOTO = 1; private void dispatchTakePictureIntent() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // Certifique-se de que há uma camera "activity" para lidar com a intent if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Criar o arquivo onde a foto deve ir File photoFile = null; try { photoFile = createImageFile(); } catch (IOException ex) { // Erro enquanto tentava criar o arquivo ... } // se o arquivo foi criado com sucesso continua if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(this, "com.example.android.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO); } } }
Nota: Nós estamos usando getUriForFile(Context, String, File) que retorna um content:// URI.Para aplicações mais recentes visando Android N e superior, passando a file:// URI entre um limite de pacote faz com que um FileUriExposedException. Portanto, apresentamos agora uma forma mais genérica de armazenamento de imagens usando um FileProvider.
Agora, você precisa configurar o FileProvider. No manifesto do aplicativo, adicionar um provedor para sua aplicação:
<application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.android.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data> </provider> ...</application>
Certifique-se de que a cadeia autoridades corresponde ao segundo argumento para getUriForFile(Context, String, File).Na seção de meta-dados da definição do fornecedor, você pode ver que o provedor espera caminhos elegíveis para ser configurado em um arquivo de recurso dedicado, res/xml/file_paths.xml. Aqui está o conteúdo necessário para este exemplo particular:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> </paths>
O componente do caminho corresponde ao caminho que é devolvido pelo getExternalFilesDir() quando chamado com Environment.DIRECTORY_PICTURES. Certifique-se de substituir com.example.package.name com o nome do pacote real do seu aplicativo. Além disso, confira a documentação de FileProvider para uma extensa descrição do caminho especifica que você pode usar além external-path.
Adicionando a Foto a galeria
Quando você cria uma foto através de uma intenção, você deve saber onde sua imagem está localizada, por isso você disse em primeiro lugar onde ela será salva. Para todos os outros, aplicativos talvez a maneira mais fácil de fazer a sua foto acessível é a partir de provedor de mídia do sistema.
Note: Se você salvou sua foto para o diretório fornecido pela getExternalFilesDir(), o scanner de mídia não pode acessar os arquivos porque eles são privados para a sua aplicação.
O seguinte método de exemplo demonstra como invocar scanner de mídia do sistema para adicionar sua foto ao banco de dados do Provedor de mídia, tornando-o disponível no aplicativo Gallery Android a outros aplicativos.
private void galleryAddPic() { Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); File f = new File(mCurrentPhotoPath); Uri contentUri = Uri.fromFile(f); mediaScanIntent.setData(contentUri); this.sendBroadcast(mediaScanIntent); }
Decodificar uma imagem dimensionada
Gerenciar várias imagens de tamanho normal pode ser complicado com a memória limitada. Se seu aplicativo em execução causar uma falta de memória após a exibição de apenas algumas imagens, você pode reduzir drasticamente a quantidade de heap dinâmica usada pela expansão do JPEG em uma matriz de memória que já está dimensionado para corresponder ao tamanho da exibição de destino. O seguinte exemplo demonstra o método desta técnica.
private void setPic() { // Obtém as dimensões para o View int targetW = mImageView.getWidth(); int targetH = mImageView.getHeight(); // Obtém as dimensões do bitmap BitmapFactory.Options bmOptions = new BitmapFactory.Options(); bmOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); int photoW = bmOptions.outWidth; int photoH = bmOptions.outHeight; // Determinar o quanto de reduzir a imagem int scaleFactor = Math.min(photoW/targetW, photoH/targetH); // Decodificar o arquivo de imagem em um tamanho de bitmap para preencher o view bmOptions.inJustDecodeBounds = false; bmOptions.inSampleSize = scaleFactor; bmOptions.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); mImageView.setImageBitmap(bitmap); }
Baseado nas informações do site oficial do Android Development
Nenhum comentário:
Postar um comentário