2 커밋 7e117d432c ... d9bcf76080

작성자 SHA1 메시지 날짜
  ifengouy d9bcf76080 Merge remote-tracking branch 'origin/master' 2 년 전
  ifengouy 401660e75f 百度身份证识别、人证核验提示、删除fpimg文件 2 년 전

+ 8 - 0
app/build.gradle

@@ -90,4 +90,12 @@ dependencies {
     implementation 'com.liaoinstan.springview:library:1.5.1'
 
     implementation 'net.sourceforge.jexcelapi:jxl:2.6.12'
+
+
+    implementation files('libs/baidu_idcard.jar')
+    implementation files('libs/baidu_easymobile_license.jar')
+    implementation files('libs/bd_unifylicense.jar')
+    implementation files('libs/liantian.jar')
+    implementation project(':cameraui')
+    
 }

+ 11 - 0
app/src/main/AndroidManifest.xml

@@ -41,10 +41,21 @@
         <activity android:name=".activity.VisitInputActivity" />
         <activity android:name=".activity.VisitLogActivity" />
         <activity android:name=".activity.AuthActivity" />
+        <activity android:name=".baidu.IDCardReadActivity" />
 
         <service
             android:name=".service.PullDataService"
             android:permission="android.permission.BIND_JOB_SERVICE" />
+
+        <provider
+            android:name="androidx.core.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/filepath" />
+        </provider>
     </application>
 
 </manifest>

+ 3 - 2
app/src/main/java/com/sunwin/visitorapp/BaseFragment.java

@@ -1,6 +1,5 @@
 package com.sunwin.visitorapp;
 
-import android.app.Activity;
 import android.content.Context;
 import android.os.Bundle;
 
