title: Digital Signature Clear issue in Android app
body: <p>I am working on implementing digital signature functionality in android app using custom view.<br>
  I want user be able to clear and retry new signature without closing dialog or re-creating activity.When I clear,it successfully clears the signature but doesn't allow to draw a new signature and draws some black overlays along with previously drawn signature.  </p>
  
  <p>Here is the class which draws digital signature.<br>
  Signature.java  </p>
  
  <pre><code>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.provider.MediaStore;  
  import android.util.AttributeSet;  
  import android.util.Log;  
  import android.view.MotionEvent;  
  import android.view.View;  
  import java.io.File;  
  import java.io.FileOutputStream;  
  
  public class Signature extends View  
  {  
      public static final float STROCK_WIDTH = 5f;  
      public static final float HALF_STROKE_WIDTH = STROCK_WIDTH / 2;  
      private Paint paint = new Paint();  
      View mContent;  
      File mPath1;  
      private Paint mPaint;  
      private Bitmap mBitmap;  
      private Canvas mCanvas;  
      private Path mPath;  
      private Paint mBitmapPaint;  
      boolean clear = false;    
  
      public Signature(Context context)
      {
          super(context);
      }
  
      public Signature(Context context, AttributeSet attrs)
      {
          super(context, attrs);
          paint.setAntiAlias(true);
          paint.setColor(Color.BLACK);
          paint.setStyle(Paint.Style.STROKE);
          paint.setStrokeJoin(Paint.Join.ROUND);
          paint.setStrokeWidth(STROCK_WIDTH);
      }
  
      public Signature(Context context, AttributeSet attrs, View view, File pathToSave)
      {
          this(context, attrs);
          mContent = view;
          mPath1 = pathToSave;
          mPath = new Path();
          mBitmapPaint = new Paint(Paint.DITHER_FLAG);
          setPaint();
      }
  
      public void setPaint()
      {
          mPaint = new Paint();
          mPaint.setAntiAlias(true);
          mPaint.setDither(true);
          mPaint.setColor(0xFFFF0000);
          mPaint.setStyle(Paint.Style.STROKE);
          mPaint.setStrokeJoin(Paint.Join.ROUND);
          mPaint.setStrokeCap(Paint.Cap.ROUND);
          mPaint.setStrokeWidth(12);
      }
  
      public String save(View v)
      {
          String imagePath = null;
          Log.v("TAG", "Width :" + v.getWidth());
          Log.v("TAG", "Height :" + v.getHeight());
          if (mBitmap == null)
          {
              mBitmap = Bitmap.createBitmap(mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565);
          }
          mBitmap = v.getDrawingCache();
          try
          {
              FileOutputStream mFileOutStream = new FileOutputStream(mPath1);
              mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
              mFileOutStream.flush();
              mFileOutStream.close();
              imagePath = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), mBitmap, "title", null);
              Log.v("log_tag", "url: " + imagePath + "::we are saving at :" + mPath1);
          }
          catch (Exception e)
          {
              Log.v("log_tag", e.toString());
          }
          return imagePath;
      }
  
      public void clear()
      {
          mPath.reset();  
          mPaint.reset();  
          clear = true;  
          mPath1.delete();  
          mBitmapPaint = new Paint(Paint.DITHER_FLAG);  
          postInvalidate();  
      }  
  
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh)
      {
          super.onSizeChanged(w, h, oldw, oldh);
          try
          {
              mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
              mCanvas = new Canvas(mBitmap);
          }
          catch (Exception e)
          {
              e.printStackTrace();
          }
      }
  
      @Override
      protected void onDraw(Canvas canvas)
      {
          if (clear)
          {
              clear = false;
          }
          else
          {
              canvas.drawColor(0xFFFFFFFF);
              canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
              canvas.drawPath(mPath, mPaint);
          }
      }
  
      private float mX, mY;
      private static final float TOUCH_TOLERANCE = 4;
  
      private void touch_start(float x, float y)
      {
          mPath.reset();
          mPath.moveTo(x, y);
          mX = x;
          mY = y;
      }
  
      private void touch_move(float x, float y)
      {
          float dx = Math.abs(x - mX);
          float dy = Math.abs(y - mY);
          if (dx &gt;= TOUCH_TOLERANCE || dy &gt;= TOUCH_TOLERANCE)
          {
              mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
              mX = x;
              mY = y;
          }
      }
  
      private void touch_up()
      {
          mPath.lineTo(mX, mY);
          // commit the path to our offscreen
          mCanvas.drawPath(mPath, mPaint);
          // kill this so we don't double draw
          mPath.reset();
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent event)
      {
          float x = event.getX();
          float y = event.getY();
  
          switch (event.getAction())
          {
              case MotionEvent.ACTION_DOWN:
                  touch_start(x, y);
                  invalidate();
                  break;
              case MotionEvent.ACTION_MOVE:
                  touch_move(x, y);
                  invalidate();
                  break;
              case MotionEvent.ACTION_UP:
                  touch_up();
                  invalidate();
                  break;
          }
          return true;
      }  
  }  
  </code></pre>
  
  <p>Activity in which above class is used<br>
  MainActivity.java  </p>
  
  <pre><code>import android.annotation.SuppressLint;
  import android.app.Activity;
  import android.app.Dialog;
  import android.content.ContextWrapper;
  import android.graphics.Bitmap;
  import android.graphics.Color;
  import android.graphics.drawable.BitmapDrawable;
  import android.net.Uri;
  import android.os.Bundle;
  import android.os.Environment;
  import android.provider.MediaStore;
  import android.support.annotation.Nullable;
  import android.support.v7.app.ActionBarActivity;
  import android.support.v7.app.AppCompatActivity;
  import android.util.Base64;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.Window;
  import android.widget.Button;
  import android.widget.ImageView;
  import android.widget.LinearLayout;
  import android.widget.Toast;
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.IOException;
  import java.util.Calendar;
  
  public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  
      Button btnOpen;
      String imagePath = null,str_signature = "";
      ImageView iv_sign;
      public static String tempDir;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
  
          try {
              btnOpen= (Button) findViewById(R.id.btnOpen);
              btnOpen.setOnClickListener(this);
  
              iv_sign= (ImageView) findViewById(R.id.ivSign);
          }
          catch (Exception ex)
          {
              ex.printStackTrace();
          }
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          // Inflate the menu; this adds items to the action bar if it is present.
          getMenuInflater().inflate(R.menu.menu_main, menu);
          return true;
      }
  
      @Override
      public boolean onOptionsItemSelected(MenuItem item) {
          // Handle action bar item clicks here. The action bar will
          // automatically handle clicks on the Home/Up button, so long
          // as you specify a parent activity in AndroidManifest.xml.
          int id = item.getItemId();
  
          //noinspection SimplifiableIfStatement
          if (id == R.id.action_settings) {
              return true;
          }
  
          return super.onOptionsItemSelected(item);
      }
  
      @Override
      public void onClick(View v) {
  
          if(v==btnOpen)
          {
              SignatureFragment dialog = new SignatureFragment(onImageClicked);
              dialog.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
          }
      }
  
      ImageSaved onImageClicked = new ImageSaved() {
          @Override
          public void onImageSaved(String path) {
              imagePath = path;
              Uri uri = Uri.parse(imagePath);
              Log.d("TAG", "We got image path :" + imagePath);
              try {
                  Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                  iv_sign.setImageBitmap(bitmap);
  
                  ImageView img = iv_sign;
                  BitmapDrawable mBitmapDrawable = (BitmapDrawable) img.getDrawable();
                  Bitmap mBitmap = mBitmapDrawable.getBitmap();
                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                  byte[] byteArrayImage = baos.toByteArray();
                  str_signature = Base64.encodeToString(byteArrayImage,
                          Base64.DEFAULT);
  
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      };
  
      public static class SignatureFragment extends android.support.v4.app.DialogFragment implements View.OnClickListener {
          LinearLayout ll_signature_view;
          Signature signature;
          Button btn_done, btn_clear,btnCancel;
          String EXTERNAL_DIR = "TTD";
          ImageSaved saveListner;
          File mypath;
  
          @SuppressLint("ValidFragment")
          public SignatureFragment(ImageSaved onImageClicked) {
              saveListner = onImageClicked;
          }
  
          @Override
          public void onAttach(Activity activity) {
              super.onAttach(activity);
          }
  
          @Override
          public void onDetach() {
              saveListner = null;
              super.onDetach();
          }
  
          public SignatureFragment() {
          }
  
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setStyle(android.support.v4.app.DialogFragment.STYLE_NO_FRAME, R.style.Base_Theme_AppCompat_Light_Dialog);
          }
  
          @Override
          public Dialog onCreateDialog(Bundle savedInstanceState) {
              Dialog dialog = super.onCreateDialog(savedInstanceState);
              dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
              return dialog;
          }
  
          @Nullable
          @Override
          public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
              View rootView = inflater.inflate(R.layout.signature_view, container, false);
              try
              {
                  ll_signature_view = (LinearLayout) rootView.findViewById(R.id.ll_signature_view);
                  btn_done = (Button) rootView.findViewById(R.id.btn_done);
                  btn_clear = (Button) rootView.findViewById(R.id.btn_clear);
                  btnCancel = (Button) rootView.findViewById(R.id.btn_cancel);
                  tempDir = Environment.getExternalStorageDirectory() + "/" + EXTERNAL_DIR + "/";
                  File directory = getActivity().getCacheDir();
                  prepareDirectory();
                  String uniqueId = getTodaysDate() + "_" + getCurrentTime() + "_" + Math.random();
                  String current = uniqueId + ".png";
                  mypath = new File(directory, current);
  
                  signature = new Signature(getActivity(), null, ll_signature_view, mypath);
                  ll_signature_view.setBackgroundColor(Color.WHITE);
                  ll_signature_view.addView(signature, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
                  btn_done.setOnClickListener(this);
                  btn_clear.setOnClickListener(this);
                  btnCancel.setOnClickListener(this);
              }
              catch(Exception ex)
              {
                  ex.printStackTrace();
              }
  
              return rootView;
          }
  
          @Override
          public void onClick(View v) {
              if (v == btn_done) {
                  ll_signature_view.setDrawingCacheEnabled(true);
                  String imagePath = signature.save(ll_signature_view);
                  if (saveListner != null) {
                      saveListner.onImageSaved(imagePath);
                  }
                  dismiss();
  
              }
              if (v == btnCancel) {
                  dismiss();
              }
              if(v==btn_clear)
              {
                  signature.clear();
              }
          }
  
          private boolean prepareDirectory() {
              try {
                  if (makedirs()) {
                      return true;
                  } else {
                      return false;
                  }
              } catch (Exception e) {
                  e.printStackTrace();
                  Toast.makeText(getActivity(), "Could not initiate File System.. Is Sdcard mounted properly?", Toast.LENGTH_SHORT).show();
                  return false;
              }
          }
  
          private boolean makedirs() {
              File tempdir = new File(tempDir);
              if (!tempdir.exists()) {
                  tempdir.mkdirs();
              }
  
              if (tempdir.isDirectory()) {
                  File[] files = tempdir.listFiles();
                  for (File file : files) {
                      if (!file.delete()) {
                          System.out.println("Failed to delete " + file);
                      }
                  }
              }
              return (tempdir.isDirectory());
          }
  
          private String getTodaysDate() {
  
              final Calendar c = Calendar.getInstance();
              int todaysDate = (c.get(Calendar.YEAR) * 10000) +
                      ((c.get(Calendar.MONTH) + 1) * 100) +
                      (c.get(Calendar.DAY_OF_MONTH));
              Log.w("DATE:", String.valueOf(todaysDate));
              return (String.valueOf(todaysDate));
  
          }
  
          private String getCurrentTime() {
  
              final Calendar c = Calendar.getInstance();
              int currentTime = (c.get(Calendar.HOUR_OF_DAY) * 10000) +
                      (c.get(Calendar.MINUTE) * 100) +
                      (c.get(Calendar.SECOND));
              Log.w("TIME:", String.valueOf(currentTime));
              return (String.valueOf(currentTime));
          }
      }
  
  }
  </code></pre>
  
  <p>Layout File<br>
    signature_view.xml  </p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:layout_margin="8dp"&gt;
  
      &lt;LinearLayout
          android:id="@+id/ll_signature_view"
          android:layout_width="match_parent"
          android:layout_height="0dp"
          android:layout_weight="1"
          android:background="@drawable/edittext_border_white"
          android:orientation="horizontal"&gt;
  
      &lt;/LinearLayout&gt;
  
      &lt;LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_marginBottom="8dp"
          android:layout_marginTop="8dp"&gt;
  
          &lt;Button
              android:id="@+id/btn_done"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:text="DONE" /&gt;
  
          &lt;Button
              android:id="@+id/btn_clear"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:text="CLEAR" /&gt;
  
          &lt;Button
              android:id="@+id/btn_cancel"
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:text="CANCEL" /&gt;
  
      &lt;/LinearLayout&gt;
  &lt;/LinearLayout&gt;  
  </code></pre>
  
  <p>activity_main.xml  </p>
  
  <pre><code>&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="@dimen/activity_vertical_margin"
      tools:context=".MainActivity"
      android:background="@android:color/white"&gt;
  
      &lt;TextView
          android:id="@+id/tvWelcome"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/Welcome" /&gt;
  
      &lt;Button
          android:layout_marginTop="10dp"
          android:id="@+id/btnOpen"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="@string/Open"
          android:gravity="center"
          android:layout_below="@+id/tvWelcome"/&gt;
  
      &lt;ImageView
          android:id="@+id/ivSign"
          android:layout_marginTop="10dp"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:background="@android:color/white"
          android:layout_below="@+id/btnOpen"
          /&gt;
  
  &lt;/RelativeLayout&gt; 
  </code></pre>