Java tutorial
/* * Copyright (C) 2017 Breno Marques * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package br.com.brolam.cloudvision.ui.helpers; import android.app.Activity; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.signature.StringSignature; import com.firebase.ui.storage.images.FirebaseImageLoader; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.ValueEventListener; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import br.com.brolam.cloudvision.R; import br.com.brolam.cloudvision.data.CloudVisionProvider; import br.com.brolam.cloudvision.data.models.DeletedFiles; import br.com.brolam.cloudvision.data.models.NoteVision; /** * Armazenar e recupear imagens no Firebase Storage. * @author Breno Marques * @version 1.00 * @since Release 01 */ public class ImagesHelper implements ValueEventListener { private static final String TAG = "ImagesHelper"; public static final int REQUEST_IMAGE_CAPTURE = 2000; //Informar a chave do Note Vision que est solicitando o armazenamento da image // {@see takeNoteVisionBackground} e {@see saveNoteVisionBackground} private static String requestImageNoteVisionKey = null; private Activity activity; private CloudVisionProvider cloudVisionProvider; private FirebaseStorage firebaseStorage; //Armazenar as solicitaes de armazenamentos para restourar os uploads //se a atividade for reconstruida. private static HashMap<String, String> notesVisionUploadsReference; private int noteVisionBackgroundWidth; private int noteVisionBackgroundHeight; public ImagesHelper(Activity activity, CloudVisionProvider cloudVisionProvider) { this.activity = activity; Resources resources = activity.getResources(); this.noteVisionBackgroundWidth = resources.getInteger(R.integer.note_vision_background_width); this.noteVisionBackgroundHeight = resources.getInteger(R.integer.note_vision_background_height); this.cloudVisionProvider = cloudVisionProvider; this.firebaseStorage = FirebaseStorage.getInstance(); if (notesVisionUploadsReference == null) { notesVisionUploadsReference = new HashMap<>(); } else { restoreStorageReference(); } } /** * Restaurar os uploads se a atividade for reconstruida. */ private void restoreStorageReference() { //Se o saveImageNoteVisonBackground for executado nesse mtodo, significa que a tela foi reconstruida, //provavelmente na rotao, dessa forma, necessrio salvar nesse mtodo. if (requestImageNoteVisionKey != null) { saveImageNoteVisonBackground(requestImageNoteVisionKey); } for (Map.Entry<String, String> map : this.notesVisionUploadsReference.entrySet()) { requestNoteVisionBackgroundPutFile(map.getKey()); } } /** * Realizar a solicitao do download ou recuperar a imagem do arquivo temporrio e exibir * em um ImageView para uma imagem de background Note Vision * @param noteVisionKey informar uma chave vlida. * @param noteVision informar um Note Vision vlido. * @param imageView informar um ImageView vlido. */ public void loadNoteVisionBackground(String noteVisionKey, HashMap noteVision, ImageView imageView) { //Endereo da imagem no Firebase Storage. String pathNoteVisionBackground = NoteVision.getBackgroundPath(this.cloudVisionProvider.getUserId(), noteVisionKey); imageView.setImageBitmap(null); NoteVision.BackgroundOrigin backgroundOrigin = NoteVision.getBackground(noteVision); if (backgroundOrigin == NoteVision.BackgroundOrigin.LOCAL) { /** * Se o upload da imagem de background ainda no foi realizado, ser exibida * a imagem do arquivo temporrio. */ imageView.setImageURI(getImageUriFile(noteVisionKey)); //Relizar uma requisio de upload se ainda no existir uma requisio ativia. requestNoteVisionBackgroundPutFile(noteVisionKey); } else if (backgroundOrigin == NoteVision.BackgroundOrigin.REMOTE) { Glide.with(this.activity).using(new FirebaseImageLoader()) .load(this.firebaseStorage.getReference(pathNoteVisionBackground)) .diskCacheStrategy(DiskCacheStrategy.RESULT) //Quando uma imagem atualizado, uma nova assinatura deve ser criada //para o Glide tambm atualizar a imagem em cache. .signature(new StringSignature(NoteVision.getBackgroundSignature(noteVision))).into(imageView); } } /** * Realizar uma requisio de uma foto na camera fotogrfica nativa do Android para uma imagem * de background Note Vision. * @param noteVisionKey informar uma chave vlida. * @throws IOException */ public void takeNoteVisionBackground(String noteVisionKey) throws IOException { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) { //Informar o arquivo temporrio onde a imagem ser gravada. takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUriFileProvider(noteVisionKey)); //Informar a chave do Note Vision que ser recuperado no mtodo {@see saveNoteVisionBackground} requestImageNoteVisionKey = noteVisionKey; activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } } /* Acionar esse mtodo no onActivityResult da atividade para finalizar a confirmao da imagem. */ public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == activity.RESULT_OK) { if (requestImageNoteVisionKey != null) { saveImageNoteVisonBackground(requestImageNoteVisionKey); } } } /** * Salvar a imagens do Note Vision background. * @param noteVisionKey informar uma chave vlida. */ private void saveImageNoteVisonBackground(String noteVisionKey) { if (parseImageNoteVisionBackground(noteVisionKey)) { //Sinalizar que o Note Vision deve considerado uma imagem temporria. cloudVisionProvider.setNoteVisionBackground(noteVisionKey, NoteVision.BackgroundOrigin.LOCAL); //Realizar a requisio de upload da imagem. requestNoteVisionBackgroundPutFile(noteVisionKey); } requestImageNoteVisionKey = null; } /** * Realizar uma requisio de upload no Firebase Storage para uma imagem de background Note Vision. * @param noteVisionKey informar uma chave vlida. */ private void requestNoteVisionBackgroundPutFile(String noteVisionKey) { //Endereo da imagem no Firebase Storage. String pathNoteVisionBackground = NoteVision.getBackgroundPath(this.cloudVisionProvider.getUserId(), noteVisionKey); //Recuperar uma referncia para o arquivo no Firebase Storage e verificar se j //existe uma requisio ativa ou gerar uma nova requisio. StorageReference reference = firebaseStorage.getReference(pathNoteVisionBackground); if (reference != null) { List<UploadTask> activeUploadTasks = reference.getActiveUploadTasks(); UploadTask uploadTask = null; if (activeUploadTasks.size() > 0) { uploadTask = activeUploadTasks.get(0); } else { uploadTask = reference.putFile(getImageUriFileProvider(noteVisionKey)); } //Adicionar ouvintes para os eventos de falha e sucesso. uploadTask.addOnFailureListener(new OnFailureNoteVisionBackground(noteVisionKey)); uploadTask.addOnSuccessListener(new OnSuccessNoteVisionBackground(noteVisionKey)); //Atualizar a lista de requisies de upload. notesVisionUploadsReference.put(noteVisionKey, pathNoteVisionBackground); } } /** * Realizar uma requisio de excluso no Firebase Storage. * @param deletedFileKey informar uma chave vlida. */ private void requestDeleteFile(String deletedFileKey, String path) { //Recuperar uma referncia para o arquivo no Firebase Storage e verificar se j //existe uma requisio ativa ou gerar uma nova requisio. StorageReference reference = firebaseStorage.getReference(path); if (reference != null) { List<UploadTask> activeUploadTasks = reference.getActiveUploadTasks(); Task<Void> taskDelete = null; if (activeUploadTasks.size() == 0) { taskDelete = reference.delete(); //Adicionar ouvintes para os eventos de falha e sucesso. taskDelete.addOnFailureListener(new OnFailureDeletedFile(deletedFileKey)); taskDelete.addOnSuccessListener(new OnSuccessDeletedFile(deletedFileKey)); } } } /** * Monitorar os registros de arquivos deletados e solicitar a excluso no Firebase Storage. * @param dataSnapshot informar uma lista de {@link DeletedFiles} */ @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot deletedFile : dataSnapshot.getChildren()) { HashMap deletedFileValues = (HashMap) deletedFile.getValue(); String path = DeletedFiles.getPath(deletedFileValues); if (path != null) { requestDeleteFile(deletedFile.getKey(), path); } } } @Override public void onCancelled(DatabaseError databaseError) { } /** * Ouvinte para o evento de falha no upload de uma imagem de background Note Vision */ private class OnFailureNoteVisionBackground implements OnFailureListener { String noteVisionKey; public OnFailureNoteVisionBackground(String noteVisionKey) { this.noteVisionKey = noteVisionKey; } @Override public void onFailure(@NonNull Exception e) { notesVisionUploadsReference.remove(this.noteVisionKey); } } /** * Ouvinte para o evento de falha na excluso de um arquivo */ private class OnFailureDeletedFile implements OnFailureListener { String deletedFileKey; public OnFailureDeletedFile(String deletedFileKey) { this.deletedFileKey = deletedFileKey; } @Override public void onFailure(@NonNull Exception e) { if (e.getMessage().indexOf("Object does not exist") > -1) { cloudVisionProvider.deleteDeletedFile(deletedFileKey); } } } /** * Ouvinte para o evento de sucesso no upload de uma imagem de background Note Vision */ private class OnSuccessNoteVisionBackground implements OnSuccessListener<UploadTask.TaskSnapshot> { String noteVisionKey; public OnSuccessNoteVisionBackground(String noteVisionKey) { this.noteVisionKey = noteVisionKey; } @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { if (deleteImage(getImageUriFile(this.noteVisionKey).getPath())) { notesVisionUploadsReference.remove(this.noteVisionKey); cloudVisionProvider.setNoteVisionBackground(this.noteVisionKey, NoteVision.BackgroundOrigin.REMOTE); } ; } } /** * Ouvinte para o evento de sucesso na excluso no upload de uma imagem de background Note Vision */ private class OnSuccessDeletedFile implements OnSuccessListener<Void> { String deletedFileKey; public OnSuccessDeletedFile(String deletedFileKey) { this.deletedFileKey = deletedFileKey; } @Override public void onSuccess(Void aVoid) { cloudVisionProvider.deleteDeletedFile(deletedFileKey); } } /** * Reduzir o tamanho de uma imagem e atualizar o arquivo da imagem. * @param filepath informar o endereo completo da imagem * @param width informar a largura em pixel * @param height informar a altura em pixels * @throws IOException */ private void resizeImage(String filepath, int width, int height) throws IOException { //Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath), 720, 1280, true); Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath), width, height, true); File imageFile = new File(filepath); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); byte[] data = byteArrayOutputStream.toByteArray(); FileOutputStream outputStream = new FileOutputStream(imageFile); outputStream.write(data); outputStream.close(); } /** * Excluir o arquivo de uma imagem. * @param filepath informar o endereo completo da imagem * @return Verdadeiro se a excluso for realizada com sucesso. */ private boolean deleteImage(String filepath) { File file = new File(filepath); return file.delete(); } /** * Recuperar o endereo no File Provider conforme a chave de um Note Vision. * @param noteVisionKey informar uma chave vlida. * @return Uri com o endereo da imagem no File Provider. */ private Uri getImageUriFileProvider(String noteVisionKey) { File imageFile = new File(getImageUriFile(noteVisionKey).getPath()); return FileProvider.getUriForFile(this.activity, "br.com.brolam.cloudvision.fileprovider", imageFile); } /** * Recuperar o endereo fisico do arquivo de imagem conforme uma chave. * @param key informar uma chave vlida. * @return Uri com o endereo fisico do arquvio da imagem. */ private Uri getImageUriFile(String key) { File storageDir = this.activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES); return Uri.parse(String.format("%s/%s.jpg", storageDir, key)); } /** * Analisar e validar uma imagem de background para um Note Vision. * @param noteVisionKey * @return verdadeiro se a imagem for vlida. */ private boolean parseImageNoteVisionBackground(String noteVisionKey) { Uri imageUri = getImageUriFile(noteVisionKey); File imageFile = new File(imageUri.getPath()); if (imageFile.exists()) { //Reduzir o tamanho de imagens acima de 1MB. if (imageFile.getTotalSpace() > 1048576) { //Tentar reduzir o tamanho da imagem. try { resizeImage(imageUri.getPath(), noteVisionBackgroundWidth, noteVisionBackgroundHeight); } catch (IOException e) { e.printStackTrace(); } } else if (imageFile.getTotalSpace() == 0) { //Excluir a imagem se a mesma no for vlida. imageFile.delete(); return false; } return true; } ; return false; } }