@@ -12,8 +11,10 @@ import com.sunwin.visitorapp.view.LoadingDialog;
 public class BaseFragment extends Fragment {
     protected static String TAG = "";
     protected BaseActivity mContext;
-    private LoadingDialog loadingDialog;
+    protected LoadingDialog loadingDialog;
 
+    protected static final int INTENT_CODE_PICK_IMAGE = 1001;
+    protected static final int INTENT_CODE_CAMERA_IMAGE = 1002;
 
     public void onAttach(Context context) {
         super.onAttach(context);

+ 47 - 7
app/src/main/java/com/sunwin/visitorapp/SplashActivity.java

@@ -14,10 +14,16 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.core.app.ActivityCompat;
 
+import com.baidu.vis.general.Predictor;
+import com.baidu.vis.general.SDKExceptions;
+import com.baidu.vis.unified.license.AndroidLicenser;
+import com.baidu.vis.unified.license.BDLicenseActivator;
+import com.baidu.vis.unified.license.BDLicenseLocalInfo;
 import com.srp.AuthApi.AuthApi;
 import com.srp.AuthApi.AuthApplyResponse;
 import com.srp.AuthApi.ErrorCodeConfig;
@@ -39,6 +45,8 @@ import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Iterator;
 
+import static android.content.ContentValues.TAG;
+
 public class SplashActivity extends BaseActivity {
 
     private static final int REQUEST_FOR_PERMISSION = 100;
@@ -79,11 +87,7 @@ public class SplashActivity extends BaseActivity {
 //        String cert = readExternal(CERT_PATH).trim();
         String cert = SharePrefenceUtils.getString(Constant.ISharePrefence.CERT, "");
         if (TextUtils.isEmpty(cert)) {
-            if(BuildConfig.DEBUG){
-                openApplication();
-            }else{
-                startAuthActivity();
-            }
+            startAuthActivity();
             return;
         }
 
@@ -109,9 +113,9 @@ public class SplashActivity extends BaseActivity {
                         public void run() {
                             ToastUtils.showToast("Apply update: error. error code is: " + result.errorCode + " , error message: " + result.errorMessage);
                             loadingDialog.dismissLoadingDialog();
-                            if(BuildConfig.DEBUG){
+                            if (BuildConfig.DEBUG) {
                                 openApplication();
-                            }else{
+                            } else {
                                 startAuthActivity();
                             }
 
@@ -227,8 +231,44 @@ public class SplashActivity extends BaseActivity {
 
     protected void authAndOpenApplication() {
         authPermission();
+        baiduPermission();
+
     }
 
+    private void baiduPermission() {
+        BDLicenseLocalInfo bdLicenseLocalInfo = AndroidLicenser.getInstance().authGetLocalInfo(this, Predictor.getAlgorithmId());
+        LogUtil.e(TAG,"bdLicenseLocalInfo:" + bdLicenseLocalInfo.toString());
+        // 在线自动激活
+        int ret = BDLicenseActivator.initLicenseOnLine(this, "XQCX-PDX5-FXCM-GFC4",
+                "license.ini", Predictor.getAlgorithmId());
+        if (ret != 0) {
+            Log.e(TAG, "init: init license : " + ret);
+            return;
+        }
+        int modelStatus = initIDCard();
+        if (modelStatus != 0) {
+            LogUtil.e(TAG,"model init error:" + modelStatus);
+        }
+    }
+    int initIDCard() {
+        String model_path = "general_assert.bundle";
+        int modelInit = 0;
+        try {
+            modelInit = com.baidu.vis.general.Predictor.getInstance().initModel(
+                    this, model_path, 0);
+        } catch (SDKExceptions.IlleagleLicense illeagleLicense) {
+            illeagleLicense.printStackTrace();
+            Log.e(TAG, "illeagleLicense");
+            return -1;
+        } catch (SDKExceptions.MissingModleFileInAssetFolder
+                missingModleFileInAssetFolder) {
+            missingModleFileInAssetFolder.printStackTrace();
+            Log.e(TAG, "missingModleFileInAssetFolder");
+            return -2;
+        }
+        Log.e(TAG, "onCreate: model init : " + modelInit);
+        return 0;
+    }
     private final String ACTION_USB_PERMISSION = "com.sunwin.visitorapp.USB_PERMISSION";
 
     private void requestDevicePermission() {

+ 11 - 1
app/src/main/java/com/sunwin/visitorapp/activity/HomeAc.java

@@ -2,6 +2,7 @@ package com.sunwin.visitorapp.activity;
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Environment;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
@@ -23,6 +24,7 @@ import com.sunwin.visitorapp.fragment.TimeFragment;
 import com.sunwin.visitorapp.fragment.VisitSignFragment;
 import com.sunwin.visitorapp.manage.RunDataManage;
 import com.sunwin.visitorapp.utils.Constant;
+import com.sunwin.visitorapp.utils.FileUtil;
 import com.sunwin.visitorapp.utils.NetUtils;
 import com.sunwin.visitorapp.utils.PopupWindowHelper;
 import com.sunwin.visitorapp.utils.SharePrefenceUtils;
@@ -63,7 +65,7 @@ public class HomeAc extends BaseActivity implements View.OnClickListener, RegTyp
     @Override
     protected void onResume() {
         super.onResume();
-
+        FileUtil.DeleteFolder(Environment.getExternalStorageDirectory().getPath()+"/fpimg/");
     }
 
     @Override
@@ -208,4 +210,12 @@ public class HomeAc extends BaseActivity implements View.OnClickListener, RegTyp
         Intent intent = new Intent(this, VisitInputActivity.class);
         startActivity(intent);
     }
+
+    @Override
+    public void showOCRReg() {
+        Intent intent = new Intent(this, VisitorRegActivity.class);
+        intent.putExtra(Constant.IIntentValue.VISIT_REG_TYPE, 4);
+        intent.putExtra(Constant.IIntentValue.ISLOGINUSER, isLogin);
+        startActivity(intent);
+    }
 }

+ 1 - 1
app/src/main/java/com/sunwin/visitorapp/activity/VisitSignActivity.java

@@ -116,7 +116,7 @@ public class VisitSignActivity extends BaseActivity implements IdCardReadCallbac
     @Override
     public void onIdNumRead(String idNum, String idCardPath) {
         LogUtil.e(TAG, "idNum = " + idNum);
-        FRImpl.getInstance().idCardInfo = null;
+        FRImpl.getInstance().mMyIdCardInfo = null;
         this.idCardPath = idCardPath;
         updataUserInfoByIdNum(idNum, 5);
     }

+ 8 - 2
app/src/main/java/com/sunwin/visitorapp/activity/VisitorRegActivity.java

@@ -13,6 +13,7 @@ import com.sunwin.visitorapp.BaseActivity;
 import com.sunwin.visitorapp.R;
 import com.sunwin.visitorapp.adapter.VisitorRegAdapter;
 import com.sunwin.visitorapp.fragment.IdcardRegFragment;
+import com.sunwin.visitorapp.fragment.OcrFragmnet;
 import com.sunwin.visitorapp.fragment.RegTypeFragment;
 import com.sunwin.visitorapp.fragment.TimeFragment;
 import com.sunwin.visitorapp.utils.Constant;
@@ -87,8 +88,8 @@ public class VisitorRegActivity extends BaseActivity implements  RegTypeFragment
 //        RegTypeFragment regTypeFragment = new RegTypeFragment(this);
         if (visitRegType == 1) {
             showFragment(new IdcardRegFragment());
-        } else {
-//            showFragment(new NoCardRegFragment());
+        } else if (visitRegType == 4) {
+            showFragment(new OcrFragmnet());
         }
 
 
@@ -141,4 +142,9 @@ public class VisitorRegActivity extends BaseActivity implements  RegTypeFragment
     public void showNoCardReg() {
         startActivity(new Intent(this, NoCardRegActivity.class));
     }
+
+    @Override
+    public void showOCRReg() {
+        replaceFragment(new OcrFragmnet());
+    }
 }

+ 2 - 1
app/src/main/java/com/sunwin/visitorapp/face/FRAbs.java

@@ -10,6 +10,7 @@ import android.os.Environment;
 import android.util.Log;
 
 import com.guo.android_extend.java.ExtByteArrayOutputStream;
+import com.sunwin.visitorapp.model.MyIDCardInfo;
 import com.sunwin.visitorapp.model.UserModel;
 import com.sunwin.visitorapp.model.bus.DescEvent;
 import com.sunwin.visitorapp.utils.BitmapUtils;
@@ -30,7 +31,7 @@ public abstract class FRAbs {
     static final String TAG = FRAbs.class.getSimpleName();
 
     protected volatile IFaceInfo mCurFaceInfo; //当前正在处理的人脸信息
-    public IDCardInfo idCardInfo;//刷身份证开门时的身份证信息
+    public MyIDCardInfo mMyIdCardInfo;//刷身份证开门时的身份证信息
     public static int DETECTER_FRONT_TYPE = 1;//前端提取的数据
 
     //初始化引擎

+ 17 - 12
app/src/main/java/com/sunwin/visitorapp/face/FRImpl.java

@@ -9,7 +9,6 @@ import android.graphics.YuvImage;
 import android.os.Environment;
 
 import com.guo.android_extend.java.ExtByteArrayOutputStream;
-import com.nostra13.universalimageloader.core.ImageLoader;
 import com.sunwin.visitorapp.BaseApplication;
 import com.sunwin.visitorapp.db.DatabaseManager;
 import com.sunwin.visitorapp.db.UserInfoModel;
@@ -347,7 +346,7 @@ public class FRImpl extends FRAbs {
 
                     if (isLocalGroupExist) {
 
-                        if (idCardInfo != null) {
+                        if (mMyIdCardInfo != null) {
                             idCardRecognite(detectResult);
 
                         } else {
@@ -450,12 +449,12 @@ public class FRImpl extends FRAbs {
 
         OpenDoorByFaceNetResultInfo openDoorByFaceNetResultInfo = new OpenDoorByFaceNetResultInfo();
         openDoorByFaceNetResultInfo.setCode(-1);
-        if (idCardInfo.getPhoto() != null) {
-            String fileName = idCardInfo.getId() + ".jpg";  //jpeg文件名定义
-            String dirPath = Constant.RecognitionDir;    //系统路径
-            String path = "file://" + dirPath + fileName;
+        if (mMyIdCardInfo.getIdNum() != null) {
+//            String fileName = mMyIdCardInfo.getIdNum() + ".jpg";  //jpeg文件名定义
+//            String dirPath = Constant.RecognitionDir;    //系统路径
+            String path = mMyIdCardInfo.getIdNumImagePath();
             String currentFacePath;
-            Bitmap idBitmap = ImageLoader.getInstance().loadImageSync(path);
+            Bitmap idBitmap = FileUtil.getBitMapFromFile(path);
             CameraPreviewData cameraPreviewData = detectResult.getCameraPreviewData();
             final YuvImage yuv = new YuvImage(cameraPreviewData.nv21Data, ImageFormat.NV21, cameraPreviewData.width, cameraPreviewData.height, null);
             ExtByteArrayOutputStream ops = new ExtByteArrayOutputStream();
@@ -481,33 +480,39 @@ public class FRImpl extends FRAbs {
                  * */
                 if (facePassCompareResult1 != null && facePassCompareResult1.score > Constant.FACE_ID_COMPARE_VALUE) {
                     LogUtil.e(DEBUG_TAG, "人证识别时间:" + (System.currentTimeMillis() - startTimer) + ",分数=" + facePassCompareResult1.score);
-                    currentFacePath = BitmapUtils.transToFileFromNv21("current" + idCardInfo.getId(), cameraPreviewData.nv21Data, cameraPreviewData.width, cameraPreviewData.height, new Rect(0, 0, cameraPreviewData.width, cameraPreviewData.height));
+                    currentFacePath = BitmapUtils.transToFileFromNv21("current" + mMyIdCardInfo.getIdNum(), cameraPreviewData.nv21Data, cameraPreviewData.width, cameraPreviewData.height, new Rect(0, 0, cameraPreviewData.width, cameraPreviewData.height));
                     LogUtil.e("currentFacePath", currentFacePath);
                     openDoorByFaceNetResultInfo.setCode(0);
                     openDoorByFaceNetResultInfo.setSimilarity(facePassCompareResult1.score);
                     openDoorByFaceNetResultInfo.setCurrentFace(currentFacePath);
-                    openDoorByFaceNetResultInfo.setIdNum(idCardInfo.getId());
-                    openDoorByFaceNetResultInfo.setPerson_name(idCardInfo.getName());
+                    openDoorByFaceNetResultInfo.setIdNum(mMyIdCardInfo.getIdNum());
+                    openDoorByFaceNetResultInfo.setPerson_name(mMyIdCardInfo.getName());
                     ArrayList<FacesModel> arrayList = new ArrayList<>();
                     FacesModel facesModel = new FacesModel();
                     facesModel.setFace_image(ConvertUtil.bitmapToBase64(idBitmap));
                     arrayList.add(facesModel);
                     openDoorByFaceNetResultInfo.setFaces(arrayList);
                     EventBus.getDefault().post(new DescEvent().setDesc(DescEvent.DESC_FR_SUCC).setOpenDoorByFaceNetResultInfo(openDoorByFaceNetResultInfo));
+
                     recognizeTime = 0;
-                    idCardInfo = null;
+                    mMyIdCardInfo = null;
                     LogUtil.e("step", "6");
                 } else {
                     LogUtil.e(TAG, "人证识别时间:" + recognizeTime);
                     recognizeTime++;
                     if (recognizeTime == Constant.COMPARSION_FREQUENCY) {
                         EventBus.getDefault().post(new DescEvent().setDesc(DescEvent.DESC_FR_NO_BODY));
-                        idCardInfo = null;
+                        mMyIdCardInfo = null;
                         recognizeTime = 0;
                     }
                 }
             } catch (Exception e) {
                 e.printStackTrace();
+            } finally {
+                if (idBitmap!= null){
+                    idBitmap.recycle();
+                    idBitmap = null;
+                }
             }
         }
     }

+ 6 - 6
app/src/main/java/com/sunwin/visitorapp/face/IDCardReaderUtil.java

@@ -3,6 +3,7 @@ package com.sunwin.visitorapp.face;
 import android.content.Context;
 import android.graphics.Bitmap;
 
+import com.sunwin.visitorapp.model.MyIDCardInfo;
 import com.sunwin.visitorapp.utils.BitmapUtils;
 import com.sunwin.visitorapp.utils.Constant;
 import com.sunwin.visitorapp.utils.LogUtil;
@@ -40,7 +41,6 @@ public class IDCardReaderUtil implements Runnable {
     private boolean bopen;
     private boolean bStoped;
     private CountDownLatch countdownLatch;
-    private String mAuthentticaImagePath;
 
     private IdCardReadCallback mIdCardReadCallback;
 
@@ -137,15 +137,15 @@ public class IDCardReaderUtil implements Runnable {
 //                            if (!mkDir.exists()) {
 //                                mkDir.mkdirs();   //目录不存在,则创建
 //                            }
-                            mAuthentticaImagePath = dirPath + fileName;
+                            String idNumImagePath = dirPath + fileName;
                             Bitmap bitmap = IDPhotoHelper.Bgr2Bitmap(buf);
-                            BitmapUtils.saveJPGE_After(mContext, bitmap, mAuthentticaImagePath, 100);
-                            mFRAbsLoop.detectFace(new File(mAuthentticaImagePath), FRAbs.DETECTER_FRONT_TYPE);
-                            mFRAbsLoop.idCardInfo = idCardInfo;
+                            BitmapUtils.saveJPGE_After(mContext, bitmap, idNumImagePath, 100);
+                            mFRAbsLoop.detectFace(new File(idNumImagePath), FRAbs.DETECTER_FRONT_TYPE);
+                            mFRAbsLoop.mMyIdCardInfo = new MyIDCardInfo(idCardInfo, idCardInfo.getId(), idCardInfo.getName(),idNumImagePath);
                             if (mContext != null) {
                                 LogUtil.e("detecterView", idCardInfo.getName());
                                 if (mIdCardReadCallback != null) {
-                                    mIdCardReadCallback.onIdNumRead(idCardInfo.getId(),mAuthentticaImagePath);
+                                    mIdCardReadCallback.onIdNumRead(idCardInfo.getId(), idNumImagePath);
                                 }
 
                             }

+ 41 - 0
app/src/main/java/com/sunwin/visitorapp/fragment/BaseRegFragment.java

@@ -0,0 +1,41 @@
+package com.sunwin.visitorapp.fragment;
+
+import com.sunwin.visitorapp.BaseFragment;
+import com.sunwin.visitorapp.face.IDCardReaderUtil;
+import com.sunwin.visitorapp.utils.LogUtil;
+import com.sunwin.visitorapp.view.FaceDetecterView;
+
+public class BaseRegFragment extends BaseFragment {
+
+    protected IDCardReaderUtil idCardReaderUtil;
+    protected FaceDetecterView mFaceDetecterView;
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        LogUtil.e(TAG, "=======onResume = ");
+//        mFaceDetecterView.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        LogUtil.e(TAG, "=======onPause = ");
+
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();  LogUtil.e(TAG, "=======onDestroy = ");
+        if (idCardReaderUtil!= null){
+            idCardReaderUtil.stopRead();
+        }
+        mFaceDetecterView.onPause();
+        mFaceDetecterView.onDestroy();
+    }
+
+    @Override
+    public void onDestroyView() {LogUtil.e(TAG, "=======onDestroyView = ");
+        super.onDestroyView();
+    }
+}

+ 28 - 5
app/src/main/java/com/sunwin/visitorapp/fragment/IdcardRegFragment.java

@@ -3,6 +3,7 @@ package com.sunwin.visitorapp.fragment;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Handler;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -13,6 +14,7 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AlertDialog;
 
+import com.sunwin.visitorapp.BaseActivity;
 import com.sunwin.visitorapp.BaseApplication;
 import com.sunwin.visitorapp.BaseFragment;
 import com.sunwin.visitorapp.R;
@@ -134,6 +136,15 @@ public class IdcardRegFragment extends BaseFragment implements IdCardReadCallbac
         builder.show();
 
     }
+    AlertDialog dialog;
+    private void showSuccess(){
+        AlertDialog.Builder  builder = new AlertDialog.Builder(mContext);
+        builder.setTitle("提示");
+        builder.setCancelable(false);
+        builder.setMessage("核验成功");
+        dialog = builder.show();
+
+    }
     /**
      * ------------------FaceDetecterView.Listener 开始------------------------------
      */
@@ -146,11 +157,23 @@ public class IdcardRegFragment extends BaseFragment implements IdCardReadCallbac
     @Override
     public void detectedUser(OpenDoorByFaceNetResultInfo info) {
         FileUtil.deleteFile(mCardPath);
-        BaseApplication.getSystemTTS().playText("识别成功");
-        Intent intent = new Intent(mContext, VisitorRegisterAc.class);
-        intent.putExtra(Constant.IIntentValue.CURRENTFACEPATH, info.getCurrentFace());
-        intent.putExtra(Constant.IIntentValue.RECOGNIZE_INFO, info);
-        startActivity(intent);
+        FileUtil.DeleteFolder(Environment.getExternalStorageDirectory().getPath()+"/fpimg/");
+        showSuccess();
+
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (dialog!= null){
+                    dialog.dismiss();
+                }
+
+                BaseApplication.getSystemTTS().playText("核验成功");
+                Intent intent = new Intent(mContext, VisitorRegisterAc.class);
+                intent.putExtra(Constant.IIntentValue.CURRENTFACEPATH, info.getCurrentFace());
+                intent.putExtra(Constant.IIntentValue.RECOGNIZE_INFO, info);
+                startActivity(intent);
+            }
+        },2000);
     }
 
     @Override

+ 252 - 0
app/src/main/java/com/sunwin/visitorapp/fragment/OcrFragmnet.java

@@ -0,0 +1,252 @@
+package com.sunwin.visitorapp.fragment;
+
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.baidu.ai.cameraui.IDcardCardActivity;
+import com.baidu.ai.cameraui.parameter.BaseParameter;
+import com.baidu.vis.general.IdcardModel;
+import com.baidu.vis.general.Predictor;
+import com.baidu.vis.general.SDKExceptions;
+import com.sunwin.visitorapp.BaseApplication;
+import com.sunwin.visitorapp.MainActivity;
+import com.sunwin.visitorapp.R;
+import com.sunwin.visitorapp.activity.VisitorRegisterAc;
+import com.sunwin.visitorapp.baidu.IDCardReadActivity;
+import com.sunwin.visitorapp.db.BlackUserModel;
+import com.sunwin.visitorapp.db.DatabaseManager;
+import com.sunwin.visitorapp.face.CameraPreviewData;
+import com.sunwin.visitorapp.face.FRImpl;
+import com.sunwin.visitorapp.model.MyIDCardInfo;
+import com.sunwin.visitorapp.model.OpenDoorByFaceNetResultInfo;
+import com.sunwin.visitorapp.utils.Constant;
+import com.sunwin.visitorapp.utils.FileUtil;
+import com.sunwin.visitorapp.utils.ImageUtil;
+import com.sunwin.visitorapp.utils.LogUtil;
+import com.sunwin.visitorapp.utils.PhotoUtil;
+import com.sunwin.visitorapp.view.FaceDetecterView;
+import com.zkteco.android.biometric.module.idcard.meta.IDCardInfo;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import static com.zkteco.android.biometric.core.utils.ToolUtils.getApplicationContext;
+
+public class OcrFragmnet extends BaseRegFragment implements View.OnClickListener, FaceDetecterView.Listener {
+
+
+    private LinearLayout mLlIdCardReg;
+    private ImageView mIv;
+    private TextView mTvAlum;
+    private TextView mTvPhoto;
+    private Bitmap snapShotBitmap;
+    private String outputFilePath;
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
+
+        View view = inflater.inflate(R.layout.fragment_ocr_reg, container, false);
+
+
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull @NotNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        initView(view);
+        outputFilePath  = getApplicationContext().getFilesDir() + "/output.jpg";
+        mFaceDetecterView.config(mContext, this);
+    }
+
+    private void initView(@NotNull View view) {
+        mLlIdCardReg = view.findViewById(R.id.ll_id_card_reg);
+        mFaceDetecterView = view.findViewById(R.id.faceDetecterView);
+        mIv = view.findViewById(R.id.iv);
+        mTvAlum = view.findViewById(R.id.tv_alum);
+        mTvPhoto = view.findViewById(R.id.tv_photo);
+        mTvAlum.setOnClickListener(this);
+        mTvPhoto.setOnClickListener(this);
+    }
+
+    String takePhotoPath;
+
+    @Override
+    public void onClick(View view) {
+        switch (view.getId()) {
+            case R.id.tv_alum:
+                PhotoUtil.openAlum(this, INTENT_CODE_PICK_IMAGE);
+                break;
+            case R.id.tv_photo:
+//                takePhotoPath = PhotoUtil.takePicture(this, INTENT_CODE_CAMERA_IMAGE);
+
+                Intent intent = new Intent(mContext, IDCardReadActivity.class);
+                Bundle bundle = new Bundle();
+                bundle.putInt(BaseParameter.KEY_TAKE_PICTURE_TYPE, BaseParameter.TYPE_MANUAL);
+                bundle.putInt(BaseParameter.KEY_MASK_TYPE, BaseParameter.MASK_TYPE_IDCARD_FRONT);
+                bundle.putString(BaseParameter.KEY_OUTPUT_FILE_PATH, outputFilePath);
+                intent.putExtra(BaseParameter.KEY_MAIN, bundle);
+                startActivity(intent);
+//                startActivityForResult(intent, CODE_GENERAL);
+                break;
+        }
+    }
+
+    String idCrdPath;
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == INTENT_CODE_PICK_IMAGE) {
+            if (resultCode == Activity.RESULT_OK) {
+                Uri uri = data.getData();
+                String path = FileUtil.getRealPathFromURI(mContext, uri);
+                Bitmap rotateBitmap = dealPic(path);
+                pictureFromAlbum(rotateBitmap);
+            } else {
+                // 取消的时候退出到的是预览界面
+//                isToAlbumActivity = false;
+            }
+        } else if (requestCode == INTENT_CODE_CAMERA_IMAGE) {
+//            loadingDialog.showLoadingDialog("");
+            LogUtil.debugLog("拍照path = " + takePhotoPath);
+            if (resultCode == Activity.RESULT_OK) {
+                Bitmap bitmap = dealPic(takePhotoPath);
+                pictureFromAlbum(bitmap);
+            }
+        }
+    }
+
+    private Bitmap dealPic(String path) {
+        idCrdPath = path;
+        LogUtil.d(TAG, "pick image url: " + path);
+        Bitmap bitmap = FileUtil.getBitMapFromFile(path);
+        ExifInterface exif = null;
+        int exifRotation = 0;
+        try {
+            exif = new ExifInterface(path);
+            exifRotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
+                    ExifInterface.ORIENTATION_NORMAL);
+        } catch (IOException e) {
+            LogUtil.e(TAG, "album selection picture get exif info error");
+        }
+
+        int rotation = ImageUtil.exifToDegrees(exifRotation);
+        Bitmap rotateBitmap = ImageUtil.createRotateBitmap(bitmap, rotation);
+        return rotateBitmap;
+    }
+
+    private void pictureFromAlbum(final Bitmap bitmap) {
+        snapShotBitmap = bitmap;
+        LogUtil.d(TAG, "albumSelectPictureSuccess");
+        mIv.setImageBitmap(bitmap);
+//        changeToAction(true);
+//        setCropBound();
+        onPictureProcess();
+    }
+
+    private void onPictureProcess() {
+        try {
+
+            int result = Predictor.getInstance().predict(snapShotBitmap);
+            if (result == 0) {
+                return;
+            }
+
+            IdcardModel resp = Predictor.getInstance().idcardDetection(1);
+            if (resp.nErrorCode != 0) {
+
+                LogUtil.e(TAG, "身份证质量异常,错误码:" + resp.nErrorCode);
+                return;
+            }
+            LogUtil.e(TAG, "id:" + resp.number + "name:" + resp.name);
+            List<BlackUserModel> model = DatabaseManager.getInstance().query(BlackUserModel.class, "id_card_code", resp.number);
+            if (model.size() > 0) {
+                if (model.size() > 0) {
+                    mContext.showBlackUserDialog();
+                    return;
+                }
+            }
+            MyIDCardInfo idCardInfo = new MyIDCardInfo(new IDCardInfo(), resp.number, resp.name, idCrdPath);
+
+            FRImpl.getInstance().mMyIdCardInfo = idCardInfo;
+            mLlIdCardReg.setVisibility(View.GONE);
+            showTipDialog();
+        } catch (SDKExceptions.IlleagleLicense illeagleLicense) {
+            LogUtil.e(TAG, "SDKExceptions.IlleagleLicense:" + illeagleLicense);
+
+        } catch (SDKExceptions.NotInit notInit) {
+            LogUtil.e(TAG, "SDKExceptions.NotInit:" + notInit);
+        }
+    }
+
+    private void showTipDialog() {        // 创建退出对话框
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        builder.setTitle("温馨提示");
+        builder.setCancelable(false);
+        builder.setMessage("将对您的面部拍摄一张照片,用于人员信息录入,使用完成后会进行删除,不做保存。如同意请点击”确定“按钮");
+        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                new Handler().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mFaceDetecterView.setVisibility(View.VISIBLE);
+                    }
+                });
+                BaseApplication.getSystemTTS().playText("请看摄像头");
+            }
+        });
+        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                mContext.finish();
+            }
+        });
+        builder.show();
+
+    }
+
+    @Override
+    public void detectedFace() {
+
+    }
+
+    @Override
+    public void detectedUser(OpenDoorByFaceNetResultInfo info) {
+        BaseApplication.getSystemTTS().playText("识别成功");
+        Intent intent = new Intent(mContext, VisitorRegisterAc.class);
+        intent.putExtra(Constant.IIntentValue.CURRENTFACEPATH, info.getCurrentFace());
+        intent.putExtra(Constant.IIntentValue.RECOGNIZE_INFO, info);
+        startActivity(intent);
+    }
+
+    @Override
+    public void detecterFail(String st) {
+
+    }
+
+    @Override
+    public void takePic(CameraPreviewData data) {
+
+    }
+}

