com.raffaele.squarecash4glass.CVVConfirmActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.raffaele.squarecash4glass.CVVConfirmActivity.java

Source

/*
 * Copyright (c) 2014 Rex St. John on behalf of AirPair.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.raffaele.squarecash4glass;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.builder.RecursiveToStringStyle;
import org.apache.commons.lang3.builder.ToStringBuilder;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.media.AudioManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.google.android.glass.media.Sounds;
import com.google.android.glass.touchpad.Gesture;
import com.google.android.glass.touchpad.GestureDetector;
import com.googlecode.tesseract.android.TessBaseAPI;

/**
 * Take a picture directly from inside the app using this fragment.
 * 
 * Reference: http://developer.android.com/training/camera/cameradirect.html
 * Reference:
 * http://stackoverflow.com/questions/7942378/android-camera-will-not-
 * work-startpreview-fails Reference:
 * http://stackoverflow.com/questions/10913181/camera-preview-is-not-restarting
 * 
 * Created by Rex St. John (on behalf of AirPair.com) on 3/4/14.
 */
public class CVVConfirmActivity extends Activity {

    private static final String CVVRegExprStr = "^[0-9]{3,4}$";
    private static final Pattern CVVPattern = Pattern.compile(CVVRegExprStr);

    private static final String TAG = "CVVConfirmActivity";

    private String CVVCode = null;

    private GestureDetector mGestureDetector;

    // Native camera.
    private Camera mCamera;
    private boolean cameraAvailable;

    // View to display the camera output.
    private CameraPreview mPreview;
    private View mCameraView;

    private int maxZoomLevel;

    private int currentZoomLevel;

    /**
     * Default empty constructor.
     */
    public CVVConfirmActivity() {
        super();
    }

    private GestureDetector createGestureDetector(Context context) {
        GestureDetector gestureDetector = new GestureDetector(context);
        gestureDetector.setBaseListener(new GestureDetector.BaseListener() {
            @Override
            public boolean onGesture(Gesture gesture) {
                if (gesture == Gesture.TAP) {
                    Log.i(TAG, "TAP is detected");
                    if (mCamera != null && cameraAvailable) {
                        cameraAvailable = false;
                        mCamera.takePicture(mShutterCallback, null, mPictureCallback);
                    }
                    return true;
                } else if (gesture == Gesture.TWO_TAP) {
                    doLaunchTransactionCompleted();
                    return true;
                } else if (gesture == Gesture.SWIPE_RIGHT) {
                    currentZoomLevel = Math.max(currentZoomLevel + 1, 1);
                    updateCameraZoom();
                    return true;
                } else if (gesture == Gesture.SWIPE_LEFT) {
                    currentZoomLevel = Math.max(currentZoomLevel - 1, 1);
                    updateCameraZoom();
                    return true;
                }
                if (gesture == Gesture.TWO_SWIPE_RIGHT) {
                    currentZoomLevel = Math.min(currentZoomLevel + 10, maxZoomLevel);
                    updateCameraZoom();
                    return true;
                }
                if (gesture == Gesture.TWO_SWIPE_LEFT) {
                    currentZoomLevel = Math.max(currentZoomLevel - 10, 0);
                    updateCameraZoom();
                    return true;
                }
                return false;
            }
        });
        return gestureDetector;
    }

    private void doLaunchTransactionCompleted() {
        // startActivity(new Intent(this,
        // ContactActivity.class).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY|Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK));
        startActivity(new Intent(this, TransactionCompleted.class).addFlags(
                Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));

    }

    class ProcessPictureTask extends AsyncTask<byte[], Void, String> {
        @Override
        protected String doInBackground(byte[]... bytes) {
            if (bytes.length != 1)
                return null;
            byte[] data = bytes[0];
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            String lang = "eng";
            // Make sure this path exist
            File dataPathDir = new File(getFilesDir(), InstallationListener.tesseactDirName);
            // String DATA_PATH = this.getDir(dataPathDir.getAbsolutePath(),
            // Context.MODE_PRIVATE).getAbsolutePath()+"/";
            TessBaseAPI baseApi = new TessBaseAPI();
            baseApi.setVariable("tessedit_char_whitelist", "0123456789");
            baseApi.setDebug(true);
            baseApi.init(dataPathDir.getAbsolutePath(), lang);
            baseApi.setImage(bitmap);
            String recognizedText = baseApi.getUTF8Text();
            Log.i(TAG, "recognizedText: " + recognizedText);
            Matcher CVVMatcher = CVVPattern.matcher(recognizedText);
            // we print the first occurrence if it exists
            String result = null;
            if (CVVMatcher.find()) {
                result = CVVMatcher.group();
            }
            Log.i(TAG, "ProcessPictureTask.doInBackground() completed, result: " + result);
            return result;
        }

        protected void onPostExecute(String result) {
            if (result != null) {
                CVVCode = result;
                ((TextView) findViewById(R.id.TextView1)).setText("Scanned Code: " + CVVCode);
            }
        }

    }

