Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package de.ebuero.android.feedback.appfeedback;
- import android.Manifest;
- import android.app.Activity;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.pm.PackageManager;
- import android.database.Cursor;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Color;
- import android.graphics.Matrix;
- import android.media.ExifInterface;
- import android.net.Uri;
- import android.os.Build;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.support.annotation.NonNull;
- import android.support.v4.app.ActivityCompat;
- import android.support.v4.content.PermissionChecker;
- import android.support.v7.app.AlertDialog;
- import android.util.Log;
- import android.view.View;
- import android.view.inputmethod.InputMethodManager;
- import android.widget.CheckBox;
- import android.widget.EditText;
- import android.widget.ImageView;
- import android.widget.ListAdapter;
- import android.widget.RelativeLayout;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.afollestad.materialdialogs.MaterialDialog;
- import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter;
- import com.afollestad.materialdialogs.simplelist.MaterialSimpleListItem;
- import com.google.firebase.perf.FirebasePerformance;
- import com.google.firebase.perf.metrics.Trace;
- import com.google.firebase.storage.FirebaseStorage;
- import com.google.firebase.storage.StorageMetadata;
- import com.google.firebase.storage.StorageReference;
- import com.google.firebase.storage.StorageTask;
- import com.google.firebase.storage.UploadTask;
- import com.google.firebase.storage.UploadTask.TaskSnapshot;
- import de.ebuero.android.R;
- import de.ebuero.android.application.model.ApplicationState;
- import de.ebuero.android.common.Contextor;
- import de.ebuero.android.common.interfaces.RefreshableFragment;
- import de.ebuero.android.common.interfaces.UpdatableFragment;
- import de.ebuero.android.common.permission.PermissionUtil;
- import de.ebuero.android.common.permission.PreferencesUtil;
- import de.ebuero.android.common.tracking.TrackableEvent;
- import de.ebuero.android.common.ui.ArrayAdapterWithIcon;
- import de.ebuero.android.common.ui.TabMenuFragment;
- import de.ebuero.android.common.ui.Toaster;
- import de.ebuero.android.common.ui.dialogs.ProgressDialog;
- import de.ebuero.android.dayplanner.ui.PlanDayFragment_;
- import de.ebuero.android.dayplanner.ui.PlanDaySettingFragment_;
- import de.ebuero.android.feedback.appfeedback.AppFeedbackContract.Presenter;
- import de.ebuero.android.login.db.UserAccountDAO;
- import de.ebuero.android.login.model.UserAccount;
- import de.ebuero.android.settings.utils.LocaleHelper;
- import pl.aprilapps.easyphotopicker.DefaultCallback;
- import pl.aprilapps.easyphotopicker.EasyImage;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import org.androidannotations.annotations.AfterViews;
- import org.androidannotations.annotations.Background;
- import org.androidannotations.annotations.Bean;
- import org.androidannotations.annotations.Click;
- import org.androidannotations.annotations.EFragment;
- import org.androidannotations.annotations.InstanceState;
- import org.androidannotations.annotations.SystemService;
- import org.androidannotations.annotations.UiThread;
- import org.androidannotations.annotations.ViewById;
- import org.joda.time.DateTime;
- import static android.Manifest.permission.CAMERA;
- import static android.Manifest.permission.READ_CONTACTS;
- import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
- import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
- import static de.ebuero.android.common.tracking.TrackableActions.ATTACH_SCREEN_SHOT;
- import static de.ebuero.android.common.tracking.TrackableActions.LOAD_CALL_FORWARDING;
- /**
- * Created by Aemgtz on 3/30/2017 AD.
- */
- @EFragment(R.layout.fragment_app_feedback)
- public class AppFeedbackFragment extends TabMenuFragment implements UpdatableFragment,RefreshableFragment,AppFeedbackContract.View {
- @ViewById(R.id.message)
- protected EditText messageEditText;
- @ViewById(R.id.loading_layout) protected RelativeLayout loadingLayout;
- @ViewById(R.id.checkbox_idea) protected CheckBox ideaCheckbox;
- @ViewById(R.id.checkbox_problem) protected CheckBox problemCheckbox;
- @ViewById(R.id.checkbox_question) protected CheckBox questionCheckbox;
- @ViewById(R.id.checkbox_praise) protected CheckBox praiseCheckbox;
- @ViewById(R.id.screen_shot_1) protected RelativeLayout screenshot1;
- @ViewById(R.id.screen_shot_2) protected RelativeLayout screenshot2;
- @ViewById(R.id.screenshot_image_1) protected ImageView screenshotImage1;
- @ViewById(R.id.screenshot_image_2) protected ImageView screenshotImage2;
- @ViewById(R.id.add_screenshot) protected RelativeLayout addScreenshot;
- @ViewById(R.id.submit_textview) protected TextView submitTextView;
- @Bean
- protected Toaster mToaster;
- @Bean
- AppFeedbackPresenter mPresenter;
- @Bean
- UserAccountDAO mUserAccountDAO;
- @Bean
- ApplicationState applicationState;
- Trace myTrace;
- @SystemService
- protected InputMethodManager inputMethodManager;
- @InstanceState
- ArrayList<String> imageURLs = new ArrayList<>();
- @InstanceState
- ArrayList<Bitmap> images = new ArrayList<>();
- //@InstanceState
- UploadTask uploadTask;
- private static String kFirebaseStorageBucket = "gs://ebuero-android.appspot.com/";
- private String uri = "content://com.google.android";
- private int reqSize = 512;
- private ProgressDialog progressDialog;
- private StorageReference mStorageRef;
- private boolean isDestroy = false;
- @InstanceState
- Bundle mSavedInstanceState;
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- setRetainInstance(true);
- }
- @Override
- public void setPresenter(Presenter presenter) {
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mPresenter.setUp(this);
- FirebaseStorage.getInstance().setMaxUploadRetryTimeMillis(10*1000);
- mStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl(kFirebaseStorageBucket);
- }
- @AfterViews
- public void initialize() {
- progressDialog = new ProgressDialog(getFragmentManager());
- if (images.size() > 0) {
- screenshotImage1.setImageBitmap(images.get(0));
- screenshot1.setVisibility(View.VISIBLE);
- screenshot2.setVisibility(View.GONE);
- addScreenshot.setVisibility(View.VISIBLE);
- if (images.size() > 1){
- screenshotImage2.setImageBitmap(images.get(1));
- screenshot2.setVisibility(View.VISIBLE);
- addScreenshot.setVisibility(View.GONE);
- }
- } else {
- resetFeedbackInput();
- }
- }
- @UiThread
- @Override
- public void setLoadingIndicator(boolean active) {
- if (active){
- loadingLayout.setVisibility(View.VISIBLE);
- submitTextView.setEnabled(false);
- }else{
- loadingLayout.setVisibility(View.INVISIBLE);
- submitTextView.setEnabled(true);
- }
- }
- @UiThread
- @Override
- public void showErrorMessage(int message) {
- showToast(message);
- }
- @UiThread
- @Override
- public void showSuccessfullyMessage(int message) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme);
- builder.setTitle(R.string.send_feedback_sucess_title);
- builder.setMessage(R.string.feedback_success_text);
- builder.setPositiveButton(R.string.ok, (dialog, id) -> {
- });
- resetFeedbackInput();
- builder.show();
- }
- private void resetFeedbackInput(){
- ideaCheckbox.setChecked(false);
- problemCheckbox.setChecked(false);
- questionCheckbox.setChecked(false);
- praiseCheckbox.setChecked(false);
- imageURLs.clear();
- images.clear();
- messageEditText.setText("");
- progressDialog.dismiss();
- screenshot1.setVisibility(View.GONE);
- screenshot2.setVisibility(View.GONE);
- addScreenshot.setVisibility(View.VISIBLE);
- }
- @Click(R.id.submit_textview)
- protected void submitFeedback() {
- if (messageEditText.getText().toString().equals("")) {
- mToaster.showLongToast(R.string.information_not_complete);
- return;
- }
- StringBuilder text = new StringBuilder();
- text.append("Message: " + messageEditText.getText().toString());
- if (ideaCheckbox.isChecked() || problemCheckbox.isChecked() || questionCheckbox.isChecked() || praiseCheckbox.isChecked()) {
- text.append("\n\nTag: ");
- if (ideaCheckbox.isChecked()) {
- text.append("Idea, ");
- }
- if (problemCheckbox.isChecked()) {
- text.append("Problem, ");
- }
- if (questionCheckbox.isChecked()) {
- text.append("Question, ");
- }
- if (praiseCheckbox.isChecked()) {
- text.append("Praise, ");
- }
- text.delete(text.length() - 2, text.length());
- }
- for (String url : imageURLs) {
- if (url != null) {
- text.append("\n\nAttached file: " + url);
- }
- }
- Bundle bundle = new Bundle();
- bundle.putString("message",text.toString());
- trackEvent(TrackableEvent.FEEDBACK_SEND,bundle );
- inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
- mPresenter.sendAppFeedback(text.toString());
- }
- @Click(R.id.add_screenshot)
- protected void addScreenshot(){
- trackEvent(TrackableEvent.FEEDBACK_ADD_SCREEN_SHOT, null);
- showSelectingSourceDialog();
- }
- private void showSelectingSourceDialog() {
- final MaterialSimpleListAdapter adapter =
- new MaterialSimpleListAdapter(
- (dialog, index1, item) -> selectSourceClicked(dialog ,index1));
- adapter.add(
- new MaterialSimpleListItem.Builder(getContext())
- .content(getResources().getString(R.string.source_camera))
- .icon(R.drawable.ic_camera)
- .backgroundColor(Color.WHITE)
- .build());
- adapter.add(
- new MaterialSimpleListItem.Builder(getContext())
- .content(getResources().getString(R.string.source_gallery))
- .icon(R.drawable.ic_gallery)
- .backgroundColor(Color.WHITE)
- .build());
- new MaterialDialog.Builder(getContext()).adapter(adapter, null).show();
- }
- private void selectSourceClicked(MaterialDialog dialog, int which) {
- dialog.dismiss();
- if (which == 0) {
- checkCameraPermission();
- } else if (which == 1) {
- checkReadExternalPermission();
- }
- }
- private void checkReadExternalPermission() {
- PermissionUtil.checkPermission(getActivity(), READ_EXTERNAL_STORAGE, new PermissionUtil.PermissionAskListener() {
- @Override
- public void onNeedPermission() {
- requestPermissions(new String[]{READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE}, 0);
- }
- @Override
- public void onPermissionPreviouslyDenied() {
- requestPermissions(new String[]{READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE}, 0);
- }
- @Override
- public void onPermissionDisabled() {
- showPermissionDeniedMessage(R.string.no_permission);
- }
- @Override
- public void onPermissionGranted() {
- EasyImage.openGallery(AppFeedbackFragment.this, 0);
- }
- });
- }
- private void checkCameraPermission() {
- PermissionUtil.checkPermission(getActivity(), CAMERA, new PermissionUtil.PermissionAskListener() {
- @Override
- public void onNeedPermission() {
- requestPermissions(new String[]{CAMERA}, 0);
- }
- @Override
- public void onPermissionPreviouslyDenied() {
- requestPermissions(new String[]{CAMERA}, 0);
- }
- @Override
- public void onPermissionDisabled() {
- showPermissionDeniedMessage(R.string.no_permission);
- }
- @Override
- public void onPermissionGranted() {
- EasyImage.openCamera(AppFeedbackFragment.this, 0);
- }
- });
- }
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- if (permissions != null){
- if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
- if (permissions[0].equals(CAMERA)){
- EasyImage.openCamera(AppFeedbackFragment.this, 0);
- } else if (permissions[0].equals(READ_EXTERNAL_STORAGE)){
- EasyImage.openGallery(AppFeedbackFragment.this, 0);
- }
- }
- }
- }
- @Override
- public void updateFragment(Object data) {
- }
- @Override
- public void restartFragment() {
- }
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if ((resultCode != Activity.RESULT_OK)) {
- return;
- }
- EasyImage.handleActivityResult(requestCode, resultCode, data, getActivity(), new DefaultCallback() {
- @Override
- public void onImagePickerError(Exception e, EasyImage.ImageSource source, int type) {
- //Some error handling
- progressDialog.dismiss();
- Toast.makeText(getContext(),"Pick image fail",Toast.LENGTH_SHORT).show();
- return;
- }
- @Override
- public void onImagePicked(File imageFile, EasyImage.ImageSource source, int type) {
- Bitmap bitmap = null;
- try {
- myTrace = FirebasePerformance.getInstance().newTrace(ATTACH_SCREEN_SHOT);
- myTrace.start();
- progressDialog.show();
- bitmap = handleSamplingAndRotationBitmap(getContext(), Uri.fromFile(imageFile));
- uploadBitmap(bitmap);
- LocaleHelper.onAttach(Contextor.getInstance().getContext());
- } catch (IOException e) {
- Toast.makeText(getContext(),"Pick image fail",Toast.LENGTH_SHORT).show();
- progressDialog.dismiss();
- e.printStackTrace();
- }
- }
- @Override
- public void onCanceled(EasyImage.ImageSource source, int type) {
- super.onCanceled(source, type);
- progressDialog.dismiss();
- }
- });
- }
- @Background
- protected void uploadBitmap(final Bitmap bitmap) {
- UserAccount userAccount = mUserAccountDAO.findById(applicationState.currentUserId);
- StorageReference feedbackImageRef = mStorageRef.child("feedback-images/");
- DateTime today = DateTime.now();
- String imageName = "feedback_" + userAccount.getUsername() + "_" + today.toString() + "jpg";
- StorageReference imageRef = feedbackImageRef.child(imageName);
- StorageMetadata metadata = new StorageMetadata.Builder()
- .setContentType("image/jpg")
- .build();
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream);
- byte[] data = stream.toByteArray();
- imageRef.putBytes(data,metadata);
- uploadTask = imageRef.putBytes(data,metadata);
- StorageTask<TaskSnapshot> taskSnapshotStorageTask = uploadTask
- .addOnFailureListener(exception -> {
- // Handle unsuccessful uploads
- showToast(getResources().getString(R.string.no_network));
- progressDialog.dismiss();
- }).addOnSuccessListener(taskSnapshot -> {
- progressDialog.dismiss();
- imageRef.getDownloadUrl().addOnSuccessListener(uri -> {
- if (!isDestroy) setBitmap(bitmap,uri.toString());
- Log.d("AppFeedback",uri.toString());
- });
- });
- myTrace = FirebasePerformance.getInstance().newTrace(ATTACH_SCREEN_SHOT);
- myTrace.stop();
- }
- @UiThread
- protected void setBitmap(Bitmap bitmap, String url) {
- progressDialog.dismiss();
- images.add(bitmap);
- imageURLs.add(url);
- int index = images.size();
- switch (index) {
- case 1:
- screenshotImage1.setImageBitmap(bitmap);
- screenshot1.setVisibility(View.VISIBLE);
- addScreenshot.setVisibility(View.VISIBLE);
- break;
- case 2:
- screenshotImage2.setImageBitmap(bitmap);
- screenshot2.setVisibility(View.VISIBLE);
- addScreenshot.setVisibility(View.GONE);
- break;
- }
- }
- @Override
- public void refreshContent() {
- }
- @Click(R.id.screen_shot_1)
- protected void screenshot1Clicked(){
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme);
- builder.setMessage(R.string.remove_screenshot);
- builder.setPositiveButton(R.string.delete, (dialog, id) -> {
- trackEvent(TrackableEvent.FEEDBACK_REMOVE_SCREEN_SHOT, null);
- if (images.size() > 1){
- images.remove(0);
- imageURLs.remove(0);
- setScreenshots();
- }else{
- images.remove(0);
- imageURLs.remove(0);
- setScreenshots();
- }
- });
- builder.setNegativeButton(R.string.cancel, (dialog, id) -> {
- // User cancelled the dialog
- });
- builder.show();
- }
- @Click(R.id.screen_shot_2)
- protected void screenshot2Clicked(){
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme);
- builder.setMessage(R.string.remove_screenshot);
- builder.setPositiveButton(R.string.remove, (dialog, id) -> {
- trackEvent(TrackableEvent.FEEDBACK_REMOVE_SCREEN_SHOT, null);
- if (images.size() > 1){
- images.remove(1);
- imageURLs.remove(1);
- setScreenshots();
- }
- });
- builder.setNegativeButton(R.string.cancel, (dialog, id) -> {
- });
- builder.show();
- }
- private void setScreenshots(){
- screenshot1.setVisibility(View.GONE);
- screenshot2.setVisibility(View.GONE);
- addScreenshot.setVisibility(View.VISIBLE);
- for(int i = 0; i < images.size(); i++){
- if (i == 0){
- screenshot1.setVisibility(View.VISIBLE);
- Bitmap bitmap = images.get(i);
- screenshotImage1.setImageBitmap(bitmap);
- }
- if (i == 1){
- screenshot2.setVisibility(View.VISIBLE);
- Bitmap bitmap = images.get(i);
- screenshotImage2.setImageBitmap(bitmap);
- addScreenshot.setVisibility(View.GONE);
- }
- }
- }
- /**
- * This method is responsible for solving the rotation issue if exist. Also scale the images to
- * 1024x1024 resolution
- *
- * @param context The current context
- * @param selectedImage The Image URI
- * @return Bitmap image results
- * @throws IOException
- */
- public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
- throws IOException {
- int MAX_HEIGHT = 1024;
- int MAX_WIDTH = 1024;
- // First decode with inJustDecodeBounds=true to check dimensions
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
- BitmapFactory.decodeStream(imageStream, null, options);
- imageStream.close();
- // Calculate inSampleSize
- options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);
- // Decode bitmap with inSampleSize set
- options.inJustDecodeBounds = false;
- imageStream = context.getContentResolver().openInputStream(selectedImage);
- Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);
- img = rotateImageIfRequired(img, selectedImage, context);
- return img;
- }
- /**
- * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
- * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
- * the closest inSampleSize that will result in the final decoded bitmap having a width and
- * height equal to or larger than the requested width and height. This implementation does not
- * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
- * results in a larger bitmap which isn't as useful for caching purposes.
- *
- * @param options An options object with out* params already populated (run through a decode*
- * method with inJustDecodeBounds==true
- * @param reqWidth The requested width of the resulting bitmap
- * @param reqHeight The requested height of the resulting bitmap
- * @return The value to be used for inSampleSize
- */
- private static int calculateInSampleSize(BitmapFactory.Options options,
- int reqWidth, int reqHeight) {
- // Raw height and width of image
- final int height = options.outHeight;
- final int width = options.outWidth;
- int inSampleSize = 1;
- if (height > reqHeight || width > reqWidth) {
- // Calculate ratios of height and width to requested height and width
- final int heightRatio = Math.round((float) height / (float) reqHeight);
- final int widthRatio = Math.round((float) width / (float) reqWidth);
- // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
- // with both dimensions larger than or equal to the requested height and width.
- inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
- // This offers some additional logic in case the image has a strange
- // aspect ratio. For example, a panorama may have a much larger
- // width than height. In these cases the total pixels might still
- // end up being too large to fit comfortably in memory, so we should
- // be more aggressive with sample down the image (=larger inSampleSize).
- final float totalPixels = width * height;
- // Anything more than 2x the requested pixels we'll sample down further
- final float totalReqPixelsCap = reqWidth * reqHeight * 2;
- while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
- inSampleSize++;
- }
- }
- return inSampleSize;
- }
- /**
- * Rotate an image if required.
- *
- * @param img The image bitmap
- * @param selectedImage Image URI
- * @return The resulted Bitmap after manipulation
- */
- private static Bitmap rotateImageIfRequired(Bitmap img, Uri selectedImage, Context _mContext) throws IOException {
- InputStream input = _mContext.getContentResolver().openInputStream(selectedImage);
- ExifInterface ei;
- if (Build.VERSION.SDK_INT > 23)
- ei = new ExifInterface(input);
- else
- ei = new ExifInterface(selectedImage.getPath());
- int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
- switch (orientation) {
- case ExifInterface.ORIENTATION_ROTATE_90:
- return rotateImage(img, 90);
- case ExifInterface.ORIENTATION_ROTATE_180:
- return rotateImage(img, 180);
- case ExifInterface.ORIENTATION_ROTATE_270:
- return rotateImage(img, 270);
- default:
- return img;
- }
- }
- private static Bitmap rotateImage(Bitmap img, int degree) {
- Matrix matrix = new Matrix();
- matrix.postRotate(degree);
- Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
- img.recycle();
- return rotatedImg;
- }
- @Override
- public void onDestroy() {
- isDestroy = true;
- super.onDestroy();
- }
- @Override
- public void onResume() {
- super.onResume();
- if (progressDialog!=null){
- progressDialog.onResume();
- }
- }
- @Override
- public void onStop() {
- super.onStop();
- if (progressDialog!=null){
- progressDialog.onStop();
- }
- }
- }
Add Comment
Please, Sign In to add comment