Sfoglia il codice sorgente

refactor(更新) :
- 指纹、人脸识别优化

周文健 4 mesi fa
parent
commit
70b765e101

+ 30 - 0
app/src/main/java/com/grkj/iscs/extentions/Rect.kt

@@ -0,0 +1,30 @@
+package com.grkj.iscs.extentions
+
+import android.graphics.Rect
+
+
+/**
+ * 判断 Rect 是否在父容器中心区域内。
+ *
+ * @param parentWidth 父容器宽度(px)
+ * @param parentHeight 父容器高度(px)
+ * @param horizontalMarginPercent 水平边距百分比,范围 0f…0.5f(比如 0.1667f 表示左右各留 16.67%)
+ * @param verticalMarginPercent   垂直边距百分比,范围 0f…0.5f(同理)
+ * @return 如果 rect 完全在这块中心区域内,返回 true
+ */
+fun Rect.isInCenterArea(
+    parentWidth: Int,
+    parentHeight: Int,
+    horizontalMarginPercent: Float = 0.1667f,
+    verticalMarginPercent: Float = 0.1667f
+): Boolean {
+    // 计算左右、上下的像素边距
+    val marginX = parentWidth * horizontalMarginPercent
+    val marginY = parentHeight * verticalMarginPercent
+
+    // rect 的四条边都要在“margin 区域”之外
+    return left   >= marginX &&
+            right  <= parentWidth - marginX &&
+            top    >= marginY &&
+            bottom <= parentHeight - marginY
+}

+ 3 - 3
app/src/main/java/com/grkj/iscs/model/UrlConsts.kt

