Undo and Redo path in canvas
===

I have seen many examples of how to implement undo and redo feature in a drawn path of a canvas but i can´t make it works, here is my code:

Paint activity:

    public class Pintar extends View {
	private Bitmap mBitmap = null;
	Canvas mCanvas = null;
	public Path mPath = null;
	private float mX, mY;
	private int posicion = 0;
	private static final float TOLERANCE = 4;
	Display display;
	Context context;
	public ArrayList<Path> paths = new ArrayList<Path>();
    public ArrayList<Path> undonePaths = new ArrayList<Path>();
    
	public Pintar(Context context) {
		super(context);
		this.context = context;
		// obtener pantalla
		this.display = ((WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
		//

		this.mBitmap = Bitmap.createBitmap(this.display.getWidth(),
				this.display.getHeight(), Bitmap.Config.ARGB_8888);
		//

		this.mCanvas = new Canvas(this.mBitmap);
		this.mPath = new Path();
	}

	public int getPosicion() {
		return posicion;
	}

	public void setPosicion(int posicion) {
		this.posicion = posicion;
	}

	public void establecerFondo(int posicion, int tipoFondo) {
		this.setPosicion(posicion);
		if (!(posicion < 0)) {
			switch (tipoFondo) {
			case 1:
				this.mBitmap = BitmapFactory.decodeResource(getResources(),
						Animales.animalesArray[posicion]);
				break;
			case 2:
				this.mBitmap = BitmapFactory.decodeResource(getResources(),
						Numeros.numerosArray[posicion]);
				break;
			case 3:
				this.mBitmap = BitmapFactory.decodeResource(getResources(),
						Juguetes.juguetesArray[posicion]);
				break;
			default:
				this.mBitmap = Bitmap.createBitmap(this.display.getWidth(),
						this.display.getHeight(), Bitmap.Config.ARGB_8888);
				break;

			}
			int w = this.mBitmap.getWidth();
			int h = this.mBitmap.getHeight();
			float scaleHeight = (float) h
					/ (float) Blackboard.pizarra.getHeight();
			float scaleWidth = (float) w
					/ (float) Blackboard.pizarra.getWidth();
			this.mBitmap = Bitmap.createScaledBitmap(this.mBitmap,
					(int) (w / scaleWidth), (int) (h / scaleHeight), true);
		} else {
			this.mBitmap = Bitmap.createBitmap(this.display.getWidth(),
					this.display.getHeight(), Bitmap.Config.ARGB_8888);
		}
		this.mCanvas = new Canvas(mBitmap);
		this.mPath = new Path();

		invalidate();

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		float x = event.getX();
		float y = event.getY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			touchStart(x, y);
			invalidate();
			break;
		case MotionEvent.ACTION_MOVE:
			touchMove(x, y);
			invalidate();
			break;
		case MotionEvent.ACTION_UP:
			touchUp();
			invalidate();
			break;
		}
		return true;
	}

	private void touchStart(float x, float y) {
		this.mPath.reset();
		this.mPath.moveTo(x, y);
		this.mX = x;
		this.mY = y;
	}

	private void touchMove(float x, float y) {
		if (Math.abs(x - this.mX) >= Pintar.TOLERANCE
				|| Math.abs(y - this.mY) >= Pintar.TOLERANCE) {
			this.mPath.quadTo(this.mX, this.mY, (x + this.mX) / 2,
					(y + this.mY) / 2);
			this.mX = x;
			this.mY = y;
		}
	}

	private void touchUp() {
		this.mPath.lineTo(this.mX, this.mY);
		this.mCanvas.drawPath(this.mPath, Blackboard.mPaint);
		mPath = new Path();
		paths.add(mPath);
		
		
	}
	
	public void onClickUndo () { 
        if (paths.size()>0) 
        { 
        	undonePaths.add(paths.remove(paths.size()-1));
            invalidate();
            Toast.makeText(context, "Undo", Toast.LENGTH_LONG).show();
         }
        else
        {

        }
         //toast the user 
    }

    public void onClickRedo (){
       if (undonePaths.size()>0) 
       { 
           paths.add(undonePaths.remove(undonePaths.size()-1)); 
           invalidate();
           
       }
         //toast the user 
    }


	@Override
	protected void onDraw(Canvas canvas) {
		// fondo
		canvas.drawColor(Color.WHITE);
		// lo ya pintado
		canvas.drawBitmap(this.mBitmap, 0, 0, null);
		// el trazo actual
		canvas.drawPath(this.mPath, Blackboard.mPaint);
	}
}



in the main class:

    public class Blackboard extends Activity {

	public static Paint mPaint = null;
	public static int color;
	private Dialog dialog;
	public static Pintar board;
	private static Intent intent;
	static final int CODE=0;
	public static String fondo="-1";
	private int tipoFondo;
	public static LinearLayout pizarra;
	private ImageButton animales, paleta, numeros, juguetes, goma, deshacer;
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		Blackboard.board = new Pintar(this);
		
		setContentView(R.layout.main);
		Blackboard.pizarra =(LinearLayout)findViewById(R.id.pizarra);
		Blackboard.pizarra.addView(Blackboard.board, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		// preparamos el pincel
		Blackboard.mPaint = new Paint();
		Blackboard.mPaint.setStyle(Paint.Style.STROKE);
		Blackboard.mPaint.setStrokeJoin(Paint.Join.ROUND);
		Blackboard.mPaint.setStrokeCap(Paint.Cap.ROUND);
		Blackboard.mPaint.setAntiAlias(true);
		Blackboard.mPaint.setDither(true);
		Blackboard.mPaint.setColor(0XFF00E1FF);
		Blackboard.mPaint.setStrokeWidth(10);
		
		this.animales = (ImageButton) findViewById(R.id.animales);
		this.animales.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Blackboard.intent = new Intent (Blackboard.this, Animales.class);
				startActivityForResult(Blackboard.intent, Blackboard.CODE);
				tipoFondo=1;
			}
		});
		this.goma = (ImageButton) findViewById(R.id.goma);
		this.goma.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Blackboard.board.establecerFondo(Integer.parseInt(Blackboard.fondo), tipoFondo);
			}
		});
		
		this.paleta= (ImageButton) findViewById(R.id.paleta);
		this.paleta.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				dialog = new RainbowPickerDialog(Blackboard.this);
				dialog.show();
				
			}
		});
		
		this.numeros= (ImageButton) findViewById(R.id.numeros);
		this.numeros.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Blackboard.intent = new Intent (Blackboard.this, Numeros.class);
				startActivityForResult(Blackboard.intent, Blackboard.CODE);
				tipoFondo=2;
			}
		});
		
		this.juguetes= (ImageButton) findViewById(R.id.juguetes);
		this.juguetes.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Blackboard.intent = new Intent (Blackboard.this, Juguetes.class);
				startActivityForResult(Blackboard.intent, Blackboard.CODE);
				tipoFondo=3;
			}
		});
		
		this.deshacer= (ImageButton) findViewById(R.id.deshacer);
		this.deshacer.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Blackboard.board.onClickUndo();
			}
		});
	}
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode==Blackboard.CODE){
			if (resultCode==RESULT_OK){
				Blackboard.fondo=data.getStringExtra("fondo");
				Blackboard.board.establecerFondo(Integer.parseInt(Blackboard.fondo), tipoFondo);
			}else{
				Blackboard.fondo="Cancelado";
			}
		}
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
	    if ((keyCode == KeyEvent.KEYCODE_BACK))
	    {
	    	Blackboard.fondo="-1";
	        finish();
	    }
	    return super.onKeyDown(keyCode, event);
	}

	
}



The app works but when i click the undo button only appears the toast, the undo feature doesn´t work.