Android实现人脸支付的示例代码

目录
  • 效果展示
  • 功能实现
    • 人脸支付
    • 密码框输入支付
  • 尾言

    效果展示

    人脸支付效果视频

    密码框输入支付效果视频

    因为密码支付时会调起系统安全键盘,开启自动保护功能,防止泄露,会导致输入密码时录屏黑屏,故使用另一台手机拍摄。

    功能实现

    人脸支付

    API初始化

            ftEngine = new FaceEngine();
            ftInitCode = ftEngine.init(this, DetectMode.ASF_DETECT_MODE_VIDEO, ConfigUtil.getFtOrient(this),
                    16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_DETECT);
    
            frEngine = new FaceEngine();
            frInitCode = frEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY,
                    16, MAX_DETECT_NUM, FaceEngine.ASF_FACE_RECOGNITION);
    
            flEngine = new FaceEngine();
            flInitCode = flEngine.init(this, DetectMode.ASF_DETECT_MODE_IMAGE, DetectFaceOrientPriority.ASF_OP_0_ONLY,
                    16, MAX_DETECT_NUM, FaceEngine.ASF_LIVENESS);
    
    

    人脸特征提取

        private void searchFace(final FaceFeature frFace, final Integer requestId) {
            Observable.create(new ObservableOnSubscribe<CompareResult>() {
                        @Override
                        public void subscribe(ObservableEmitter<CompareResult> emitter) {
                            CompareResult compareResult = FaceServer.getInstance().getTopOfFaceLib(frFace);
                            emitter.onNext(compareResult);
                        }
                    })
                    .subscribeOn( Schedulers.computation())
                    .observeOn( AndroidSchedulers.mainThread())
                    .subscribe(new Observer<CompareResult>() {
                        @Override
                        public void onSubscribe(Disposable d) {
    
                        }
                        @Override
                        public void onNext(CompareResult compareResult) {
                            if (compareResult == null || compareResult.getUserName() == null) {
                                requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);
                                faceHelper.setName(requestId, "VISITOR " + requestId);
                                return;
                            }
                            if (compareResult.getSimilar() > SIMILAR_THRESHOLD) {
                                boolean isAdded = false;
                                if (compareResultList == null) {
                                    requestFeatureStatusMap.put(requestId, RequestFeatureStatus.FAILED);
                                    faceHelper.setName(requestId, "VISITOR " + requestId);
                                    return;
                                }
                                for (CompareResult compareResult1 : compareResultList) {
                                    if (compareResult1.getTrackId() == requestId) {
                                        isAdded = true;
                                        break;
                                    }
                                }
                                if (!isAdded) {
                                    //对于多人脸搜索,假如最大显示数量为 MAX_DETECT_NUM 且有新的人脸进入,则以队列的形式移除
                                    if (compareResultList.size() >= MAX_DETECT_NUM) {
                                        compareResultList.remove(0);
                                        adapter.notifyItemRemoved(0);
                                    }
                                    //添加显示人员时,保存其trackId
                                    compareResult.setTrackId(requestId);
                                    compareResultList.add(compareResult);
                                    adapter.notifyItemInserted(compareResultList.size() - 1);
                                }
                                requestFeatureStatusMap.put(requestId, RequestFeatureStatus.SUCCEED);
                                faceHelper.setName(requestId, getString(R.string.recognize_success_notice, compareResult.getUserName()));
    
                            } else {
                                faceHelper.setName(requestId, getString(R.string.recognize_failed_notice, "NOT_REGISTERED"));
                                retryRecognizeDelayed(requestId);
                            }
                        }
    
    

    返回支付结果

    根据匹配人脸注册时所获取的trackid,判断识别结果

    Integer recognizeStatus = requestFeatureStatusMap.get(facePreviewInfoList.get(i).getTrackId());
    

    根据返回码修改识别框颜色,并修改跳转状态的值

    if (recognizeStatus != null) {
                    handler.sendEmptyMessageDelayed( 1,1000 );
                    if (recognizeStatus == RequestFeatureStatus.FAILED) {
                        color = RecognizeColor.COLOR_FAILED;
                        returnFlag = false;
                    }
                    if (recognizeStatus == RequestFeatureStatus.SUCCEED) {
                        color = RecognizeColor.COLOR_SUCCESS;
                        returnFlag = true;
                    }
                }
    

    利用异步通信进行延迟跳转

        Handler handler = new Handler(  ){
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage( msg );
                if (msg.what == 1){
                    CountDown();
                    handler.sendEmptyMessageDelayed( 1,1000 );
                }
            }
        };
    

    密码框输入支付

    自定义密码输入框控件

    public class PayPwdEditText extends RelativeLayout {
    
        private EditText editText; //文本编辑框
        private Context context;
    
        private LinearLayout linearLayout; //文本密码的文本
        private TextView[] textViews; //文本数组
    
        private int pwdlength = 6; //密码长度, 默认6
    
        private OnTextFinishListener onTextFinishListener;
    
    
        public PayPwdEditText(Context context) {
            this(context, null);
        }
    
        public PayPwdEditText(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PayPwdEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.context = context;
        }
    
        /**
         * @param bgdrawable 背景drawable
         * @param pwdlength 密码长度
         * @param splilinewidth 分割线宽度
         * @param splilinecolor 分割线颜色
         * @param pwdcolor 密码字体颜色
         * @param pwdsize 密码字体大小
         */
        public void initStyle(int bgdrawable, int pwdlength, float splilinewidth, int splilinecolor, int pwdcolor, int pwdsize)
        {
            this.pwdlength = pwdlength;
            initEdit(bgdrawable);
            initShowInput(bgdrawable, pwdlength, splilinewidth, splilinecolor, pwdcolor, pwdsize);
        }
    
        /**
         * 初始化编辑框
         * @param bgcolor
         */
        private void initEdit(int bgcolor)
        {
            editText = new EditText(context);
            editText.setBackgroundResource(bgcolor);
            editText.setCursorVisible(false);
            editText.setTextSize(0);
            //设置为密文输入模式和数字
            editText.setInputType( InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
            //设置输入长度为6
            editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(pwdlength)});
            editText.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    Editable etext = editText.getText();
                    Selection.setSelection(etext, etext.length());
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    initDatas(s);
                    if(s.length() == pwdlength)
                    {
                        if(onTextFinishListener != null)
                        {
                            onTextFinishListener.onFinish(s.toString().trim());
                        }
                    }
                }
            });
            LayoutParams lp = new LayoutParams( LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            lp.addRule( RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
            addView(editText, lp);
    
        }
    
        /**
         * @param bgcolor 背景drawable
         * @param pwdlength 密码长度
         * @param slpilinewidth 分割线宽度
         * @param splilinecolor 分割线颜色
         * @param pwdcolor 密码字体颜色
         * @param pwdsize 密码字体大小
         */
        public void initShowInput(int bgcolor, int pwdlength, float slpilinewidth, int splilinecolor, int pwdcolor, int pwdsize)
        {
            //添加密码框父布局
            linearLayout = new LinearLayout(context);
            linearLayout.setBackgroundResource(bgcolor);
            LayoutParams layoutParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            linearLayout.setLayoutParams(layoutParams);
            linearLayout.setOrientation( LinearLayout.HORIZONTAL);
            addView(linearLayout);
    
            //添加密码框
            textViews = new TextView[pwdlength];
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT);
            params.weight = 1;
            params.gravity = Gravity.CENTER;
    
            LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(dip2px(context, slpilinewidth), LayoutParams.MATCH_PARENT);
            for(int i = 0; i < textViews.length; i++)
            {
                final int index = i;
                TextView textView = new TextView(context);
                textView.setGravity( Gravity.CENTER);
                textViews[i] = textView;
                textViews[i].setTextSize(pwdsize);
                textViews[i].setTextColor(context.getResources().getColor(pwdcolor));
                textViews[i].setInputType( InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
                linearLayout.addView(textView, params);
                if(i < textViews.length - 1)
                {
                    View view = new View(context);
                    view.setBackgroundColor(context.getResources().getColor(splilinecolor));
                    linearLayout.addView(view, params2);
                }
            }
        }
    
        /**
         * 是否显示明文
         * @param showPwd
         */
        public void setShowPwd(boolean showPwd) {
            int length = textViews.length;
            for(int i = 0; i < length; i++) {
                if (showPwd) {
                    textViews[i].setTransformationMethod( PasswordTransformationMethod.getInstance());
                } else {
                    textViews[i].setTransformationMethod( HideReturnsTransformationMethod.getInstance());
                }
            }
        }
    
        /**
         * 设置显示类型
         * @param type
         */
        public void setInputType(int type)
        {
            int length = textViews.length;
            for(int i = 0; i < length; i++) {
                textViews[i].setInputType(type);
            }
        }
    
        /**
         * 清除文本框
         */
        public void clearText()
        {
            editText.setText("");
            for(int i = 0; i < pwdlength; i++)
            {
                textViews[i].setText("");
            }
        }
    
        public void setOnTextFinishListener(OnTextFinishListener onTextFinishListener) {
            this.onTextFinishListener = onTextFinishListener;
        }
    
        /**
         * 根据输入字符,显示密码个数
         * @param s
         */
        public void initDatas(Editable s)
        {
            if(s.length() > 0)
            {
                int length = s.length();
                for(int i = 0; i < pwdlength; i++)
                {
                    if(i < length)
                    {
                        for(int j = 0; j < length; j++)
                        {
                            char ch = s.charAt(j);
                            textViews[j].setText( String.valueOf(ch));
                        }
                    }
                    else
                    {
                        textViews[i].setText("");
                    }
                }
            }
            else
            {
                for(int i = 0; i < pwdlength; i++)
                {
                    textViews[i].setText("");
                }
            }
        }
    
        public String getPwdText()
        {
            if(editText != null)
                return editText.getText().toString().trim();
            return "";
        }
    
        public static int dip2px(Context context, float dipValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dipValue * scale + 0.5f);
        }
    
        public interface OnTextFinishListener
        {
            void onFinish(String str);
        }
    
        public void setFocus()
        {
            editText.requestFocus();
            editText.setFocusable(true);
            showKeyBord(editText);
        }
    
        /**
         * 显示键盘
         * @param view
         */
        public void showKeyBord(View view)
        {
            InputMethodManager imm = (InputMethodManager) context.getSystemService( Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
        }
    
    }
    
    

    初始化控件

    分别对应密码框背景、密码位数、分割线宽度、分割线颜色、字体颜色、字体大小

    mPayPwdEditText.initStyle( R.drawable.bg_paypassword_style,6,0.8f,R.color.colorWhite,R.color.colorWhite,35);

    布局内用法

    <com.example.PayPackage.PayPwdEditText
        android:id="@+id/payPassWordEditText"
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_height="35dp"/>
    

    密码匹配

    对控件进行输入事件监听,采用测试密码用例:123456,与回调接口所携带的数据进行匹配。

     mPayPwdEditText.setOnTextFinishListener( new PayPwdEditText.OnTextFinishListener() {
                @Override
                public void onFinish(String str) {
                    if (str.equals( "123456" ))
                    {
                        startActivity( new Intent( OrderInterface.this,PaySuccess.class ) );
                    }else {
                        if (PassWordError == null) {
                            PassWordError = new Toast( OrderInterface.this );
                            View view = LayoutInflater.from( OrderInterface.this ).inflate( R.layout.passworderror,null,false );
                            ErrorTips = view.findViewById( R.id.ErrorTips );
                            PassWordError.setView( view );
                            //PassWordError.setGravity( Gravity.CENTER,0, ResHelper.dipToPx(OrderInterface.this, -100) );
                        }
                        PassWordError.show();
                        mPayPwdEditText.clearText();
                    }
                }
            } );
    

    其内部是对EditText控件进行输入事件监听。然后通过比对输入字符串长度与密码长度,然后返回其输入的字符串

                @Override
                public void afterTextChanged(Editable s) {
                    initDatas(s);
                    if(s.length() == pwdlength)
                    {
                        if(onTextFinishListener != null)
                        {
                            onTextFinishListener.onFinish(s.toString().trim());
                        }
                    }
                }
    

    尾言

    此人脸识别API采用虹软ArcSoft

    本文转自网络,如有侵权请联系客服删除。