MrShi
6 天以前 3a154bdb0a5aaa2c0ac3eac95a6ba747068bd454
keyCabinet-android/app/src/main/java/com/doumee/keyCabinet/ui/main/MainActivity.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,2106 @@
package com.doumee.keyCabinet.ui.main;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.opengl.Visibility;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import com.alibaba.fastjson.JSON;
import com.baidu.idl.main.facesdk.model.BDFaceSDKCommon;
import com.baidu.idl.main.facesdk.utils.StreamUtil;
import com.bigkoo.convenientbanner.holder.CBViewHolderCreator;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.doumee.keyCabinet.BuildConfig;
import com.doumee.keyCabinet.bean.CabinetConfigDataBean;
import com.doumee.keyCabinet.bean.DevConfigBean;
import com.doumee.keyCabinet.bean.FaceUserBean;
import com.doumee.keyCabinet.dao.CabinetGridDo;
import com.doumee.keyCabinet.dao.DaoManager;
import com.doumee.keyCabinet.databinding.MainActivityBinding;
import com.doumee.keyCabinet.event.CLGridEvent;
import com.doumee.keyCabinet.event.CLKeyEvent;
import com.doumee.keyCabinet.event.CheckGridStatusEvent;
import com.doumee.keyCabinet.event.CloseGridOneResultEvent;
import com.doumee.keyCabinet.event.GetFacesEvent;
import com.doumee.keyCabinet.event.GetKeyStatusEvent;
import com.doumee.keyCabinet.event.HeartEvent;
import com.doumee.keyCabinet.event.HttpEvent;
import com.doumee.keyCabinet.event.JiujinBeginEvent;
import com.doumee.keyCabinet.event.JiujinResultEvent;
import com.doumee.keyCabinet.event.KeyResultEvent;
import com.doumee.keyCabinet.event.ManageOpenGridResultEvent;
import com.doumee.keyCabinet.event.OpenAllGridEvent;
import com.doumee.keyCabinet.event.OpenErrEvent;
import com.doumee.keyCabinet.event.OpenGridEvent;
import com.doumee.keyCabinet.event.OpenGridListEvent;
import com.doumee.keyCabinet.event.OpenGridOneResultEvent;
import com.doumee.keyCabinet.event.TimeClockEvent;
import com.doumee.keyCabinet.ui.face.ActivationActivity;
import com.doumee.keyCabinet.ui.face.ChoseActivationActivity;
import com.doumee.keyCabinet.ui.face.FaceActivity;
import com.doumee.keyCabinet.ui.keyCabinet.ChangeUrlActivity;
import com.doumee.keyCabinet.ui.keyCabinet.KeyCabinetActivity;
import com.doumee.keyCabinet.ui.keyCabinet.ManageLoginActivity;
import com.doumee.keyCabinet.ui.service.FaceUpdateService;
import com.doumee.keyCabinet.ui.service.HeartbeatService;
import com.doumee.keyCabinet.ui.face.AddFaceActivity;
import com.doumee.keyCabinet.ui.face.ErrActivity;
import com.doumee.keyCabinet.ui.face.UserInfoManager;
import com.doumee.keyCabinet.ui.face.UserManagerActivity;
import com.doumee.keyCabinet.ui.view.BannerViewImageHolder;
import com.doumee.keyCabinet.utils.BraceletLogUtils;
import com.doumee.keyCabinet.utils.CircularQueue;
import com.doumee.keyCabinet.utils.CrashHandler;
import com.doumee.keyCabinet.utils.LMobileInfo;
import com.doumee.keyCabinet.utils.TimeUtils;
import com.doumee.keyCabinet.utils.face.FaceSDKManager;
import com.doumee.keyCabinet.utils.face.FaceUtils;
import com.doumee.keyCabinet.utils.face.GateConfigUtils;
import com.doumee.keyCabinet.utils.face.ImportFileManager;
import com.doumee.keyCabinet.utils.face.RegisterConfigUtils;
import com.doumee.keyCabinet.utils.face.model.SingleBaseConfig;
import com.doumee.keyCabinet.utils.i485.SerialPortModel;
import com.doumee.keyCabinet.utils.i485.SerialPortReadObserver;
import com.doumee.keyCabinet.utils.i485.SportUtils;
import com.doumee.keyCabinet.utils.update.PermissionUtils;
import com.doumee.keyCabinet.utils.update.PermissiondDialog;
import com.doumee.keyCabinet.utils.update.UpdateUtil;
import com.doumee.lib_coremodel.bean.event.ActionEventData;
import com.doumee.keyCabinet.MApplication;
import com.doumee.keyCabinet.R;
import com.doumee.keyCabinet.base.MyBaseActivity;
import com.doumee.keyCabinet.utils.AdListResponseParam;
import com.doumee.lib_coremodel.http.utils.GsonTools;
import com.doumee.lib_coremodel.util.SpUtil;
import com.doumee.lib_coremodel.util.StringUtil;
import com.doumee.lib_coremodel.view.ToastView;
import com.example.datalibrary.api.FaceApi;
import com.example.datalibrary.listener.DBLoadListener;
import com.example.datalibrary.listener.SdkInitListener;
import com.example.datalibrary.model.ImportFeatureResult;
import com.example.datalibrary.model.User;
import com.example.datalibrary.utils.ToastUtils;
import com.example.datalibrary.view.PreviewTexture;
import com.innohi.YNHAPI;
import com.yanzhenjie.permission.runtime.Permission;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import dagger.hilt.android.AndroidEntryPoint;
import timber.log.Timber;
import static android.Manifest.permission.RECEIVE_BOOT_COMPLETED;
@AndroidEntryPoint
public class MainActivity extends MyBaseActivity<MainVM, MainActivityBinding> {
    private List<AdListResponseParam> lbs = new ArrayList<>();
    //是否已激活
    public static boolean isFaceOk = false;
    private boolean isActivation = false;
    private boolean isDBLoad;
    private PopupWindow popupWindow;
    private Future future;
    //相机相关
    private Camera[] mCamera;
    private PreviewTexture[] previewTextures;
    private static final int PREFER_WIDTH = 640;
    private static final int PREFER_HEIGHT = 480;
    //是否有要更新人脸
    private boolean isNeedUpdateFace;
    //是否正在更新中
    private boolean isUpdatingFace;
    private boolean isUpdateVersion;
    private int downCount = 0;
    private Long lastDownTime;
    private Long showTime;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(!isFinishing()){
                switch (msg.what) {
                    case 0:
                    initM();
                    TimeUtils.updateTimeUi(getVM().dayObs, getVM().timeObs);
                    handler.sendEmptyMessageDelayed(0, 1000);
                    EventBus.getDefault().post(new TimeClockEvent());
                    /*if (isDBLoad && isNeedUpdateFace && !isUpdatingFace) {
                        isNeedUpdateFace = false;
                        getVM().getFaceLD();
                    }
                    getVM().upBraceletLog();*/
                    case 1:
                        if(isShowing) {
                            EventBus.getDefault().post(new OpenGridEvent((String) msg.obj));
                            handler.sendEmptyMessageDelayed(1, 1000);
                        }
                        break;
                    case 2:
                        if(isShowing){
                            //重新发送钥匙查询
                            //发送查询钥匙号
                            EventBus.getDefault().post(new GetKeyStatusEvent());
                            handler.sendEmptyMessageDelayed(2,1200);
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    };
    @Override
    public int getLayoutId() {
        return R.layout.main_activity;
    }
    @Override
    public void initView(@Nullable Bundle savedInstanceState) {
        isAddCountTimer = false;
        SpUtil.initWH(this);
        normalConfig();
        getDB().setModel(getVM());
        initRGBCheck();
        handler.sendEmptyMessageDelayed(0, 1000);
        /*//启动心跳
        Intent intent = new Intent(MainActivity.this, HeartbeatService.class);
        startService(intent);
        //启动更新人脸
        Intent intent2 = new Intent(MainActivity.this, FaceUpdateService.class);
        startService(intent2);*/
        getPermission();
        Timber.tag("====>").d(LMobileInfo.getDeviceUniqueId());
    }
    private void initM(){
        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
        activityManager.getMemoryInfo(memoryInfo);
        long totalMemory = memoryInfo.totalMem/(1024*1024);
        long availableMemory = memoryInfo.availMem/(1024*1024);
        long usedMemory = totalMemory - availableMemory;
        //getDB().tvM.setText("总内存:"+totalMemory+",使用内存:"+usedMemory+",可用内存:"+availableMemory);
        if((availableMemory<100&&showTime!=null&&(System.currentTimeMillis()-showTime>5000))||
                ("02:00:00".equals(StringUtil.getHM()))){
            //可用内存小于400M,或者每天凌晨2点,重启app
            restartApp();
        }
    }
    private void upErrInfo(){
        List<SpUtil.SPBean> datas = SpUtil.getMatchingStrings(CrashHandler.FILE_NAME);
        for(SpUtil.SPBean data : datas){
            getVM().upErrInfo(data);
        }
    }
    @Override
    public void initData(@Nullable Bundle savedInstanceState) {
        //handler.sendEmptyMessageDelayed(0,1000);
        getDB().tvId.setText("NO:"+LMobileInfo.getDeviceUniqueId());
        getDB().tvVersion.setText("V"+BuildConfig.VERSION_NAME);
        getVM().getFaceLD().observe(this, new Observer<List<FaceUserBean>>() {
            @Override
            public void onChanged(List<FaceUserBean> beans) {
                //更新人脸数据
                if(beans!=null&&beans.size()>0){
                    initModel(beans);
                }
            }
        });
        getDB().img.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(lastDownTime!=null){
                    if(System.currentTimeMillis()-lastDownTime>1000){
                        downCount=0;
                    }
                }
                lastDownTime = System.currentTimeMillis();
                Timber.d("downCount="+downCount);
                downCount++;
                if(downCount>4) {
                    downCount=0;
                    lastDownTime=null;
                    initPopupWindow();
                }
            }
        });
        getDB().tv1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //管理员登录
                if(lastDownTime1!=null){
                    if(System.currentTimeMillis()-lastDownTime1>1000){
                        downCount1=0;
                    }
                }
                lastDownTime1 = System.currentTimeMillis();
                downCount1++;
                System.out.println();
                //Timber.tag("==>").d(""+downCount1);
                if(downCount1>4) {
                    downCount1=0;
                    lastDownTime1=null;
                    startActivity(ManageLoginActivity.class);
                }
            }
        });
        getDB().tvId.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //更改url
                if(lastDownTime2!=null){
                    if(System.currentTimeMillis()-lastDownTime2>1000){
                        downCount2=0;
                    }
                }
                lastDownTime2 = System.currentTimeMillis();
                downCount2++;
                if(downCount2>4) {
                    downCount2=0;
                    lastDownTime2=null;
                    startActivity(ChangeUrlActivity.class);
                }
            }
        });
        getDB().imgLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v1) {
                //todo ä¸´æ—¶ä»£ç 
                if (getDB().nsv.getVisibility()== View.VISIBLE) {
                    getDB().nsv.setVisibility(View.GONE);
                }else {
                    getDB().nsv.setVisibility(View.VISIBLE);
                }
                YNHAPI mAPI = YNHAPI.getInstance();
                mAPI.setNavigationBarVisibility(YNHAPI.NavigationBarVisibility.VISIBLE);
            }
        });
        upErrInfo();
        getVM().devLogin();
        getVM().devHeart();
        getVM().getConfidLD().observe(this, new Observer<DevConfigBean>() {
            @Override
            public void onChanged(DevConfigBean devConfigBean) {
                if(devConfigBean!=null){
                    if(devConfigBean.getBannerList()!=null) {
                        setBanner(devConfigBean.getBannerList());
                    }
                    setJiuConfig();
                    initPort();
                }
            }
        });
    }
    private void setJiuConfig(){
        getVM().addInfo("酒精配置:"+(MApplication.getConfigBean().getCabinetConfigDataVO()!=null)+
                ",串口开启:"+(jiuPort!=null));
        if(MApplication.getConfigBean().getCabinetConfigDataVO()!=null&&
            jiuPort!=null){
            setJiuConfig(0);
        }
    }
    boolean isOne;
    private void setBanner(List<String> bannerList){
        getDB().banner.setPages(new CBViewHolderCreator<BannerViewImageHolder>() {
            @Override
            public BannerViewImageHolder createHolder() {
                return new BannerViewImageHolder();
            }
        },bannerList ).setPageIndicator(new int[]{R.drawable.bg_dot_gray, R.drawable.bg_dot_blue});
        isOne = bannerList.size()==1;
        if(!isOne) {
            getDB().banner.startTurning(3000);
        }else {
            getDB().banner.stopTurning();
        }
    }
    private boolean isHavePermission = false;
    //获取权限
    private void getPermission(){
        PermissionUtils.getPermission(this, new PermissionUtils.CallBack() {
            @Override
            public void sucess() {
                //显示
                isHavePermission = true;
                checkUpdate();
            }
            @Override
            public void fail(List<String> permissions) {
                showNoPermissionTip();
            }
        }, new String[]{Permission.WRITE_EXTERNAL_STORAGE,RECEIVE_BOOT_COMPLETED});
    }
    private Long lastDownTime1;
    private int downCount1;
    private Long lastDownTime2;
    private int downCount2;
    @Override
    protected void doRegister(int type, ActionEventData data) {
        switch (type){
            case 2:
            case 3: {
                //校验是否登录
                if(MApplication.getConfigBean().getId()==null){
                    Toast.makeText(mContext, "设备未添加,无法操作", Toast.LENGTH_SHORT).show();
                    getVM().devLogin();
                    return;
                }
                checkGridStatus(0);
                List<CabinetGridDo> gridDos = getVM().getOpenGrids();
                if (gridDos.size() > 0) {
                    showUnCloseTip(gridDos);
                    return;
                }
                MApplication.setLoginBean(null);
                MApplication.getLoginBean().setFlag(type == 2 ? 0 : 1);
                startActivity(FaceActivity.class);
                }
                break;
            case 4:
                isShowTip = false;
                getDB().clTip.setVisibility(View.GONE);
                break;
            case 5: {
                List<CabinetGridDo> gridDos = getVM().getOpenGrids();
                if (gridDos.size() > 0) {
                    showUnCloseTip(gridDos);
                }else {
                    isShowTip = false;
                    getDB().clTip.setVisibility(View.GONE);
                }
                }
                break;
            case 55:
                getVM().infoObs.set("");
                break;
            default:
                break;
        }
    }
    private void showUnCloseTip(List<CabinetGridDo> gridDos){
        tipDownCount = 10;
        isShowTip = true;
        getDB().tvDjs.setText(tipDownCount + "s");
        StringBuilder sb = new StringBuilder();
        for(CabinetGridDo d:gridDos){
            if (sb.length()>0) {
                sb.append("、");
            }
            String name = d.getCabinetName();
            if (TextUtils.isEmpty(name)) {
                name = gridDos.get(0).getGridKey();
            }
            sb.append(name);
        }
        getDB().tvTip22.setText(getTipText(sb.toString()), TextView.BufferType.SPANNABLE);
        getDB().tvTip23.setText(getErrPhoneText(), TextView.BufferType.SPANNABLE);
        getDB().clTip.setVisibility(View.VISIBLE);
    }
    private SpannableString getErrPhoneText(){
        String phone = MApplication.getConfigBean().getLinkPhone();
        if(phone==null){
            String text = "如有问题请联系管理员";
            SpannableString styledText = new SpannableString(text);
            styledText.setSpan(new TextAppearanceSpan(this, R.style.style_tip3), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            return styledText;
        }
        String text = "如有问题请联系管理员"+phone;
        SpannableString styledText = new SpannableString(text);
        styledText.setSpan(new TextAppearanceSpan(this, R.style.style_tip3), 0, text.length()-phone.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        styledText.setSpan(new TextAppearanceSpan(this,R.style.style_tip1), text.length()-phone.length()+1, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        return styledText;
    }
    private boolean isShowing = false;
    @Override
    protected void onResume() {
        super.onResume();
        isShowing = true;
        YNHAPI mAPI = YNHAPI.getInstance();
        mAPI.setNavigationBarVisibility(YNHAPI.NavigationBarVisibility.ALWAYS_INVISIBLE);
        mAPI.setBootLaunchApk("com.doumee.keyCabinet", true);
        showTime = System.currentTimeMillis();
        if(!isFaceOk) {
            initLicense();
        }
        if(isHavePermission) {
            checkUpdate();
        }
        triggerGarbageCollection();
        if(!isOne) {
            getDB().banner.startTurning(3000);
        }else {
            getDB().banner.stopTurning();
        }
        //检查所有柜格门、钥匙状态
        checkKeyStatus(0);
        checkGridStatus(900);
    }
    private void unCloseGrid(){
        //未关门,调用接口
        List<CabinetGridDo> gridDos = getVM().getOpenGrids();
        if(gridDos.size()>0){
            getVM().timeOutUnCloseAlarm(gridDos.get(0));
        }
    }
    // è¿™æ˜¯ä¸€ä¸ªç¤ºä¾‹æ–¹æ³•,用于手动触发垃圾回收
    public void triggerGarbageCollection() {
        // è¯·æ±‚进行垃圾回收
        System.gc();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (future != null && !future.isDone()) {
            future.cancel(true);
        }
        FaceApi.getInstance().cleanRecords();
        handler.removeCallbacksAndMessages(null);
        handler = null;
        faceHandler.removeCallbacksAndMessages(null);
        faceHandler = null;
        portHandler.removeCallbacksAndMessages(null);
        portHandler = null;
        closePort(gridPort);
        closePort(keyPort);
        closePort(jiuPort);
        closePort(chosePort);
    }
    private void restartApp(){
        // åˆ›å»ºä¸€ä¸ªæ–°çš„启动意图
        Intent intent = new Intent(mContext, MainActivity.class);
        // è®¾ç½®FLAG_ACTIVITY_CLEAR_TASK标志位
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        // ä½¿ç”¨PendingIntent包装启动意图
        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
        // èŽ·å–AlarmManager实例
        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        // åœ¨500毫秒后触发重启操作
        alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 10, pendingIntent);
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }
    @Subscribe
    public void GetFacesEvent(GetFacesEvent event){
        if(!isFinishing()&&!isUpdatingFace){
            if(isDBLoad){
                isNeedUpdateFace = false;
                //查询人脸
                getVM().getFaceDatas();
            }else {
                isNeedUpdateFace = true;
            }
        }
    }
    //判断设备是否已激活
    private void initLicense() {
        FaceSDKManager.getInstance().init(mContext, new SdkInitListener() {
            @Override
            public void initStart() {
            }
            public void initLicenseSuccess() {
                //已激活
                isFaceOk = true;
                initDBApi();
            }
            @Override
            public void initLicenseFail(int errorCode, String msg) {
                //未激活,跳转激活页面
                TimerTask task = new TimerTask() {
                    @Override
                    public void run() {
                        /*
                         *要执行的操作*/
                        startActivity(new Intent(mContext, ChoseActivationActivity.class));
                    }
                };
                Timer timer = new Timer();
                timer.schedule(task, 2000);
            }
            @Override
            public void initModelSuccess() {
            }
            @Override
            public void initModelFail(int errorCode, String msg) {
            }
        });
    }
    private void initDBApi(){
        if (future != null && !future.isDone()) {
            future.cancel(true);
        }
        isDBLoad = false;
        future = Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                FaceApi.getInstance().init(new DBLoadListener() {
                    @Override
                    public void onStart(int successCount) {
                        if (successCount < 5000 && successCount != 0){
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    loadProgress(10);
                                }
                            });
                        }
                    }
                    @Override
                    public void onLoad(final int finishCount, final int successCount, final float progress) {
                        if (successCount > 5000 || successCount == 0) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    getDB().progressBar.setProgress((int) (progress * 100));
                                    getDB().progressText.setText(((int) (progress * 100)) + "%");
                                }
                            });
                        }
                    }
                    @Override
                    public void onComplete(final List<User> users , final int successCount) {
//                        FileUtils.saveDBList(HomeActivity.this, users);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                FaceApi.getInstance().setUsers(users);
                                initFaceSDKManager(null);
                                if (successCount > 5000 || successCount == 0) {
                                    getDB().progressGroup.setVisibility(View.GONE);
                                    isDBLoad = true;
                                    isFaceOk = true;
                                }
                            }
                        });
                    }
                    @Override
                    public void onFail(final int finishCount, final int successCount, final List<User> users) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                FaceApi.getInstance().setUsers(users);
                                initFaceSDKManager(null);
                                getDB().progressGroup.setVisibility(View.GONE);
                                Toast.makeText(MainActivity.this, String.format(getString(R.string.main_tip3),successCount,finishCount), Toast.LENGTH_SHORT).show();
                                isDBLoad = true;
                                isFaceOk = true;
                            }
                        });
                    }
                }, mContext);
            }
        });
    }
    private void loadProgress(float i){
        getDB().progressGroup.setVisibility(View.VISIBLE);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                getDB().progressBar.setProgress((int) ((i / 5000f) * 100));
                getDB().progressText.setText(((int) ((i / 5000f) * 100)) + "%");
                if (i < 5000){
                    loadProgress(i + 100);
                }else {
                    getDB().progressGroup.setVisibility(View.GONE);
                    isDBLoad = true;
                    isFaceOk = true;
                }
            }
        },10);
    }
    private void initModel(List<FaceUserBean> userBeans) {
        if (com.example.datalibrary.manager.FaceSDKManager.initStatus == com.example.datalibrary.manager.FaceSDKManager.SDK_MODEL_LOAD_SUCCESS) {
            waitUpdate(userBeans);
        }else {
            initFaceSDKManager(userBeans);
        }
    }
    private void initFaceSDKManager(List<FaceUserBean> userBeans){
        //开始后去初始化
        com.example.datalibrary.manager.FaceSDKManager.getInstance().initModel(mContext,
                FaceUtils.getInstance().getBDFaceSDKConfig() , new SdkInitListener() {
                    @Override
                    public void initStart() {
                    }
                    @Override
                    public void initLicenseSuccess() {
                    }
                    @Override
                    public void initLicenseFail(int errorCode, String msg) {
                    }
                    @Override
                    public void initModelSuccess() {
                        com.example.datalibrary.manager.FaceSDKManager.initModelSuccess = true;
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(mContext, getString(R.string.main_tip4), Toast.LENGTH_SHORT).show();
                                getDB().progressGroup.setVisibility(View.GONE);
                                if(userBeans!=null){
                                    waitUpdate(userBeans);
                                }
                            }
                        });
                    }
                    @Override
                    public void initModelFail(int errorCode, String msg) {
                        com.example.datalibrary.manager.FaceSDKManager.initModelSuccess = false;
                        if (errorCode != -12) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(mContext, getString(R.string.main_tip5), Toast.LENGTH_SHORT).show();
                                }
                            });
                        }
                    }
                });
    }
    @Override
    protected void onPause() {
        super.onPause();
        showTime = null;
        isShowing = false;
    }
    private int finishCount;
    private List<FaceUserBean> selectBeans = new ArrayList<>();
    //待更新数据
    private List<FaceUserBean> waitBeans = new ArrayList<>();
    private Handler faceHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(!isFinishing()){
                switch (msg.what){
                    case 0:
                        if(finishCount<selectBeans.size()){
                            isUpdatingFace = true;
                            repeatCount = 0;
                            updateFace(selectBeans.get(finishCount));
                        }else {
                            //结束
                            isUpdatingFace = false;
                            //System.out.println("==UpdatingFace==>更新结束:");
                            // æ¸…除内存缓存
                            Glide.get(MainActivity.this).clearMemory();
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    };
    private void waitUpdate(List<FaceUserBean> userBeans){
        if(isUpdatingFace){
            //正在更新
            waitBeans.addAll(userBeans);
        }else {
            selectBeans.clear();
            selectBeans.addAll(waitBeans);
            waitBeans.clear();
            selectBeans.addAll(userBeans);
            finishCount=0;
            /*//删除全部
            FaceApi.getInstance().userClean();
            faceHandler.sendEmptyMessage(0);*/
            HashMap<String,String> uMap = new HashMap<>();
            for(FaceUserBean d:selectBeans){
                String key = d.getMemberId().toString()+"_"+d.getGroupId();
                uMap.put(key,"");
            }
            //删除不存在用户
            List<User> users = FaceApi.getInstance().getAllUserList();
            List<User> dels = new ArrayList<>();
            for(User u:users){
                String key = u.getUserId()+"_"+u.getGroupId();
                if(!uMap.containsKey(key)){
                    dels.add(u);
                }
            }
            if(dels.size()>0){
                UserInfoManager.getInstance().deleteUserListInfo(dels,
                        "", new UserInfoManager.UserInfoListener() {
                            @Override
                            public void userListDeleteSuccess() {
                                // ç”¨æˆ·åˆ—表删除成功
                                faceHandler.sendEmptyMessage(0);
                            }
                            @Override
                            public void userListDeleteFailure(String message) {
                                // ç”¨æˆ·åˆ—表删除失败
                                faceHandler.sendEmptyMessage(0);
                            }
                        },
                        new DBLoadListener() {
                            @Override
                            public void onStart(int successCount) {
                            }
                            @Override
                            public void onLoad(int finishCount, int successCount, float progress) {
                            }
                            @Override
                            public void onComplete(List<User> features, int successCount) {
                            }
                            @Override
                            public void onFail(int finishCount, int successCount, List<User> features) {
                            }
                        });
            }else {
                faceHandler.sendEmptyMessage(0);
            }
        }
    }
    private int repeatCount = 0;
    private void updateFace(FaceUserBean bean){
        Timber.d("==UpdatingFace==>完成数量 "+finishCount);
        if (TextUtils.isEmpty(bean.getFaceImg())||bean.getFaceImg().endsWith("null")) {
            finishCount++;
            faceHandler.sendEmptyMessage(0);
            return;
        }
        repeatCount++;
        //System.out.println("==UpdatingFace==>开始:" + bean.getName());
        Glide.with(this)
                .asBitmap()
                .load(bean.getFaceImg())
                .addListener(new RequestListener<Bitmap>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                        if(repeatCount==1) {
                            finishCount++;
                        }
                        faceHandler.sendEmptyMessage(0);
                        return false;
                    }
                    @Override
                    public boolean onResourceReady(Bitmap bitmap, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                        if(repeatCount==1) {
                            finishCount++;
                        }
                        if (bitmap != null) {
                            //System.out.println("==UpdatingFace==>开始解析人脸");
                            byte[] secondFeature = new byte[512];
                            ImportFeatureResult result = null;
                            // 10、走人脸SDK接口,通过人脸检测、特征提取拿到人脸特征值
                            try {
                                result = ImportFileManager.getInstance().getFeature(bitmap, secondFeature,
                                        BDFaceSDKCommon.FeatureType.BDFACE_FEATURE_TYPE_LIVE_PHOTO);
                            }catch (OutOfMemoryError e){
                                e.printStackTrace();
                                faceHandler.sendEmptyMessage(0);
                                return false;
                            }catch (Exception e){
                                e.printStackTrace();
                                faceHandler.sendEmptyMessage(0);
                                return false;
                            }
                            // 11、判断是否提取成功:128为成功,-1为参数为空,-2表示未检测到人脸
                            float ret = result.getResult();
                            //System.out.println("==UpdatingFace==>提取特征值" + ret);
                            // æå–特征值
                            if (ret != -1) {
                                //有人脸
                                // åˆ¤æ–­è´¨é‡æ£€æµ‹ï¼Œé’ˆå¯¹æ¨¡ç³Šåº¦ã€é®æŒ¡ã€è§’度
                                if (ret == 128) {
                                    Timber.d("==UpdatingFace==>图片特征抽取成功: %s", JSON.toJSONString(bean));
                                    User user = new User();
                                    user.setUserId(bean.getMemberId().toString());
                                    user.setGroupId(bean.getGroupId());
                                    user.setUserName(bean.getMemberName());
                                    user.setImageName(bean.getFaceImg());
                                    user.setUserInfo(GsonTools.changeGsonToJson(bean));
                                    user.setFeature(secondFeature);
                                    insertOrUpdate(user);
                                    faceHandler.sendEmptyMessage(0);
                                } else {
                                    Timber.e("==UpdatingFace==>图片特征抽取失败: %s", JSON.toJSONString(bean));
                                    if(repeatCount>3) {
                                        faceHandler.sendEmptyMessage(0);
                                    }else {
                                        updateFace(bean);
                                    }
                                }
                            } else {
                                // ä¸Šä¼ å›¾ç‰‡æ— äººè„¸éšè—
                                Timber.e("==UpdatingFace==>图片特征抽取失败: %s", JSON.toJSONString(bean));
                                if(repeatCount>3) {
                                    faceHandler.sendEmptyMessage(0);
                                }else {
                                    updateFace(bean);
                                }
                            }
                        } else {
                            if(repeatCount>3) {
                                faceHandler.sendEmptyMessage(0);
                            }else {
                                updateFace(bean);
                            }
                        }
                        return false;
                    }
                })
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition<? super Bitmap> transition) {
                    }
                });
    }
    private void insertOrUpdate(User newDo){
        //插入数据库
        //System.out.println("==isOk==>bean" + GsonTools.changeGsonToJson(newDo));
        User user = FaceApi.getInstance().getByUserId(newDo.getGroupId(), newDo.getUserId());
        //System.out.println("==isOk==>查询" + user.getId()+","+user.getUserId()+","+user.getUserName());
        boolean isSave = false;
        if (user == null) {
            //新增
            isSave = FaceApi.getInstance().registerUserIntoDBmanager(newDo.getGroupId(),
                    newDo.getUserId(), newDo.getUserName(), newDo.getImageName(), newDo.getUserInfo(), newDo.getFeature());
            //System.out.println("==isOk==>保存成功");
        } else {
            //更新
            user.setUserName(newDo.getUserName());
            user.setImageName(newDo.getImageName());
            user.setFeature(newDo.getFeature());
            isSave = FaceApi.getInstance().userUpdateOnly(user);
            //System.out.println("==isOk==>更新成功");
        }
        if (isSave) {
            //保存成功
            //System.out.println("==UpdatingFace==>修改成功");
            UserInfoManager.getInstance();
        } else {
            Timber.d("==isOk==>人脸保存失败: %s", JSON.toJSONString(newDo));
        }
    }
    //弹窗
    private void initPopupWindow() {
        if(popupWindow!=null&&popupWindow.isShowing()){
            return;
        }
        View contentView = LayoutInflater.from(mContext).inflate(R.layout.popup_menu_home, null);
        popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        // ç‚¹å‡»æ¡†å¤–可以使得popupwindow消失
        popupWindow.setFocusable(false);
        popupWindow.setOutsideTouchable(false);
        popupWindow.setTouchable(true);
        popupWindow.setBackgroundDrawable(new BitmapDrawable());
        popupWindow.showAtLocation(getDB().clRoot, Gravity.CENTER, 0, 0);
        RelativeLayout relativeRegister = contentView.findViewById(R.id.relative_register);
        RelativeLayout mPopRelativeManager = contentView.findViewById(R.id.relative_manager);
        RelativeLayout mRlErr = contentView.findViewById(R.id.rl_err);
        relativeRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(AddFaceActivity.class);
            }
        });
        mPopRelativeManager.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(UserManagerActivity.class);
            }
        });
        mRlErr.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(ErrActivity.class);
            }
        });
        //自动关闭
        initHandler();
    }
    private void initHandler() {
        new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                // å®žçŽ°é¡µé¢è·³è½¬
                popupWindow.dismiss();
                return false;
            }
        }).sendEmptyMessageDelayed(0, 5000);
    }
    private void initRGBCheck(){
        String index = SpUtil.getString("rbgCameraId","0");
        setRgbCameraId(Integer.parseInt(index));
        /*if (isSetCameraId()){
            setRgbCameraId(SingleBaseConfig.getBaseConfig().getRBGCameraId());
            return;
        }
        int mCameraNum = Camera.getNumberOfCameras();
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
            Camera.getCameraInfo(i, cameraInfo);
        }
        if (mCameraNum > 1){
            try {
                mCamera = new Camera[mCameraNum];
                previewTextures = new PreviewTexture[mCameraNum];
                mCamera[0] = Camera.open(0);
                previewTextures[0] = new PreviewTexture(this, getDB().checkRgbTexture);
                previewTextures[0].setCamera(mCamera[0], PREFER_WIDTH, PREFER_HEIGHT);
                mCamera[0].setPreviewCallback(new Camera.PreviewCallback() {
                    @Override
                    public void onPreviewFrame(byte[] data, Camera camera) {
                        int check = StreamUtil.checkNirRgb(data, PREFER_WIDTH, PREFER_HEIGHT);
                        if (check == 1){
                            setRgbCameraId(0);
                        }
                        release(0);
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
            }
            try {
                mCamera[1] = Camera.open(1);
                previewTextures[1] = new PreviewTexture(this, getDB().checkNirTexture);
                previewTextures[1].setCamera(mCamera[1], PREFER_WIDTH, PREFER_HEIGHT);
                mCamera[1].setPreviewCallback(new Camera.PreviewCallback() {
                    @Override
                    public void onPreviewFrame(byte[] data, Camera camera) {
                        int check = StreamUtil.checkNirRgb(data, PREFER_WIDTH, PREFER_HEIGHT);
                        if (check == 1){
                            setRgbCameraId(1);
                        }
                        release(1);
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
            }
        } else {
            setRgbCameraId(0);
        }*/
    }
    private void setRgbCameraId(int index){
        getVM().addInfo("设置相机:"+index);
        //Toast.makeText(mContext, "设置相机"+index, Toast.LENGTH_SHORT).show();
        SpUtil.saveString("rbgCameraId",index+"");
        BraceletLogUtils.saveLog("设置相机("+index+")");
        SingleBaseConfig.getBaseConfig().setRBGCameraId(index);
        SingleBaseConfig.getBaseConfig().setRgbRevert(true);
        SingleBaseConfig.getBaseConfig().setRgbDetectDirection(90);
        SingleBaseConfig.getBaseConfig().setRgbVideoDirection(270);
        GateConfigUtils.modityJson();
        RegisterConfigUtils.modityJson();
    }
    private boolean isSetCameraId(){
        if (SingleBaseConfig.getBaseConfig().getRBGCameraId() == -1){
            return false;
        }else {
            return true;
        }
    }
    private void release(int id){
        if (mCamera != null && mCamera[id] != null) {
            if (mCamera[id] != null) {
                mCamera[id].setPreviewCallback(null);
                mCamera[id].stopPreview();
                previewTextures[id].release();
                mCamera[id].release();
                mCamera[id] = null;
            }
        }
    }
    private UpdateUtil updateUtil;
    private void checkUpdate(){
        //版本更新
        if(updateUtil==null){
            updateUtil = new UpdateUtil(this);
            updateUtil.setShowToast(false);
        }
        if(!updateUtil.isShowing()){
            updateUtil.getServerVerCode(new UpdateUtil.VersionCallBack() {
                @Override
                public void isNeedUpdate(boolean isUpdate) {
                    isUpdateVersion = isUpdate;
                }
            });
        }
    }
    private PermissiondDialog permissiondDialog;
    private void showNoPermissionTip() {
        try {
            Toast.makeText(this,getString(R.string.guide_permiss_1) , Toast.LENGTH_LONG).show();
            if (permissiondDialog == null) {
                permissiondDialog = new PermissiondDialog(this, getString(R.string.help), getString(R.string.guide_permiss_2), getString(R.string.cancel),
                        getString(R.string.empower), new PermissiondDialog.OnClickListener() {
                    @Override
                    public void clickOk() {
                        permissiondDialog.dismiss();
                        PermissionUtils.gotoPermission(getContext());
                    }
                    @Override
                    public void clickNo() {
                        permissiondDialog.dismiss();
                        finish();
                    }
                });
            }
            if (!permissiondDialog.isShowing()) {
                permissiondDialog.show();
            }
        } catch (Exception e) {
        }
    }
    private int tipDownCount = 10;
    private int loopDownCount = 60;
    private boolean isShowTip;
    @Subscribe
    public void TimeClockEvent(TimeClockEvent e){
        if(!isFinishing()) {
            if(isShowTip){
                if(tipDownCount==0){
                    isShowTip = false;
                    getDB().clTip.setVisibility(View.GONE);
                }else {
                    tipDownCount--;
                    getDB().tvDjs.setText(tipDownCount+"s");
                }
            }
            if(loopDownCount==0){
                loopDownCount = SpUtil.getInt("loop_time",60);
                //定时拉取基本信息
                getVM().devLogin();
                getPermission();
                getVM().devHeart();
                EventBus.getDefault().post(new GetFacesEvent());
            }else {
                loopDownCount--;
            }
        }
    }
    /**
     * ç›‘听开门
     * @param e
     */
    @Subscribe(threadMode=ThreadMode.MAIN)
    public void OpenGridEvent(OpenGridEvent e){
        if(!isFinishing()){
            //开启柜门
            String key = e.getKey();
            if(TextUtils.isEmpty(key)) {
                key = SportUtils.intToHex(Integer.parseInt(e.getBoardCode()))
                        + SportUtils.intToHex(Integer.parseInt(e.getChannelCode()));
            }
            String code = "8A" + key + "11";
            code += SportUtils.getBCC(code);
            send485(0,code);
        }
    }
    //柜门全开
    @Subscribe(threadMode=ThreadMode.MAIN)
    public void OpenAllGridEvent(OpenAllGridEvent e){
        if(!isFinishing()){
            //开启柜门
            sendPortHandlerMsg(1,"8A01FF1165",0);
            sendPortHandlerMsg(1,"8A02FF1166",8000);
        }
    }
    //柜门批量开
    @Subscribe(threadMode=ThreadMode.MAIN)
    public void OpenGridListEvent(OpenGridListEvent e){
        if(!isFinishing()){
            //开启柜门
            long time = 0;
            for(String key:e.getKeys()){
                String code = "8A"+key+"11";
                code += SportUtils.getBCC(code);
                sendPortHandlerMsg(1,code,time);
                time+=400;
            }
        }
    }
    private SpannableString getTipText(String name){
        String text = "请关闭"+name+"柜门";
        SpannableString styledText = new SpannableString(text);
        styledText.setSpan(new TextAppearanceSpan(this,R.style.style_tip2), 0, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        styledText.setSpan(new TextAppearanceSpan(this, R.style.style_tip1),
                3, 3+name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        styledText.setSpan(new TextAppearanceSpan(this,R.style.style_tip2), name.length()+3, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        return styledText;
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        getVM().devHeart();
    }
    @Subscribe
    public void HeartEvent(HeartEvent e){
        if(!isFinishing()){
            getVM().devHeart();
        }
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void JiujinBeginEvent(JiujinBeginEvent e){
        if(!isFinishing()){
            //开启酒精检测
            sendPortHandlerMsg(3,"go_wnd:0",0);
        }
    }
    private SerialPortModel gridPort;
    private SerialPortReadObserver gridReadObserver = new SerialPortReadObserver() {
        @Override
        public void onResult(String result) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(result==null){
                    }else {
                        getVM().addInfo("发送指令失败:");
                    }
                }
            });
        }
        @Override
        public void onResultBytes(byte[] bytes) {
            if(isFinishing()){
                return;
            }
            if(bytes.length==0){
                return;
            }
            runOnUiThread(() -> {
                getVM().addInfo("获取到门数据:"+StringUtil.DateToStrSS(new Date())+"==>"+ SportUtils.bytesToHexSimple(bytes));
            });
            EventBus.getDefault().post(new CLGridEvent(SportUtils.bytesToHexSimple(bytes)));
        }
    };
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void HttpEvent(HttpEvent e){
        if(!isFinishing()){
            getVM().addInfo(e.getMsg());
        }
    }
    private long lastCloseDoorTime;
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void CLGridEvent(CLGridEvent e){
        if(!isFinishing()){
            String data = e.getData();
            data = data.toUpperCase();
            data = data.replaceAll("\\s+", "");
            if(data.startsWith("8A")){
                //开锁反馈
                String bh = data.substring(2,4);
                if(data.length()==10){
                    //单个
                    String tdh = data.substring(4,6);
                    String open = data.substring(6,8);
                    /*runOnUiThread(() -> {
                        getVM().addInfo("获取到门数据:" + "版号:"+bh+",锁号:"+tdh+",是否开门--"+("00".equals(open)?"是":"否"));
                    });*/
                    String key = bh+tdh;
                    CabinetGridDo gridDo = DaoManager.getCabinetGridDao().getGridByKey(key);
                    if(gridDo!=null){
                        gridDo.setIsOpen("00".equals(open)?1:0);
                        gridDo.setUpdateTime(StringUtil.DateToStr(new Date()));
                        DaoManager.getCabinetGridDao().update(gridDo);
                        EventBus.getDefault().post(new ManageOpenGridResultEvent());
                        if(gridDo.getIsOpen()==0) {
                            //开门失败
                            EventBus.getDefault().post(new OpenErrEvent(key));
                        }else {
                            //开门返回
                            EventBus.getDefault().post(new OpenGridOneResultEvent(key,"00".equals(open)?1:0));
                        }
                    }
                }else if(data.length()==16){
                    //批量
                    //8A 02 00 00 00 00 11 99
                    String dm = data.substring(4,12);
                    dm = SportUtils.hexToBinary(dm);
                    StringBuilder sb = new StringBuilder(dm);
                    dm = sb.reverse().toString();
                    List<CabinetGridDo> gridDos = DaoManager.getCabinetGridDao().loadAll();
                    HashMap<String,CabinetGridDo> oldMap = new HashMap<>();
                    for(CabinetGridDo d:gridDos){
                        oldMap.put(d.getGridKey(),d);
                    }
                    List<CabinetGridDo> updateList = new ArrayList<>();
                    try {
                        for(int i=1;i<=dm.length();i++){
                            String key = bh+SportUtils.intToHex(i);
                            if(oldMap.containsKey(key)){
                                CabinetGridDo gridDo = oldMap.get(key);
                                gridDo.setIsOpen("1".equals(dm.substring(i-1,i))?0:1);
                                gridDo.setUpdateTime(StringUtil.DateToStr(new Date()));
                                updateList.add(gridDo);
                            }
                        }
                        getVM().updateGrids(updateList);
                        EventBus.getDefault().post(new ManageOpenGridResultEvent());
                    }catch (Exception exception){
                        runOnUiThread(() -> {
                            getVM().addInfo("批量开门报错:" +exception.getMessage());
                        });
                    }
                }
            }else if(data.startsWith("81")){
                //主动关门 81 01 01 11 90
                String bh = data.substring(2,4);
                String tdh = data.substring(4,6);
                String open = data.substring(6,8);
                String key = bh+tdh;
                CabinetGridDo gridDo = DaoManager.getCabinetGridDao().getGridByKey(key);
                lastCloseDoorTime = System.currentTimeMillis();
                if(gridDo!=null){
                    gridDo.setIsOpen("00".equals(open)?1:0);
                    gridDo.setUpdateTime(StringUtil.DateToStr(new Date()));
                    DaoManager.getCabinetGridDao().update(gridDo);
                }
                //关门返回
                EventBus.getDefault().post(new CloseGridOneResultEvent(key,"00".equals(open)?1:0));
                if(isShowing&&isShowTip){
                    //修改显示提醒
                    getVM().doAction(5);
                }
            }else if(data.startsWith("80")){
                //查询所有门状态
                //80 01 00 00 FF FF 33 B2
                //80 02 00 00 00 F7 33 46
                if(data.length()>=14){
                    String bh = data.substring(2,4);
                    String dm = data.substring(4,12);
                    dm = dm.replaceAll("0","");
                    dm = SportUtils.hexToBinary(dm);
                    StringBuilder sb = new StringBuilder(dm);
                    dm = sb.reverse().toString();
                    List<CabinetGridDo> gridDos = DaoManager.getCabinetGridDao().loadAll();
                    HashMap<String,CabinetGridDo> oldMap = new HashMap<>();
                    for(CabinetGridDo d:gridDos){
                        oldMap.put(d.getGridKey(),d);
                    }
                    List<CabinetGridDo> addList = new ArrayList<>();
                    List<CabinetGridDo> updateList = new ArrayList<>();
                    String finalDm = dm;
                    runOnUiThread(() -> {
                        getVM().addInfo("批量查询返回:" +bh+","+ finalDm+",总数据:"+oldMap.size());
                    });
                    try {
                        for(int i=1;i<=dm.length();i++){
                            String key = bh+SportUtils.intToHex(i);
                            /*String finalDm1 = dm;
                            int finalI = i;
                            runOnUiThread(() -> {
                                getVM().addInfo("key:" +key+","+("1".equals(finalDm1.substring(finalI -1, finalI))?"关":"开"));
                            });*/
                            //System.out.println("===>"+key+","+("1".equals(dm.substring(i-1,i))?"关":"开"));
                            if(oldMap.containsKey(key)){
                                CabinetGridDo gridDo = oldMap.get(key);
                                gridDo.setIsOpen("1".equals(dm.substring(i-1,i))?0:1);
                                gridDo.setUpdateTime(StringUtil.DateToStr(new Date()));
                                updateList.add(gridDo);
                            }
                        }
                        runOnUiThread(() -> {
                            getVM().addInfo("更新库数据:版号:" +bh+","+ addList.size()+","+updateList.size());
                        });
                        getVM().updateGrids(updateList);
                        if(isShowing){
                            unCloseGrid();
                        }
                    }catch (Exception exception){
                        runOnUiThread(() -> {
                            getVM().addInfo("报错:" +exception.getMessage());
                        });
                    }
                }
            }
        }
    }
    private SerialPortModel keyPort;
    //上一次数据
    private String keyPreviousData;
    private SerialPortReadObserver keyReadObserver = new SerialPortReadObserver() {
        @Override
        public void onResult(String result) {
            if(result==null){
            }else {
                getVM().addInfo("发送指令失败:");
            }
        }
        @Override
        public void onResultBytes(byte[] bytes) {
            if(isFinishing()){
                return;
            }
            if(bytes.length==0){
                return;
            }
            EventBus.getDefault().post(new CLKeyEvent(SportUtils.bytesToHexSimple(bytes)));
        }
    };
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void CLKeyEvent(CLKeyEvent e){
        if(!isFinishing()){
            //校验现在的数据是否是全数据
            String data1 = e.getData();
            data1 = data1.toUpperCase();
            String data = data1.replaceAll("\\s+", "");
            if(data.startsWith("CC01")){
                keyPreviousData = data;
            }else if(data.startsWith("CC02")){
                runOnUiThread(() -> {
                    getVM().addInfo("获取到钥匙数据:" + data);
                    jxKey(data);
                });
                keyPreviousData = null;
            }else {
                if(!TextUtils.isEmpty(keyPreviousData)){
                    String data2 = keyPreviousData+data;
                    runOnUiThread(() -> {
                        getVM().addInfo("获取到钥匙数据:" + data2);
                        if(data2.contains("CC01")&&data2.contains("CC02")){
                            String[] sp = data2.split("CC02");
                            if(sp.length==2){
                                jxKey(sp[0]);
                                jxKey("CC02"+sp[1]);
                            }
                        }else {
                            jxKey(data2);
                        }
                    });
                    keyPreviousData = null;
                }
            }
        }
    }
    @Subscribe
    public void GetKeyStatusEvent(GetKeyStatusEvent e){
        if(!isFinishing()){
            checkKeyStatus(0);
        }
    }
    //解析钥匙数据
    private void jxKey(String data){
        List<CabinetGridDo> gridDos = DaoManager.getCabinetGridDao().loadAll();
        HashMap<String,CabinetGridDo> oldMap = new HashMap<>();
        for(CabinetGridDo d:gridDos){
            oldMap.put(d.getGridKey(),d);
        }
        List<CabinetGridDo> addList = new ArrayList<>();
        List<CabinetGridDo> updateList = new ArrayList<>();
        //二号版
        int bh = 2;
        if(data.startsWith("CC01")){
            //一号版
            bh = 1;
        }
        List<String> sp = new ArrayList<>();
        String data2 = data.substring(8,data.length());
        while (data2.length()>0){
            if (data2.length()<22) {
                sp.add(data2+"");
                data2 = "";
            }else {
                sp.add(data2.substring(0,22));
                data2 = data2.substring(22);
            }
        }
        for(String s:sp){
            if(s.length()>=20){
                String key = SportUtils.intToHex(bh)+s.substring(4,6);
                String isHaveKey = s.substring(8,10);
                String keyCode = s.substring(10,18);
                if(oldMap.containsKey(key)){
                    //修改
                    CabinetGridDo gridDo = oldMap.get(key);
                    if("01".equals(isHaveKey)) {
                        gridDo.setCurKeyCode(keyCode);
                    }else {
                        gridDo.setCurKeyCode("");
                    }
                    /*if("0101".equals(key)) {
                        getVM().addInfo(key+" , "+isHaveKey+"  "+keyCode);
                        getVM().addInfo(key + "设置钥匙:" + gridDo.getCurKeyCode());
                    }*/
                    gridDo.setUpdateTime(StringUtil.DateToStr(new Date()));
                    updateList.add(gridDo);
                }
            }
        }
        getVM().updateGrids(updateList);
        EventBus.getDefault().post(new KeyResultEvent(bh+""));
    }
    private SerialPortModel jiuPort;
    private SerialPortReadObserver jiuReadObserver = new SerialPortReadObserver() {
        @Override
        public void onResult(String result) {
            if(result==null){
            }else {
                getVM().addInfo("发送指令失败:");
            }
        }
        @Override
        public void onResultBytes(byte[] bytes) {
            if(isFinishing()){
                return;
            }
            if(bytes.length==0){
                return;
            }
            try {
                runOnUiThread(() -> {
                    getVM().addInfo("获取到酒精检测数据:"+StringUtil.DateToStrSS(new Date())+" " + new String(bytes));
                });
                String data = new String(bytes);
                if(data.contains("blow fail")){
                    //检测失败
                    EventBus.getDefault().post(new JiujinResultEvent(false,null));
                }else if(data.startsWith("Result:")){
                    Pattern pattern = Pattern.compile("([0-9]+\\.[0-9]+)");
                    Matcher matcher = pattern.matcher(data);
                    if (matcher.find()) {
                        EventBus.getDefault().post(new JiujinResultEvent(true,new BigDecimal(matcher.group(1))));
                    }
                }
            }catch (Exception e){
                getVM().addInfo("获取到酒精检测报错:" + e.getMessage());
            }
        }
    };
    private SerialPortModel chosePort;
    private SerialPortReadObserver choseReadObserver = new SerialPortReadObserver() {
        @Override
        public void onResult(String result) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(result==null){
                    }else {
                        getVM().addInfo("发送指令失败:");
                    }
                }
            });
        }
        @Override
        public void onResultBytes(byte[] bytes) {
            if(bytes.length==0){
                return;
            }
            runOnUiThread(() -> {
                getVM().addInfo("获取到门数据:" + SportUtils.bytesToHexSimple(bytes));
            });
            if(startIndex==1){
                gridPath = path;
                getVM().addInfo("设置门串口路径:" + path);
                SpUtil.saveString("port_grid",path);
            }else if(startIndex==2){
                keyPath = path;
                getVM().addInfo("设置钥匙串口路径:" + path);
                SpUtil.saveString("port_key",path);
            }else if(startIndex==3){
                jiuPath = path;
                getVM().addInfo("设置酒精串口路径:" + path);
                SpUtil.saveString("port_jiu",path);
            }
        }
    };
    List<String> ports;
    private int index = 0;
    private String path;
    private int startIndex;
    private String gridPath;
    private String keyPath;
    private String jiuPath;
    private int xhCount = 0;
    private Handler portHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 0:
                    if(index>=1&&!checkEnd()){
                        path = ports.get(index);
                        index--;
                        portHandler.sendEmptyMessage(4);
                    }else if(checkEnd()){
                        initPort();
                    }else if(xhCount<3){
                        initPort();
                    }
                    break;
                case 1:
                    //发送柜格命令
                    send485(0, (String) msg.obj);
                    break;
                case 2:
                    //发送钥匙命令
                    send485(1, (String) msg.obj);
                    break;
                case 3:
                    //发送酒精检查命令
                    send485(2, (String) msg.obj);
                    break;
                case 4:
                    if(startIndex>2){
                        portHandler.sendEmptyMessage(0);
                    }else {
                        try {
                            chosePort();
                        } catch (SecurityException e) {
                            portHandler.sendEmptyMessageDelayed(5, 1000);
                        }
                    }
                    break;
                case 5:
                    closePort(chosePort);
                    portHandler.sendEmptyMessageDelayed(4,1000);
                    break;
                case 6:
                    break;
                default:
                    break;
            }
        }
    };
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void CheckGridStatusEvent(CheckGridStatusEvent e){
        if(!isFinishing()){
            checkGridStatus(0);
        }
    }
    //检查所有门状态
    private void checkGridStatus(long time){
        sendPortHandlerMsg(1,"80010033B2",time+100);
        sendPortHandlerMsg(1,"80020033B1",time+800);
    }
    //检查所有钥匙状态
    private void checkKeyStatus(long time){
        sendPortHandlerMsg(2,"A001010000000002",time+200);
        sendPortHandlerMsg(2,"A002010000000003",time+400);
    }
    private String jiu_blow;
    private String jiu_mic_ad;
    private String jiu_alarm;
    private String jiu_unit;
    private void setJiuConfig(long time){
        CabinetConfigDataBean config = MApplication.getConfigBean().getCabinetConfigDataVO();
        if(!config.getBlowTime().equals(jiu_blow)) {
            //设置吹气时间
            jiu_blow = config.getBlowTime();
            sendPortHandlerMsg(3, "blow:" + config.getBlowTime(), time += 100);
        }
        if(!config.getPressure().equals(jiu_mic_ad)) {
            //压力值
            jiu_mic_ad = config.getPressure();
            sendPortHandlerMsg(3, "mic_ad:" + config.getPressure(), time += 300);
        }
        if(!config.getConcentration().equals(jiu_alarm)) {
            //浓度阈值
            jiu_alarm = config.getConcentration();
            sendPortHandlerMsg(3, "alarm:" + config.getConcentration(), time += 300);
        }
        if("3".equals(config.getThreshold())){
            config.setThreshold("0");
        }
        if(!config.getThreshold().equals(jiu_unit)) {
            //浓度阈值单位 (1=mg/100ml;2=mg/L;3=%BAC)
            jiu_unit = config.getThreshold();
            sendPortHandlerMsg(3, "unit:" + config.getThreshold(), time += 300);
        }
    }
    private void sendPortHandlerMsg(int what,String obj,long time){
        Message mc = Message.obtain();
        mc.what=what;
        mc.obj = obj;
        portHandler.sendMessageDelayed(mc,time);
    }
    private boolean isInitPort;
    //初始化串口
    private void initPort(){
        //SpUtil.setString("port_grid","/dev/ttyS7");
        //SpUtil.setString("port_key","/dev/ttyS1");
        //SpUtil.setString("port_jiu","/dev/ttyS2");
        gridPath = SpUtil.getString("port_grid");
        getVM().addInfo("门串口链接:"+gridPath);
        keyPath = SpUtil.getString("port_key");
        getVM().addInfo("钥匙串口链接:"+keyPath);
        jiuPath = SpUtil.getString("port_jiu");
        getVM().addInfo("酒精串口链接:"+jiuPath);
        if(!TextUtils.isEmpty(SpUtil.getString("port_grid"))&&
                !TextUtils.isEmpty(SpUtil.getString("port_key"))&&
                !TextUtils.isEmpty(SpUtil.getString("port_jiu"))){
            if(isInitPort){
                return;
            }
            xhCount=0;
            closePort(chosePort);
            if(!TextUtils.isEmpty(SpUtil.getString("port_grid"))){
                String path = SpUtil.getString("port_grid");
                closePort(gridPort);
                getVM().addInfo("门串口链接:"+path);
                gridPort = new SerialPortModel(path,9600 ,8
                        ,1 , 0,gridReadObserver);
                boolean isSucc = gridPort.open();
                if(isSucc) {
                    isInitPort = true;
                    getVM().addInfo("门串口链接成功:"+path);
                    String msg = isSucc ? "成功" : "失败";
                    //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                    gridPort.startRead();
                    //查询所有柜格门信息
                   checkGridStatus(300);
                }else {
                    getVM().addInfo("门串口链接失败:"+path);
                }
            }
            if(!TextUtils.isEmpty(SpUtil.getString("port_key"))){
                String path = SpUtil.getString("port_key");
                closePort(keyPort);
                keyPort = new SerialPortModel(path,115200 ,8
                        ,1 , 0,keyReadObserver);
                boolean isSucc = keyPort.open();
                if(isSucc) {
                    isInitPort = true;
                    getVM().addInfo("钥匙串口链接成功:"+path);
                    String msg = isSucc ? "成功" : "失败";
                    //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                    keyPort.startRead();
                    checkKeyStatus(1500);
                }else {
                    getVM().addInfo("钥匙串口链接失败:"+path);
                }
            }
            if(!TextUtils.isEmpty(SpUtil.getString("port_jiu"))){
                String path = SpUtil.getString("port_jiu");
                closePort(jiuPort);
                jiuPort = new SerialPortModel(path,9600 ,8
                        ,1 , 0,jiuReadObserver);
                boolean isSucc = jiuPort.open();
                if(isSucc) {
                    isInitPort = true;
                    getVM().addInfo("酒精串口链接成功:"+path);
                    String msg = isSucc ? "成功" : "失败";
                    //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                    jiuPort.startRead();
                }else {
                    getVM().addInfo("酒精串口链接失败:"+path);
                }
            }
        }else {
            if(xhCount>2){
                return;
            }
            xhCount++;
            ports = SportUtils.getSerialPortPaths(this);
            if(ports==null){
                getVM().addInfo("未查询到串口列表");
            }else {
                getVM().addInfo("串口列表:"+ports.size());
            }
            if(ports.size()>0){
                index = ports.size()-1;
                portHandler.sendEmptyMessage(0);
            }
        }
    }
    private void chosePort(){
        getVM().addInfo("当前下标:"+startIndex+" ,path="+path);
        if(startIndex==0&&TextUtils.isEmpty(gridPath)){
            startIndex++;
            getVM().addInfo("门串口链接:"+path);
            chosePort = new SerialPortModel(path,9600 ,8
                    ,1 , 0,choseReadObserver);
            boolean isSucc = chosePort.open();
            if(isSucc) {
                getVM().addInfo("门串口链接成功:"+path);
                String msg = isSucc ? "成功" : "失败";
                //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                chosePort.startRead();
                //发送柜格校验信息
                send485(3,"80010033B2");
            }else {
                getVM().addInfo("门串口链接失败:"+path);
            }
            portHandler.sendEmptyMessageDelayed(5,1500);
            return;
        }
        if(startIndex==1&&TextUtils.isEmpty(keyPath)){
            startIndex++;
            chosePort = new SerialPortModel(path,115200 ,8
                    ,1 , 0,choseReadObserver);
            boolean isSucc = chosePort.open();
            if(isSucc) {
                getVM().addInfo("钥匙串口链接成功:"+path);
                String msg = isSucc ? "成功" : "失败";
                //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                chosePort.startRead();
                //发送钥匙校验信息
                send485(3,"A001010000000002");
            }else {
                getVM().addInfo("钥匙串口链接失败:"+path);
            }
            portHandler.sendEmptyMessageDelayed(5,1500);
            return;
        }
        if(startIndex==2&&TextUtils.isEmpty(jiuPath)){
            startIndex++;
            chosePort = new SerialPortModel(path,9600 ,8
                    ,1 , 0,choseReadObserver);
            boolean isSucc = chosePort.open();
            if(isSucc) {
                getVM().addInfo("酒精串口链接成功:"+path);
                String msg = isSucc ? "成功" : "失败";
                //getVM().append("串口 "+ settingBean.getDevicePath() + " -连接"+msg);
                chosePort.startRead();
                //发送酒精校验信息
                send485(4,"read");
            }else {
                getVM().addInfo("酒精串口链接失败:"+path);
            }
            portHandler.sendEmptyMessageDelayed(5,1500);
            return;
        }
        portHandler.sendEmptyMessageDelayed(0,0);
    }
    private CircularQueue openGridQueue = new CircularQueue();
    private void send485(int type,String code){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                getVM().addInfo("发送指令:"+StringUtil.DateToStrSS(new Date())+"==>"+code);
            }
        });
        if(type==0){
            if(gridPort!=null){
                if(code.startsWith("8A")){
                    openGridQueue.enqueue(code);
                }
                byte[] sendByte = SportUtils.hexToByteArray(code);
                gridPort.write(sendByte);
            }
        }else if(type==1){
            if(keyPort!=null){
                byte[] sendByte = SportUtils.hexToByteArray(code);
                keyPort.write(sendByte);
            }
        }else if(type==2){
            if(jiuPort!=null){
                byte[] sendByte =code.getBytes();
                jiuPort.write(sendByte);
            }
        }else if(type==3){
            if(chosePort!=null){
                byte[] sendByte = SportUtils.hexToByteArray(code);
                chosePort.write(sendByte);
            }
        }else if(type==4){
            if(chosePort!=null){
                byte[] sendByte =code.getBytes();
                chosePort.write(sendByte);
            }
        }
    }
    private void closePort(SerialPortModel port){
        try {
            if(port==null){
                return;
            }
            port.stopRead();
            port.close();
            port = null;
        }catch (Exception e){
        }
    }
    private boolean checkEnd(){
        if(TextUtils.isEmpty(gridPath)){
            getVM().addInfo("门错误");
            startIndex=0;
            return false;
        }
        if(TextUtils.isEmpty(keyPath)){
            getVM().addInfo("钥匙错误");
            startIndex=1;
            return false;
        }
        if(TextUtils.isEmpty(jiuPath)){
            getVM().addInfo("酒精错误");
            startIndex=2;
            return false;
        }
        getVM().addInfo("串口全部链接成功:");
        return true;
    }
    //开门
    @Subscribe
    public void OpenGridOneResultEvent(OpenGridOneResultEvent e){
        if(!isFinishing()&&isShowing){
            //开门成功,移除开门
            if(handler.hasMessages(1)){
                handler.removeMessages(1);
                getVM().addInfo("==移除开门任务");
            }
        }
    }
    private Long keyTime;
    private HashMap<String,String> closeMap = new HashMap<>();
    /**
     * å…³é—¨
     * @param e
     */
    @Subscribe(threadMode= ThreadMode.MAIN)
    public void CloseGridOneResultEvent(CloseGridOneResultEvent e){
        if(!isFinishing()&&isShowing){
            //关门成功,移除开门
            if(handler.hasMessages(1)){
                handler.removeMessages(1);
                getVM().addInfo("==移除开门任务");
            }
            closeMap.put(e.getKey(),"");
            //发送查询钥匙号
            EventBus.getDefault().post(new GetKeyStatusEvent());
            keyTime = new Date().getTime()+500;
            if(handler.hasMessages(2)){
                handler.removeMessages(2);
            }
            handler.sendEmptyMessageDelayed(2,1200);
        }
    }
    @Subscribe(threadMode= ThreadMode.MAIN)
    public void OpenErrEvent(OpenErrEvent e){
        //开门失败
        if(!isFinishing()&&isShowing){
            //开门
            if(handler.hasMessages(1)){
                handler.removeMessages(1);
                getVM().addInfo("==移除开门任务");
            }
            EventBus.getDefault().post(new OpenGridEvent(e.getKey()));
            Message msg = Message.obtain();
            msg.what=1;
            msg.obj = e.getKey();
            handler.sendMessageDelayed(msg,1000);
        }
    }
    @Subscribe
    public void KeyResultEvent(KeyResultEvent e){
        if(!isFinishing()&&isShowing){
            //校验时间
            if(keyTime==null){
                return;
            }
            if(keyTime!=null&&keyTime>System.currentTimeMillis()){
                //校验返回时间<命令时间
                return;
            }
            if(handler.hasMessages(2)){
                handler.removeMessages(2);
            }
            HashMap<String,String> copyMap = new HashMap<>();
            copyMap.putAll(closeMap);
            closeMap.clear();
            //校验卡号不对的,直接弹出
            List<CabinetGridDo> gridDos = DaoManager.getCabinetGridDao().loadAll();
            List<String> keys = new ArrayList<>();
            StringBuilder sb = new StringBuilder();
            for(CabinetGridDo gridDo:gridDos){
                //要在范围内
                if(copyMap.containsKey(gridDo.getGridKey())){
                    boolean isFail = false;
                    if(TextUtils.isEmpty(gridDo.getGridKey())){
                        if(!TextUtils.isEmpty(gridDo.getCurKeyCode())&&gridDo.getIsOpen()==0){
                            //未绑定的存放了钥匙
                            keys.add(gridDo.getGridKey());
                            if(sb.length()>0){
                                sb.append("、");
                            }
                            sb.append(gridDo.getCabinetName());
                            isFail = true;
                        }
                    }else {
                        if(!TextUtils.isEmpty(gridDo.getCurKeyCode())){
                            if(!gridDo.getCurKeyCode().equals(gridDo.getKeyCode())&&gridDo.getIsOpen()==0){
                                //钥匙不匹配
                                keys.add(gridDo.getGridKey());
                                if(sb.length()>0){
                                    sb.append("、");
                                }
                                sb.append(gridDo.getCabinetName());
                                isFail = true;
                            }
                        }
                    }
                    if(!isFail){
                        //关门成功
                        EventBus.getDefault().post(new HttpEvent(StringUtil.DateToStrSS(new Date())+"门关闭成功***************************>目标:"+gridDo.getKeyCode()+",当前:"+gridDo.getCurKeyCode()));
                        getVM().closeGrid(gridDo);
                    }
                }
            }
            if(sb.length()>0){
                ToastView.show(MApplication.mContext, sb.toString() + "钥匙存放位置错误");
            }
            if(keys.size()>0){
                //开门
                EventBus.getDefault().post(new OpenGridListEvent(keys));
            }
        }
    }
}