@@ -4,10 +4,10 @@ object UrlConsts {
     //    const val BASE_URL = "http://192.168.28.82:9190"  // 本地
 //    const val BASE_URL = "http://192.168.28.97:9190"    // 车
 //    const val BASE_URL = "http://36.133.174.236:9190"    // 外
-    const val BASE_URL = "http://192.168.0.10:9190"    // 外
+//    const val BASE_URL = "http://192.168.0.10:9190"    // 外
 //    const val BASE_URL = "http://192.168.1.121:9190"    // 外
 
-//    const val BASE_URL = "http://120.27.232.27:9190"    // 外
+    const val BASE_URL = "http://120.27.232.27:9190"    // 外
     const val WEB_SOCKET = "ws://192.168.1.127:9090/websocket/iot/127"
 
     const val AUTOCODE_TICKET_NUMBER = "JOB_TICKET_CODE"
@@ -236,7 +236,7 @@ object UrlConsts {
      * 删除用户特征(指纹、面部)
      */
     const val REMOVE_USER_CHARACTERISTIC =
-        "/system/user/characteristic/removeSysUserCharacteristicByRecordIds"
+        "/system/user/characteristic/deleteSysUserCharacteristicByRecordIds"
 
     /**
      * 新增异常记录

+ 2 - 0
app/src/main/java/com/grkj/iscs/model/vo/characteristic/CharacteristicPageRespVO.kt

@@ -25,6 +25,8 @@ data class CharacteristicPageRespVO(
 
         val imagePath: String?,
 
+        val group: String?,
+
         val orderNum: Int?,
 
         val delFlag: String?,

+ 16 - 5
app/src/main/java/com/grkj/iscs/util/ArcSoftUtil.kt

@@ -19,6 +19,7 @@ import com.arcsoft.face.LivenessInfo
 import com.arcsoft.face.enums.DetectFaceOrientPriority
 import com.arcsoft.face.enums.DetectMode
 import com.grkj.iscs.R
+import com.grkj.iscs.extentions.isInCenterArea
 import com.grkj.iscs.model.Constants
 import com.grkj.iscs.util.log.LogUtil
 import com.grkj.iscs.view.activity.test.face.arcsoft.CameraHelper
@@ -30,6 +31,8 @@ object ArcSoftUtil {
     private var previewSize: Camera.Size? = null
     private val rgbCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
     private var faceEngine: FaceEngine? = null
+    private val cameraWidth: Int = 640
+    private val cameraHeight: Int = 480
     private var afCode = -1
     private val processMask: Int =
         FaceEngine.ASF_AGE or FaceEngine.ASF_FACE3DANGLE or FaceEngine.ASF_GENDER or FaceEngine.ASF_LIVENESS
@@ -78,7 +81,7 @@ object ArcSoftUtil {
             DetectMode.ASF_DETECT_MODE_VIDEO,
             DetectFaceOrientPriority.valueOf("ASF_OP_0_ONLY"),
             16,
-            20,
+            1,
             FaceEngine.ASF_FACE_DETECT or FaceEngine.ASF_AGE or FaceEngine.ASF_FACE3DANGLE or FaceEngine.ASF_GENDER or FaceEngine.ASF_LIVENESS
         )
         LogUtil.i("initEngine:  init: $afCode")
@@ -94,10 +97,12 @@ object ArcSoftUtil {
         }
     }
 
+    @JvmOverloads
     fun initCamera(
         context: Context,
         windowManager: WindowManager,
         preview: View,
+        needCheckCenter: Boolean = false,
         callBack: (Bitmap?, Int, Boolean) -> Unit
     ) {
         val metrics = DisplayMetrics()
@@ -165,8 +170,14 @@ object ArcSoftUtil {
                     previewSize!!.width,
                     previewSize!!.height
                 )
-                LogUtil.d("人脸检测结果-识别结果 : ${bitmap == null} - $faceInfoList")
-                callBack(bitmap, faceInfoList.size, true)
+                if (!needCheckCenter || (faceInfoList[0].rect.isInCenterArea(
+                        previewSize!!.width,
+                        previewSize!!.height
+                    ))
+                ) {
+                    LogUtil.d("人脸检测结果-识别结果 : ${bitmap == null} - $faceInfoList")
+                    callBack(bitmap, faceInfoList.size, true)
+                }
             }
 
             override fun onCameraClosed() {
@@ -182,7 +193,7 @@ object ArcSoftUtil {
             }
         }
         cameraHelper = CameraHelper.Builder()
-            .previewViewSize(Point(preview.measuredWidth, preview.measuredHeight))
+            .previewViewSize(Point(cameraWidth, cameraHeight))
             .rotation(windowManager.defaultDisplay.rotation)
             .specificCameraId(rgbCameraId ?: Camera.CameraInfo.CAMERA_FACING_FRONT)
             .isMirror(false)
@@ -200,7 +211,7 @@ object ArcSoftUtil {
         callBack: (Bitmap?, Int, Boolean) -> Unit
     ) {
         initEngine(context)
-        initCamera(context, windowManager, preview, callBack)
+        initCamera(context, windowManager, preview, false, callBack)
     }
 
     fun stop() {

+ 50 - 0
app/src/main/java/com/grkj/iscs/util/CancellableTimer.kt

@@ -0,0 +1,50 @@
+package com.grkj.iscs.util
+
+import android.os.Handler
+import android.os.Looper
+
+/**
+ * 可取消的重复定时器:
+ * – 每隔 intervalMillis 调用 onTick()
+ * – 累计时间 >= delayMillis 时,调用一次 onFinish() 并自动停止
+ *
+ * @param delayMillis    总时长(毫秒),当累计时间达到或超过这个值时触发 onFinish
+ * @param intervalMillis 触发 onTick 的间隔(毫秒)
+ * @param onTick         每次间隔到时的回调
+ * @param onFinish       总时长到时的回调(触发一次后不再继续)
+ */
+class CancellableTimer(
+    private val delayMillis: Long,
+    private val intervalMillis: Long,
+    private val onTick: (Long) -> Unit,
+    private val onFinish: () -> Unit
+) {
+    private val handler = Handler(Looper.getMainLooper())
+    private var elapsed = 0L
+
+    private val job = object : Runnable {
+        override fun run() {
+            elapsed += intervalMillis
+            if (elapsed < delayMillis) {
+                // 还没到总时长,继续 onTick 并重发
+                onTick(elapsed)
+                handler.postDelayed(this, intervalMillis)
+            } else {
+                // 累计到达或超过总时长,触发一次 onFinish 并不再重发
+                onFinish()
+            }
+        }
+    }
+
+    /** 启动定时器(若已在运行会先取消并重置) */
+    fun start() {
+        cancel()
+        elapsed = 0L
+        handler.postDelayed(job, intervalMillis)
+    }
+
+    /** 取消定时器(之后不会再触发 onTick 或 onFinish) */
+    fun cancel() {
+        handler.removeCallbacks(job)
+    }
+}

+ 9 - 7
app/src/main/java/com/grkj/iscs/util/NetApi.kt

@@ -457,7 +457,7 @@ object NetApi {
             { res, msg, code ->
                 res?.let {
                     callBack.invoke(getRefBean(it), code)
-                }?:callBack.invoke(null, code)
+                } ?: callBack.invoke(null, code)
             }, isGet = true, isAuth = true
         )
     }
