Search code examples
androidandroid-studioviewandroid-canvasundo-redo

Undo inside canvas for Image sketch


I am using above code for undo but canvas can not update by calling this method. I have created DrawingView class for sketch feature i just need do Undo for every functionality like, 1. Smoothline 2.Rectangle 3.Circle 4.Straight line etc.

public class DrawingView extends View {

    protected Path mPath = new Path();
    public static Paint mPaint;
    protected Bitmap mBitmap;
    public static Canvas mCanvas;
    public int TOUCH_TOLERANCE = 5;
    public static int lineThickness = 5;
    public static int mCurrentShape;
    public boolean isDrawing = false;
    float mx,my,mStartX,mStartY;

    private int stateToSave;

    public static Paint mPaintErase = new Paint();
    protected Path mPathErase = new Path();

    private ArrayList<Path> paths = new ArrayList<Path>();
    private ArrayList<Path> undonePaths = new ArrayList<Path>();

    public DrawingView(Context context) {
        super(context);
        init();
        EraseLine();
    }

    public DrawingView(Context context,AttributeSet attrs)
    {
        super(context, attrs);
        init();
        EraseLine();
    }



    /**
     * Create Path from Event.
     * @param event
     * @return
     */
    private Path createPath(MotionEvent event) {
        Path path = new Path();

        // Save for ACTION_MOVE
        this.mStartX = event.getX();
        this.mStartY = event.getY();

        path.moveTo(this.mStartX, this.mStartY);

        return path;
    }


    protected void init()
    {
        mPaint = new Paint(Paint.DITHER_FLAG);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(getContext().getResources().getColor(R.color.colorYellow));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(lineThickness);

        mPath = new Path();
        paths.add(mPath);
    }

    public Bitmap getBitmap()
    {
        this.setDrawingCacheEnabled(true);
        this.buildDrawingCache();
        Bitmap bmp = Bitmap.createBitmap(this.getDrawingCache());
        this.setDrawingCacheEnabled(false);

        return bmp;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        mx = event.getX();
        my = event.getY();

        switch (mCurrentShape)
        {
            case 1:
                onTouchEventSmoothLine(event);
                break;

            case 2:

                onTouchEventErase(event);
                break;

            case 3:

                onTouchEventLine(event);
                break;

            case 4:

                onTouchEventCircle(event);
                break;

            case 5:

                onTouchEventRectangle(event);
                break;

            case 6:

                break;

            default:
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap(mBitmap, 0, 0, mPaint);

        if (isDrawing)
        {
            switch (mCurrentShape)
            {
                case 1:

                    break;

                case 2:

                 //   EraseLine();
                    break;

                case 3:

                    onDrawLine(canvas);
                    break;

                case 4:

                    onDrawCircle(canvas);
                    break;

                case 5:

                    onDrawRectangle(canvas);
                    break;

                case 6:

                    onDrawSmoothLine(canvas);
                    break;

                default:
                    break;
            }
        }
    }

    //------------------------------------------------------------------
    // Rectangle
    //------------------------------------------------------------------
    private void onTouchEventRectangle(MotionEvent event) {

        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:

                isDrawing = true;
                mStartX = mx;
                mStartY = my;
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:

                invalidate();
                break;

            case MotionEvent.ACTION_UP:

                isDrawing = false;
                drawRectangle(mCanvas,mPaint);
                invalidate();
                break;
        }
    }

    private void onDrawRectangle(Canvas canvas) {
        drawRectangle(canvas, mPaint);
    }

    private void drawRectangle(Canvas canvas,Paint paint){
        float right = mStartX > mx ? mStartX : mx;
        float left = mStartX > mx ? mx : mStartX;
        float bottom = mStartY > my ? mStartY : my;
        float top = mStartY > my ? my : mStartY;
        canvas.drawRect(left, top, right, bottom, paint);
    }

    //------------------------------------------------------------------
    // Circle
    //------------------------------------------------------------------
    private void onDrawCircle(Canvas canvas) {
        canvas.drawCircle(mStartX, mStartY, calculateRadius(mStartX, mStartY, mx, my), mPaint);
    }

