package com.kernal.passportreader.sdk.view; import android.annotation.TargetApi; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Color; import android.hardware.Camera; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.AttributeSet; import android.view.Gravity; import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.kernal.passportreader.sdk.OcrRecogTask; import com.kernal.passportreader.sdk.R; import com.kernal.passportreader.sdk.ThreadManager; import com.kernal.passportreader.sdk.utils.CardScreenUtil; import com.kernal.passportreader.sdk.utils.ManageIDCardRecogResult; import kernal.idcard.android.Frame; import kernal.idcard.android.IDCardAPI; import kernal.idcard.android.RecogService; import kernal.idcard.android.ResultMessage; import kernal.idcard.camera.CardOcrRecogConfigure; import kernal.idcard.camera.IScanReturnMessage; import kernal.idcard.camera.IdCardType; import kernal.idcard.camera.OcrIdCardRecogParams; import kernal.idcard.camera.ScanICamera; /** * @author A@H * @describle 自定义扫描识别View实现了实时预览方法 */ public class ScanCardsView extends RelativeLayout implements Camera.PreviewCallback, ScanICamera { CameraPreview mPreview; TextView text_idCardType, text_tips; Handler mHandler; protected Camera mCamera; private boolean mSpotAble;//保持预览识别中线程单个执行 private volatile boolean isFirstCreate = true; private Intent recogIntent; private IScanReturnMessage iScanReturnMessage; private int nMainIDX; private int nSubID; private RecogService.recogBinder recogBinder; private OcrIdCardRecogParams ocrIdCardRecogParams; private OcrRecogTask ocrRecogTask; private ViewfinderView viewfinderView; private Frame frame=new Frame(); private int ConfirmSideSuccess; private int nCropType = 1; private volatile boolean isTakePic = false; private boolean isOpendetectLightspot = false; private int orientation; public static int[] IdcardTypes; private String[] picPath; private ResultMessage resultMessage; String errorMessage = ""; Toast toast; /** * 实时预览,定时获取检测边线结果值 */ private Handler PreViewHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (frame != null) { if (ConfirmSideSuccess == -139) { ViewfinderView.FRAMECOLOR = Color.rgb(238, 65, 86); text_tips.setText(getContext().getString(getResources().getIdentifier("please_place", "string", getContext().getPackageName())) + text_idCardType.getText().toString()); if (nCropType == 1) { viewfinderView.setFourLines(frame, null); } PreViewHandler.sendEmptyMessageDelayed(100, 1500); } else if (ConfirmSideSuccess == -145) { ViewfinderView.FRAMECOLOR = Color.rgb(238, 65, 86); if (nCropType == 1) { viewfinderView.setFourLines(frame, null); } text_tips.setText(getContext().getString(getResources().getIdentifier("too_far_away", "string", getContext().getPackageName())) + text_idCardType.getText().toString()); PreViewHandler.sendEmptyMessageDelayed(100, 1500); } else { text_tips.setText(null); ViewfinderView.FRAMECOLOR = Color.rgb(77, 223, 68); if (nCropType == 1) { viewfinderView.setFourLines(frame, null); } PreViewHandler.sendEmptyMessageDelayed(100, 1500); } } } }; /** * 光斑检测提示 */ private Handler spotDectionHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if(toast==null){ toast= Toast.makeText(getContext(), getContext().getString(R.string.detectLightspot), Toast.LENGTH_SHORT); }else{ toast.setText(getContext().getString(R.string.detectLightspot)); } toast.show(); } }; /** * 识别成功更新UI */ private Handler recogSucessHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ViewfinderView.FRAMECOLOR = Color.rgb(77, 223, 68); viewfinderView.setFourLines(frame, null); text_tips.setText(""); isTakePic = false; iScanReturnMessage.scanOCRIdCardSuccess(resultMessage, picPath); } }; private Handler recogErrorHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: iScanReturnMessage.scanOCRIdCardError(errorMessage,picPath); break; case 1: ViewfinderView.FRAMECOLOR = Color.rgb(238, 65, 86); text_tips.setText(getContext().getString(getResources().getIdentifier("please_place", "string", getContext().getPackageName())) + text_idCardType.getText().toString()); if (nCropType == 1) { viewfinderView.setFourLines(frame, null); } if(mCamera!=null&&mSpotAble){ mCamera.setOneShotPreviewCallback(ScanCardsView.this); } break; } } }; public ScanCardsView(Context context) { this(context, null); } public ScanCardsView(Context context, AttributeSet attributeSet) { this(context, attributeSet, 0); } public ScanCardsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mHandler = new Handler(); initOcr(); initView(context, attrs); } /** * 初始化布局 * * @param context * @param attrs */ @TargetApi(16) private void initView(Context context, AttributeSet attrs) { mPreview = new CameraPreview(getContext()); mPreview.setId(R.id.cards_camera_preview); orientation = CardScreenUtil.getScreenOrientation(context); //证件类型 LayoutParams textLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); textLayoutParams.addRule(CENTER_VERTICAL); text_idCardType = new TextView(getContext()); text_idCardType.setText(IdCardType.getIdName(getContext(), nMainIDX, nSubID)); text_idCardType.setGravity(Gravity.CENTER); text_idCardType.setTextColor(Color.RED); text_idCardType.setTextSize(18); text_idCardType.setAlpha(1); //错误提示 text_tips = new TextView(getContext()); LayoutParams texttipLayoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); texttipLayoutParams.addRule(ALIGN_PARENT_BOTTOM); texttipLayoutParams.bottomMargin = CardScreenUtil.dp2px(getContext(), 80); text_tips.setTextSize(14); text_tips.setTextColor(Color.RED); text_tips.setGravity(Gravity.CENTER); text_tips.setAlpha(1); //扫描框 if (nMainIDX != 3000) { viewfinderView = new ViewfinderView(getContext(), nCropType, 0); } else { viewfinderView = new ViewfinderView(getContext(), nCropType, 1); } viewfinderView.setIdcardType(nMainIDX); LayoutParams viewfindParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); //viewfindParams.addRule(RelativeLayout.ALIGN_TOP, mPreview.getId()); // viewfindParams.addRule(RelativeLayout.ALIGN_BOTTOM, mPreview.getId()); this.addView(mPreview); this.addView(text_idCardType, textLayoutParams); this.addView(viewfinderView, viewfindParams); this.addView(text_tips, texttipLayoutParams); } /** * 初始化识别 */ private void initOcr() { initRecogService(); /* if (IdcardTypes != null && IdcardTypes.length > 1) { RecogService.listLoadXMLIdCardType.clear(); for (int i = 0; i < IdcardTypes.length; i++) { if (IdcardTypes[i] == 2 || IdcardTypes[i] == 3) { RecogService.listLoadXMLIdCardType.add(2); RecogService.listLoadXMLIdCardType.add(3); } else { RecogService.listLoadXMLIdCardType.add(IdcardTypes[i]); } } }*/ recogIntent = new Intent(getContext(), RecogService.class); getContext().bindService(recogIntent, recogConn, Service.BIND_AUTO_CREATE); } /** * 识别服务静态数值赋值 */ private void initRecogService() { nMainIDX = CardOcrRecogConfigure.getInstance().nMainId; nSubID = CardOcrRecogConfigure.getInstance().nSubID; nCropType = CardOcrRecogConfigure.getInstance().nCropType; RecogService.isOnlyReadSDAuthmodeLSC = false; if (nMainIDX == 3000) { RecogService.nMainID = 1034; } else { RecogService.nMainID = nMainIDX; } RecogService.isRecogByPath = false; } /** * 实时预览,对每一帧数据进行处理 * @param data * @param camera */ @Override public void onPreviewFrame(final byte[] data, Camera camera) { if (mSpotAble) { if (isFirstCreate) { //WriteUtil.writeLog("预览图和屏幕分辨率的比率为:"+mPreview.getScale()); ocrIdCardRecogParams = new OcrIdCardRecogParams.Build() //设置预览的宽度 .setPreWidth(mPreview.getPreViewSize().x) //设置预览的高度 .setPreHeight(mPreview.getPreViewSize().y) // .setScanICamera(ScanCardsView.this) //设置识别服务 .setRecogBinder(recogBinder) //设置屏幕大小与预览大小的比 .setscale((1 / mPreview.getScale())) //设置图片的方向 .setPicOrientation(CardScreenUtil.getPicOrientation(getContext())) .create(); ocrRecogTask = new OcrRecogTask(getContext(), ocrIdCardRecogParams); //设置扫描识别的敏感区域 ocrRecogTask.setNv21Point(getNV21Point()); } // 传递识别数据,设置是否是拍照 ocrRecogTask.setData(data).setTakePic(isTakePic); ThreadManager.getThreadPool().execute(ocrRecogTask); } } @Override public void setIScan(IScanReturnMessage iScanReturnMessage) { this.iScanReturnMessage = iScanReturnMessage; } /** * 关闭摄像头 */ @Override public void stopCamera() { try { PreViewHandler.removeCallbacksAndMessages(null); spotDectionHandler.removeCallbacksAndMessages(null); recogSucessHandler.removeCallbacksAndMessages(null); recogErrorHandler.removeCallbacksAndMessages(null); if(toast!=null){ toast.cancel(); } if (mCamera != null) { mSpotAble = false; mPreview.stopCameraPreview(); mPreview.setCamera(null, null); mCamera.release(); mCamera = null; } } catch (Exception e) { } } /** * 管理光斑检测 * @param isOpendetectLightspot */ public void managerSpotDection(boolean isOpendetectLightspot) { this.isOpendetectLightspot = isOpendetectLightspot; if(ocrRecogTask!=null){ ocrRecogTask.setOpendetectLightspot(isOpendetectLightspot); } } /** * 管理闪光灯 * * @param */ @Override public void managerFlashLight(boolean isOpenFlash) { if (isOpenFlash) { mPreview.openFlashlight(); } else { mPreview.closeFlashlight(); } } /** * 开启后置相机 */ @Override public void startCamera() { startCameraById(Camera.CameraInfo.CAMERA_FACING_BACK); } /** * 开启指定相机 * * @param var */ @Override public void startCameraById(int var) { if (mCamera != null) { return; } Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); cameraId++) { Camera.getCameraInfo(cameraId, cameraInfo); if (cameraInfo.facing == var) { try { mCamera = Camera.open(var); mPreview.setCamera(mCamera, this); starOcr(); } catch (Exception e) { iScanReturnMessage.openCameraError(e.toString()); } break; } } } /** * 切换证件类型 */ public void switchIDCardType(int nMainIDX, int nSubID) { int[] nSubIDs={nSubID}; CardOcrRecogConfigure.getInstance().setnMainId(nMainIDX).setnSubID(nSubID); initRecogService(); if(recogBinder!=null) { recogBinder.SetParameter(1, nMainIDX); recogBinder.SetIDCardID(nMainIDX, nSubIDs); } ocrRecogTask.setnMainIDX(nMainIDX); viewfinderView.setIdcardType(nMainIDX); viewfinderView.setFourLines(new Frame(), ""); text_idCardType.setText(IdCardType.getIdName(getContext(), nMainIDX, nSubID)); } /** * 开启预览识别 */ private void starOcr() { mSpotAble = true; mHandler.removeCallbacks(mOneShotPreviewCallbackTask); mHandler.post(mOneShotPreviewCallbackTask); PreViewHandler.removeCallbacks(mPreViewUpdateUiTask); PreViewHandler.post(mPreViewUpdateUiTask); } public ServiceConnection recogConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { recogBinder = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { recogBinder = (RecogService.recogBinder) service; if (recogBinder != null) { if (recogBinder.getReturnAuthority() != 0) { iScanReturnMessage.authOCRIdCardError("授权失败" + recogBinder.getReturnAuthority()); } } } }; /** * 根据屏幕上预览框的坐标点计算出图片上的坐标点 * * @return */ int[] getNV21Point() { int[] NV21Point = new int[4]; float scale=mPreview.getScale(); if (CardScreenUtil.ORIENTATION_PORTRAIT == CardScreenUtil.getScreenOrientation(getContext()) && !ViewfinderView.isSameScreen) { NV21Point[0] = (int) (viewfinderView.getFrame().top * scale); NV21Point[1] = (int) (viewfinderView.getFrame().left * scale); NV21Point[2] = (int) (viewfinderView.getFrame().bottom * scale); NV21Point[3] = (int) (viewfinderView.getFrame().right * scale); } else { NV21Point[0] = (int) (viewfinderView.getFrame().left * scale); NV21Point[1] = (int) (viewfinderView.getFrame().top * scale); NV21Point[2] = (int) (viewfinderView.getFrame().right * scale); NV21Point[3] = (int) (viewfinderView.getFrame().bottom *scale); } return NV21Point; } /** * 实现循环回调 */ @Override public void addPreviewCallBack() { isFirstCreate = false; if (mCamera != null && mSpotAble) { try { mCamera.setOneShotPreviewCallback(ScanCardsView.this); } catch (Exception e) { e.printStackTrace(); } } } /** * 取消识别任务,解绑识别服务 */ @Override public void destroyService() { ThreadManager.getThreadPool().cancel(ocrRecogTask); IdcardTypes = null; if (recogBinder != null) { getContext().unbindService(recogConn); recogBinder = null; } } /** * 实时更新界面 * * @param frame * @param ConfirmSideSuccess */ @Override public void UpdateFrame(Frame frame, int ConfirmSideSuccess,int detectLightspot) { this.frame = frame; this.ConfirmSideSuccess = ConfirmSideSuccess; if (isOpendetectLightspot&&ConfirmSideSuccess>=0&&detectLightspot==0) { spotDectionHandler.sendEmptyMessage(0); } if (nCropType == 1) { viewfinderView.setFourLines(frame, null); } } /** * 证件识别成功 * * @param resultMessage * @param picPath */ @Override public void recogSucessUpdateUi(ResultMessage resultMessage, String[] picPath) { this.resultMessage=resultMessage; this.picPath = picPath; PreViewHandler.removeCallbacksAndMessages(null); spotDectionHandler.removeCallbacksAndMessages(null); isTakePic = false; recogSucessHandler.sendEmptyMessage(0); } /** * 证件识别失败 * * @param resultMessage */ @Override public void recogErrorUpdateUi(ResultMessage resultMessage,String[] picPath) { if (isTakePic) { isTakePic = false; this.picPath=picPath; PreViewHandler.removeCallbacksAndMessages(null); errorMessage = ManageIDCardRecogResult.managerErrorRecogResult(getContext(), resultMessage); recogErrorHandler.sendEmptyMessage(0); } else { if(resultMessage.ReturnRecogIDCard!=-6){ this.picPath=picPath; PreViewHandler.removeCallbacksAndMessages(null); errorMessage = ManageIDCardRecogResult.managerErrorRecogResult(getContext(), resultMessage); recogErrorHandler.sendEmptyMessage(0); return; }else{ recogErrorHandler.sendEmptyMessage(1); } } } /** * 拍照识别 */ @Override public void takePicRecog() { isTakePic = true; } @Override public void importPicRecog(String picPath) { OcrRecogTask.importPicPath= picPath; isTakePic = true; RecogService.isRecogByPath = true; ConfirmSideSuccess = -1; /* viewfinderView.setFourLines(new Frame(), null); text_tips.setText("");*/ } /** * 循环监听扫描检测边线返回值 */ private Runnable mPreViewUpdateUiTask = new Runnable() { @Override public void run() { PreViewHandler.sendEmptyMessageDelayed(100, 1000); } }; /** * 设置预览回调 */ private Runnable mOneShotPreviewCallbackTask = new Runnable() { @Override public void run() { if (mCamera != null && mSpotAble) { try { mCamera.setOneShotPreviewCallback(ScanCardsView.this); } catch (Exception e) { e.printStackTrace(); } } } }; @Override public void stopPreview() { if (mCamera != null) { mCamera.stopPreview(); } } }