+ 7 - 2
app/src/main/java/com/sunwin/visitorapp/fragment/RegTypeFragment.java

@@ -14,7 +14,6 @@ import com.sunwin.visitorapp.R;
 import com.sunwin.visitorapp.adapter.VisitorRegAdapter;
 import com.sunwin.visitorapp.utils.Constant;
 import com.sunwin.visitorapp.utils.LogUtil;
-import com.sunwin.visitorapp.utils.ToastUtils;
 import com.sunwin.visitorapp.view.MyGridView;
 
 import org.jetbrains.annotations.NotNull;
@@ -70,6 +69,8 @@ public class RegTypeFragment extends BaseFragment implements AdapterView.OnItemC
         iconList = new ArrayList<>();
         itemList.add("身份证");
         itemList.add("无证登记");
+        itemList.add("OCR读卡登记");
+        iconList.add(R.mipmap.visitor_reg_default);
         iconList.add(R.mipmap.visitor_reg_default);
         iconList.add(R.mipmap.visitor_reg_default);
         if (isLoginUser) {
@@ -104,7 +105,9 @@ public class RegTypeFragment extends BaseFragment implements AdapterView.OnItemC
 //                    startActivity(new Intent(this, NoCardRegActivity.class));
                     break;
                 case 2:
-                    ToastUtils.showToast("开发中...");
+                    if (mListener != null) {
+//                        mListener.showOCRReg();
+                    }
                     break;
             }
         } else {
@@ -119,6 +122,8 @@ public class RegTypeFragment extends BaseFragment implements AdapterView.OnItemC
         void showIdCardReg();
 
         void showNoCardReg();
+
+        void showOCRReg();
     }
 
 //    public void setListener(Listener listener) {