@@ -901,20 +901,22 @@ object NetApi {
      */
     fun insertFinger(
         userName: String,
+        groupName: String,
         fileList: MutableList<FileStreamReqParam>?,
-        callBack: (Boolean) -> Unit
+        callBack: (Long?) -> Unit
     ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.INSERT_FINGER,
             false,
             mapOf(
-                "userName" to userName
+                "userName" to userName,
+                "group" to groupName
             ),
             { res, _, _ ->
                 res?.let {
-                    callBack.invoke(true)
+                    callBack.invoke(getBaseVO<Long?>(it)?.data)
                 } ?: run {
-                    callBack.invoke(false)
+                    callBack.invoke(null)
                 }
             }, isGet = false, isAuth = true, fileList = fileList
         )
@@ -975,7 +977,7 @@ object NetApi {
      */
     fun deleteUserCharacteristic(recordIds: String, callBack: (Boolean) -> Unit) {
         NetHttpManager.getInstance().doRequestNet(
-            UrlConsts.REMOVE_USER_CHARACTERISTIC,
+            "${UrlConsts.REMOVE_USER_CHARACTERISTIC}?recordIds=${recordIds}",
             false,
             mapOf(
                 "recordIds" to recordIds
@@ -986,7 +988,7 @@ object NetApi {
                 } ?: run {
                     callBack.invoke(false)
                 }
-            }, isGet = true, isAuth = true
+            }, isGet = false, isAuth = true
         )
     }
 

+ 47 - 16
app/src/main/java/com/grkj/iscs/view/dialog/FaceCaptureDialog.kt

@@ -6,6 +6,7 @@ import androidx.core.view.isVisible
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogFaceCaptureBinding
 import com.grkj.iscs.util.ArcSoftUtil
+import com.grkj.iscs.util.CancellableTimer
 import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.util.log.LogUtil
 import com.grkj.iscs.view.base.BaseActivity
@@ -18,18 +19,34 @@ class FaceCaptureDialog(val ctx: BaseActivity<*>, var callback: (Bitmap?) -> Uni
     BaseDialog<DialogFaceCaptureBinding>(ctx) {
 
     private var mCapturedBitmap: Bitmap? = null
-
+    private var isFaceDetect = false
+    private var isInCountDown: Boolean = false
+    private val captureTimer = CancellableTimer(3000, 1000, {
+        viewBinding.countDownTip.text = "${(3000 - it) / 1000 + 1}"
+    }) {
+        ArcSoftUtil.stop()
+        isFaceDetect = true
+        viewBinding.previewLayout.visibility = View.INVISIBLE
+        viewBinding.image.visibility = View.VISIBLE
+        viewBinding.cbRecapture.visibility = View.VISIBLE
+        viewBinding.cbConfirm.visibility = View.VISIBLE
+        viewBinding.countDownTip.text = ctx.getString(R.string.detect_face_tip)
+        viewBinding.countDownTip.isVisible = false
+    }
+    private val reCaptureTimer = CancellableTimer(2000, 1000, {}) {
+        isFaceDetect = false
+        isInCountDown = false
+    }
     override val viewBinding: DialogFaceCaptureBinding
         get() = DialogFaceCaptureBinding.inflate(layoutInflater)
 
     override fun initView() {
         mBinding?.cbRecapture?.setOnClickListener {
-            mBinding?.preview?.visibility = View.VISIBLE
-            mBinding?.preview?.bringToFront()
-
+            mBinding?.image?.isVisible =false
+            mBinding?.previewLayout?.visibility = View.VISIBLE
             mBinding?.cbRecapture?.visibility = View.GONE
             mBinding?.cbConfirm?.visibility = View.GONE
-
+            reCaptureTimer.start()
             startFace()
         }
 
@@ -48,8 +65,7 @@ class FaceCaptureDialog(val ctx: BaseActivity<*>, var callback: (Bitmap?) -> Uni
     override fun show() {
         super.show()
         // 启动预览
-        mBinding?.preview?.visibility = View.VISIBLE
-        mBinding?.preview?.bringToFront()
+        mBinding?.previewLayout?.visibility = View.VISIBLE
         if (!ArcSoftUtil.isActivated) {
             ToastUtils.tip(R.string.face_can_not_process)
         }
@@ -61,30 +77,45 @@ class FaceCaptureDialog(val ctx: BaseActivity<*>, var callback: (Bitmap?) -> Uni
         ArcSoftUtil.initCamera(
             context,
             ctx.windowManager,
-            mBinding?.preview!!
+            mBinding?.preview!!,
+            true
         ) { bitmap, faceSize, alive ->
             mBinding?.tipTv?.isVisible = faceSize > 1 || alive == false
             LogUtil.i("人脸检测结果: ${bitmap == null},$faceSize,$alive")
             if (faceSize > 1) {
                 mBinding?.tipTv?.text = context.getString(R.string.only_one_person_allowed)
+                stopCountDown()
                 return@initCamera
             }
             if (alive == false) {
                 mBinding?.tipTv?.text =
                     context.getString(R.string.real_person_verification_required)
+                stopCountDown()
                 return@initCamera
             }
-            ArcSoftUtil.stop()
-            mBinding?.preview?.visibility = View.INVISIBLE
-            mBinding?.image?.visibility = View.VISIBLE
-            mCapturedBitmap = bitmap
-            mBinding?.image?.setImageBitmap(bitmap)
-
-            mBinding?.cbRecapture?.visibility = View.VISIBLE
-            mBinding?.cbConfirm?.visibility = View.VISIBLE
+            if (!isInCountDown){
+                startCountDown()
+            }
+            if (!isFaceDetect){
+                mCapturedBitmap = bitmap
+                mBinding?.image?.setImageBitmap(bitmap)
+            }
         }
     }
 
+    private fun startCountDown() {
+        isInCountDown = true
+        viewBinding.countDownTip.text = ctx.getString(R.string.detect_face_tip)
+        viewBinding.countDownTip.isVisible = true
+        captureTimer.start()
+    }
+
+    private fun stopCountDown() {
+        isInCountDown = false
+        viewBinding.countDownTip.text = ctx.getString(R.string.detect_face_tip)
+        viewBinding.countDownTip.isVisible = false
+        captureTimer.cancel()
+    }
     override fun dismiss() {
         super.dismiss()
         mCapturedBitmap = null

+ 54 - 30
app/src/main/java/com/grkj/iscs/view/fragment/FingerprintConfigFragment.kt

@@ -18,10 +18,15 @@ import com.zhy.adapter.recyclerview.base.ViewHolder
 class FingerprintConfigFragment :
     BaseMvpFragment<IFingerprintConfigView, FingerprintConfigPresenter, FragmentFingerprintConfigBinding>() {
 
-    private val mFingerList = mutableListOf<CharacteristicPageRespVO.Record>()
+    private val mFingerList = mutableListOf<Pair<String?, List<CharacteristicPageRespVO.Record>>>()
     private var mTipDialog: TipDialog? = null
     private var mFingerDialog: FingerScanDialog? = null
     private var mFingerprintLimit: Int = 5
+    private var mFingerprintPressTimes: Int = 0
+    private var mFingerprintInputErrorTimes: Int = 0
+    private var mFingerprintGroupName: Long = 0L
+    private val maxPressTimes = 3
+    private val inputFingerprintIds: MutableList<Long> = mutableListOf()
 
     override val viewBinding: FragmentFingerprintConfigBinding
         get() = FragmentFingerprintConfigBinding.inflate(layoutInflater)
@@ -32,30 +37,36 @@ class FingerprintConfigFragment :
                 ToastUtils.tip(getString(R.string.fingerprint_config_tip, mFingerprintLimit))
                 return@setOnClickListener
             }
+            mFingerprintPressTimes = 0
+            mFingerprintInputErrorTimes = 0
             showFingerScanDialog()
         }
 
-        mBinding?.rvFinger?.adapter = object : CommonAdapter<CharacteristicPageRespVO.Record>(
-            requireContext(),
-            R.layout.item_rv_finger,
-            mFingerList
-        ) {
-            override fun convert(
-                holder: ViewHolder,
-                record: CharacteristicPageRespVO.Record,
-                position: Int
+        mBinding?.rvFinger?.adapter =
+            object : CommonAdapter<Pair<String?, List<CharacteristicPageRespVO.Record>>>(
+                requireContext(),
+                R.layout.item_rv_finger,
+                mFingerList
             ) {
-                holder.setText(R.id.tv_name, "${getString(R.string.fingerprint)}${position + 1}")
-                holder.setOnClickListener(R.id.root) {
-                    showTipDialog(
-                        getString(
-                            R.string.fingerprint_delete_confirm_tip,
-                            "${getString(R.string.fingerprint)}${position + 1}"
-                        ), record.recordId
+                override fun convert(
+                    holder: ViewHolder,
+                    record: Pair<String?, List<CharacteristicPageRespVO.Record>>,
+                    position: Int
+                ) {
+                    holder.setText(
+                        R.id.tv_name,
+                        "${getString(R.string.fingerprint)}${position + 1}"
                     )
+                    holder.setOnClickListener(R.id.root) {
+                        showTipDialog(
+                            getString(
+                                R.string.fingerprint_delete_confirm_tip,
+                                "${getString(R.string.fingerprint)}${position + 1}"
+                            ), record.second.mapNotNull { it.recordId?.toString() }
+                        )
+                    }
                 }
             }
-        }
 
         refreshFingerList()
         presenter?.getFingerprintLimit {
@@ -68,14 +79,15 @@ class FingerprintConfigFragment :
     private fun refreshFingerList() {
         presenter?.getFingerPage {
             mFingerList.clear()
-            it?.records?.let {
-                mFingerList.addAll(it)
+            it?.records?.groupBy { it.group }?.let {
+                val fingerList = it.mapNotNull { it.key to it.value }.toMutableList()
+                mFingerList.addAll(fingerList)
             }
             mBinding?.rvFinger?.adapter?.notifyDataSetChanged()
         }
     }
 
-    private fun showTipDialog(tip: String, recordId: Long? = null, isAdd: Boolean = false) {
+    private fun showTipDialog(tip: String, recordId: List<String>? = null, isAdd: Boolean = false) {
         mTipDialog ?: let {
             mTipDialog = TipDialog(requireContext())
         }
@@ -84,7 +96,7 @@ class FingerprintConfigFragment :
         mTipDialog?.setConfirmListener {
             if (!isAdd) {
                 recordId?.let {
-                    presenter?.deleteFinger(it) {
+                    presenter?.deleteFinger(it.joinToString(",")) {
                         refreshFingerList()
                     }
                 }
@@ -95,16 +107,28 @@ class FingerprintConfigFragment :
 
     private fun showFingerScanDialog() {
         mFingerDialog ?: let {
+            mFingerprintGroupName = System.currentTimeMillis()
             mFingerDialog = FingerScanDialog(requireContext()) {
                 if (it != null) {
-                    presenter?.insertFinger(it) {
-                        mFingerDialog?.dismiss()
-                        if (it) {
-                            showTipDialog(
-                                getString(R.string.fingerprint_add_success_tip),
-                                isAdd = true
-                            )
-                            refreshFingerList()
+                    presenter?.insertFinger(it, "$mFingerprintGroupName") {
+                        if (it!=null) {
+                            mFingerprintPressTimes++
+                            if (mFingerprintPressTimes == 3) {
+                                mFingerDialog?.dismiss()
+                                showTipDialog(
+                                    getString(R.string.fingerprint_add_success_tip),
+                                    isAdd = true
+                                )
+                                refreshFingerList()
+                            } else {
+                                ToastUtils.tip(R.string.please_press_fingerprint_again)
+                            }
+                        }else{
+                            mFingerprintInputErrorTimes++
+                            if (mFingerprintInputErrorTimes+mFingerprintPressTimes>maxPressTimes){
+                                mFingerprintGroupName = System.currentTimeMillis()
+                                ToastUtils.tip(R.string.please_re_press_fingerprint_again)
+                            }
                         }
                     }
                 }

+ 4 - 3
app/src/main/java/com/grkj/iscs/view/presenter/FingerprintConfigPresenter.kt

@@ -24,9 +24,10 @@ class FingerprintConfigPresenter : BasePresenter<IFingerprintConfigView>() {
         }
     }
 
-    fun insertFinger(bitmap: Bitmap, callBack: (Boolean) -> Unit) {
+    fun insertFinger(bitmap: Bitmap, groupName: String, callBack: (Long?) -> Unit) {
         NetApi.insertFinger(
             SPUtils.getLoginUser(MyApplication.instance!!.applicationContext)?.userName!!,
+            groupName,
             mutableListOf(FileStreamReqParam("file", BitmapUtil.bitmapToByteArray(bitmap), ".bmp"))
         ) {
             Executor.runOnMain {
@@ -35,8 +36,8 @@ class FingerprintConfigPresenter : BasePresenter<IFingerprintConfigView>() {
         }
     }
 
-    fun deleteFinger(recordId: Long, callBack: (Boolean) -> Unit) {
-        NetApi.deleteUserCharacteristic(recordId.toString()) {
+    fun deleteFinger(recordId: String, callBack: (Boolean) -> Unit) {
+        NetApi.deleteUserCharacteristic(recordId) {
             Executor.runOnMain {
                 callBack(it)
             }

+ 37 - 0
app/src/main/res/drawable/mask_vector_circle.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <!-- 白底 + 半径8dp的透明圆孔 -->
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:fillType="evenOdd"
+        android:pathData="
+            M0,0 H24 V24 H0 Z
+            M12,12
+            m-8,0
+            a8,8 0 1,0 16,0
+            a8,8 0 1,0 -16,0" />
+
+    <!-- 黑色描边,圆角 0.8dp -->
+    <path
+        android:fillColor="@android:color/transparent"
+        android:strokeColor="@color/black"
+        android:strokeWidth="0.15"
+        android:strokeLineJoin="round"
+        android:strokeLineCap="round"
+        android:fillType="nonZero"
+        android:pathData="
+            M0,0.8
+            A0.8,0.8 0 0,1 0.8,0
+            H23.2
+            A0.8,0.8 0 0,1 24,0.8
+            V23.2
+            A0.8,0.8 0 0,1 23.2,24
+            H0.8
+            A0.8,0.8 0 0,1 0,23.2
+            Z" />
+</vector>

+ 42 - 17
app/src/main/res/layout/dialog_face_capture.xml

@@ -76,17 +76,55 @@
                 android:layout_weight="1"
                 android:background="@drawable/face_capture_tip_bg">
 
-                <TextureView
-                    android:id="@+id/preview"
+                <FrameLayout
+                    android:id="@+id/preview_layout"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:visibility="invisible" />
+                    android:visibility="visible">
+
+                    <TextureView
+                        android:id="@+id/preview"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent" />
+
+                    <ImageView
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:scaleType="fitXY"
+                        android:src="@drawable/mask_vector_circle" />
+
+                    <TextView
+                        android:id="@+id/count_down_tip"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center|bottom"
+                        android:layout_marginBottom="@dimen/common_spacing"
+                        android:textColor="@color/dialogxColorBlue"
+                        android:textSize="@dimen/common_text_size_big"
+                        android:textStyle="bold"
+                        android:visibility="gone"
+                        android:text="@string/detect_face_tip"
+                        tools:text="检测到人脸,即将拍摄" />
+
+                    <TextView
+                        android:id="@+id/tip_tv"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:gravity="center"
+                        android:text="@string/only_one_person_allowed"
+                        android:textColor="@color/common_status_red"
+                        android:textSize="@dimen/common_text_size_big"
+                        android:visibility="gone"
+                        tools:text="请保证画面中只有自己" />
+                </FrameLayout>
 
                 <ImageView
                     android:id="@+id/image"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:scaleType="centerCrop" />
+                    android:scaleType="centerCrop"
+                    android:visibility="gone"/>
 
             </FrameLayout>
 
@@ -125,19 +163,6 @@
                     android:text="@string/capture_tip_content"
                     android:textColor="@color/black"
                     android:textSize="@dimen/common_text_size_small" />
-
-                <TextView
-                    android:id="@+id/tip_tv"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="10dp"
-                    android:background="@color/common_status_red"
-                    android:gravity="center"
-                    android:text="@string/only_one_person_allowed"
-                    android:textColor="@color/white"
-                    android:textSize="@dimen/common_text_size_big"
-                    android:visibility="gone"
-                    tools:text="请保证画面中只有自己" />
             </LinearLayout>
         </LinearLayout>
     </RelativeLayout>

+ 3 - 0
app/src/main/res/values-en/strings.xml

@@ -386,4 +386,7 @@
     <string name="device_registration_scan_result_tip">Identified unrecorded keys (%1$d) and padlocks (%2$d).</string>
     <string name="current_step_can_not_modify_colocker">Current step can not modify co-locker</string>
     <string name="please_done_operation">Please done operation %s first</string>
+    <string name="please_press_fingerprint_again">Please press fingerprint again</string>
+    <string name="detect_face_tip">Detected face, about to shoot</string>
+    <string name="please_re_press_fingerprint_again">Please press the fingerprint again</string>
 </resources>

+ 3 - 0
app/src/main/res/values-zh/strings.xml

@@ -386,4 +386,7 @@
     <string name="device_registration_scan_result_tip">已识别未录入的钥匙 (%1$d把)与挂锁(%2$d把)。</string>
     <string name="current_step_can_not_modify_colocker">当前步骤无法修改共锁人</string>
     <string name="please_done_operation">请先完成%s</string>
+    <string name="please_press_fingerprint_again">请再次按压指纹</string>
+    <string name="detect_face_tip">检测到人脸,即将拍摄</string>
+    <string name="please_re_press_fingerprint_again">请重新按压指纹</string>
 </resources>

+ 1 - 0
app/src/main/res/values/colors.xml

@@ -44,4 +44,5 @@
     <color name="common_switch_enable">#91ce93</color>
     <color name="common_switch_disable">#f0f0f0</color>
     <color name="color_d7d2d2">#d7d2d2</color>
+    <color name="dialogxColorBlue">#2196F3</color>
 </resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -386,4 +386,7 @@
     <string name="device_registration_scan_result_tip">已识别未录入的钥匙 (%1$d把)与挂锁(%2$d把)。</string>
     <string name="current_step_can_not_modify_colocker">当前步骤无法修改共锁人</string>
     <string name="please_done_operation">请先完成%s</string>
+    <string name="please_press_fingerprint_again">请再次按压指纹</string>
+    <string name="detect_face_tip">检测到人脸,即将拍摄</string>
+    <string name="please_re_press_fingerprint_again">请重新按压指纹</string>
 </resources>