Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Android Canvas Tutorial – Capture Digital Signature and Save

Android Canvas Tutroial – Capture Digital Signature and Save

Hello developers, In this tutorial we will learn about the how to capture digital Signature using android canvas and also save the signature in image format for further usage. Capturing the Digital Signature has multiple usages in the internet age. Digital signatures are used for authentication and integrity assurance of digital data. It is used as proof of any product delivery, to accept an agreement which is confidential, or on legal/contractual documents. The most important component we have used to capture the signature is android canvas.

Android Canvas is a graphic component which allows us to call the draw() method to draw or write anything on the screen.

Capturing Digital Signature in android.

To capture the Digital Signature using android canvas, we first create an XML file which contains the canvas on which we can register our signatures using our fingers or stylus. Then we convert that signature into an Image, create a directory in mobile storage and save the signature image in that directory on click of the save button. We can also show the image in another activity using the path of the directory.


Create Android Canvas Example App

  1. Go to File → New → New Project and enter your Application Name. Let’s say Android Canvas Example App
  2. Enter company domain, this is used to uniquely identify your App’s package worldwide.
  3. Choose project location and minimum SDK and on the next screen choose Simple Activity, since we would be adding most of the code ourselves. Then Click on Next.
  4. Choose an Activity Name. Make sure Generate Layout File check box is selected, Otherwise, we have to generate it ourselves. Then click on Finish. We have kept the Activity Name as BillDetailsActivity.java. This will be the default screen when the user opens the app for the first time.

Gradle will configure your android canvas example project in the android studio and resolve the dependencies, Once it is complete proceed to the next steps.

Add Layout to Android Canvas Project

  1. Now we will create layout for the BillDetailsActivity. In this layout we use the TableLayout to create a table like structure in which we show the details of the product we buy like its price, date, order number, buyer’s details etc. It also contains Checkbox for confirmation, ImageView for getting the image of signature and a button to go to the another activity where we capture the signature.
  2. So, open activity_bill_details.xml file which is present in res -> layouts folder and add the below code.

    activity_bill_details.xml

    
    
  3. Now we will create a table_borders.xml file in drawable folder which is used to make a border on every textview of the table rows which makes the table clear to see and attractive. To create a xml file in drawable folder, right click on the drawable folder which is present in res -> drawable. Click on New and then click on Drawable resource file. Then add the file name table_border.xml you can give name to file according to your choice and click ok and add the below code in this xml file.
  4. table_border.xml

  5. To capture the signature using android canvas we will create a new activity SignatureActivity in which we add android canvas component and get the signature on that canvas. To create the activity right click on package New ⇒ Activity ⇒ Empty Activity.
    Now open the activity_signature.xml and add the below code which contains the three buttons for cancel, clear and save the signature. It also contains the LinearLayout on which we add the canvas which is used to write the signature using our fingers.
  6. activity_signature.xml

    
            
            
        

Capture Signature using canvas

Now open BillDetailsActivity.java class and add the below code. In this activity, we show the details of the product. We also add a checkbox and enable the button to go to another activity if the checkbox is checked. We also set the image of signature which we get from another activity using the image path of signature. It also contains the button by which we can go to other activity from where we get the signature of the customer.

BillDetailsActivity.java

package com.androidtutorialpoint.androidcanvasexample;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;

public class BillDetailsActivity extends Activity {
    Button signatureButton;
    ImageView signImage;
    CheckBox checkBox;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bill_details);
        signatureButton = (Button) findViewById(R.id.getSign);
        signImage = (ImageView) findViewById(R.id.imageView1);
        signatureButton.setOnClickListener(onButtonClick);
        checkBox = (CheckBox) findViewById(R.id.checkbox);
        //disable button if checkbox is not checked else enable button
        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
        {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
            {
                if ( isChecked )
                {
                    signatureButton.setEnabled(true);
                }
                else{
                    signatureButton.setEnabled(false);
                }
            }
        });
        //to get imagepath from SignatureActivity and set it on ImageView
        String image_path = getIntent().getStringExtra("imagePath");
        Bitmap bitmap = BitmapFactory.decodeFile(image_path);
        signImage.setImageBitmap(bitmap);
    }

    Button.OnClickListener onButtonClick = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (checkBox.isChecked()){
                Intent i = new Intent(BillDetailsActivity.this, SignatureActivity.class);
                startActivity(i);
            }
            else {
                signatureButton.setEnabled(false);
            }
        }
    };
}

Now open SignatureActivity.java class. In this activity first, we create the directory in our storage where all the images of user signature have been saved. We also add the canvas to the layout on which we are able to write our signature. It also contains three buttons i.e. cancel, clear and saves. In the onClick() of Cancel we move to the previous activity without signature. In the onClick() of Clear, we erase the data if the user is not able to write the signature properly. In the onClick() of Save, the signature is converted into an image file and save into the directory which we have created earlier and also we move to the previous activity on which the signature is shown as a proof.
So, open SignatureActivity.java class and add the below code.

SignatureActivity.xml