+ 1 - 1
app/src/main/java/com/sunwin/visitorapp/utils/Constant.java

@@ -51,7 +51,7 @@ public class Constant {
         String CURRENTFACEPATH = "currentFacePath";
         String ISLOGINUSER = "isLoginUser";
         String VISIT_SIGN_TYPE = "visitSignType";//1,身份证,2 人脸
-        String VISIT_REG_TYPE = "visitRegType";//访客登记类型:1,身份证,2 无证,3驾驶证
+        String VISIT_REG_TYPE = "visitRegType";//访客登记类型:1,身份证,2 无证,3驾驶证,4ocr
         String VISIT_TYPE = "visitType";//1,签到,2 签离
         String RECOGNIZE_INFO = "recognizeInfo";
     }

+ 92 - 0
app/src/main/java/com/sunwin/visitorapp/utils/FileUtil.java

@@ -1,6 +1,7 @@
 package com.sunwin.visitorapp.utils;
 
 import android.content.Context;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.ImageFormat;
@@ -8,6 +9,7 @@ import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.YuvImage;
 import android.net.Uri;
+import android.provider.MediaStore;
 import android.text.TextUtils;
 
 import com.sunwin.visitorapp.face.CameraPreviewData;
@@ -50,6 +52,42 @@ public class FileUtil {
         SharePrefenceUtils.putString(Constant.ISharePrefence.CERT, content);
         return content;
     }