    /*
     * Send generic motion events to the gesture detector
     */
    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        if (mGestureDetector != null) {
            return mGestureDetector.onMotionEvent(event);
        }
        return false;
    }

    public void onResume() {
        super.onResume();

        // Create our Preview view and set it as the content of our activity.
        boolean opened = safeCameraOpenInView(mCameraView);

        if (opened == false) {
            Log.d("CameraGuide", "Error, Camera failed to open");
            return;
        }
        maxZoomLevel = mCamera.getParameters().getMaxZoom();
        currentZoomLevel = mCamera.getParameters().getZoom();

    }

    /**
     * OnCreateView fragment override
     * 
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.cvv_confirm_view);
        mCameraView = findViewById(R.id.camera_preview);
        mGestureDetector = createGestureDetector(this);
        Log.i(TAG, "onCreate completed.");

    }

    /**
     * Recommended "safe" way to open the camera.
     * 
     * @param view
     * @return
     */
    private boolean safeCameraOpenInView(View view) {
        boolean qOpened = false;
        releaseCameraAndPreview();
        mCamera = getCameraInstance();
        qOpened = (mCamera != null);

        if (qOpened == true) {
            mPreview = new CameraPreview(getBaseContext(), mCamera, view);
            FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview);
            preview.addView(mPreview);
            mPreview.startCameraPreview();
            Log.i(TAG, "camera parameters:" + mCamera.getParameters());
            Log.i(TAG, "camera current size:"
                    + ToStringBuilder.reflectionToString(mCamera.getParameters().getPictureSize()));
            Log.i(TAG,
                    "camera supported sizes:" + ToStringBuilder.reflectionToString(
                            mCamera.getParameters().getSupportedPictureSizes().toArray(),
                            new RecursiveToStringStyle()));
            cameraAvailable = true;
        }
        Log.i(TAG, "safeCameraOpenInView completed.");
        return qOpened;
    }

    /**
     * Safe method for getting a camera instance.
     * 
     * @return
     */
    public static Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        } catch (Exception e) {
            e.printStackTrace();
        }
        return c; // returns null if camera is unavailable
    }

    @Override
    public void onPause() {
        super.onPause();
        releaseCameraAndPreview();
        Log.i(TAG, "onPause completed.");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.i(TAG, "onDestroy completed.");
    }

    /**
     * Clear any existing preview / camera.
     */
    private void releaseCameraAndPreview() {

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        if (mPreview != null) {
            mPreview.destroyDrawingCache();
            mPreview.mCamera = null;
        }
    }

    /**
     * @param parameters
     */
    private void updateCameraZoom() {
        Log.i(TAG, "currentZoomLevel" + currentZoomLevel);
        Log.i(TAG, "maxZoomLevel" + maxZoomLevel);
        Camera.Parameters parameters = mCamera.getParameters();
        Log.i(TAG, "zoomSupported" + parameters.isZoomSupported());
        Log.i(TAG, "smoothZoomSupported" + parameters.isSmoothZoomSupported());
        if (parameters.isZoomSupported()) {
            if (parameters.isSmoothZoomSupported()) {
                mCamera.startSmoothZoom(currentZoomLevel);
            } else {
                parameters.setZoom(currentZoomLevel);
                mCamera.setParameters(parameters);
            }
        }
        Log.i(TAG, "updateCameraZoom completed.");
    }

    /**
     * Surface on which the camera projects it's capture results. This is derived
     * both from Google's docs and the excellent StackOverflow answer provided
     * below.
     * 
     * Reference / Credit:
     * http://stackoverflow.com/questions/7942378/android-camera
     * -will-not-work-startpreview-fails
     */
    class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        // SurfaceHolder
        private SurfaceHolder mHolder;

        // Our Camera.
        private Camera mCamera;

        // Parent Context.
        private Context mContext;

        // Camera Sizing (For rotation, orientation changes)
        private Camera.Size mPreviewSize;

        // List of supported preview sizes
        private List<Camera.Size> mSupportedPreviewSizes;

        // Flash modes supported by this camera
        private List<String> mSupportedFlashModes;

        // View holding this camera.
        private View mCameraView;

        public CameraPreview(Context context, Camera camera, View cameraView) {
            super(context);

            // Capture the context
            mCameraView = cameraView;
            mContext = context;
            setCamera(camera);

            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            mHolder.setKeepScreenOn(true);
            // deprecated setting, but required on Android versions prior to 3.0
            //mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            Log.i(TAG, "CameraPreview() completed.");
        }

        /**
         * Begin the preview of the camera input.
         */
        public void startCameraPreview() {
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(TAG, "startCameraPreview() completed.");
        }

        /**
         * Extract supported preview and flash modes from the camera.
         * 
         * @param camera
         */
        private void setCamera(Camera camera) {
            // Source:
            // http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
            mCamera = camera;
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();

            // Set the camera to Auto Flash mode.
            if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
                Camera.Parameters parameters = mCamera.getParameters();
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
                mCamera.setParameters(parameters);
            }

            requestLayout();
            Log.i(TAG, "setCamera() completed.");
        }

        /**
         * The Surface has been created, now tell the camera where to draw the
         * preview.
         * 
         * @param holder
         */
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                mCamera.setPreviewDisplay(holder);
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.i(TAG, "surfaceCreated() completed.");
        }

        /**
         * Dispose of the camera preview.
         * 
         * @param holder
         */
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (mCamera != null) {
                mCamera.stopPreview();
            }
            Log.i(TAG, "surfaceDestroyed() completed.");
        }

        /**
         * React to surface changed events
         * 
         * @param holder
         * @param format
         * @param w
         * @param h
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.

            if (mHolder.getSurface() == null) {
                // preview surface does not exist
                return;
            }

            // stop preview before making changes
            try {
                Camera.Parameters parameters = mCamera.getParameters();

                // Set the auto-focus mode to "continuous"
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
                // Preview size must exist.
                if (mPreviewSize != null) {
                    Camera.Size previewSize = mPreviewSize;
                    parameters.setPreviewSize(previewSize.width, previewSize.height);
                }
                mCamera.setParameters(parameters);
                mCamera.startPreview();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(TAG, "surfaceChanged() camera focus more: " + mCamera.getParameters().getFocusMode());
            Log.i(TAG, "surfaceChanged() completed.");
        }

        /**
         * Calculate the measurements of the layout
         * 
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // Source:
            // http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
            final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
            final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
            setMeasuredDimension(width, height);

            if (mSupportedPreviewSizes != null) {
                mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
            }
            Log.i(TAG, "onMeasure() completed. witdh: " + width + " height: " + height);
        }

        /**
         * Update the layout based on rotation and orientation changes.
         * 
         * @param changed
         * @param left
         * @param top
         * @param right
         * @param bottom
         */
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            // Source:
            // http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
            if (changed) {
                final int width = right - left;
                final int height = bottom - top;

                int previewWidth = width;
                int previewHeight = height;

                // if (mPreviewSize != null) {
                // Display display = ((WindowManager)
                // mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                // Log.i(TAG, "display:" + display);
                // switch (display.getRotation()) {
                // case Surface.ROTATION_0:
                // previewWidth = mPreviewSize.width;
                // previewHeight = mPreviewSize.height;
                // // mCamera.setDisplayOrientation(90);
                // break;
                // case Surface.ROTATION_90:
                // previewWidth = mPreviewSize.width;
                // previewHeight = mPreviewSize.height;
                // break;
                // case Surface.ROTATION_180:
                // previewWidth = mPreviewSize.height;
                // previewHeight = mPreviewSize.width;
                // break;
                // case Surface.ROTATION_270:
                // previewWidth = mPreviewSize.width;
                // previewHeight = mPreviewSize.height;
                // mCamera.setDisplayOrientation(180);
                // break;
                // }
                // }

                final int scaledChildHeight = previewHeight * width / previewWidth;
                mCameraView.layout(0, height - scaledChildHeight, width, height);
                Log.i(TAG, "onLayout() completed." + 0 + " " + (height - scaledChildHeight) + " " + width + " "
                        + height);
            }
        }

        /**
         * 
         * @param sizes
         * @param width
         * @param height
         * @return
         */
        private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int width, int height) {
            // Source:
            // http://stackoverflow.com/questions/7942378/android-camera-will-not-work-startpreview-fails
            Camera.Size optimalSize = null;

            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) height / width;

            // Try to find a size match which suits the whole screen minus the menu on
            // the left.
            for (Camera.Size size : sizes) {

                if (size.height != width)
                    continue;
                double ratio = (double) size.width / size.height;
                if (ratio <= targetRatio + ASPECT_TOLERANCE && ratio >= targetRatio - ASPECT_TOLERANCE) {
                    optimalSize = size;
                }
            }

            // If we cannot find the one that matches the aspect ratio, ignore the
            // requirement.
            if (optimalSize == null) {
                // TODO : Backup in case we don't get a size.
            }
            Log.i(TAG, "getOptimalPreviewSize() completed: " + ToStringBuilder.reflectionToString(optimalSize));
            return optimalSize;
        }
    }

    private final ShutterCallback mShutterCallback = new ShutterCallback() {

        @Override
        public void onShutter() {
            // TODO Auto-generated method stub
            AudioManager audio = (AudioManager) CVVConfirmActivity.this.getSystemService(Context.AUDIO_SERVICE);
            audio.playSoundEffect(Sounds.TAP);
            Log.i(TAG, "onShutter() completed.");
        }

    };

    /**
     * Picture Callback for handling a picture capture and saving it out to a
     * file.
     */
    private final PictureCallback mPictureCallback = new PictureCallback() {

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            new ProcessPictureTask().execute(data);
            mCamera.startPreview();
            //safeCameraOpenInView(mCameraView);
            cameraAvailable = true;
            Log.i(TAG, "onPictureTaken() completed.");
        }
    };

}