    private void onTouchEventCircle(MotionEvent event)
    {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                isDrawing = true;
                mStartX = mx;
                mStartY = my;
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                isDrawing = false;
                mCanvas.drawCircle(mStartX, mStartY,
                        calculateRadius(mStartX,mStartY,mx,my),mPaint);
                invalidate();
                break;

            default:
                break;
        }
    }

    /**
     * @return
     */
    protected float calculateRadius(float x1, float y1, float x2, float y2) {

        return (float) Math.sqrt(
                Math.pow(x1 - x2, 2) +
                        Math.pow(y1 - y2, 2)
        );
    }

    //------------------------------------------------------------------
    // Line
    //------------------------------------------------------------------
    private void onDrawLine(Canvas canvas) {

        float dx = Math.abs(mx - mStartX);
        float dy = Math.abs(my - mStartY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
        {
            canvas.drawLine(mStartX, mStartY, mx, my, mPaint);
        }
    }

    private void onTouchEventLine(MotionEvent event) {

        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                isDrawing = true;
                mStartX = mx;
                mStartY = my;
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                isDrawing = false;
                mCanvas.drawLine(mStartX, mStartY, mx, my, mPaint);
                invalidate();
                break;
        }
    }

    //------------------------------------------------------------------
    // Smooth Line
    //------------------------------------------------------------------
    private void onDrawSmoothLine(Canvas canvas)
    {
        for (Path p : paths)
        {
            canvas.drawPath(p, mPaint);
        }
    }

    private void onTouchEventSmoothLine(MotionEvent event)
    {

        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                isDrawing = true;
                mStartX = mx;
                mStartY = my;

                mPath.reset();
                mPath.moveTo(mx, my);

                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:

                float dx = Math.abs(mx - mStartX);
                float dy = Math.abs(my - mStartY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    mPath.quadTo(mStartX, mStartY, (mx + mStartX) / 2, (my + mStartY) / 2);
                    mStartX = mx;
                    mStartY = my;
                }
                mCanvas.drawPath(mPath, mPaint);
                invalidate();
                break;

            case MotionEvent.ACTION_UP:
                isDrawing = false;
                mPath.lineTo(mStartX, mStartY);
                mCanvas.drawPath(mPath, mPaint);
                mPath.reset();
                paths.add(mPath);
                invalidate();
                break;
        }
    }

    //------------------------------------------------------------------
    // Erase Line
    //------------------------------------------------------------------
    public void EraseLine()
    {
        mPaintErase.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        mPaintErase.setColor(Color.TRANSPARENT);
        mPaintErase.setAntiAlias(true);
        mPaintErase.setDither(true);
        mPaintErase.setStyle(Paint.Style.STROKE);
        mPaintErase.setStrokeJoin(Paint.Join.ROUND);
        mPaintErase.setStrokeCap(Paint.Cap.ROUND);
        mPaintErase.setStrokeWidth(lineThickness);
    }

    private void onTouchEventErase(MotionEvent event)
    {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:

                isDrawing = true;
                mStartX = mx;
                mStartY = my;
                mPathErase.reset();
                mPathErase.moveTo(mx, my);
                invalidate();
                break;

            case MotionEvent.ACTION_MOVE:

                float dx = Math.abs(mx - mStartX);
                float dy = Math.abs(my - mStartY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    mPathErase.quadTo(mStartX, mStartY, (mx + mStartX) / 2, (my + mStartY) / 2);
                    mStartX = mx;
                    mStartY = my;
                }
                mCanvas.drawPath(mPathErase, mPaintErase);
                invalidate();
                break;

            case MotionEvent.ACTION_UP:

                isDrawing = false;
                mPathErase.lineTo(mStartX, mStartY);
                mCanvas.drawPath(mPathErase, mPaintErase);
                mPathErase.reset();
                invalidate();
                break;
        }
    }

    /**
     * Undo functionality.
     */
    public void onClickUndo ()
    {
        if (paths.size()>0)
        {
            paths.remove(paths.size()-1);
            invalidate();
        }
        else
        {
            Toast.makeText(getContext().getApplicationContext(),"Undo not found.",Toast.LENGTH_SHORT).show();
        }
        //toast the user
    }

    @Override
    public Parcelable onSaveInstanceState() {
        //begin boilerplate code that allows parent classes to save state
        Parcelable superState = super.onSaveInstanceState();

        SavedState ss = new SavedState(superState);
        //end

        ss.stateToSave = this.stateToSave;

        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        //begin boilerplate code so parent classes can restore state
        if(!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState)state;
        super.onRestoreInstanceState(ss.getSuperState());
        //end

        this.stateToSave = ss.stateToSave;
    }

    static class SavedState extends BaseSavedState {
        int stateToSave;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            this.stateToSave = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(this.stateToSave);
        }

        //required field that makes Parcelables from a Parcel
        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }
                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