+    /**
+     * 从相册读取图片
+     * @param path
+     * @return
+     */
+    public static Bitmap getBitMapFromFile(String path) {
+        BitmapFactory.Options option = new BitmapFactory.Options();
+
+        BitmapFactory.decodeFile(path, option);
+        option.inJustDecodeBounds = true;
+        if (option.outWidth > 1080 || option.outHeight > 1920) {
+            option.inSampleSize = 2;
+        }
+        option.inJustDecodeBounds = false;
+        Bitmap bitmap = BitmapFactory.decodeFile(path, option);
+        LogUtil.d(TAG,"pick image success");
+        return bitmap;
+    }
+    public static String getRealPathFromURI(Context context,Uri contentURI) {
+        String result;
+        Cursor cursor = null;
+        try {
+            cursor = context.getContentResolver().query(contentURI, null, null, null, null);
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+        if (cursor == null) {
+            result = contentURI.getPath();
+        } else {
+            cursor.moveToFirst();
+            int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
+            result = cursor.getString(idx);
+            cursor.close();
+        }
+        return result;
+    }
 
     public static String copyToFilesDir(Context context, Uri uri) {
         try {
@@ -178,4 +216,58 @@ public class FileUtil {
         }
         return false;
     }
+    /**
+     *  根据路径删除指定的目录或文件,无论存在与否
+     *@param filePath  要删除的目录或文件
+     *@return 删除成功返回 true,否则返回 false。
+     */
+    public static boolean DeleteFolder(String filePath) {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            return false;
+        } else {
+            if (file.isFile()) {
+                // 为文件时调用删除文件方法
+                return deleteFile(filePath);
+            } else {
+                // 为目录时调用删除目录方法
+                return deleteDirectory(filePath);
+            }
+        }
+    }
+
+    /**
+     * 删除文件夹以及目录下的文件
+     * @param   filePath 被删除目录的文件路径
+     * @return  目录删除成功返回true,否则返回false
+     */
+    public static  boolean deleteDirectory(String filePath) {
+        boolean flag = false;
+        //如果filePath不以文件分隔符结尾,自动添加文件分隔符
+        if (!filePath.endsWith(File.separator)) {
+            filePath = filePath + File.separator;
+        }
+        File dirFile = new File(filePath);
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return false;
+        }
+        flag = true;
+        File[] files = dirFile.listFiles();
+        //遍历删除文件夹下的所有文件(包括子目录)
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].isFile()) {
+                //删除子文件
+                flag = deleteFile(files[i].getAbsolutePath());
+                if (!flag) break;
+            } else {
+                //删除子目录
+                flag = deleteDirectory(files[i].getAbsolutePath());
+                if (!flag) break;
+            }
+        }
+        if (!flag) return false;
+        //删除当前空目录
+        return dirFile.delete();
+    }
+
 }

