package com.doumee.keyCabinet.ui.face;
|
|
import androidx.annotation.CallSuper;
|
import androidx.annotation.NonNull;
|
import androidx.annotation.Nullable;
|
import androidx.lifecycle.Observer;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import android.content.Context;
|
import android.graphics.Bitmap;
|
import android.graphics.Color;
|
import android.os.Bundle;
|
import android.os.Handler;
|
import android.os.Message;
|
import android.text.Editable;
|
import android.text.TextWatcher;
|
import android.view.MotionEvent;
|
import android.view.View;
|
import android.widget.Button;
|
import android.widget.CheckBox;
|
import android.widget.CompoundButton;
|
import android.widget.EditText;
|
import android.widget.ImageView;
|
import android.widget.LinearLayout;
|
import android.widget.ProgressBar;
|
import android.widget.RelativeLayout;
|
import android.widget.TextView;
|
import android.widget.Toast;
|
|
import com.alibaba.fastjson.JSON;
|
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.R;
|
import com.doumee.keyCabinet.base.MyBaseActivity;
|
import com.doumee.keyCabinet.bean.FaceUserBean;
|
import com.doumee.keyCabinet.databinding.AddFaceActivityBinding;
|
import com.doumee.keyCabinet.ui.face.adapter.FaceRcvAdapter;
|
import com.doumee.keyCabinet.ui.view.TipDialog;
|
import com.doumee.keyCabinet.utils.face.FaceUtils;
|
import com.example.datalibrary.api.FaceApi;
|
import com.example.datalibrary.listener.DBLoadListener;
|
import com.example.datalibrary.manager.FaceSDKManager;
|
import com.example.datalibrary.model.KeyboardsUtils;
|
import com.example.datalibrary.model.User;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
|
import dagger.hilt.android.AndroidEntryPoint;
|
import timber.log.Timber;
|
|
@AndroidEntryPoint
|
public class AddFaceActivity extends MyBaseActivity<AddFaceVM, AddFaceActivityBinding> implements View.OnClickListener,
|
CompoundButton.OnCheckedChangeListener, TipDialog.OnTipDialogClickListener {
|
// view
|
private RecyclerView mRecyclerUserManager;
|
private ImageView mImageIconSearch; // title中的搜索按钮
|
private RelativeLayout mRelativeStandard; // title中的常规布局
|
private LinearLayout mLinearSearch; // title中的搜索布局
|
private boolean isCheck = false; // title菜单点击状态
|
private TextView mTextCancel; // title中的取消按钮
|
private RelativeLayout mRelativeEmpty; // 暂无内容
|
private TextView mTextEmpty;
|
private EditText mEditTitleSearch;
|
|
private RelativeLayout mRelativeDelete; // 导入人脸布局
|
private CheckBox mCheckAll; // 全选
|
private TextView mTextDelete; // 导入人脸
|
private TextView textAll;
|
private TipDialog mTipDialog;
|
|
private Context mContext;
|
private FaceRcvAdapter mFaceUserAdapter;
|
private List<FaceUserBean> mUserInfoList;
|
private int mSelectCount; // 选中的个数
|
private boolean mIsLongClick; // 是否是长按
|
|
private ProgressBar progressBar;
|
private TextView progressText;
|
private View progressGroup;
|
|
@Override
|
public int getLayoutId() {
|
return R.layout.add_face_activity;
|
}
|
|
@Override
|
public void initView(@Nullable Bundle savedInstanceState) {
|
isAddCountTimer = false;
|
normalConfig();
|
getDB().setModel(getVM());
|
mContext = this;
|
initView();
|
}
|
|
@Override
|
public void initData(@Nullable Bundle savedInstanceState) {
|
getVM().getDatasLD().observe(this, new Observer<List<FaceUserBean>>() {
|
@Override
|
public void onChanged(List<FaceUserBean> beans) {
|
mUserInfoList = beans;
|
if (beans == null || beans.size() == 0) {
|
mFaceUserAdapter.refreshData(new ArrayList<>());
|
mFaceUserAdapter.notifyDataSetChanged();
|
mRelativeEmpty.setVisibility(View.VISIBLE);
|
mRecyclerUserManager.setVisibility(View.GONE);
|
// 显示无内容判断
|
if (mEditTitleSearch.getText().length()>0) {
|
mTextEmpty.setText(getString(R.string.addface_zwnr));
|
updateDeleteUI(false);
|
} else {
|
mTextEmpty.setText(getString(R.string.addface_tip1));
|
mRelativeDelete.setVisibility(View.GONE);
|
}
|
return;
|
}
|
|
// 恢复默认状态
|
resetDeleteData();
|
mRelativeEmpty.setVisibility(View.GONE);
|
mRecyclerUserManager.setVisibility(View.VISIBLE);
|
mFaceUserAdapter.refreshData(mUserInfoList);
|
mFaceUserAdapter.notifyDataSetChanged();
|
}
|
});
|
getVM().getDatas("");
|
}
|
|
@Override
|
protected void onDestroy() {
|
super.onDestroy();
|
handler.removeCallbacksAndMessages(null);
|
handler = null;
|
}
|
|
private Handler handler = new Handler(){
|
@Override
|
public void handleMessage(@NonNull Message msg) {
|
if(!isFinishing()){
|
switch (msg.what){
|
case 0:
|
if(finishCount<selectBeans.size()){
|
datasToBitmap(selectBeans.get(finishCount));
|
}else {
|
//结束
|
loadListener.onComplete(new ArrayList<>(),finishCount);
|
if(failCount>0){
|
Toast.makeText(mContext, String.format(getString(R.string.addface_tip2),failCount,failStr.toString()), Toast.LENGTH_LONG).show();
|
}
|
}
|
break;
|
}
|
}
|
}
|
};
|
private List<FaceUserBean> selectBeans = new ArrayList<>();
|
private int finishCount = 0;
|
private int failCount = 0;
|
private StringBuilder failStr = new StringBuilder();
|
private void datasToBitmap(FaceUserBean bean){
|
// 使用 Glide 加载图片并转换为 Bitmap
|
Glide.with(this)
|
.asBitmap()
|
.load(bean.getFaceUrl())
|
.addListener(new RequestListener<Bitmap>() {
|
@Override
|
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
|
//加载失败
|
Timber.d("====>图片下载失败%s",bean.getName());
|
failCount++;
|
if(failStr.length()>0){
|
failStr.append(",");
|
}
|
failStr.append(bean.getName());
|
finishCount++;
|
loadListener.onLoad(finishCount, mSelectCount, finishCount * 1.0f / mSelectCount);
|
if (finishCount == mSelectCount) {
|
loadListener.onComplete(new ArrayList<>(), finishCount);
|
if(failCount>0){
|
Toast.makeText(mContext, String.format(getString(R.string.addface_tip2),failCount,failStr.toString()), Toast.LENGTH_LONG).show();
|
}
|
}
|
handler.sendEmptyMessage(0);
|
return false;
|
}
|
|
@Override
|
public boolean onResourceReady(Bitmap bitmap, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
|
boolean fail = true;
|
if (bitmap != null) {
|
byte[] secondFeature = new byte[512];
|
// 提取特征值
|
float ret = FaceSDKManager.getInstance().personDetect(bitmap, secondFeature,
|
FaceUtils.getInstance().getBDFaceCheckConfig(), AddFaceActivity.this);
|
// 提取特征值
|
if (ret != -1) {
|
//有人脸
|
// 判断质量检测,针对模糊度、遮挡、角度
|
if (ret == 128) {
|
Timber.d("====>图片特征抽取成功: %s", bean.getName());
|
//插入数据库
|
User user = FaceApi.getInstance().getByUserId(bean.getType(), bean.getId());
|
boolean isSave = false;
|
if (user == null) {
|
//新增
|
isSave = FaceApi.getInstance().registerUserIntoDBmanager(bean.getType(),
|
bean.getId(), bean.getName(), bean.getFaceUrl(), JSON.toJSONString(bean), secondFeature);
|
} else {
|
//更新
|
user.setUserName(bean.getName());
|
user.setImageName(bean.getFaceUrl());
|
user.setFeature(secondFeature);
|
isSave = FaceApi.getInstance().userUpdateOnly(user);
|
}
|
|
if (isSave) {
|
//保存成功
|
Timber.d("====>录入成功%s",bean.getName());
|
fail = false;
|
} else {
|
Timber.d("====>录入失败%s",bean.getName());
|
}
|
} else {
|
Timber.d("====>图片特征抽取失败%s",bean.getName());
|
}
|
} else {
|
// 上传图片无人脸隐藏
|
Timber.d("====>图片特征抽取失败%s",bean.getName());
|
}
|
|
}
|
if(fail){
|
failCount++;
|
if(failStr.length()>0){
|
failStr.append(",");
|
}
|
failStr.append(bean.getName());
|
}else {
|
bean.setChecked(false);
|
}
|
finishCount++;
|
loadListener.onLoad(finishCount, mSelectCount, finishCount * 1.0f / mSelectCount);
|
if (finishCount == mSelectCount) {
|
loadListener.onComplete(new ArrayList<>(), finishCount);
|
if(failCount>0){
|
Toast.makeText(mContext, String.format(getString(R.string.addface_tip2),failCount,failStr.toString()), Toast.LENGTH_LONG).show();
|
}
|
}
|
handler.sendEmptyMessage(0);
|
return false;
|
}
|
})
|
.into(new SimpleTarget<Bitmap>() {
|
|
@Override
|
public void onResourceReady(@NonNull Bitmap bitmap, @Nullable Transition<? super Bitmap> transition) {
|
|
}
|
});
|
/*FrescoUtils.loadImage(this, bean.getFaceUrl(), 0, 0, new IResult<Bitmap>() {
|
@Override
|
public void onResult(Bitmap bitmap) {
|
if(handler.hasMessages(0)){
|
handler.removeMessages(0);
|
}
|
boolean fail = true;
|
if (bitmap != null) {
|
byte[] secondFeature = new byte[512];
|
// 提取特征值
|
float ret = FaceSDKManager.getInstance().personDetect(bitmap, secondFeature,
|
FaceUtils.getInstance().getBDFaceCheckConfig(), AddFaceActivity.this);
|
if (bitmap != null && !bitmap.isRecycled()) {
|
//销毁图片
|
bitmap.recycle();
|
}
|
// 提取特征值
|
if (ret != -1) {
|
//有人脸
|
// 判断质量检测,针对模糊度、遮挡、角度
|
if (ret == 128) {
|
Timber.d("====>图片特征抽取成功: %s", bean.getName());
|
//插入数据库
|
User user = FaceApi.getInstance().getByUserId(bean.getType(), bean.getId());
|
boolean isSave = false;
|
if (user == null) {
|
//新增
|
isSave = FaceApi.getInstance().registerUserIntoDBmanager(bean.getType(),
|
bean.getId(), bean.getName(), bean.getFaceUrl(), JSON.toJSONString(bean), secondFeature);
|
} else {
|
//更新
|
user.setUserName(bean.getName());
|
user.setImageName(bean.getFaceUrl());
|
user.setFeature(secondFeature);
|
isSave = FaceApi.getInstance().userUpdateOnly(user);
|
}
|
|
if (isSave) {
|
//保存成功
|
Timber.d("====>录入成功%s",bean.getName());
|
fail = false;
|
} else {
|
Timber.d("====>录入失败%s",bean.getName());
|
}
|
} else {
|
Timber.d("====>图片特征抽取失败%s",bean.getName());
|
}
|
} else {
|
// 上传图片无人脸隐藏
|
Timber.d("====>图片特征抽取失败%s",bean.getName());
|
}
|
} else {
|
Timber.d("====>图片下载失败%s",bean.getName());
|
}
|
bean.setChecked(false);
|
if(fail){
|
failCount++;
|
if(failStr.length()>0){
|
failStr.append(",");
|
}
|
failStr.append(bean.getName());
|
}
|
finishCount++;
|
loadListener.onLoad(finishCount, mSelectCount, finishCount * 1.0f / mSelectCount);
|
if (finishCount == mSelectCount) {
|
loadListener.onComplete(new ArrayList<>(), finishCount);
|
if(failCount>0){
|
Toast.makeText(mContext, "共"+failCount+"条导入失败【"+failStr.toString()+"】", Toast.LENGTH_LONG).show();
|
}
|
}
|
}
|
});*/
|
}
|
|
private void initView() {
|
mRecyclerUserManager = findViewById(R.id.recycler_user_manager);
|
mRecyclerUserManager.setOnClickListener(this);
|
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(mContext,2);
|
mRecyclerUserManager.setLayoutManager(layoutManager);
|
// title相关的控件
|
mRelativeStandard = findViewById(R.id.relative_standard);
|
mLinearSearch = findViewById(R.id.linear_title_search);
|
mImageIconSearch = findViewById(R.id.image_icon_research);
|
mImageIconSearch.setOnClickListener(this);
|
mTextCancel = findViewById(R.id.text_cancel);
|
mTextCancel.setOnClickListener(this);
|
|
mRelativeEmpty = findViewById(R.id.relative_empty);
|
mTextEmpty = findViewById(R.id.text_empty);
|
// 删除相关的控件
|
mRelativeDelete = findViewById(R.id.relative_botton_delete);
|
mRelativeDelete.setOnClickListener(this);
|
mCheckAll = findViewById(R.id.check_all);
|
mCheckAll.setOnCheckedChangeListener(this);
|
textAll = findViewById(R.id.text_all);
|
textAll.setOnClickListener(this);
|
mTextDelete = findViewById(R.id.text_delete);
|
mTextDelete.setOnClickListener(this);
|
// title中的搜索框取消按钮
|
Button btnTitleCancel = findViewById(R.id.btn_title_cancel);
|
btnTitleCancel.setOnClickListener(this);
|
ImageView imageBack = findViewById(R.id.image_back);
|
imageBack.setOnClickListener(this);
|
ImageView imageInputDelete = findViewById(R.id.image_input_delete);
|
imageInputDelete.setOnClickListener(this);
|
mTipDialog = new TipDialog(mContext);
|
mTipDialog.setOnTipDialogClickListener(this);
|
|
mFaceUserAdapter = new FaceRcvAdapter(this, R.layout.face_rcv_item, new FaceRcvAdapter.OnItemClick() {
|
@Override
|
public void onItemClick(FaceUserBean item) {
|
// 如果当前item未选中,则选中
|
if (item.isChecked()) {
|
mSelectCount++;
|
mTextDelete.setText(getString(R.string.addface_drrl)+"(" + mSelectCount + ")");
|
mTextDelete.setTextColor(Color.parseColor("#F34B56"));
|
} else {
|
// 如果当前item已经选中,则取消选中
|
mSelectCount--;
|
mTextDelete.setText(getString(R.string.addface_drrl)+"(" + mSelectCount + ")");
|
if (mSelectCount == 0) {
|
mTextDelete.setTextColor(Color.parseColor("#666666"));
|
}
|
}
|
}
|
});
|
mRecyclerUserManager.setAdapter(mFaceUserAdapter);
|
|
progressBar = findViewById(R.id.progress_bar);
|
progressText = findViewById(R.id.progress_text);
|
progressGroup = findViewById(R.id.progress_group);
|
|
// title中的搜索框
|
mEditTitleSearch = findViewById(R.id.edit_title_search);
|
// 搜索框输入监听事件
|
mEditTitleSearch.addTextChangedListener(new TextWatcher() {
|
@Override
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
}
|
|
@Override
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
if (mUserInfoList!=null&&s != null) {
|
// 读取数据库,获取用户信息
|
if(s.toString().trim().length()==0){
|
mFaceUserAdapter.refreshData(mUserInfoList);
|
}else {
|
List<FaceUserBean> beans = new ArrayList<>();
|
for(FaceUserBean d:mUserInfoList){
|
if(s.toString().trim().contains(d.getName())){
|
beans.add(d);
|
}
|
}
|
mFaceUserAdapter.refreshData(beans);
|
}
|
}
|
}
|
|
@Override
|
public void afterTextChanged(Editable s) {
|
|
}
|
});
|
}
|
|
@Override
|
public void onClick(View v) {
|
int id = v.getId();
|
if (id == R.id.btn_title_cancel) { // 取消按钮
|
mEditTitleSearch.setText("");
|
mLinearSearch.setVisibility(View.GONE);
|
mRelativeStandard.setVisibility(View.VISIBLE);
|
|
} else if (id == R.id.image_icon_research) { // 搜索按钮
|
mLinearSearch.setVisibility(View.VISIBLE);
|
mRelativeStandard.setVisibility(View.GONE);
|
} else if (id == R.id.image_back) {
|
finish();
|
} else if (id == R.id.text_all) {
|
mCheckAll.setChecked(!mCheckAll.isChecked());
|
}else if (id == R.id.relative_delete) { // 显示导入人脸UI
|
updateDeleteUI(true);
|
} else if (id == R.id.text_cancel) { // 批量导入人脸取消
|
updateDeleteUI(false);
|
} else if (id == R.id.text_delete) { // 批量导入人脸
|
if (mSelectCount == 0) {
|
Toast.makeText(mContext, getString(R.string.addface_tip3), Toast.LENGTH_SHORT).show();
|
return;
|
}
|
if(FaceSDKManager.initStatus != FaceSDKManager.SDK_MODEL_LOAD_SUCCESS){
|
Toast.makeText(mContext, getString(R.string.addface_tip4), Toast.LENGTH_SHORT).show();
|
return;
|
}
|
mTipDialog.show();
|
mTipDialog.setTextTitle(getString(R.string.addface_qrdr));
|
mTipDialog.setTextMessage(getString(R.string.addface_tip5));
|
mTipDialog.setTextConfirm(getString(R.string.addface_drrl)+"(" + mSelectCount + ")");
|
mTipDialog.setCancelable(false);
|
} else if (id == R.id.image_input_delete) {
|
mEditTitleSearch.setText("");
|
} else if (id == R.id.recycler_user_manager) {
|
KeyboardsUtils.hintKeyBoards(v);
|
} else if (id == R.id.relative_botton_delete) {
|
Timber.d( "relative_botton_delete");
|
}
|
}
|
|
/**
|
* 全选多选框的监听事件
|
*/
|
@Override
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
if (isChecked) { // 全选
|
mSelectCount = mUserInfoList.size();
|
for (int i = 0; i < mUserInfoList.size(); i++) {
|
mUserInfoList.get(i).setChecked(true);
|
}
|
mTextDelete.setTextColor(Color.parseColor("#F34B56"));
|
} else { // 取消全选
|
mSelectCount = 0;
|
for (int i = 0; i < mUserInfoList.size(); i++) {
|
mUserInfoList.get(i).setChecked(false);
|
}
|
mTextDelete.setTextColor(Color.parseColor("#666666"));
|
}
|
mTextDelete.setText(getString(R.string.addface_drrl)+"(" + mSelectCount + ")");
|
mFaceUserAdapter.notifyDataSetChanged();
|
}
|
|
// 对话框“取消”按钮
|
@Override
|
public void onCancel() {
|
if (mIsLongClick) {
|
resetDeleteData();
|
mIsLongClick = false;
|
}
|
mFaceUserAdapter.notifyDataSetChanged();
|
if (mTipDialog != null) {
|
mTipDialog.dismiss();
|
}
|
}
|
private DBLoadListener loadListener = new DBLoadListener() {
|
@Override
|
public void onStart(final int successCount) {
|
|
runOnUiThread(new Runnable() {
|
@Override
|
public void run() {
|
progressGroup.setVisibility(View.VISIBLE);
|
progressBar.setProgress(0);
|
progressText.setText(0 + "/" + successCount);
|
}
|
});
|
}
|
|
@Override
|
public void onLoad(final int finishCount, final int successCount, final float progress) {
|
// if (successCount > 50 || successCount == 0) {
|
runOnUiThread(new Runnable() {
|
@Override
|
public void run() {
|
Timber.d("====>人脸导入进度%s",finishCount+"=="+successCount+"=="+progress);
|
progressBar.setProgress((int) (progress * 100));
|
progressText.setText(finishCount + "/" + successCount);
|
}
|
});
|
// }
|
}
|
|
@Override
|
public void onComplete(List<User> features, final int successCount) {
|
progressGroup.setVisibility(View.GONE);
|
mFaceUserAdapter.notifyDataSetChanged();
|
mCheckAll.setChecked(false);
|
}
|
|
@Override
|
public void onFail(int finishCount, int successCount, List<User> features) {
|
|
}
|
};
|
|
// 对话框“导入人脸”按钮
|
@Override
|
public void onConfirm(String tipType) {
|
if (mTipDialog != null) {
|
mTipDialog.dismiss();
|
}
|
if (mSelectCount != 0) {
|
//导入人脸
|
selectBeans.clear();
|
for(FaceUserBean bean:mUserInfoList){
|
if(bean.isChecked()) {
|
selectBeans.add(bean);
|
}
|
}
|
loadListener.onStart(mSelectCount);
|
finishCount = 0;
|
failCount = 0;
|
failStr = new StringBuilder();
|
handler.sendEmptyMessage(0);
|
} else {
|
updateDeleteUI(false);
|
}
|
}
|
|
// 更新导入人脸相关的UI
|
private void updateDeleteUI(boolean isShowDeleteUI) {
|
mRelativeDelete.setVisibility(View.VISIBLE);
|
mImageIconSearch.setVisibility(View.GONE);
|
mTextCancel.setVisibility(View.VISIBLE);
|
mFaceUserAdapter.notifyDataSetChanged();
|
}
|
|
private void resetDeleteData() {
|
mSelectCount = 0;
|
for (int i = 0; i < mUserInfoList.size(); i++) {
|
mUserInfoList.get(i).setChecked(false);
|
}
|
mTextDelete.setText(getString(R.string.addface_drrl));
|
}
|
|
/**
|
* 点击非编辑区域收起键盘
|
* 获取点击事件
|
*/
|
@CallSuper
|
@Override
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
View view = getCurrentFocus();
|
if (KeyboardsUtils.isShouldHideKeyBord(view, ev)) {
|
KeyboardsUtils.hintKeyBoards(view);
|
}
|
}
|
return super.dispatchTouchEvent(ev);
|
}
|
}
|