Capturing a signature in an Android app

This is an example of capturing a signature in an Android app as text, which could be uploaded to a server as JSON and displayed in a web page with the HTML < img src="#" /> where # is the value returned from getSignatureAsBase64String().
public class MainActivity extends Activity {
    private SignatureLayout signatureLayout;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        signatureLayout = new SignatureLayout(this);
        setContentView(signatureLayout);
    }
}

public class SignatureLayout extends LinearLayout {
    private SignatureView signatureView;
    public SignatureLayout(Context context) {
        super(context);
        setOrientation(LinearLayout.VERTICAL);
        signatureView = new SignatureView(context);
        addView(signatureView);
    }
    public String getSignatureAsBase64String() {
        Bitmap signature = signatureView.getSignature();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        signature.compress(Bitmap.CompressFormat.PNG, 100, baos); //bm is the bitmap object
        byte[] bytes = baos.toByteArray();
        String base64String = Base64.encodeToString(bytes, Base64.DEFAULT);
        return "data:image/png;base64,"+base64String;
    }
    public void clearSignature() {
        signatureView.clearSignature();
    }
    private class SignatureView extends View {
        // set the stroke width
        private static final float STROKE_WIDTH = 5f;
        private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
        private Paint paint = new Paint();
        private Path path = new Path();
        private float lastTouchX;
        private float lastTouchY;
        private final RectF dirtyRect = new RectF();
        private SignatureView(Context context) {
            super(context);
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeWidth(STROKE_WIDTH);
            // set the bg color as white
            setBackgroundColor(Color.WHITE);
            // width and height should cover the screen
            setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        }
        private Bitmap getSignature() {
            Bitmap signatureBitmap = null;
            // set the signature bitmap
            if (signatureBitmap == null) {
                signatureBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
            }
            // important for saving signature
            final Canvas canvas = new Canvas(signatureBitmap);
            draw(canvas);
            return signatureBitmap;
        }
        private void clearSignature() {
            path.reset();
            invalidate();
        }
        protected void onDraw(Canvas canvas) {
            canvas.drawPath(path, paint);
        }
        public boolean onTouchEvent(MotionEvent event) {
            float eventX = event.getX();
            float eventY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    path.moveTo(eventX, eventY);
                    lastTouchX = eventX;
                    lastTouchY = eventY;
                    return true;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    resetDirtyRect(eventX, eventY);
                    int historySize = event.getHistorySize();
                    for (int i = 0; i < historySize; i++) {
                        float historicalX = event.getHistoricalX(i);
                        float historicalY = event.getHistoricalY(i);
                        expandDirtyRect(historicalX, historicalY);
                        path.lineTo(historicalX, historicalY);
                    }
                    path.lineTo(eventX, eventY);
                    break;
                default:
                    return false;
            }
            invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.top - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.right + HALF_STROKE_WIDTH),
                    (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
            lastTouchX = eventX;
            lastTouchY = eventY;
            return true;
        }
        private void expandDirtyRect(float historicalX, float historicalY) {
            if (historicalX < dirtyRect.left) {
                dirtyRect.left = historicalX;
            } else if (historicalX > dirtyRect.right) {
                dirtyRect.right = historicalX;
            }
            if (historicalY < dirtyRect.top) {
                dirtyRect.top = historicalY;
            } else if (historicalY > dirtyRect.bottom) {
                dirtyRect.bottom = historicalY;
            }
        }
        private void resetDirtyRect(float eventX, float eventY) {
            dirtyRect.left = Math.min(lastTouchX, eventX);
            dirtyRect.right = Math.max(lastTouchX, eventX);
            dirtyRect.top = Math.min(lastTouchY, eventY);
            dirtyRect.bottom = Math.max(lastTouchY, eventY);
        }
    }
}