diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 67ce82d..c9400bd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,17 +33,21 @@ android:name=".activity.LoginByPwdActivity" android:exported="true" android:launchMode="singleTask"> - - + + - - + + + + + + : AppCompatActivity() { // 确保内容延伸到导航栏区域 // WindowCompat.setDecorFitsSystemWindows(window, false) + //保持亮屏 + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + binding = inflateViewBinding() headerBinding = inflateTitleBinding() setContentView(binding.root) diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt index 8f4770a..de989a5 100644 --- a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt @@ -60,8 +60,7 @@ class LoginByFaceActivity : BaseActivity(), } override fun initialize() { - -// viewModel.activeEngine() + viewModel.activeEngine() initArcViewModel() initArcView() openRectInfoDraw = true @@ -156,6 +155,10 @@ class LoginByFaceActivity : BaseActivity(), Timber.i("recognizeUserId observe userId = $userId") viewModel.getUserInfoById(memberId = userId?.toInt() ?: 0) }) + + recognizeViewModel.drawRectInfoText.observe(this, Observer { info -> + Timber.i("drawRectInfoText observe info = $info") + }) } private fun initArcView() { @@ -250,8 +253,10 @@ class LoginByFaceActivity : BaseActivity(), val layoutParams = adjustPreviewViewSize( binding.dualCameraTexturePreviewRgb, binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, - previewSizeRgb, displayOrientation, 1.0f + previewSizeRgb, displayOrientation, 1f ) + Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") + Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") rgbFaceRectTransformer = FaceRectTransformer( previewSizeRgb.width, previewSizeRgb.height, @@ -269,7 +274,6 @@ class LoginByFaceActivity : BaseActivity(), }) } - @RequiresApi(api = Build.VERSION_CODES.Q) override fun onPreview(nv21: ByteArray?, camera: Camera?) { if (!isRecognition) { @@ -322,7 +326,6 @@ class LoginByFaceActivity : BaseActivity(), rgbCameraHelper!!.start() } - /** * 绘制RGB、IR画面的实时人脸信息 * @@ -337,7 +340,6 @@ class LoginByFaceActivity : BaseActivity(), ) // 识别成功 binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) - } } diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt index 44c7501..3fb98d0 100644 --- a/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt @@ -4,6 +4,7 @@ import android.content.Intent import androidx.activity.viewModels import androidx.lifecycle.lifecycleScope import com.sw.plate.utils.ToastUtils +import com.sw.plate.utils.arcface.face.Test import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.viewmodel.UserViewModel @@ -28,6 +29,11 @@ class LoginByPwdActivity : BaseActivity() { val pwd = binding.etPwd.text.toString() if (phone.isEmpty() || pwd.isEmpty()) { ToastUtils.showToast("手机或校验码不能为空") + val test = Test() + for (i in 1..1000) { + test.test1() + } + return@setOnClickListener } viewModel.loginWithPwd(phone = phone, password = pwd) diff --git a/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt b/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt index 6a902e1..983be92 100644 --- a/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt @@ -14,8 +14,10 @@ import com.sw.platecabinet.model.request.LoginParam import com.sw.platecabinet.model.response.EquipmentUserInfo import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.utils.ThreadUtils +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.withContext import timber.log.Timber class UserViewModel : BaseViewModel() { @@ -55,8 +57,10 @@ class UserViewModel : BaseViewModel() { val faceEntity = list.map { FaceEntity(it.userId, null, Base64.decode(it.faceFeatureString)) } - faceApi.updateFaceData(index, faceEntity) - activeEngine() + withContext(Dispatchers.Default) { + faceApi.updateFaceData(index, faceEntity) + activeEngine() + } } } } diff --git a/app/src/main/res/drawable/bg.png b/app/src/main/res/drawable/bg.png new file mode 100644 index 0000000..6794388 Binary files /dev/null and b/app/src/main/res/drawable/bg.png differ diff --git a/app/src/main/res/drawable/bg_face.png b/app/src/main/res/drawable/bg_face.png new file mode 100644 index 0000000..b280fc3 Binary files /dev/null and b/app/src/main/res/drawable/bg_face.png differ diff --git a/app/src/main/res/drawable/ic_bind_img.png b/app/src/main/res/drawable/ic_bind_img.png new file mode 100644 index 0000000..7a9de74 Binary files /dev/null and b/app/src/main/res/drawable/ic_bind_img.png differ diff --git a/app/src/main/res/drawable/ic_full.png b/app/src/main/res/drawable/ic_full.png new file mode 100644 index 0000000..1c22e16 Binary files /dev/null and b/app/src/main/res/drawable/ic_full.png differ diff --git a/app/src/main/res/drawable/ic_phone.png b/app/src/main/res/drawable/ic_phone.png new file mode 100644 index 0000000..8a61218 Binary files /dev/null and b/app/src/main/res/drawable/ic_phone.png differ diff --git a/app/src/main/res/drawable/ic_plate_open.png b/app/src/main/res/drawable/ic_plate_open.png new file mode 100644 index 0000000..a6c3bb2 Binary files /dev/null and b/app/src/main/res/drawable/ic_plate_open.png differ diff --git a/app/src/main/res/drawable/ic_pwd.png b/app/src/main/res/drawable/ic_pwd.png new file mode 100644 index 0000000..4f8d609 Binary files /dev/null and b/app/src/main/res/drawable/ic_pwd.png differ diff --git a/app/src/main/res/drawable/ic_unbind_img.png b/app/src/main/res/drawable/ic_unbind_img.png new file mode 100644 index 0000000..725766c Binary files /dev/null and b/app/src/main/res/drawable/ic_unbind_img.png differ diff --git a/app/src/main/res/layout/activity_login_by_pwd.xml b/app/src/main/res/layout/activity_login_by_pwd.xml index 7ea4e15..5116f4e 100644 --- a/app/src/main/res/layout/activity_login_by_pwd.xml +++ b/app/src/main/res/layout/activity_login_by_pwd.xml @@ -2,7 +2,7 @@ + android:src="@drawable/ic_phone" /> + android:src="@drawable/ic_pwd" /> + - - - - - + - + - - + + - - - - - - - + android:background="@drawable/bg_face" /> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3e22785..f5200d5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:background="#14141E" + android:background="@drawable/bg" tools:context=".activity.MainActivity"> + android:src="@drawable/ic_bind_img" /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_full" /> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_plate_open" /> + android:src="@drawable/ic_unbind_img" /> #F0C8B4 #F0C8B4 #32283C + + #4c91ceff \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f000453..a82b98a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,4 +4,5 @@ Hello blank fragment %s 初始化失败,错误码:%d\n错误码常量名:%s + 权限被拒绝! \ No newline at end of file diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceApi.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceApi.java index 67c4d41..c8424d9 100644 --- a/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceApi.java +++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceApi.java @@ -1,6 +1,7 @@ package com.sw.plate.utils.arcface; import android.content.Context; +import android.util.Log; import com.arcsoft.face.FaceEngine; import com.arcsoft.face.enums.RuntimeABI; @@ -14,6 +15,8 @@ import com.sw.plate.utils.arcface.facedb.entity.FaceEntity; import java.util.List; public class FaceApi { + private static final String TAG = "FaceApi"; + public interface ActiveCallback { void onSuccess(int code); @@ -27,12 +30,12 @@ public class FaceApi { * @param list */ public void updateFaceData(int index, List list) { + Log.d(TAG, "updateFaceData: index = " + index + ", listSize = " + list.size()); FaceDao faceDao = FaceDatabase.getInstance(App.getContext()).faceDao(); if (index == 0) { faceDao.deleteAll(); faceDao.resetId(); } - faceDao.insert(list); } diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java index 3f78375..411fdf1 100644 --- a/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java +++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java @@ -2,6 +2,8 @@ package com.sw.plate.utils.arcface.face; import android.graphics.Rect; import android.hardware.Camera; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import androidx.annotation.IntDef; @@ -47,7 +49,6 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; -import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; @@ -529,7 +530,7 @@ public class FaceHelper implements FaceListener { if (recognizeInfoMap.containsKey(trackId)) { onFaceFeatureInfoGet(faceFeature, trackId, errorCode); } - } catch (InterruptedException e) { + } catch (Exception e) { Log.e(TAG, "onFaceFeatureInfoGet: 等待活体结果时退出界面会执行,正常现象,可注释异常代码块"); e.printStackTrace(); } @@ -549,40 +550,35 @@ public class FaceHelper implements FaceListener { } } + + // 定义一个Handler,用于处理延迟任务 + private Handler delayHandler = new Handler(Looper.getMainLooper()); + /** * 延迟 {@link RecognizeConfiguration#getLivenessFailedRetryInterval()}后,重新进行活体检测 * * @param trackId 人脸ID */ private void retryLivenessDetectDelayed(final Integer trackId) { - Observable.timer(recognizeConfiguration.getLivenessFailedRetryInterval(), TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - Disposable disposable; + Log.d(TAG, "retryLivenessDetectDelayed: trackId = " + trackId + ", threadName =" + Thread.currentThread().getName()); + Log.d(TAG, "retryLivenessDetectDelayed: Interval = " + recognizeConfiguration.getLivenessFailedRetryInterval()); - @Override - public void onSubscribe(Disposable d) { - disposable = d; - delayFaceTaskCompositeDisposable.add(disposable); - } + // 创建延迟任务 + Runnable delayTask = new Runnable() { + @Override + public void run() { + // 将该人脸状态置为UNKNOWN,帧回调处理时会重新进行活体检测 + changeLiveness(trackId, LivenessInfo.UNKNOWN); + // 从集合中移除这个任务 + delayFaceTaskList.remove(this); + } + }; - @Override - public void onNext(Long aLong) { + // 将任务添加到集合中管理 + delayFaceTaskList.add(delayTask); - } - - @Override - public void onError(Throwable e) { - e.printStackTrace(); - } - - @Override - public void onComplete() { - // 将该人脸状态置为UNKNOWN,帧回调处理时会重新进行活体检测 - changeLiveness(trackId, LivenessInfo.UNKNOWN); - delayFaceTaskCompositeDisposable.remove(disposable); - } - }); + // 发送延迟任务 + delayHandler.postDelayed(delayTask, recognizeConfiguration.getLivenessFailedRetryInterval()); } /** @@ -591,40 +587,33 @@ public class FaceHelper implements FaceListener { * @param trackId 人脸ID */ private void retryRecognizeDelayed(final Integer trackId) { + Log.d(TAG, "retryRecognizeDelayed: trackId = " + trackId); changeRecognizeStatus(trackId, RequestFeatureStatus.FAILED); - Observable.timer(recognizeConfiguration.getRecognizeFailedRetryInterval(), TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer() { - Disposable disposable; - @Override - public void onSubscribe(Disposable d) { - disposable = d; - delayFaceTaskCompositeDisposable.add(disposable); - } + // 创建延迟任务 + Runnable delayTask = new Runnable() { + @Override + public void run() { + // 将该人脸特征提取状态置为FAILED,帧回调处理时会重新进行活体检测 + changeRecognizeStatus(trackId, RequestFeatureStatus.TO_RETRY); + // 从集合中移除这个任务 + delayFaceTaskList.remove(this); + } + }; - @Override - public void onNext(Long aLong) { + // 将任务添加到集合中管理 + delayFaceTaskList.add(delayTask); - } - - @Override - public void onError(Throwable e) { - Log.e(TAG, "retryRecognizeDelayed e = " + e); - e.printStackTrace(); - } - - @Override - public void onComplete() { - // 将该人脸特征提取状态置为FAILED,帧回调处理时会重新进行活体检测 - changeRecognizeStatus(trackId, RequestFeatureStatus.TO_RETRY); - delayFaceTaskCompositeDisposable.remove(disposable); - } - }); + // 发送延迟任务 + delayHandler.postDelayed(delayTask, recognizeConfiguration.getRecognizeFailedRetryInterval()); } + // 需要在类中定义一个集合来管理所有的延迟任务,替代原来的CompositeDisposable + private List delayFaceTaskList = new ArrayList<>(); + @Override public void onFaceLivenessInfoGet(@Nullable LivenessInfo livenessInfo, Integer trackId, Integer errorCode) { + Log.d(TAG, "onFaceLivenessInfoGet: trackId = " + trackId); if (livenessInfo != null) { int liveness = livenessInfo.getLiveness(); Log.i(TAG, "onFaceLivenessInfoGet liveness:" + liveness); diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/face/Test.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/Test.java new file mode 100644 index 0000000..535f2f8 --- /dev/null +++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/Test.java @@ -0,0 +1,49 @@ +package com.sw.plate.utils.arcface.face; + + +import android.util.Log; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.Observer; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +public class Test { + + private static final String TAG = "Test"; + private CompositeDisposable delayFaceTaskCompositeDisposable = new CompositeDisposable(); + + public void test1() { + Log.d(TAG, "test1: "); + Observable.timer(10, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + Disposable disposable; + + @Override + public void onSubscribe(Disposable d) { + disposable = d; + delayFaceTaskCompositeDisposable.add(disposable); + } + + @Override + public void onNext(Long value) { + + } + + @Override + public void onError(Throwable e) { + e.printStackTrace(); + } + + @Override + public void onComplete() { + Log.d(TAG, "onComplete: "); + delayFaceTaskCompositeDisposable.remove(disposable); + } + }); + } +} diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/facedb/FaceDatabase.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/facedb/FaceDatabase.java index 1e87446..ddb985f 100644 --- a/lib_face/src/main/java/com/sw/plate/utils/arcface/facedb/FaceDatabase.java +++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/facedb/FaceDatabase.java @@ -9,8 +9,6 @@ import androidx.room.RoomDatabase; import com.sw.plate.utils.arcface.facedb.dao.FaceDao; import com.sw.plate.utils.arcface.facedb.entity.FaceEntity; -import java.io.File; - @Database(entities = {FaceEntity.class}, version = 1, exportSchema = false) public abstract class FaceDatabase extends RoomDatabase { public abstract FaceDao faceDao(); @@ -22,7 +20,9 @@ public abstract class FaceDatabase extends RoomDatabase { synchronized (FaceDatabase.class) { if (faceDatabase == null) { faceDatabase = Room.databaseBuilder(context, FaceDatabase.class, - context.getExternalFilesDir("database") + File.separator + "faceDB.db").build(); + context.getDatabasePath("faceDB.db").getPath() +// context.getExternalFilesDir("database") + File.separator + "faceDB.db" + ).build(); } } } diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java index e414751..6a9db10 100644 --- a/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java +++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java @@ -4,7 +4,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Rect; -import android.os.Environment; import android.util.Log; import com.arcsoft.face.ErrorInfo; @@ -354,8 +353,11 @@ public class FaceServer { * @return 存放注册照的文件夹路径 */ private String getImageDir() { - return App.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) - + File.separator + "faceDB" + File.separator + "registerFaces"; +// return App.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES) +// + File.separator + "faceDB" + File.separator + "registerFaces"; + return App.getContext().getFilesDir() + + File.separator + "faceDB" + + File.separator + "registerFaces"; } /**