Solution

  • Here I have found the solutions and Its working properly.

    Please check this code for Pen, Line , Circle , Rectangle and Undo feature for Sketch over image :

    package com.thefinal3.Sketch;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.os.Parcel;
    import android.os.Parcelable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.Toast;
    
    import com.thefinal3.Bean.PathBean;
    import com.thefinal3.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by Akash patel on 11-04-2016.
     */
    public class DrawingView extends View {
    
        protected Path mPath = new Path();
        public static Paint mPaint;
        protected Bitmap mBitmap;
        public static Canvas mCanvas;
        public int TOUCH_TOLERANCE = 5;
        public static int lineThickness = 5;
        public static int ColorStroke;
        public static int mCurrentShape;
        public boolean isDrawing = false;
        float mx,my,mStartX,mStartY;
    
        private int stateToSave;
    
        public static Paint mPaintErase = new Paint();
        public static Paint mPaintBitmap;
        protected Path mPathErase = new Path();
        Context context;
    
        private ArrayList<PathBean> paths = new ArrayList<PathBean>();
    
        public DrawingView(Context context,AttributeSet attrs)
        {
            super(context, attrs);
            setFocusable(true);
            setFocusableInTouchMode(true);
            init();
            EraseLine();
            this.context = context;
        }
    
        protected void init()
        {
            mPaint = new Paint(Paint.DITHER_FLAG);
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(getContext().getResources().getColor(R.color.colorYellow));
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(lineThickness);
    
            ColorStroke = mPaint.getColor();
            lineThickness = (int)mPaint.getStrokeWidth();
            mCanvas = new Canvas();
        }
    
        public Bitmap getBitmap()
        {
            this.setDrawingCacheEnabled(true);
            this.buildDrawingCache();
            Bitmap bmp = Bitmap.createBitmap(this.getDrawingCache());
            this.setDrawingCacheEnabled(false);
    
            return bmp;
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
          //  mCanvas.setBitmap(mBitmap);
            mCanvas = new Canvas(mBitmap);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            mx = event.getX();
            my = event.getY();
    
            switch (mCurrentShape)
            {
                case 1:
                    onTouchEventSmoothLine(event);
                    break;
    
                case 2:
    
               //     onTouchEventErase(event);
                    break;
    
                case 3:
    
                    onTouchEventLine(event);
                    break;
    
                case 4:
    
                    onTouchEventCircle(event);
                    break;
    
                case 5:
    
                    onTouchEventRectangle(event);
                    break;
    
                default:
                    break;
            }
            return true;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            for (PathBean p : paths)
            {
                mPaint.setColor(p.getColor());
                mPaint.setStrokeWidth(p.getLineWidthStroke());
                switch (p.getDrawingType())
                {
                    case 1:
    
                        canvas.drawPath(p.getmPath(), mPaint);
                        Log.e("onDraw ;-->", "Path Called...");
                        break;
    
                    case 2:
    
                        break;
    
                    case 3:
    
                        float dx1 = Math.abs(p.getMx() - p.getmStartX());
                        float dy1 = Math.abs(p.getMy() - p.getmStartY());
                        if (dx1 >= TOUCH_TOLERANCE || dy1 >= TOUCH_TOLERANCE)
                        {
                            canvas.drawLine(p.getmStartX(), p.getmStartY(), p.getMx(), p.getMy(), mPaint);
                            Log.e("onDraw ;-->", "Line Called...");
                        }
                        break;
    
                    case 4:
    
                        canvas.drawCircle(p.getmStartX(), p.getmStartY(), calculateRadius(p.getmStartX(), p.getmStartY(), p.getMx(), p.getMy()), mPaint);
                        break;
    
                    case 5:
    
                        float right = p.getmStartX() > p.getMx() ? p.getmStartX() : p.getMx();
                        float left = p.getmStartX() > p.getMx() ? p.getMx() : p.getmStartX();
                        float bottom =  p.getmStartY() > p.getMy() ?  p.getmStartY() : p.getMy();
                        float top =  p.getmStartY() > p.getMy() ? p.getMy() :  p.getmStartY();
                        canvas.drawRect(left, top, right, bottom,mPaint);
                        break;
    
                    default:
                        break;
                }
            }
            mPaint.setColor(ColorStroke);
            mPaint.setStrokeWidth(lineThickness);
    
            if (isDrawing)
            {
                switch (mCurrentShape)
                {
                    case 1:
    
                        canvas.drawPath(mPath, mPaint);
                        break;
    
                    case 2:
    
                        break;
    
                    case 3:
    
                        onDrawLine(canvas);
                        break;
    
                    case 4:
    
                        onDrawCircle(canvas);
                        break;
    
                    case 5:
    
                        onDrawRectangle(canvas);
                        break;
    
                    default:
                        break;
                }
            }
        }
    
        //------------------------------------------------------------------
        // Rectangle
        //------------------------------------------------------------------
        private void onTouchEventRectangle(MotionEvent event) {
    
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
    
                    isDrawing = true;
                    mStartX = mx;
                    mStartY = my;
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
    
                    isDrawing = false;
                    drawRectangle(mCanvas,mPaint);
                    PathBean bean = new PathBean();
                    bean.setColor(ColorStroke);
                    bean.setLineWidthStroke(lineThickness);
                    bean.setmStartX(mStartX);
                    bean.setmStartY(mStartY);
                    bean.setMx(mx);
                    bean.setMy(my);
                    bean.setDrawingType(5);
                    paths.add(bean);
                    invalidate();
                    break;
            }
        }
    
        private void onDrawRectangle(Canvas canvas) {
            drawRectangle(canvas, mPaint);
        }
    
        private void drawRectangle(Canvas canvas,Paint paint){
            float right = mStartX > mx ? mStartX : mx;
            float left = mStartX > mx ? mx : mStartX;
            float bottom = mStartY > my ? mStartY : my;
            float top = mStartY > my ? my : mStartY;
            canvas.drawRect(left, top, right, bottom, paint);
        }
    
        //------------------------------------------------------------------
        // Circle
        //------------------------------------------------------------------
        private void onDrawCircle(Canvas canvas) {
            canvas.drawCircle(mStartX, mStartY, calculateRadius(mStartX, mStartY, mx, my), mPaint);
        }
    
        private void onTouchEventCircle(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
    
                    isDrawing = true;
                    mStartX = mx;
                    mStartY = my;
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
    
                    isDrawing = false;
                    mCanvas.drawCircle(mStartX, mStartY,
                            calculateRadius(mStartX, mStartY, mx, my), mPaint);
                    PathBean bean = new PathBean();
                    bean.setColor(ColorStroke);
                    bean.setLineWidthStroke(lineThickness);
                    bean.setmStartX(mStartX);
                    bean.setmStartY(mStartY);
                    bean.setMx(mx);
                    bean.setMy(my);
                    bean.setDrawingType(4);
                    paths.add(bean);
                    invalidate();
                    break;
    
                default:
                    break;
            }
        }
    
        /**
         * @return
         */
        protected float calculateRadius(float x1, float y1, float x2, float y2) {
    
            return (float) Math.sqrt(
                    Math.pow(x1 - x2, 2) +
                            Math.pow(y1 - y2, 2)
            );
        }
    
        //------------------------------------------------------------------
        // Line
        //------------------------------------------------------------------
        private void onDrawLine(Canvas canvas) {
    
            float dx = Math.abs(mx - mStartX);
            float dy = Math.abs(my - mStartY);
            if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
            {
                canvas.drawLine(mStartX, mStartY, mx, my, mPaint);
            }
        }
    
        private void onTouchEventLine(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
    
                    isDrawing = true;
                    mStartX = mx;
                    mStartY = my;
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
    
                    isDrawing = false;
                    mCanvas.drawLine(mStartX, mStartY, mx, my, mPaint);
                    PathBean bean = new PathBean();
                    bean.setColor(ColorStroke);
                    bean.setLineWidthStroke(lineThickness);
                    bean.setmStartX(mStartX);
                    bean.setmStartY(mStartY);
                    bean.setMx(mx);
                    bean.setMy(my);
                    bean.setDrawingType(3);
                    paths.add(bean);
                    invalidate();
                    break;
            }
        }
    
        //------------------------------------------------------------------
        // Smooth Line
        //------------------------------------------------------------------
        private void onDrawSmoothLine(Canvas canvas) {
    
            for (PathBean p : paths)
            {
                mPaint.setColor(p.getColor());
                canvas.drawPath(p.getmPath(), mPaint);
            }
            mPaint.setColor(ColorStroke);
            canvas.drawPath(mPath, mPaint);
        }
    
        private void onTouchEventSmoothLine(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
    
                    isDrawing = true;
                    mStartX = mx;
                    mStartY = my;
    
                    mPath.reset();
                    mPath.moveTo(mx, my);
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    float dx = Math.abs(mx - mStartX);
                    float dy = Math.abs(my - mStartY);
                    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                        mPath.quadTo(mStartX, mStartY, (mx + mStartX) / 2, (my + mStartY) / 2);
                        mStartX = mx;
                        mStartY = my;
                    }
                    mCanvas.drawPath(mPath, mPaint);
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
                    isDrawing = false;
                    mPath.lineTo(mStartX, mStartY);
                    mCanvas.drawPath(mPath, mPaint);
             //       mPath.reset();
                    PathBean bean = new PathBean();
                    bean.setmPath(mPath);
                    bean.setColor(mPaint.getColor());
                    bean.setLineWidthStroke((int)mPaint.getStrokeWidth());
                    bean.setDrawingType(1);
                    paths.add(bean);
                    mPath = new Path();
                    invalidate();
                    break;
            }
        }
    
        //------------------------------------------------------------------
        // Erase Line
        //------------------------------------------------------------------
        public void EraseLine()
        {
            mPaintErase.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mPaintErase.setColor(Color.TRANSPARENT);
            mPaintErase.setAntiAlias(true);
            mPaintErase.setDither(true);
            mPaintErase.setStyle(Paint.Style.STROKE);
            mPaintErase.setStrokeJoin(Paint.Join.ROUND);
            mPaintErase.setStrokeCap(Paint.Cap.ROUND);
            mPaintErase.setStrokeWidth(lineThickness);
    
            mPaintBitmap = new Paint(Paint.DITHER_FLAG);
        }
    
        private void onTouchEventErase(MotionEvent event)
        {
            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
    
                    isDrawing = true;
                    mStartX = mx;
                    mStartY = my;
                    mPathErase.reset();
                    mPathErase.moveTo(mx, my);
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_MOVE:
    
                    float dx = Math.abs(mx - mStartX);
                    float dy = Math.abs(my - mStartY);
                    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                        mPathErase.quadTo(mStartX, mStartY, (mx + mStartX) / 2, (my + mStartY) / 2);
                        mStartX = mx;
                        mStartY = my;
                    }
                    mCanvas.drawPath(mPathErase, mPaintErase);
                    invalidate();
                    break;
    
                case MotionEvent.ACTION_UP:
    
                    isDrawing = false;
                    mPathErase.lineTo(mStartX, mStartY);
                    mCanvas.drawPath(mPathErase, mPaintErase);
                 //   mPathErase.reset();
                    PathBean bean = new PathBean();
                    bean.setmPath(mPathErase);
                    bean.setLineWidthStroke(lineThickness);
                    bean.setDrawingType(2);
                    paths.add(bean);
                    mPathErase = new Path();
                    invalidate();
                    break;
            }
        }
    
        /**
         * Undo functionality.
         */
        public void onClickUndo ()
        {
            if (paths.size()>0)
            {
                paths.remove(paths.size()-1);
                invalidate();
            }
            else
            {
                Toast.makeText(getContext().getApplicationContext(),"There is no undo action found.",Toast.LENGTH_SHORT).show();
            }
        }
    
        @Override
        public Parcelable onSaveInstanceState() {
            //begin boilerplate code that allows parent classes to save state
            Parcelable superState = super.onSaveInstanceState();
    
            SavedState ss = new SavedState(superState);
            //end
    
            ss.stateToSave = this.stateToSave;
    
            return ss;
        }
    
        @Override
        public void onRestoreInstanceState(Parcelable state) {
            //begin boilerplate code so parent classes can restore state
            if(!(state instanceof SavedState)) {
                super.onRestoreInstanceState(state);
                return;
            }
    
            SavedState ss = (SavedState)state;
            super.onRestoreInstanceState(ss.getSuperState());
            //end
    
            this.stateToSave = ss.stateToSave;
        }
    
        static class SavedState extends BaseSavedState {
            int stateToSave;
    
            SavedState(Parcelable superState) {
                super(superState);
            }
    
            private SavedState(Parcel in) {
                super(in);
                this.stateToSave = in.readInt();
            }
    
            @Override
            public void writeToParcel(Parcel out, int flags) {
                super.writeToParcel(out, flags);
                out.writeInt(this.stateToSave);
            }
    
            //required field that makes Parcelables from a Parcel
            public static final Parcelable.Creator<SavedState> CREATOR =
                    new Parcelable.Creator<SavedState>() {
                        public SavedState createFromParcel(Parcel in) {
                            return new SavedState(in);
                        }
                        public SavedState[] newArray(int size) {
                            return new SavedState[size];
                        }
                    };
        }
    }