com.microblink.ocr.ScanActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.microblink.ocr.ScanActivity.java

Source

package com.microblink.ocr;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.microblink.geometry.Rectangle;
import com.microblink.hardware.SuccessCallback;
import com.microblink.help.HelpActivity;
import com.microblink.recognition.InvalidLicenceKeyException;
import com.microblink.recognizers.BaseRecognitionResult;
import com.microblink.recognizers.RecognitionResults;
import com.microblink.recognizers.blinkocr.BlinkOCRRecognitionResult;
import com.microblink.recognizers.blinkocr.BlinkOCRRecognizerSettings;
import com.microblink.recognizers.settings.RecognitionSettings;
import com.microblink.recognizers.settings.RecognizerSettings;
import com.microblink.util.CameraPermissionManager;
import com.microblink.util.Log;
import com.microblink.view.CameraAspectMode;
import com.microblink.view.CameraEventsListener;
import com.microblink.view.recognition.RecognizerView;
import com.microblink.view.recognition.ScanResultListener;

public class ScanActivity extends Activity implements CameraEventsListener, ScanResultListener {

    /** RecognizerView is the builtin view that controls camera and recognition */
    private RecognizerView mRecognizerView;

    // obtain your licence key at http://microblink.com/login or
    // contact us at http://help.microblink.com
    private static final String LICENSE_KEY = "OEWESRMK-OENGL3VK-IVWYB4DY-OTNT457T-5PGLUYNA-IVQ2ARLB-UBCWCAAC-IYXKU56C";
    /** CameraPermissionManager is provided helper class that can be used to obtain the permission to use camera.
     * It is used on Android 6.0 (API level 23) or newer.
     */
    private CameraPermissionManager mCameraPermissionManager;
    /** Button that controls flashlight state. */
    private ImageButton mFlashButton;
    /** Layout which holds scan result. */
    private View mResultView;
    /** Shows scan result string. */
    private EditText mResult;
    /** Flashlight state. */
    private boolean mTorchOn = false;
    /** Shows the message of current scan configuration to user. */
    private TextView mMessage;
    /** Shows the title of current scan configuration to user. */
    private SlidingTabLayout mTitleIndicator;
    /** Array of scan configurations. */
    private ScanConfiguration[] mConfiguration = Configurator.createScanConfigurations();
    /** Index of selected configuration. */
    private int mSelectedConfiguration = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_scan);

        // obtain references to needed member variables
        mRecognizerView = (RecognizerView) findViewById(R.id.rec_view);
        mFlashButton = (ImageButton) findViewById(R.id.btnFlash);
        mResultView = findViewById(R.id.layResult);
        mMessage = (TextView) findViewById(R.id.txtMessage);
        mResult = (EditText) findViewById(R.id.txtResult);
        mTitleIndicator = (SlidingTabLayout) findViewById(R.id.indicator);

        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setAdapter(new SamplePagerAdapter());

        mTitleIndicator = (SlidingTabLayout) findViewById(R.id.indicator);
        mTitleIndicator.setViewPager(viewPager);

        // set ViewPager.OnPageChangeListener to enable the layout
        // to update it's scroll position correctly
        mTitleIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                // update currently selected configuration
                mSelectedConfiguration = position;
                // hide previous result
                mResultView.setVisibility(View.INVISIBLE);
                // update message and title based on selected configuration
                // and update recognizer settings (flag is set to true)
                updateUI(true);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        // camera events listener is required as it will receive camera-related events
        // such as startup errors, autofocus callbacks etc.
        mRecognizerView.setCameraEventsListener(this);
        // scan result listener is requires as it will receive recognition results
        mRecognizerView.setScanResultListener(this);

        // we want camera to use whole available view space by cropping the camera preview
        // instead of letterboxing it
        mRecognizerView.setAspectMode(CameraAspectMode.ASPECT_FILL);
        // In order for scanning to work, you must enter a valid licence key. Without licence key,
        // scanning will not work. Licence key is bound the the package name of your app, so when
        // obtaining your licence key from Microblink make sure you give us the correct package name
        // of your app. You can obtain your licence key at http://microblink.com/login or contact us
        // at http://help.microblink.com.
        // Licence key also defines which recognizers are enabled and which are not. Since the licence
        // key validation is performed on image processing thread in native code, all enabled recognizers
        // that are disallowed by licence key will be turned off without any error and information
        // about turning them off will be logged to ADB logcat.
        try {
            mRecognizerView.setLicenseKey(LICENSE_KEY);
        } catch (InvalidLicenceKeyException e) {
            e.printStackTrace();
            Toast.makeText(this, "Invalid license key!", Toast.LENGTH_SHORT).show();
            finish();
        }
        mRecognizerView.setOptimizeCameraForNearScan(true);

        // initialize BlinkOCR recognizer with currently selected parser
        // create BlinkOCR recognizer settings object and add parser to it
        BlinkOCRRecognizerSettings ocrSett = new BlinkOCRRecognizerSettings();
        ocrSett.addParser(mConfiguration[mSelectedConfiguration].getParserName(),
                mConfiguration[mSelectedConfiguration].getParserSettings());

        // prepare the recognition settings
        RecognitionSettings recognitionSettings = new RecognitionSettings();
        // add BlinkOCR recognizer settings object to recognizer settings array
        // BlinkOCR recognizer will be used in the recognition process
        recognitionSettings.setRecognizerSettingsArray(new RecognizerSettings[] { ocrSett });

        mRecognizerView.setRecognitionSettings(recognitionSettings);

        // define the scanning region of the image that will be scanned.
        // You must ensure that scanning region define here is the same as in the layout
        // The coordinates for scanning region are relative to recognizer view:
        // the following means: rectangle starts at 10% of recognizer view's width and
        // 34% of its height. Rectangle width is 80% of recognizer view's width and
        // 13% of its height.
        // If you do not set this, OCR will be performed on full camera frame and this
        // will result in very poor performance.
        mRecognizerView.setScanningRegion(new Rectangle(0.1f, 0.34f, 0.8f, 0.13f), false);

        // instantiate the camera permission manager
        mCameraPermissionManager = new CameraPermissionManager(this);
        // get the built in layout that should be displayed when camera permission is not given
        View v = mCameraPermissionManager.getAskPermissionOverlay();
        if (v != null) {
            // add it to the current layout that contains the recognizer view
            ViewGroup vg = (ViewGroup) findViewById(R.id.custom_segment_scan_root);
            vg.addView(v);
        }

        // all activity's lifecycle methods must be passed to recognizer view
        mRecognizerView.create();
        // update message and title based on selected configuration
        // update of recognizer settings is not needed (flag is set to false)
        updateUI(false);
    }

    /**
     * Updates user interface based on currently selected configuration. Also updates the
     * recognizers configuration if {@code updateRecognizerSettings} is set to {@code true}.
     * @param updateRecognizerSettings Indicates whether the recognizers reconfiguration
     *                                 will be performed, based on current settings.
     */
    private void updateUI(boolean updateRecognizerSettings) {
        mMessage.setText(mConfiguration[mSelectedConfiguration].getText(this));

        mTitleIndicator.getViewPager().setCurrentItem(mSelectedConfiguration);

        if (updateRecognizerSettings) {
            RecognitionSettings recognitionSettings = new RecognitionSettings();

            BlinkOCRRecognizerSettings ocrSett = new BlinkOCRRecognizerSettings();
            ocrSett.addParser(mConfiguration[mSelectedConfiguration].getParserName(),
                    mConfiguration[mSelectedConfiguration].getParserSettings());

            recognitionSettings.setRecognizerSettingsArray(new RecognizerSettings[] { ocrSett });

            // unlike setRecognitionSettings that needs to be set before calling create,
            // reconfigureRecognizers is designed to be called while recognizer is active.
            mRecognizerView.reconfigureRecognizers(recognitionSettings);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        // all activity's lifecycle methods must be passed to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.start();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // all activity's lifecycle methods must be passed to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.resume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // all activity's lifecycle methods must be passed to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.pause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        // all activity's lifecycle methods must be passed to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.stop();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // all activity's lifecycle methods must be passed to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.destroy();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // all activity lifecycle events must be passed on to recognizer view
        if (mRecognizerView != null) {
            mRecognizerView.changeConfiguration(newConfig);
        }
    }

    @Override
    public void onCameraPreviewStarted() {
        // this method is called when camera preview has started
        // camera is being initialized in background thread and when
        // it is ready, this method is called.
        // You can use it to check camera properties, such as whether
        // torch is supported and then show/hide torch button.
        if (mRecognizerView != null && mRecognizerView.isCameraTorchSupported()) {
            mFlashButton.setVisibility(View.VISIBLE);
            mFlashButton.setImageResource(R.drawable.flashlight);
            mTorchOn = false;
        }

        // after camera is started, we can set the metering area for autofocus, white balance
        // and auto exposure measurements
        // we set the same rectangle as for scanning region
        // we also define that this metering area will not follow device orientation changes because
        // we have set non rotatable scanning region
        mRecognizerView.setMeteringAreas(new RectF[] { new RectF(0.1f, 0.34f, 0.1f + 0.8f, 0.34f + 0.13f) }, false);
    }

    @Override
    public void onCameraPreviewStopped() {
        // this method is called when camera preview has stopped
    }

    @Override
    public void onError(Throwable ex) {
        // This method will be called when opening of camera resulted in exception or
        // recognition process encountered an error.
        // The error details will be given in exc parameter.
        Log.e(this, ex, "Error");
        AlertDialog.Builder ab = new AlertDialog.Builder(this);
        ab.setCancelable(false).setTitle("Error").setMessage(ex.getMessage())
                .setNeutralButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (dialog != null)
                            dialog.dismiss();
                        finish();
                    }
                }).create().show();
        finish();
    }

    @Override
    @TargetApi(23)
    public void onCameraPermissionDenied() {
        // this method is called on Android 6.0 and newer if camera permission was not given
        // by user

        // ask user to give a camera permission. Provided manager asks for
        // permission only if it has not been already granted.
        // on API level < 23, this method does nothing
        mCameraPermissionManager.askForCameraPermission();
    }

    @Override
    public void onAutofocusFailed() {
        // This method is called when camera focusing has failed.
        // You should inform user to try scanning under different light.
    }

    @Override
    public void onAutofocusStarted(Rect[] focusAreas) {
        // This method is called when camera starts focusing.
        // Focus areas is array of rectangles that camera uses
        // as focus measure regions.
    }

    @Override
    public void onAutofocusStopped(Rect[] focusAreas) {
        // This method is called when camera finishes focusing.
    }

    @Override
    public void onScanningDone(RecognitionResults results) {
        BaseRecognitionResult[] dataArray = results.getRecognitionResults();
        // we've enabled only one recognizer, so we expect only one element in dataArray
        if (dataArray != null && dataArray.length == 1) {
            if (dataArray[0] instanceof BlinkOCRRecognitionResult) {
                BlinkOCRRecognitionResult result = (BlinkOCRRecognitionResult) dataArray[0];
                String scanned = result.getParsedResult(mConfiguration[mSelectedConfiguration].getParserName());
                if (scanned != null && !scanned.isEmpty()) {
                    mResult.setText(scanned);
                    mResultView.setVisibility(View.VISIBLE);
                }
                // additionally if you want to process raw OCR result of default parser group
                // instead of parsed strings you can obtain it like this
                // OcrResult ocrResult = result.getOcrResult();

                // to obtain raw OCR result for certain parser group, give a name of the parser
                // group to getOcrResult method
            }
        }
        // Finally, scanning will be resumed automatically and will reuse
        // results from previous scan to make current scan of better quality.
        // Note that preserving state preserves state of all
        // recognizers, including barcode recognizers (if enabled).
        // If you want to reset internal state call resetRecognitionState()
    }

    @Override
    @TargetApi(23)
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // on API level 23, we need to pass request permission result to camera permission manager
        mCameraPermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    public void onBtnExitClicked(View v) {
        finish();
    }

    public void onBtnHelpClicked(View v) {
        Intent intent = new Intent(this, HelpActivity.class);
        startActivity(intent);
    }

    public void onBtnFlashClicked(View v) {
        mRecognizerView.setTorchState(!mTorchOn, new SuccessCallback() {
            @Override
            public void onOperationDone(boolean success) {
                if (success) {
                    mTorchOn = !mTorchOn;

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (mTorchOn) {
                                mFlashButton.setImageResource(R.drawable.flashlight_inverse);
                            } else {
                                mFlashButton.setImageResource(R.drawable.flashlight);
                            }
                        }
                    });
                }
            }
        });
    }

    public void onBtnAcceptClicked(View v) {
        // do something with data from mResult
        mSelectedConfiguration = (mSelectedConfiguration + 1) % mConfiguration.length;
        // hide previous result
        mResultView.setVisibility(View.INVISIBLE);
        updateUI(true);
    }

    private class SamplePagerAdapter extends PagerAdapter {

        /**
         * @return the number of pages to display
         */
        @Override
        public int getCount() {
            return mConfiguration.length;
        }

        /**
         * @return true if the value returned from {@link #instantiateItem(ViewGroup, int)} is the
         * same object as the {@link View} added to the {@link ViewPager}.
         */
        @Override
        public boolean isViewFromObject(View view, Object o) {
            return o == view;
        }

        /**
         * Return the title of the item at {@code position}. This is important as what this method
         * returns is what is displayed in the {@link SlidingTabLayout}.
         * <p>
         * Here we construct one using the position value, but for real application the title should
         * refer to the item's contents.
         */
        @Override
        public CharSequence getPageTitle(int position) {
            return mConfiguration[position].getTitle(ScanActivity.this);
        }

        /**
         * Instantiate the {@link View} which should be displayed at {@code position}. Here we
         * inflate a layout from the apps resources and then change the text view to signify the position.
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            return new View(ScanActivity.this);
        }

        /**
         * Destroy the item from the {@link ViewPager}. In our case this is simply removing the
         * {@link View}.
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }

}