+ 176 - 0
app/src/main/java/com/sunwin/visitorapp/utils/ImageUtil.java

@@ -0,0 +1,176 @@
+package com.sunwin.visitorapp.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.media.ExifInterface;
+import android.util.Log;
+
+/**
+ * Created by ruanshimin on 2018/5/8.
+ */
+
+public class ImageUtil {
+    private static final String TAG = "CameraExif";
+
+    /**
+     * 旋转一张bitmap
+     * @param bitmap
+     * @param rotation
+     * @return
+     */
+    public static Bitmap createRotateBitmap(Bitmap bitmap, int rotation) {
+        Matrix matrix = new Matrix();
+        matrix.postRotate(rotation);
+        return Bitmap.createBitmap(
+                bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
+    }
+
+    public static Bitmap createMirrorRotateBitmap(Bitmap bitmap, int rotation) {
+        Matrix matrix = new Matrix();
+        matrix.postRotate(rotation);
+        matrix.postScale(-1, 1);
+        return Bitmap.createBitmap(
+                bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
+    }
+
+    /**
+     * 重新定位一张bitmap
+     * @param bitmap
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     * @param matrix
+     * @return
+     */
+    public static Bitmap createCropBitmap(Bitmap bitmap, float x, float y, float width, float height, Matrix matrix) {
+        return Bitmap.createBitmap(
+                bitmap, (int) x, (int) y, (int) width, (int) height, matrix, false);
+    }
+
+    public static int exifToDegrees(int exifOrientation) {
+        if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
+            return 90;
+        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
+            return 180;
+        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
+            return 270;
+        }
+        return 0;
+    }
+
+    // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
+    public static int getOrientation(byte[] jpeg) {
+        if (jpeg == null) {
+            return 0;
+        }
+
+        int offset = 0;
+        int length = 0;
+
+        // ISO/IEC 10918-1:1993(E)
+        while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
+            int marker = jpeg[offset] & 0xFF;
+
+            // Check if the marker is a padding.
+            if (marker == 0xFF) {
+                continue;
+            }
+            offset++;
+
+            // Check if the marker is SOI or TEM.
+            if (marker == 0xD8 || marker == 0x01) {
+                continue;
+            }
+            // Check if the marker is EOI or SOS.
+            if (marker == 0xD9 || marker == 0xDA) {
+                break;
+            }
+
+            // Get the length and check if it is reasonable.
+            length = pack(jpeg, offset, 2, false);
+            if (length < 2 || offset + length > jpeg.length) {
+                Log.e(TAG, "Invalid length");
+                return 0;
+            }
+
+            // Break if the marker is EXIF in APP1.
+            if (marker == 0xE1 && length >= 8
+                    && pack(jpeg, offset + 2, 4, false) == 0x45786966
+                    && pack(jpeg, offset + 6, 2, false) == 0) {
+                offset += 8;
+                length -= 8;
+                break;
+            }
+
+            // Skip other markers.
+            offset += length;
+            length = 0;
+        }
+
+        // JEITA CP-3451 Exif Version 2.2
+        if (length > 8) {
+            // Identify the byte order.
+            int tag = pack(jpeg, offset, 4, false);
+            if (tag != 0x49492A00 && tag != 0x4D4D002A) {
+                Log.e(TAG, "Invalid byte order");
+                return 0;
+            }
+            boolean littleEndian = (tag == 0x49492A00);
+
+            // Get the offset and check if it is reasonable.
+            int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
+            if (count < 10 || count > length) {
+                Log.e(TAG, "Invalid offset");
+                return 0;
+            }
+            offset += count;
+            length -= count;
+
+            // Get the count and go through all the elements.
+            count = pack(jpeg, offset - 2, 2, littleEndian);
+            while (count-- > 0 && length >= 12) {
+                // Get the tag and check if it is orientation.
+                tag = pack(jpeg, offset, 2, littleEndian);
+                if (tag == 0x0112) {
+                    // We do not really care about type and count, do we?
+                    int orientation = pack(jpeg, offset + 8, 2, littleEndian);
+                    switch (orientation) {
+                        case 1:
+                            return 0;
+                        case 3:
+                            return 180;
+                        case 6:
+                            return 90;
+                        case 8:
+                            return 270;
+                        default:
+                            return 0;
+                    }
+                }
+                offset += 12;
+                length -= 12;
+            }
+        }
+
+        Log.i(TAG, "Orientation not found");
+        return 0;
+    }
+
+    private static int pack(byte[] bytes, int offset, int length,
+                            boolean littleEndian) {
+        int step = 1;
+        if (littleEndian) {
+            offset += length - 1;
+            step = -1;
+        }
+
+        int value = 0;
+        while (length-- > 0) {
+            value = (value << 8) | (bytes[offset] & 0xFF);
+            offset += step;
+        }
+        return value;
+    }
+
+}

