Android实现人脸支付的示例代码
作者:FranzLiszt1847 发布时间:2023-07-30 14:23:52
标签: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
来源:https://blog.csdn.net/News53231323/article/details/122991431
0
投稿
猜你喜欢
- SharedPreferences是Android中最容易理解的数据存储技术,实际上SharedPreferences处理的就是一个key-
- 有人问我,怎么判断一个点是不是在多边形内,本来想着把这个多边形分成一个又一个三角形,如图, 然后判断这个点是不是在某个三角形中,如
- 目标效果: 点击动画按钮之后每张牌各自旋转 散开到屏幕上半部分的任意位置之后回到初始位置 比较像LOL男刀的技能动画 : )1: 创建卡牌对
- 需求基于MTK8163 8.1平台定制导航栏部分,在左边增加音量减,右边增加音量加思路需求开始做之前,一定要研读SystemUI Navig
- 一个发送验证码的需求:包括限制文本框输入长度和只允许输入数字按惯例 先上图:class MyBody extends StatefulWid
- 网络中数据传输经常是xml或者json,现在做的一个项目之前调其他系统接口都是返回的xml格式,刚刚遇到一个返回json格式数据的接口,通过
- 1.最近的项目中,有一个Activity用到Fragment+ViewPager,其中一个fragment中实现了视频播放的功能,包含有Su
- 前言在网络通信中,通信传输数据容易被截取或篡改,如果在传输用户隐私数据过程中,被不法分子截取或篡改,就可能导致用户受到伤害,比如被诈 骗,所
- Mybatis-Spring当我们使用mybatis和spring整合后为什么下面的代码可以运行?一个问题:我就写了个mapper接口为什么
- 每当想找哪个运算符优先级高时,很多时候总是想找的就没有,真让人气愤!现在,终于有个我个人觉得非常全的,分享给大家,欢迎拍砖!C语言运算符优先
- 前言本篇文章 中写到的是 flutter 调用了Android 原生的 TextView 案例添加原生组件的流程基本上可以描述为:1 and
- 1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1)&nb
- 无论哪种界面框架输入文本框都是非常重要的控件, 但是发现flutter中的输入框TextField介绍的虽然多,但是各个属性怎么组合满足需要
- JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展
- 你知道String、StringBuilder、Stringbuffer的区别吗?当你创建字符串的时候,有考虑过该使用哪个吗?别急,这篇文章
- 定义: SharedPreferences
- CompletableFuture 介绍CompletableFuture是1.8引入的新特性,一些比较复杂的异步计算场景,尤其是需要串联多
- 本文实例为大家分享了Android TextView实现跑马灯效果的具体代码,供大家参考,具体内容如下当Layout中只有一个TextVie
- 概述:Flutter中常用的滑动布局 ScrollView 有 SingleChildScrollView、NestedScrollView
- 本文主要介绍我为桌面和 Web 设计的一个超级秘密 Flutter 项目使用了画布和可拖动节点界面。本教程将展示我如何使用堆栈来使用小部件完