package com.androidtutorialpoint.androidcanvasexample;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class SignatureActivity extends AppCompatActivity {

    Button mClear, mGetSign, mCancel;
    File file;
    LinearLayout mContent;
    View view;
    signature mSignature;
    Bitmap bitmap;

    // Creating Separate Directory for saving Generated Images
    String DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/UserSignature/";
    String pic_name = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    String StoredPath = DIRECTORY + pic_name + ".png";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signature);

        mContent = (LinearLayout) findViewById(R.id.canvasLayout);
        mSignature = new signature(getApplicationContext(), null);
        mSignature.setBackgroundColor(Color.WHITE);
        // Dynamically generating Layout through java code
        mContent.addView(mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mClear = (Button) findViewById(R.id.clear);
        mGetSign = (Button) findViewById(R.id.getsign);
        mGetSign.setEnabled(false);
        mCancel = (Button) findViewById(R.id.cancel);
        view = mContent;
        mGetSign.setOnClickListener(onButtonClick);
        mClear.setOnClickListener(onButtonClick);
        mCancel.setOnClickListener(onButtonClick);

        // Method to create Directory, if the Directory doesn't exists
        file = new File(DIRECTORY);
        if (!file.exists()) {
            file.mkdir();
        }
    }

    Button.OnClickListener onButtonClick = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (v == mClear) {
                Log.v("log_tag", "Panel Cleared");
                mSignature.clear();
                mGetSign.setEnabled(false);
            } else if (v == mGetSign) {
                Log.v("log_tag", "Panel Saved");
                if (Build.VERSION.SDK_INT >= 23) {
                    isStoragePermissionGranted();
                } else {
                    view.setDrawingCacheEnabled(true);
                    mSignature.save(view, StoredPath);
                    Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show();
                    // Calling the same class
                    recreate();
                }
            } else if(v == mCancel){
                Log.v("log_tag", "Panel Canceled");
                // Calling the BillDetailsActivity
                Intent intent = new Intent(SignatureActivity.this, BillDetailsActivity.class);
                startActivity(intent);
            }
        }
    };


    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                return true;
            } else {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        } else {
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            view.setDrawingCacheEnabled(true);
            mSignature.save(view, StoredPath);
            Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show();
            // Calling the same class
            recreate();
        }
        else
        {
            Toast.makeText(this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
        }
    }

    public class signature extends View {

        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();

        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(STROKE_WIDTH);
        }

        public void save(View v, String StoredPath) {
            Log.v("log_tag", "Width: " + v.getWidth());
            Log.v("log_tag", "Height: " + v.getHeight());
            if (bitmap == null) {
                bitmap = Bitmap.createBitmap(mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565);
            }
            Canvas canvas = new Canvas(bitmap);
            try {
                // Output the file
                FileOutputStream mFileOutStream = new FileOutputStream(StoredPath);
                v.draw(canvas);

                // Convert the output file to Image such as .png
                bitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
                Intent intent = new Intent(SignatureActivity.this, BillDetailsActivity.class);
                intent.putExtra("imagePath", StoredPath);
                startActivity(intent);
                finish();
                mFileOutStream.flush();
                mFileOutStream.close();

            } catch (Exception e) {
                Log.v("log_tag", e.toString());
            }

        }

        public void clear() {
            path.reset();
            invalidate();
            mGetSign.setEnabled(false);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawPath(path, paint);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float eventX = event.getX();
            float eventY = event.getY();
            mGetSign.setEnabled(true);

            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  dirtyRect.right) {
                dirtyRect.right = historicalX;
            }

            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);
        }
    }
}

Add Permission and resources

As we want to create a directory and store the images in that directory. So we have to add the permission to write into the external storage. So add the below line in AndroidManifest.xml

AndroidManifest.xml

As we know that hard coding of resources is not a good practice for coding so we will add some new colors in colors.xml and string values in strings.xml.
Add the following resources in the respective files present in the path res -> values

strings.xml

SignatureUsingCanvasGet SignatureSign HereCancelClearSaveBill DetailsDate16 Mar 2017Order Number10798565Buyer\'s NameUmeshBuyer\'s AddressPratap NagarContact Number0000000000Total AmountRs 1500I have Successfully Received the productGet Signature

colors.xml

#000000#202324#B8B9B1#ffffff

We have used the following dimensions and styles in our android canvas example application.

dimens.xml

16dp16dp3px5dp15dip10dp150dp80dp20sp0dp50dp

styles.xml

Now run the Android Canvas Example app on an actual Android Device and you try to capture your signature and save it.

What’s Next ??

After this, We will be covering more interesting tutorials like creating a multilingual app in android.

Till then stay tuned for more tutorials.. and Don’t forget to subscribe our blog for latest android tutorials. Also do Like our Facebook Page or Add us on Twitter.

To download the full code for the Android Canvas Tutorial using the android studio, Click on the Download Now link below.


The post Android Canvas Tutorial – Capture Digital Signature and Save appeared first on Android Tutorial Point.



This post first appeared on Android Tutorial Point, please read the originial post: here

Share the post

Android Canvas Tutorial – Capture Digital Signature and Save

×

Subscribe to Android Tutorial Point

Get updates delivered right to your inbox!

Thank you for your subscription

×