+ 69 - 0
app/src/main/java/com/sunwin/visitorapp/utils/PhotoUtil.java

@@ -0,0 +1,69 @@
+package com.sunwin.visitorapp.utils;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import androidx.core.content.FileProvider;
+import androidx.fragment.app.Fragment;
+
+import com.sunwin.visitorapp.BaseFragment;
+
+import java.io.File;
+
+public class PhotoUtil {
+    /**
+     * 打开相册选图
+     */
+    public static void openAlum(Activity activity, int requestCode) {
+        Intent intent = new Intent(Intent.ACTION_PICK);
+        intent.setType("image/*");
+        activity.startActivityForResult(intent, requestCode);
+    }
+
+    public static void openAlum(Fragment activity, int requestCode) {
+        Intent intent = new Intent(Intent.ACTION_PICK);
+        intent.setType("image/*");
+        activity.startActivityForResult(intent, requestCode);
+    }
+
+    @SuppressLint("NewApi")
+    public static String takePicture(BaseFragment fragment, int requestCode) {
+        try {
+            String state = Environment.getExternalStorageState();
+            if (state.equals(Environment.MEDIA_MOUNTED)) {
+                File outDir = Environment.getExternalStorageDirectory();
+                if (!outDir.exists()) {
+                    outDir.mkdirs();
+                }
+                File outFile = new File(outDir, System.currentTimeMillis() + ".png");
+                String picFileFullName = outFile.getAbsolutePath();
+
+                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+                if (Build.VERSION.SDK_INT >= 24) {
+                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//对目标应用临时授权该Uri所代表的文件
+                    //24以上使用FileProvider
+                    Uri uriForFile = FileProvider.getUriForFile(fragment.getContext(), AppUtil.getPackageName() + ".fileprovider", outFile);
+                    intent.putExtra(MediaStore.EXTRA_OUTPUT, uriForFile);//"包名.fileprovider"
+                } else {
+                    //24以下
+                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));
+                }
+                intent.putExtra("take_path", picFileFullName);
+                fragment.startActivityForResult(intent, requestCode);
+                return picFileFullName;
+            } else {
+                Log.e("", "请确认已经插入SD卡");
+            }
+            return null;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 61 - 0
app/src/main/res/layout/fragment_ocr_reg.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/ll_id_card_reg"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+
+        android:layout_margin="50dp"
+        android:orientation="vertical">
+
+        <ImageView
+            android:id="@+id/iv"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:scaleType="fitXY"
+            android:src="@mipmap/id_card" />
+
+        <LinearLayout
+            android:layout_marginTop="20dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <TextView
+                android:id="@+id/tv_alum"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="10dp"
+                android:layout_weight="1"
+                android:padding="10dp"
+                android:gravity="center"
+                android:text="相册选择身份证"
+                android:textColor="@color/color_333333"
+                android:textSize="@dimen/sp_25" />
+
+            <TextView
+                android:id="@+id/tv_photo"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="10dp"
+                android:layout_weight="1"
+                android:padding="10dp"
+                android:gravity="center"
+                android:text="身份证拍照"
+                android:textColor="@color/color_333333"
+                android:textSize="@dimen/sp_25" />
+        </LinearLayout>
+
+    </LinearLayout>
+    <include
+        android:id="@+id/faceDetecterView"
+        layout="@layout/view_face_detecter"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone" />
+</FrameLayout>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -10,4 +10,5 @@
     <string name="veriface_hint">请正对屏幕</string>
     <string name="usb_unauthorized">usb未授权</string>
     <string name="no_permission">无权限</string>
+    <string name="check_success">核验成功</string>
 </resources>

+ 21 - 0
app/src/main/res/xml/filepath.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <paths>
+        <!-- external-path:sd ;path:你的应用保存文件的根目录;name随便定义-->
+        <external-path
+            name="/"
+            path="" />
+        <external-path
+            name="Download"
+            path="citymanage/download" />
+
+        <external-path
+            name="beta_external_path"
+            path="Download/" />
+        <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
+        <external-path
+            name="beta_external_files_path"
+            path="Android/data/" />
+
+    </paths>
+</resources>