edu.mum.ml.group7.guessasketch.android.EasyPaint.java Source code

Java tutorial

Introduction

Here is the source code for edu.mum.ml.group7.guessasketch.android.EasyPaint.java

Source

/*
 * Copyright (C) 2014, 2016 Valerio Bozzolan & James Dearing (TheOpenSourceNinja)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.mum.ml.group7.guessasketch.android;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.net.Uri;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.InputType;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout.LayoutParams;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.FileEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

@SuppressLint("ClickableViewAccessibility")
public class EasyPaint extends GraphicsActivity implements ColorPickerDialog.OnColorChangedListener {

    enum ApiCallType {
        GUESS_IMAGE, POSITIVE_FEEDBACK, NEGATIVE_FEEDBACK
    }

    public static int DEFAULT_BRUSH_SIZE = 10;
    private static int MAX_POINTERS = 10;
    private static final float TOUCH_TOLERANCE = 4;

    private Paint mPaint;
    private MaskFilter mEmboss;
    private MaskFilter mBlur;
    private boolean doubleBackToExitPressedOnce = false;
    private static final int CHOOSE_IMAGE = 0;
    private MyView contentView;

    private boolean waitingForBackgroundColor = false; //If true and colorChanged() is called, fill the background, else mPaint.setColor()
    private boolean extractingColor = false; //If this is true, the next touch event should extract a color rather than drawing a line.
    private float pixels5 = 0.f;
    private LinearLayout predictions;
    ProgressBar loader;
    Button saveButton;
    View.OnClickListener otherLabelOnClickListener;
    ApiCallType feedbackType = ApiCallType.POSITIVE_FEEDBACK;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // it removes the title from the actionbar(more space for icons?)
        // this.getActionBar().setDisplayShowTitleEnabled(false);

        pixels5 = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        LinearLayout parent = new LinearLayout(this);

        parent.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        parent.setOrientation(LinearLayout.VERTICAL);

        LinearLayout scrollViewParent = new LinearLayout(this);

        scrollViewParent.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        scrollViewParent.setOrientation(LinearLayout.HORIZONTAL);

        HorizontalScrollView predictionsHorizontalScrollView = new HorizontalScrollView(this);
        //predictionsHorizontalScrollView.setLayoutParams(new ViewGroup.LayoutParams());

        predictions = new LinearLayout(this);
        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        params.gravity = Gravity.CENTER_VERTICAL;
        predictions.setLayoutParams(params);

        predictions.setOrientation(LinearLayout.HORIZONTAL);

        resetPredictionsView(predictions, true);
        predictionsHorizontalScrollView.addView(predictions);

        saveButton = new Button(this);
        saveButton.setText("Send Feedback");

        predictionsHorizontalScrollView.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 10.0f));

        saveButton.setLayoutParams(
                new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT, 1.0f));

        saveButton.setVisibility(View.INVISIBLE);

        FrameLayout frameLayout = new FrameLayout(this);
        frameLayout
                .setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
        frameLayout.addView(saveButton);

        loader = new ProgressBar(this);
        loader.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        loader.setIndeterminate(true);
        loader.setVisibility(ProgressBar.INVISIBLE);

        frameLayout.addView(loader);

        scrollViewParent.addView(predictionsHorizontalScrollView);
        scrollViewParent.addView(frameLayout);

        contentView = new MyView(this);
        parent.addView(scrollViewParent);
        parent.addView(contentView);

        setContentView(parent);

        otherLabelOnClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e("Clicked", "Other Label label '" + (String) view.getTag() + "'");
                sendScreenshot(false, feedbackType, (String) view.getTag());
            }
        };

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(DEFAULT_BRUSH_SIZE);

        // Where did these magic numbers come from? What do they mean? Can I change them? ~TheOpenSourceNinja
        // Absolutely random numbers in order to see the emboss. asd! ~Valerio
        mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);

        mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);

        if (isFirstTime()) {
            AlertDialog.Builder alert = new AlertDialog.Builder(this);

            alert.setTitle(R.string.app_name);
            alert.setMessage(R.string.app_description);
            alert.setNegativeButton(R.string.continue_button, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    Toast.makeText(getApplicationContext(), R.string.here_is_your_canvas, Toast.LENGTH_SHORT)
                            .show();
                }
            });

            alert.show();
        } else {
            Toast.makeText(getApplicationContext(), R.string.here_is_your_canvas, Toast.LENGTH_SHORT).show();
        }

        loadFromIntents();
    }

    private void resetPredictionsView(LinearLayout predictions, boolean showInitLabel) {

        predictions.removeAllViews();

        if (showInitLabel) {
            TextView tv1 = new TextView(this);
            tv1.setText("Predictions will appear Here");
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            params.weight = 1.f;
            params.gravity = Gravity.CENTER_VERTICAL;

            tv1.setLayoutParams(params);

            tv1.setTextSize(pixels5);
            predictions.addView(tv1);
        }

        if (saveButton != null)
            saveButton.setVisibility(View.INVISIBLE);
        if (loader != null)
            loader.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(this, R.string.press_back_again, Toast.LENGTH_SHORT).show();

        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, 3000);
    }

    public void colorChanged(int color) {
        if (waitingForBackgroundColor) {
            waitingForBackgroundColor = false;
            contentView.mBitmapBackground.eraseColor(color);
            //int[] colors = new int[ 1 ];
            //colors[ 0 ] = color;
            //contentView.mBitmapBackground = Bitmap.createBitmap( colors, contentView.mBitmapBackground.getWidth(), contentView.mBitmapBackground.getHeight(), contentView.mBitmapBackground.getConfig() );
        } else {
            mPaint.setColor(color);
        }
    }

    public void refreshLabels(JSONObject jObject) {

        /* Button btn = new Button(this);
          btn.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
        getResources().getDimensionPixelSize(R.dimen.prediction_text_view_height) ));
        btn.setTextSize(pixels);
        btn.setText("Cat");
        predictions.addView(btn); */
        final List<RadioButton> buttons = new ArrayList<>();

        String result = "I think it's: ";
        try {
            JSONArray jArray = jObject.getJSONArray("data");
            for (int i = 0; i < jArray.length(); i++) {
                JSONObject prediction = jArray.getJSONObject(i);
                // Pulling items from the array
                int score = prediction.getInt("score");
                if (score < Constants.minScoreThershold) {
                    continue;
                }
                String label = prediction.getString("label");

                result += "\"" + label + "\" : " + score + "% ";

                RadioButton radioButton = new RadioButton(EasyPaint.this);
                radioButton.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                        getResources().getDimensionPixelSize(R.dimen.prediction_text_view_height)));
                radioButton.setTextSize(pixels5);
                radioButton.setText(label + " (" + score + "%)");
                radioButton.setTag(label);
                //radioButton.set
                //predictions.addView(radioButton);
                radioButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        saveButton.setTag(view.getTag());
                        feedbackType = ApiCallType.POSITIVE_FEEDBACK;
                    }
                });

                buttons.add(radioButton);

            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

        final RadioButton radioButton = new RadioButton(EasyPaint.this);
        radioButton.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                getResources().getDimensionPixelSize(R.dimen.prediction_text_view_height)));
        radioButton.setTextSize(pixels5);
        radioButton.setText(R.string.other_label);
        buttons.add(radioButton);

        radioButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                AlertDialog.Builder builder = new AlertDialog.Builder(EasyPaint.this);
                builder.setTitle(R.string.other_label);

                // Set up the input
                final EditText input = new EditText(EasyPaint.this);
                // Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
                input.setInputType(InputType.TYPE_CLASS_TEXT);
                builder.setView(input);

                // Set up the buttons
                builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (input.getText().toString().length() > 0) {
                            radioButton.setText(input.getText().toString());
                            saveButton.setTag(input.getText().toString());
                            feedbackType = ApiCallType.NEGATIVE_FEEDBACK;
                        } else {
                            EasyPaint.this.runOnUiThread(new Runnable() {
                                public void run() {
                                    Toast.makeText(getApplicationContext(),
                                            "You didn't specify a name, try again please", Toast.LENGTH_LONG)
                                            .show();
                                }
                            });
                            saveButton.setTag("");
                            feedbackType = ApiCallType.POSITIVE_FEEDBACK;
                            dialog.cancel();
                        }
                    }
                });
                builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        saveButton.setTag("");
                        feedbackType = ApiCallType.POSITIVE_FEEDBACK;
                        dialog.cancel();
                    }
                });

                builder.show();
            }
        });

        saveButton.setOnClickListener(otherLabelOnClickListener);

        toastMessage = result;

        EasyPaint.this.runOnUiThread(new Runnable() {
            public void run() {
                resetPredictionsView(predictions, false);
                Toast.makeText(getApplicationContext(), toastMessage, Toast.LENGTH_LONG).show();
                for (RadioButton r : buttons) {
                    predictions.addView(r);
                }
            }
        });

    }

    private String toastMessage = "";

    public class MyView extends View {

        public Bitmap mBitmap;
        private Bitmap mBitmapBackground;
        private Canvas mCanvas;
        private Paint mBitmapPaint;
        private MultiLinePathManager multiLinePathManager;

        private class LinePath extends Path {
            private Integer idPointer;
            private float lastX;
            private float lastY;

            LinePath() {
                this.idPointer = null;
            }

            public float getLastX() {
                return lastX;
            }

            public float getLastY() {
                return lastY;
            }

            public void touchStart(float x, float y) {
                this.reset();
                this.moveTo(x, y);
                this.lastX = x;
                this.lastY = y;
            }

            public void touchMove(float x, float y) {
                float dx = Math.abs(x - lastX);
                float dy = Math.abs(y - lastY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    this.quadTo(lastX, lastY, (x + lastX) / 2, (y + lastY) / 2);
                    lastX = x;
                    lastY = y;
                }
            }

            public boolean isDisassociatedFromPointer() {
                return idPointer == null;
            }

            public boolean isAssociatedToPointer(int idPointer) {
                return this.idPointer != null && (int) this.idPointer == idPointer;
            }

            public void disassociateFromPointer() {
                idPointer = null;
            }

            public void associateToPointer(int idPointer) {
                this.idPointer = idPointer;
            }
        }

        private class MultiLinePathManager {
            public LinePath[] superMultiPaths;

            MultiLinePathManager(int maxPointers) {
                superMultiPaths = new LinePath[maxPointers];
                for (int i = 0; i < maxPointers; i++) {
                    superMultiPaths[i] = new LinePath();
                }
            }

            public LinePath findLinePathFromPointer(int idPointer) {
                for (LinePath superMultiPath : superMultiPaths) {
                    if (superMultiPath.isAssociatedToPointer(idPointer)) {
                        return superMultiPath;
                    }
                }
                return null;
            }

            public LinePath addLinePathWithPointer(int idPointer) {
                for (LinePath superMultiPath : superMultiPaths) {
                    if (superMultiPath.isDisassociatedFromPointer()) {
                        superMultiPath.associateToPointer(idPointer);
                        return superMultiPath;
                    }
                }
                return null;
            }
        }

        public MyView(Context c) {
            super(c);

            setId(R.id.CanvasId);
            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            mBitmapBackground = Bitmap.createBitmap(size.x, size.y - 30, Bitmap.Config.ARGB_8888);
            mBitmap = Bitmap.createBitmap(size.x, size.y - 30, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
            multiLinePathManager = new MultiLinePathManager(MAX_POINTERS);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(0xFFFFFFFF);
            canvas.drawBitmap(mBitmapBackground, 0, 0, new Paint());
            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
            for (int i = 0; i < multiLinePathManager.superMultiPaths.length; i++) {
                canvas.drawPath(multiLinePathManager.superMultiPaths[i], mPaint);
            }
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            LinePath linePath;
            int index;
            int id;
            int eventMasked = event.getActionMasked();
            switch (eventMasked) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN: {
                index = event.getActionIndex();
                id = event.getPointerId(index);

                if (extractingColor) { //If the user chose the 'extract color' menu option, the touch event indicates where they want to extract the color from.
                    extractingColor = false;

                    View v = findViewById(R.id.CanvasId);
                    v.setDrawingCacheEnabled(true);
                    Bitmap cachedBitmap = v.getDrawingCache();

                    int newColor = cachedBitmap.getPixel(Math.round(event.getX(index)),
                            Math.round(event.getY(index)));

                    v.destroyDrawingCache();
                    colorChanged(newColor);

                    Toast.makeText(getApplicationContext(), R.string.color_extracted, Toast.LENGTH_SHORT).show();
                } else {

                    linePath = multiLinePathManager.addLinePathWithPointer(id);
                    if (linePath != null) {
                        linePath.touchStart(event.getX(index), event.getY(index));
                    } else {
                        Log.e("Guess-a-sketch", "Too many fingers!");
                    }
                }

                resetPredictionsView(predictions, true);
                saveButton.setVisibility(View.INVISIBLE);
                loader.setVisibility(View.INVISIBLE);
                break;
            }
            case MotionEvent.ACTION_MOVE:
                for (int i = 0; i < event.getPointerCount(); i++) {
                    id = event.getPointerId(i);
                    index = event.findPointerIndex(id);
                    linePath = multiLinePathManager.findLinePathFromPointer(id);
                    if (linePath != null) {
                        linePath.touchMove(event.getX(index), event.getY(index));
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_CANCEL:
                index = event.getActionIndex();
                id = event.getPointerId(index);
                linePath = multiLinePathManager.findLinePathFromPointer(id);
                if (linePath != null) {
                    linePath.lineTo(linePath.getLastX(), linePath.getLastY());

                    // Commit the path to our offscreen
                    mCanvas.drawPath(linePath, mPaint);

                    // Kill this so we don't double draw
                    linePath.reset();

                    // Allow this LinePath to be associated to another idPointer
                    linePath.disassociateFromPointer();
                }
                break;
            }
            invalidate();
            return true;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        mPaint.setXfermode(null);
        mPaint.setAlpha(0xFF);

        switch (item.getItemId()) {
        case R.id.normal_brush_menu:
            mPaint.setShader(null);
            mPaint.setMaskFilter(null);
            return true;
        case R.id.color_menu:
            new ColorPickerDialog(this, this, mPaint.getColor()).show();
            return true;

        case R.id.size_menu: {
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View layout = inflater.inflate(R.layout.brush, (ViewGroup) findViewById(R.id.root));
            AlertDialog.Builder builder = new AlertDialog.Builder(this).setView(layout);
            builder.setTitle(R.string.choose_width);
            final AlertDialog alertDialog = builder.create();
            alertDialog.show();
            SeekBar sb = (SeekBar) layout.findViewById(R.id.brushSizeSeekBar);
            sb.setProgress(getStrokeSize());
            final TextView txt = (TextView) layout.findViewById(R.id.sizeValueTextView);
            txt.setText(
                    String.format(getResources().getString(R.string.your_selected_size_is), getStrokeSize() + 1));
            sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                public void onProgressChanged(SeekBar seekBar, final int progress, boolean fromUser) {
                    // Do something here with new value
                    mPaint.setStrokeWidth(progress);
                    txt.setText(
                            String.format(getResources().getString(R.string.your_selected_size_is), progress + 1));
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                    // TODO Auto-generated method stub
                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    // TODO Auto-generated method stub
                }
            });
            return true;
        }
        case R.id.erase_menu: {
            LayoutInflater inflater_e = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View layout_e = inflater_e.inflate(R.layout.brush, (ViewGroup) findViewById(R.id.root));
            AlertDialog.Builder builder_e = new AlertDialog.Builder(this).setView(layout_e);
            builder_e.setTitle(R.string.choose_width);
            final AlertDialog alertDialog_e = builder_e.create();
            alertDialog_e.show();
            SeekBar sb_e = (SeekBar) layout_e.findViewById(R.id.brushSizeSeekBar);
            sb_e.setProgress(getStrokeSize());
            final TextView txt_e = (TextView) layout_e.findViewById(R.id.sizeValueTextView);
            txt_e.setText(
                    String.format(getResources().getString(R.string.your_selected_size_is), getStrokeSize() + 1));
            sb_e.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                public void onProgressChanged(SeekBar seekBar, final int progress, boolean fromUser) {
                    // Do something here with new value
                    mPaint.setStrokeWidth(progress);
                    txt_e.setText(
                            String.format(getResources().getString(R.string.your_selected_size_is), progress + 1));
                }

                public void onStartTrackingTouch(SeekBar seekBar) {
                    // TODO Auto-generated method stub
                }

                public void onStopTrackingTouch(SeekBar seekBar) {
                    // TODO Auto-generated method stub
                }
            });
            mPaint.setShader(null);
            mPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
            return true;
        }
        case R.id.clear_all_menu: {
            contentView.mBitmap.eraseColor(Color.TRANSPARENT);
            if (predictions != null) {
                resetPredictionsView(predictions, true);
            }
            return true;
        }
        case R.id.save_menu:
            sendScreenshot(false, ApiCallType.GUESS_IMAGE, "");
            break;

        case R.id.about_menu:
            startActivity(new Intent(this, AboutActivity.class));
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * This takes the screenshot of the whole screen. Is this a good thing?
     */
    private File sendScreenshot(boolean showToast, ApiCallType callType, String label) {
        saveButton.setVisibility(View.INVISIBLE);
        loader.setVisibility(View.VISIBLE);

        View v = findViewById(R.id.CanvasId);
        v.setDrawingCacheEnabled(true);
        Bitmap cachedBitmap = v.getDrawingCache();
        Bitmap copyBitmap = toGrayscale(cachedBitmap.copy(Bitmap.Config.RGB_565, true));
        v.destroyDrawingCache();
        FileOutputStream output = null;
        File file = null;
        try {
            File path = Places.getScreenshotFolder();
            Calendar cal = Calendar.getInstance();

            file = new File(path,

                    cal.get(Calendar.YEAR) + "_" + (1 + cal.get(Calendar.MONTH)) + "_"
                            + cal.get(Calendar.DAY_OF_MONTH) + "_" + cal.get(Calendar.HOUR_OF_DAY) + "_"
                            + cal.get(Calendar.MINUTE) + "_" + cal.get(Calendar.SECOND) + ".jpg");
            output = new FileOutputStream(file);
            copyBitmap.compress(CompressFormat.JPEG, 60, output);
            sendPost(file, callType, label);

        } catch (FileNotFoundException e) {
            file = null;
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        if (file != null) {
            if (showToast)
                Toast.makeText(getApplicationContext(), String
                        .format(getResources().getString(R.string.saved_your_location_to), file.getAbsolutePath()),
                        Toast.LENGTH_LONG).show();
            /*
            // sending a broadcast to the media scanner so it will scan the new
            // screenshot.
            Intent requestScan = new Intent(
                Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            requestScan.setData(Uri.fromFile(file));
            sendBroadcast(requestScan); */

            return file;
        } else {
            return null;
        }
    }

    public Bitmap toGrayscale(Bitmap bmpOriginal) {
        int width, height;
        height = bmpOriginal.getHeight();
        width = bmpOriginal.getWidth();

        Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmpGrayscale);
        Paint paint = new Paint();
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
        paint.setColorFilter(f);
        c.drawBitmap(bmpOriginal, 0, 0, paint);
        return bmpGrayscale;
    }

    private void sendPost(final File file, final ApiCallType apiCallType, final String label) {

        AsyncTask<File, Void, String> task = new AsyncTask<File, Void, String>() {
            private boolean success_call = false;

            @Override
            protected void onCancelled() {
                super.onCancelled();
                if (apiCallType != ApiCallType.GUESS_IMAGE) {
                    resetPredictionsView(predictions, true);
                }
                if (success_call && apiCallType == ApiCallType.GUESS_IMAGE) {
                    saveButton.setVisibility(View.VISIBLE);
                }
                loader.setVisibility(View.INVISIBLE);

                file.delete();

            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                if (apiCallType != ApiCallType.GUESS_IMAGE) {
                    resetPredictionsView(predictions, true);
                }
                if (success_call && apiCallType == ApiCallType.GUESS_IMAGE) {
                    saveButton.setVisibility(View.VISIBLE);
                }
                loader.setVisibility(View.INVISIBLE);

                file.delete();

            }

            @Override
            protected String doInBackground(File... files) {
                String responseString = "";

                try {
                    String endpointURL = Constants.guessAPI;
                    String callType = "";
                    switch (apiCallType) {
                    case NEGATIVE_FEEDBACK:
                        callType = "neg";
                        break;
                    case POSITIVE_FEEDBACK:
                        callType = "pos";
                        break;
                    case GUESS_IMAGE:
                    default:
                        callType = "guess";

                    }
                    Log.e("sendPost", "Trying API " + endpointURL);
                    MultipartUtility multipart = new MultipartUtility(endpointURL, "utf8");

                    // label is only needed if we're sending pos/neg feedback
                    if (!callType.equals("guess")) {
                        multipart.addFormField("label", label);
                    }

                    multipart.addFormField("call_type", callType);
                    multipart.addFilePart("file", file);

                    String TAG = "upload";

                    List<String> response = multipart.finish();
                    Log.e(TAG, "SERVER REPLIED:");
                    for (String line : response) {
                        Log.e(TAG, "Upload Files Response:::" + line);
                        // get your server response here.
                        responseString += line;
                    }
                    success_call = true;
                } catch (final IOException e) {
                    e.printStackTrace();
                    Log.e("sendPost", e.getMessage());
                    EasyPaint.this.runOnUiThread(new Runnable() {
                        public void run() {
                            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
                        }
                    });

                    success_call = false;
                }

                try {
                    JSONObject jObject = new JSONObject(responseString);
                    if (apiCallType == ApiCallType.GUESS_IMAGE) {
                        refreshLabels(jObject);
                    } else {
                        EasyPaint.this.runOnUiThread(new Runnable() {
                            public void run() {
                                saveButton.setVisibility(View.INVISIBLE);
                                Toast.makeText(getApplicationContext(), R.string.feedback_submitted,
                                        Toast.LENGTH_LONG).show();

                            }
                        });
                    }

                } catch (final JSONException e) {
                    e.printStackTrace();
                    Log.e("sendPost", e.getMessage());
                    EasyPaint.this.runOnUiThread(new Runnable() {
                        public void run() {
                            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
                        }
                    });
                    success_call = false;
                }

                return responseString;

            }
        };

        task.execute(file);

    }

    private boolean isFirstTime() {
        SharedPreferences preferences = getPreferences(MODE_PRIVATE);
        boolean ranBefore = preferences.getBoolean("RanBefore", false);
        if (!ranBefore) {
            // first time
            SharedPreferences.Editor editor = preferences.edit();
            editor.putBoolean("RanBefore", true);
            editor.commit();
        }
        return !ranBefore;
    }

    private int getStrokeSize() {
        return (int) mPaint.getStrokeWidth();
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode != RESULT_CANCELED) { //"The resultCode will be RESULT_CANCELED if the activity explicitly returned that, didn't return any result, or crashed during its operation." (quote from https://developer.android.com/reference/android/app/Activity.html#onActivityResult(int,%20int,%20android.content.Intent) )
            switch (requestCode) {
            case CHOOSE_IMAGE: {
                setBackgroundUri(data.getData());
            }
            }
        }
    }

    public void setBackgroundUri(Uri uri) {
        if (uri == null) {
            return;
        }

        try {
            //I don't like loading both full-sized and reduced-size copies of the image (the larger copy can use a lot of memory), but I couldn't find any other way to do this.
            Bitmap fullsize = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
            Bitmap resized = Bitmap.createScaledBitmap(fullsize, contentView.mBitmap.getWidth(),
                    contentView.mBitmap.getHeight(), true);
            contentView.mBitmapBackground = resized;
            //contentView.mCanvas = new Canvas( contentView.mBitmapBackground );
        } catch (IOException exception) {
            //TODO: How should we handle this exception?
        }
    }

    public void loadFromIntents() {
        Intent intent = getIntent();
        String action = intent.getAction();
        String type = intent.getType();
        System.out.println("Intentoso " + action + " type " + type);
        if (Intent.ACTION_SEND.equals(action) && type != null) {
            if (type.startsWith("image/")) {
                setBackgroundUri((Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM));
            }

        }
    }
}