Browse Source

1.集成星马SDK,实现导航栏和状态栏的控制
2.实现MLkit人脸检测
3.规避一些子线程占用导致的内存泄露

JaycePC 1 year ago
parent
commit
eec535d1ff

+ 1 - 1
HttpCoreLibrary/build.gradle

@@ -32,7 +32,7 @@ android {
 dependencies {
 
     implementation fileTree(dir: "libs", include: ["*.jar"])
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.21"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
     implementation "androidx.core:core-ktx:1.3.1"
     implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.0.0"
 

+ 1 - 1
RcCore/build.gradle

@@ -37,7 +37,7 @@ dependencies {
     implementation project(':HttpCoreLibrary')
 
     api fileTree(dir: "libs", include: ["*.jar"])
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.21"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
     implementation "androidx.core:core-ktx:1.3.1"
     implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
 

+ 1 - 3
RcCore/src/main/java/com/rc/core/ui/activity/RcBaseActivity.kt

@@ -74,10 +74,8 @@ abstract class RcBaseActivity<VB : ViewBinding> : AppCompatActivity(), IUIListen
     }
 
     override fun onDestroy() {
+        mUIDelegate.clearDisposable()
         super.onDestroy()
-        if (!isFinishing) {
-            mUIDelegate.clearDisposable()
-        }
         ActivityCollector.removeActivity(this)
     }
 

+ 32 - 16
app/build.gradle

@@ -10,8 +10,8 @@ android {
         applicationId "com.dlc.eboard"
         minSdkVersion 21
         targetSdkVersion 34
-        versionCode 11
-        versionName "1.1.1-alpha-kuangda"
+        versionCode 12
+        versionName "1.1.2-alpha-kuangda"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 
@@ -37,10 +37,10 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
         release {
-            minifyEnabled true
-            multiDexEnabled true
-            signingConfig signingConfigs.signing
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+//            minifyEnabled true
+//            multiDexEnabled true
+//            signingConfig signingConfigs.signing
+//            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
     }
     compileOptions {
@@ -50,11 +50,11 @@ android {
     kotlinOptions {
         jvmTarget = '1.8'
     }
-    kotlin {
-        experimental {
-            coroutines 'enable'
-        }
-    }
+//    kotlin {
+//        experimental {
+//            coroutines 'enable'
+//        }
+//    }
     viewBinding {
         enabled = true
     }
@@ -80,7 +80,7 @@ dependencies {
     implementation project(':HttpCoreLibrary')
     implementation project(':RcCore')
 
-    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.21"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.0"
     implementation "androidx.core:core-ktx:1.3.1"
     implementation "androidx.appcompat:appcompat:1.2.0"
     implementation "androidx.constraintlayout:constraintlayout:2.0.1"
@@ -102,19 +102,27 @@ dependencies {
     implementation "com.github.bingoogolapple.BGAQRCode-Android:zxing:1.3.8"
 
     implementation "com.joanzapata.pdfview:android-pdfview:1.0.4@aar"
+    implementation 'androidx.activity:activity:1.8.0'
+    implementation files('libs\\smdt.jar')
 
     // CameraX core library using the camera2 implementation
-    def camerax_version = "1.0.1"
+    def camerax_version = "1.4.0-rc01"
     // The following line is optional, as the core library is included indirectly by camera-camera2
     implementation "androidx.camera:camera-core:${camerax_version}"
     implementation "androidx.camera:camera-camera2:${camerax_version}"
     // If you want to additionally use the CameraX Lifecycle library
     implementation "androidx.camera:camera-lifecycle:${camerax_version}"
+    // If you want to additionally use the CameraX VideoCapture library
+    implementation "androidx.camera:camera-video:${camerax_version}"
     // If you want to additionally use the CameraX View class
-    implementation "androidx.camera:camera-view:1.0.0-alpha20"
+    implementation "androidx.camera:camera-view:${camerax_version}"
+    // If you want to additionally add CameraX ML Kit Vision Integration
+    implementation "androidx.camera:camera-mlkit-vision:${camerax_version}"
     // If you want to additionally use the CameraX Extensions library
-    implementation "androidx.camera:camera-extensions:1.0.0-alpha20"
-    implementation "com.squareup.leakcanary:leakcanary-android:2.14"
+    implementation "androidx.camera:camera-extensions:${camerax_version}"
+
+
+//    implementation "com.squareup.leakcanary:leakcanary-android:2.14"
 
     implementation "com.github.NodeMedia:NodeMediaClient-Android:2.9.23"
     implementation(name: 'facedetector-1.0.0', ext: 'aar')
@@ -123,4 +131,12 @@ dependencies {
     implementation(name: 'flowlayout-1.0.0', ext: 'aar')
 
     implementation 'com.blankj:utilcodex:1.31.1'
+//    implementation 'com.github.jenly1314.MLKit:mlkit-common:2.2.1'
+//    implementation 'com.github.jenly1314.MLKit:mlkit-face-detection:2.2.1'
+//    implementation 'com.github.jenly1314:camera-scan:1.2.0'
+
+    implementation 'com.google.mlkit:face-detection:16.1.7'
+    implementation 'com.otaliastudios:cameraview:2.7.2'
+
+
 }

BIN
app/libs/smdt.jar


+ 22 - 82
app/src/main/AndroidManifest.xml

@@ -13,36 +13,25 @@
 
     <uses-feature android:name="android.hardware.camera" />
     <uses-feature android:name="android.hardware.camera.autofocus" />
-    <uses-feature android:name="android.hardware.camera.any" />
-
-    <!--连接网络权限,用于执行云端语音能力 -->
-    <uses-permission android:name="android.permission.INTERNET" />
-    <!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
-    <uses-permission android:name="android.permission.RECORD_AUDIO" />
-    <!--读取网络信息状态 -->
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <!--获取当前wifi状态 -->
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <!--允许程序改变网络连接状态 -->
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <!--读取手机信息权限 -->
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
-    <!--读取联系人权限,上传联系人需要用到此权限 -->
-    <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <!--外存储写权限,构建语法需要用到此权限 -->
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <!--外存储读权限,构建语法需要用到此权限 -->
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <!--配置权限,用来记录应用配置信息 -->
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-    <!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务-->
-    <!--定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <!--如需使用人脸识别,还要添加:摄相头权限,拍照需要用到 -->
+    <uses-feature android:name="android.hardware.camera.any" /> <!-- 连接网络权限,用于执行云端语音能力 -->
+    <uses-permission android:name="android.permission.INTERNET" /> <!-- 获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
+    <uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- 读取网络信息状态 -->
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 获取当前wifi状态 -->
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 允许程序改变网络连接状态 -->
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <!-- 读取手机信息权限 -->
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 读取联系人权限,上传联系人需要用到此权限 -->
+    <uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- 外存储写权限,构建语法需要用到此权限 -->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 外存储读权限,构建语法需要用到此权限 -->
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 配置权限,用来记录应用配置信息 -->
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <!-- 手机定位信息,用来为语义等功能提供定位,提供更精准的服务 -->
+    <!-- 定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 如需使用人脸识别,还要添加:摄相头权限,拍照需要用到 -->
     <uses-permission android:name="android.permission.CAMERA" />
-
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission
+        android:name="android.hardware.usb.host"
+        android:required="false" />
 
     <application
         android:name=".LabApp"
@@ -55,12 +44,12 @@
         android:theme="@style/Theme.AppFullTheme"
         android:usesCleartextTraffic="true"
         tools:targetApi="m">
-
         <receiver
             android:name=".broadcast.BootBroadcastReceiver"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
+
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </receiver>
@@ -77,49 +66,40 @@
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
-
         </activity>
-
         <activity
             android:name=".ui.HomeActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.MainActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.LabMainActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
-
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.rule.SafetyRegulationActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.guide.GuideActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.things.ThingsActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.risk.RiskActivity"
             android:configChanges="orientation|keyboardHidden|navigation|screenSize"
@@ -127,93 +107,78 @@
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.sign.SignInActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.leave.LeaveActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.settings.SettingsActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.settings.ScanSettingsActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.msds.InstructionActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.person.LaboratoryPersonActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.lib.LabDetailActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.rule.SafetyRegulationDetailActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.common.HtmlFullScreenActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.things.SelectAuthMethodActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.notice.NoticeActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.lib.LabDescActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.monitor.MonitorListActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.monitor.MonitorFullScreenActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.auth.FourChoiceAuthActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
@@ -221,112 +186,91 @@
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.auth.TwoChoiceAuthActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.auth.FingerAuthActivity"
-
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.auth.DualAuthActivity"
-
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.finger.FingerEnrollActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.finger.EnrollAuthActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name=".ui.finger.SelectFingerActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.lib.ExLabDetailActivity"
             android:exported="true"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.rule.ExSafetyRegulationActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.msds.ExInstructionActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.risk.ExRiskActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.person.ExLaboratoryPersonActivity"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.sign.ExSignInActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
             android:windowSoftInputMode="adjustPan" />
-
         <activity
             android:name="com.dlc.laboratory.ui.leave.ExLeaveActivity"
             android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale"
             android:launchMode="singleTask"
             android:screenOrientation="sensorLandscape"
-            android:windowSoftInputMode="adjustPan" />
-
-        <!--        <service-->
-        <!--            android:name=".ui.HeartService"-->
-        <!--            android:enabled="true"-->
-        <!--            android:exported="false" />-->
-
+            android:windowSoftInputMode="adjustPan" /> <!-- <service -->
+        <!-- android:name=".ui.HeartService" -->
+        <!-- android:enabled="true" -->
+        <!-- android:exported="false" /> -->
         <service
             android:name=".mqtt.MqttService"
             android:enabled="true"
             android:exported="false" />
-
         <service
             android:name=".mqtt.AudioService"
             android:enabled="true"
             android:exported="false" />
-
         <service
             android:name=".serial.SerialPortService"
             android:enabled="true"
             android:exported="false" />
-
         <service
             android:name=".finger.FingerService"
             android:enabled="true"
@@ -347,6 +291,7 @@
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.PACKAGE_REPLACED" />
+
                 <data android:scheme="${applicationId}" />
             </intent-filter>
         </receiver>
@@ -355,11 +300,6 @@
             android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
             android:label="dexopt"
             android:process=":dexopt" />
-
     </application>
 
-    <uses-permission
-        android:name="android.hardware.usb.host"
-        android:required="false" />
-
 </manifest>

+ 34 - 94
app/src/main/java/com/dlc/eboard/ui/HomeActivity.kt

@@ -139,6 +139,7 @@ class HomeActivity :
         unbindService(mAudioConnection)
         mSerialPortHelper.unbindService()
         lifecycle.removeObserver(mFingerHelper)
+        viewBinding.bulletinBoardView.stopAuto()
         handler.removeCallbacks(runnable)
         handler.removeCallbacksAndMessages(null)
         super.onDestroy()
@@ -270,95 +271,33 @@ class HomeActivity :
             RcLog.info("==================LabApp.sLabConfig?.authType:" + LabApp.sLabConfig?.authType)
             val authType = LabApp.sLabConfig?.authType ?: return@FastClickDelegate
             RcLog.info("==================authType:$authType")
-//            when (authType) {
-//                "1" -> {
-//                    val intent = Intent(this, FingerAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "2" -> {
-//                    val intent = Intent(this, FourChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "3" -> {
-//                    val intent = Intent(this, TwoChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "4",
-//                "5",
-//                "6" -> {
-            val intent = Intent(this, DualAuthActivity::class.java)
-            startActivity(intent)
-//                }
-//            }
-        })
-//        viewBinding.accessVerify.setOnClickListener {
-//            showToast("当前返回:${LabApp.sLabConfig?.authType}")
-//            var authType = LabApp.sLabConfig?.authType
-//            val isRelationGuard = LabApp.sLabConfig?.isRelationGuard
-//            authType="2"
-//            RcLog.info("==================authType:${LabApp.sLabConfig?.authType}")
-//            RcLog.info("==================authType:$authType  时间:${LabApp.sLabConfig?.logoutTime}  是否关联门禁:${isRelationGuard}  标记:${LabApp.sLabConfig?.isStart}")
-//            when (authType) {
-//                "1" -> {
-//                    val intent = Intent(this, FingerAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "2" -> {
-//                    val intent = Intent(this, FourChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "3" -> {
-//                    val intent = Intent(this, TwoChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "4",
-//                "5",
-//                "6" -> {
-//                    val intent = Intent(this, DualAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//            }
-//        }
+            when (authType) {
+                "1" -> {
+                    Intent(this, FingerAuthActivity::class.java)
+                }
+
+                "2" -> {
+                    Intent(this, FourChoiceAuthActivity::class.java)
+                }
 
+                "3" -> {
+                    Intent(this, TwoChoiceAuthActivity::class.java)
+                }
 
-//
-//
-//        viewBinding.accessVerify.setOnClickListener(FastClickDelegate {
-//            RcLog.info("==================LabApp.sLabConfig?.authType:"+LabApp.sLabConfig?.authType)
-//            val authType = LabApp.sLabConfig?.authType ?: return@FastClickDelegate
-//            RcLog.info("==================authType:$authType")
-//            when (authType) {
-//                "1" -> {
-//                    val intent = Intent(this, FingerAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "2" -> {
-//                    val intent = Intent(this, FourChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "3" -> {
-//                    val intent = Intent(this, TwoChoiceAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//                "4",
-//                "5",
-//                "6" -> {
-//                    val intent = Intent(this, DualAuthActivity::class.java)
-//                    startActivity(intent)
-//                }
-//            }
-//        })
-
-
-//        viewBinding.accessVerify.setOnClickListener {
-//            when ("1") {
-//                AuthTypeConfig.FINGER.type -> {
-//                    val intent = Intent(this, FingerAuthActivity::class.java)
-//                    startActivity(intent)
-//                }}
-//            val intent = Intent(this, FourChoiceAuthActivity::class.java)
-//            startActivity(intent)
-//        }
+                "4",
+                "5",
+                "6" -> {
+                    Intent(this, DualAuthActivity::class.java)
+                }
+
+                else -> {
+                    null
+                }
+            }?.let {
+                startActivity(it)
+            }
+
+        })
     }
 
     override fun initData() {
@@ -442,14 +381,15 @@ class HomeActivity :
         val disposable = ApiRepository.functionList(LabApp.sLabConfig!!.labId)
             .subscribe({ data ->
                 dismissLoading()
-                mBulletinBoardAdapter.setNewInstance(data.toMutableList())
-                viewBinding.bulletinBoardView.initTimer(4, data.size)
-                viewBinding.bulletinBoardView.startAuto(SENSOR_SPLASH_TIME)
-                if (data.isNullOrEmpty()) {
-                    mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
+                if (data.isNotEmpty()) {
+                    mBulletinBoardAdapter.setNewInstance(data.toMutableList())
+                    viewBinding.bulletinBoardView.initTimer(4, data.size)
+                    viewBinding.bulletinBoardView.startAuto(SENSOR_SPLASH_TIME)
+                    if (data.isNullOrEmpty()) {
+                        mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
+                    }
+                    queryWarning()
                 }
-
-                queryWarning()
             }, { throwable ->
                 dismissLoading()
                 throwable.printStackTrace()

+ 77 - 58
app/src/main/java/com/dlc/eboard/ui/MainActivity.kt

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
 import android.content.ComponentName
 import android.content.Intent
 import android.content.ServiceConnection
+import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.GradientDrawable
@@ -15,6 +16,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import cn.bingoogolapple.qrcode.core.BGAQRCodeUtil
 import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder
+import com.blankj.utilcode.util.ThreadUtils
+import com.blankj.utilcode.util.ThreadUtils.SimpleTask
 import com.bumptech.glide.Glide
 import com.bumptech.glide.load.DataSource
 import com.bumptech.glide.load.engine.DiskCacheStrategy
@@ -38,17 +41,17 @@ import com.dlc.eboard.serial.SerialPortHelper
 import com.dlc.eboard.sp.DeviceSp
 import com.dlc.eboard.ui.common.BaseCountDownActivity
 import com.dlc.eboard.ui.dialog.*
+import com.dlc.eboard.ui.leave.LeaveActivity
 import com.dlc.eboard.ui.lib.LabDetailActivity
 import com.dlc.eboard.ui.monitor.MonitorListActivity
 import com.dlc.eboard.ui.msds.InstructionActivity
-import com.dlc.eboard.ui.leave.LeaveActivity
 import com.dlc.eboard.ui.person.LaboratoryPersonActivity
 import com.dlc.eboard.ui.risk.RiskActivity
 import com.dlc.eboard.ui.rule.SafetyRegulationActivity
 import com.dlc.eboard.ui.settings.PasswordDialog
 import com.dlc.eboard.ui.settings.SettingsActivity
-import com.dlc.eboard.ui.things.ThingsActivity
 import com.dlc.eboard.ui.sign.SignInActivity
+import com.dlc.eboard.ui.things.ThingsActivity
 import com.dlc.eboard.ui.widget.HomeSensorView
 import com.dlc.eboard.ui.widget.LooperLayoutManager
 import com.dlc.eboard.ui.widget.NavViewCompat
@@ -69,10 +72,7 @@ import kotlinx.coroutines.withContext
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
-import java.lang.Exception
 import java.util.*
-import kotlin.collections.HashMap
-import kotlin.collections.HashSet
 
 /**
  * 首页
@@ -148,7 +148,8 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         // 第一次启动定时任务
         handler.post(runnable)
     }
-    fun listenIn(){
+
+    fun listenIn() {
         val disposable = ApiRepository.heartbeat(CommonUtils.getAndroidId())
             .subscribe({
 
@@ -157,11 +158,13 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
             })
         addDisposable(disposable)
     }
+
     override fun onDestroy() {
 //        stopService(Intent(this, HeartService::class.java))
         unbindService(mAudioConnection)
         mSerialPortHelper.unbindService()
         mBannerHandler.removeCallbacksAndMessages(null)
+        viewBinding.bulletinBoardView.stopAuto()
         handler.removeCallbacks(runnable)
         handler.removeCallbacksAndMessages(null)
         super.onDestroy()
@@ -591,25 +594,27 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         }
 
         showLoading()
-        val disposable = ApiRepository.signOutCheck(true, LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
-            .subscribe({ data ->
-                dismissLoading()
-                if (data.state) {
-                    callback.invoke(data)
-                } else {
-                    val message = if (data.message.isNullOrEmpty()) "核验失败,请联系管理员!" else data.message[0]
-                    SafetyCheckResultDialog(this, ResultEnum.FAIL, message, 3000).apply {
-                        setCancelable(false)
-                        show()
+        val disposable =
+            ApiRepository.signOutCheck(true, LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
+                .subscribe({ data ->
+                    dismissLoading()
+                    if (data.state) {
+                        callback.invoke(data)
+                    } else {
+                        val message =
+                            if (data.message.isNullOrEmpty()) "核验失败,请联系管理员!" else data.message[0]
+                        SafetyCheckResultDialog(this, ResultEnum.FAIL, message, 3000).apply {
+                            setCancelable(false)
+                            show()
+                        }
                     }
-                }
-            }, { throwable ->
-                dismissLoading()
-                if (!pretreatmentError(throwable, "签退核验")) {
-                    throwable.printStackTrace()
-                    showNetError(throwable)
-                }
-            })
+                }, { throwable ->
+                    dismissLoading()
+                    if (!pretreatmentError(throwable, "签退核验")) {
+                        throwable.printStackTrace()
+                        showNetError(throwable)
+                    }
+                })
         addDisposable(disposable)
     }
 
@@ -621,21 +626,22 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         }
 
         showLoading()
-        val disposable = ApiRepository.isSignInType(LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
-            .subscribe({ patrol ->
-                dismissLoading()
-                if (patrol) {
-                    callLeaveApi(SignType.PATROL)
-                } else {
-                    callback.invoke()
-                }
-            }, { throwable ->
-                dismissLoading()
-                if (!pretreatmentError(throwable, "签退")) {
-                    throwable.printStackTrace()
-                    showNetError(throwable)
-                }
-            })
+        val disposable =
+            ApiRepository.isSignInType(LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
+                .subscribe({ patrol ->
+                    dismissLoading()
+                    if (patrol) {
+                        callLeaveApi(SignType.PATROL)
+                    } else {
+                        callback.invoke()
+                    }
+                }, { throwable ->
+                    dismissLoading()
+                    if (!pretreatmentError(throwable, "签退")) {
+                        throwable.printStackTrace()
+                        showNetError(throwable)
+                    }
+                })
         addDisposable(disposable)
     }
 
@@ -647,7 +653,11 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         }
 
         showLoading("签退中...")
-        val disposable = ApiRepository.commonLeave(signType.code, LabApp.sLabConfig!!.labId, LabApp.sUserVo!!.userId)
+        val disposable = ApiRepository.commonLeave(
+            signType.code,
+            LabApp.sLabConfig!!.labId,
+            LabApp.sUserVo!!.userId
+        )
             .subscribe({
                 dismissLoading()
                 EventBus.getDefault().post(OnlineUserEvent())
@@ -713,11 +723,13 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         // 开门按钮显示控制
         if ("1" == LabApp.sLabConfig?.isRelationGuard) {
             viewBinding.openDoor.visibility = View.VISIBLE
-            val drawable = ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right)
+            val drawable =
+                ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right)
             viewBinding.rightContent.dividerDrawable = drawable
         } else {
             viewBinding.openDoor.visibility = View.GONE
-            val drawable = ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right_v2)
+            val drawable =
+                ContextCompat.getDrawable(this, R.drawable.divider_transparent_main_right_v2)
             viewBinding.rightContent.dividerDrawable = drawable
         }
         // 视频监控按钮显示控制
@@ -828,19 +840,25 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         viewBinding.labName.text = laboratoryVo.address
 
         // 二维码
-        GlobalScope.launch(Dispatchers.Main) {
-            val bitmap = withContext(Dispatchers.IO) {
-                QRCodeEncoder.syncEncodeQRCode(
+        ThreadUtils.executeByCached(object : SimpleTask<Bitmap?>() {
+            @Throws(Throwable::class)
+            override fun doInBackground(): Bitmap? {
+                return QRCodeEncoder.syncEncodeQRCode(
                     laboratoryVo.qrCodeUrl,
                     BGAQRCodeUtil.dp2px(this@MainActivity, 150f)
                 )
             }
-            Glide.with(this@MainActivity)
-                .asBitmap()
-                .load(bitmap)
-                .error(R.mipmap.img_error)
-                .into(viewBinding.qrCode)
-        }
+
+            override fun onSuccess(result: Bitmap?) {
+                if (result != null) {
+                    Glide.with(this@MainActivity)
+                        .asBitmap()
+                        .load(result)
+                        .error(R.mipmap.img_error)
+                        .into(viewBinding.qrCode)
+                }
+            }
+        })
     }
 
     private fun queryBulletinBoard() {
@@ -848,14 +866,15 @@ class MainActivity : BaseCountDownActivity<ActivityMainBinding>() {
         val disposable = ApiRepository.functionList(LabApp.sLabConfig!!.labId)
             .subscribe({ data ->
                 dismissLoading()
-                mBulletinBoardAdapter.setNewInstance(data.toMutableList())
-                viewBinding.bulletinBoardView.initTimer(4, data.size)
-                viewBinding.bulletinBoardView.startAuto(SENSOR_SPLASH_TIME)
-                if (data.isNullOrEmpty()) {
-                    mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
+                if (data.isNotEmpty()) {
+                    mBulletinBoardAdapter.setNewInstance(data.toMutableList())
+                    viewBinding.bulletinBoardView.initTimer(4, data.size)
+                    viewBinding.bulletinBoardView.startAuto(SENSOR_SPLASH_TIME)
+                    if (data.isNullOrEmpty()) {
+                        mBulletinBoardAdapter.setEmptyView(R.layout.view_list_empty)
+                    }
+                    queryWarning()
                 }
-
-                queryWarning()
             }, { throwable ->
                 dismissLoading()
                 throwable.printStackTrace()

+ 41 - 81
app/src/main/java/com/dlc/eboard/ui/SplashActivity.kt

@@ -1,24 +1,22 @@
 package com.dlc.eboard.ui
 
 import android.Manifest
+import android.app.smdt.SmdtManagerNew
 import android.content.Intent
 import android.os.Bundle
-import android.os.Handler
 import android.view.LayoutInflater
 import androidx.appcompat.app.AlertDialog
+import com.blankj.utilcode.constant.TimeConstants
+import com.blankj.utilcode.util.LogUtils
+import com.blankj.utilcode.util.TimeUtils
 import com.dlc.eboard.BuildConfig
 import com.dlc.eboard.LabApp
 import com.dlc.eboard.common.CommonUtils
 import com.dlc.eboard.databinding.ActivitySplashBinding
-import com.dlc.eboard.serial.OnSerialScanListener
-import com.dlc.eboard.serial.SerialPortHelper
 import com.dlc.eboard.sp.DeviceSp
-import com.dlc.eboard.ui.dialog.ResultEnum
-import com.dlc.eboard.ui.dialog.SafetyCheckResultDialog
 import com.dlc.eboard.ui.settings.PasswordDialog
 import com.dlc.eboard.ui.settings.SettingsActivity
 import com.dlc.eboard.utils.NetworkUtils
-import com.dlc.eboard.utils.SharedPreferencesUtil
 import com.dlc.laboratory.ui.LabMainActivity
 import com.rc.core.log.RcLog
 import com.rc.core.ui.activity.RcBaseActivity
@@ -35,10 +33,30 @@ import com.tbruyelle.rxpermissions2.RxPermissions
  */
 class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
 
-    private var isOk = false
+
     override fun createViewBinding() = ActivitySplashBinding.inflate(LayoutInflater.from(this))
 
     override fun initViews(savedInstanceState: Bundle?) {
+        val smdtManagerNew = SmdtManagerNew.getInstance(this)
+        if (smdtManagerNew != null) {
+            // 设置导航栏不可见
+            if (1 == smdtManagerNew.disp_getNavigationBar()) {
+                smdtManagerNew.disp_setNavigationBar(false)
+            }
+            // 设置状态栏不可见
+            if (1 == smdtManagerNew.disp_getStatusBar()) {
+                smdtManagerNew.disp_setStatusBar(false)
+            }
+            // 设置手势不可呼出导航栏
+            if (1 == smdtManagerNew.disp_getGestureBar()) {
+                smdtManagerNew.disp_setGestureBar(false)
+            }
+            // 设置手势不可呼出状态栏
+            if (1 == smdtManagerNew.disp_getStatusBarDrag()) {
+                smdtManagerNew.disp_setStatusBarDrag(false)
+            }
+        }
+
         RcLog.info(
             "versionName:${DeviceUtils.getVersionName(this)}, versionCode:${
                 DeviceUtils.getVersionCode(
@@ -50,16 +68,17 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
         viewBinding.versionName.text = "版本号:${DeviceUtils.getVersionName(this)}"
 
         viewBinding.copyRight.setOnLongClickListener {
-            myHandler.stop()
             PasswordDialog(this) {
                 val intent = Intent(this, SettingsActivity::class.java)
                 startActivity(intent)
             }.show()
             true
         }
+    }
 
+    override fun onPostCreate(savedInstanceState: Bundle?) {
+        super.onPostCreate(savedInstanceState)
         requestPermission()
-//        mSerialPortHelper.bindService()
     }
 
     private fun requestPermission() {
@@ -74,11 +93,9 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
             .subscribe { granted ->
                 if (granted) {
                     // 登录获取token
-                    myHandler.start()
                     val isNetworkAvailable = NetworkUtils.isNetworkAvailable(this)
                     if (isNetworkAvailable) {
                         authLogin()
-                        myHandler.stop()
                     } else {
                         // 当前网络不可用
                         showToast("当前网络不可用,请等待")
@@ -95,20 +112,30 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
         addDisposable(disposable)
     }
 
+
+    private var lastErrTime: Long = 0L
+
     /**
      * 登录获取token
      */
     private fun authLogin() {
-        showToast("系统登陆中...")
+        viewBinding.tips.text = "正在登录系统"
         val disposable = ApiRepository.authOneLogin()
             .subscribe({ success ->
                 if (success) {
                     // 没有新版本
                     queryLabConfig()
 //                    queryAppVersion()
+                } else {
+                    authLogin()
                 }
             }, { throwable ->
-                //初始化进入后网络反应太慢 重新调用
+                val nowTime = System.currentTimeMillis()
+                if (0L == lastErrTime && nowTime - lastErrTime > 20000) {
+                    lastErrTime = nowTime
+                    //初始化进入后网络反应太慢 重新调用
+                    authLogin()
+                }
                 showNetError(throwable)
             })
         addDisposable(disposable)
@@ -165,8 +192,7 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
     }
 
     private fun queryLabConfig() {
-        showToast("系统登陆中...")
-//        showLoading("加载中...")
+        viewBinding.tips.text = "正在查询实验室配置"
         RcLog.info("============CommonUtils.getAndroidId()" + CommonUtils.getAndroidId())
         val disposable = ApiRepository.queryLabConfig(CommonUtils.getAndroidId())
             .subscribe({ data ->
@@ -182,33 +208,6 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
     }
 
 
-    private val mSerialPortHelper by lazy {
-        SerialPortHelper(this, object : OnSerialScanListener {
-            override fun onServiceConnected() {
-//                if ("1" == LabApp.sLabConfig?.isRelationGuard) {
-//                    // 有门禁,登录成功后自动开门
-//                    RcLog.info("MainActivity# auto open door")
-//
-//                }
-                handleOpenDoor()
-            }
-        })
-    }
-
-    private fun handleOpenDoor() {
-        mSerialPortHelper.openDoor()
-        SafetyCheckResultDialog(
-            this,
-            ResultEnum.SUCCESS,
-            "开锁成功",
-            3000
-        ).apply {
-            setCancelable(false)
-            show()
-        }
-    }
-
-
     private fun queryLaboratoryInfo(openEBoard: Boolean, labId: String) {
         val id = if (openEBoard) labId else CommonUtils.getAndroidId()
         val disposable = ApiRepository.laboratoryInfo(openEBoard, id)
@@ -230,47 +229,8 @@ class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
         finish()
     }
 
-    private val myHandler = MyHandler {
-        // 在这里执行你的业务操作
-        //校验版本更新
-        val isNetworkAvailable = NetworkUtils.isNetworkAvailable(this)
-        if (isNetworkAvailable) {
-//            queryLabConfig()
-            authLogin()
-        } else {
-            // 当前网络不可用
-            showToast("当前网络不可用,请等待")
-        }
-
-    }
-
-    class MyHandler(private val callback: () -> Unit) {
-
-        private val handler = Handler()
-
-        //        private val interval: Long = 10 * 60 * 1000 // 10分钟
-        private val interval: Long = 15000 // 15秒
-
-        private val runnable = object : Runnable {
-            override fun run() {
-                callback.invoke()
-                handler.postDelayed(this, interval)
-            }
-        }
-
-        fun start() {
-            handler.postDelayed(runnable, interval)
-        }
-
-        fun stop() {
-            handler.removeCallbacks(runnable)
-        }
-    }
 
     override fun onDestroy() {
         super.onDestroy()
-//        mSerialPortHelper.unbindService()
-        // 停止定时任务
-        myHandler.stop()
     }
 }

+ 133 - 105
app/src/main/java/com/dlc/eboard/ui/auth/fragment/FaceAuthFragment.kt

@@ -1,33 +1,32 @@
 package com.dlc.eboard.ui.auth.fragment
 
+import android.graphics.Matrix
+import android.graphics.RectF
 import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.os.Message
 import android.view.LayoutInflater
 import android.view.ViewGroup
 import androidx.appcompat.app.AlertDialog
-import com.blankj.utilcode.util.LogUtils
 import com.dlc.eboard.LabApp
 import com.dlc.eboard.databinding.FragmentAuthFaceMatchingBinding
 import com.dlc.eboard.ui.auth.AuthType
 import com.dlc.eboard.ui.auth.OnAuthResultListener
 import com.dlc.eboard.utils.SharedPreferencesUtil
-import com.rc.core.log.RcLog
+import com.google.mlkit.vision.common.InputImage
+import com.google.mlkit.vision.face.Face
+import com.google.mlkit.vision.face.FaceDetection
+import com.google.mlkit.vision.face.FaceDetectorOptions
+import com.otaliastudios.cameraview.CameraListener
+import com.otaliastudios.cameraview.PictureResult
+import com.otaliastudios.cameraview.controls.Facing
+import com.otaliastudios.cameraview.frame.Frame
+import com.otaliastudios.cameraview.frame.FrameProcessor
+import com.otaliastudios.cameraview.size.Size
+import com.otaliastudios.cameraview.size.SizeSelector
 import com.rc.core.ui.fragment.RcBaseFragment
 import com.rc.core.util.MediaUtils
 import com.rc.httpcore.client.ApiRepository
 import com.rc.httpcore.exception.NetException
-import io.fotoapparat.Fotoapparat
-import io.fotoapparat.facedetector.processor.FaceDetectorProcessor
-import io.fotoapparat.log.fileLogger
-import io.fotoapparat.log.logcat
-import io.fotoapparat.log.loggers
-import io.fotoapparat.selector.back
-import io.fotoapparat.selector.front
 import java.io.File
-import java.text.SimpleDateFormat
-import java.util.*
 
 /**
  * 人脸识别
@@ -42,15 +41,17 @@ class FaceAuthFragment :
 
         private const val WHAT_TAKE_PICTURE = 1
 
-        //        private const val TIMEOUT_TAKE_PICTURE = 2000L
         private const val TIMEOUT_TAKE_PICTURE = 200L
 
         fun newInstance() = FaceAuthFragment()
     }
 
-    private var isMatching = false
-    private lateinit var mFotoapparat: Fotoapparat
-
+    /**
+     * A: 是否需要人脸验证
+     * B: 是否已完成验证
+     */
+    private var isInComparison: Pair<Boolean, Boolean> = Pair(true, false)
+    private var faceDetectorOptions: FaceDetectorOptions? = null
     override fun createViewBinding(
         inflater: LayoutInflater,
         container: ViewGroup?
@@ -59,107 +60,136 @@ class FaceAuthFragment :
     }
 
     override fun initViews(savedInstanceState: Bundle?) {
+        // 相机选择
         val retrievedValue = SharedPreferencesUtil.getString(requireActivity(), "0")
-        isMatching = false
-        mFotoapparat = Fotoapparat.with(requireActivity())
-            .into(viewBinding.cameraView)
-            .lensPosition(
-                if (retrievedValue == "0") {
-                    front()
-                } else {
-                    back()
+        if (retrievedValue == "0") {
+            viewBinding.mlCameraView.facing = Facing.FRONT
+        } else if (retrievedValue == "1") {
+            viewBinding.mlCameraView.facing = Facing.BACK
+        }
+        viewBinding.mlCameraView.setPreviewStreamSize(SizeSelector { source ->
+            val sizeList: MutableList<Size> = ArrayList()
+            for (size in source) {
+                val width = size.width
+                if (width == 800) {
+                    sizeList.add(size)
                 }
-            )//front()前置  back 后置
-            .frameProcessor(
-                FaceDetectorProcessor.with(requireActivity())
-                    .listener { faces ->
-                        if (null != faces) {
-                            LogUtils.d("Jayce", "无人脸")
-                        } else {
-                            LogUtils.d("Jayce", "有人脸")
-                        }
-                        viewBinding.rectanglesView.setRectangles(faces)
-//                        if (!isMatching && isResumed && !faces.isNullOrEmpty()) takePicture()
-//                        if (!isMatching && isResumed) {
-//                            isMatching = true
-//                            mTakePictureHandler.sendEmptyMessageDelayed(WHAT_TAKE_PICTURE, TIMEOUT_TAKE_PICTURE)
-//                        }
-                    }.build()
-            )
-            .logger(loggers(logcat(), fileLogger(requireActivity())))
-            .build()
+            }
+            if (sizeList.isEmpty()) {
+                return@SizeSelector source
+            }
+            sizeList
+        })
+        isInComparison = Pair(true, false)
+        faceDetectorOptions = FaceDetectorOptions.Builder()
+            .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
+            .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL).build()
     }
 
-    private val myHandler = MyHandler {
-        takePicture()
+    /**
+     * 人脸角度是否符合预期
+     */
+    private fun isHeadEulerAngleAccord(face: Face): Boolean {
+        return face.headEulerAngleY < 10 && face.headEulerAngleY > -10
+                && face.headEulerAngleX < 10 && face.headEulerAngleX > -10
+                && face.headEulerAngleZ < 10 && face.headEulerAngleZ > -10
     }
 
-    class MyHandler(private val callback: () -> Unit) {
-
-        private val handler = Handler()
-
-        //        private val interval: Long = 10 * 60 * 1000 // 10分钟
-        private val interval: Long = 3000 // 10秒
-
-        private val runnable = object : Runnable {
-            override fun run() {
-                callback.invoke()
-                handler.postDelayed(this, interval)
-            }
-        }
-
-        fun start() {
-            handler.postDelayed(runnable, interval)
-        }
+    override fun onResume() {
+        super.onResume()
+        isInComparison = Pair(true, false)
 
-        fun stop() {
-            handler.removeCallbacks(runnable)
-        }
+        viewBinding.mlCameraView.addCameraListener(cameraListener)
+        viewBinding.mlCameraView.addFrameProcessor(frameProcessor)
+        viewBinding.mlCameraView.open()
     }
 
-    private val mTakePictureHandler = object : Handler(Looper.getMainLooper()) {
-
-        override fun handleMessage(msg: Message) {
-            if (!isResumed) return
-            if (WHAT_TAKE_PICTURE == msg.what) takePicture()
-        }
+    /**
+     * 帧捕获
+     */
+    private var frameProcessor: FrameProcessor = FrameProcessor { frame ->
+        onProcess(frame)
     }
-
-    private fun takePicture() {
-//        isMatching = true
-        val format = SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault())
-        val fileName = "${format.format(Calendar.getInstance().time)}.jpg"
-        val photoFile = File(requireActivity().getExternalFilesDir("photos"), fileName)
-        mFotoapparat.takePicture()
-            .saveToFile(photoFile)
-            .whenAvailable {
-                callFaceMatchingApi(photoFile)
+    private var matrix: Matrix = Matrix()
+
+    /**
+     * 帧处理
+     */
+    private fun onProcess(frame: Frame) {
+        if (isInComparison.first) {
+            val size = frame.size
+            val image = InputImage.fromByteArray(
+                frame.getData(),
+                size.width,
+                size.height,
+                frame.rotation,
+                InputImage.IMAGE_FORMAT_NV21
+            )
+            val faceDetector = FaceDetection.getClient(faceDetectorOptions!!)
+            // 发起人脸识别
+            faceDetector.process(image).addOnSuccessListener { faces: MutableList<Face> ->
+                // 是否检测到人脸
+                if (faces.isNotEmpty()) {
+                    val face = faces[0]
+                    val srcRect = RectF(face.boundingBox);
+                    val dstRect = RectF(0f, 0f, 0f, 0f)
+                    matrix.mapRect(dstRect, srcRect)
+                    viewBinding.detectView.onDetectFace(dstRect);
+                    // 人脸角度是否符合
+                    if (isHeadEulerAngleAccord(face)) {
+                        if (null != face.leftEyeOpenProbability && null != face.rightEyeOpenProbability) {
+                            // 睁眼检测
+                            if (face.leftEyeOpenProbability!! > 0.5 && face.rightEyeOpenProbability!! > 0.5) {
+                                // 需要人脸识别,也没有在比对中
+                                if (isInComparison.first && !isInComparison.second) {
+                                    // 需要人脸识别,正在比对中
+                                    isInComparison = Pair(true, true)
+                                    // 快速捕获一帧图片
+                                    viewBinding.mlCameraView.takePicture()
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    viewBinding.detectView.onDetectFace(RectF(0f, 0f, 0f, 0f));
+                }
             }
+        }
     }
 
-    override fun onResume() {
-        super.onResume()
-//        mFotoapparat.start()
-        try {
-            mFotoapparat.stop()
-            myHandler.stop()
-        } catch (e: Exception) {
-
+    /**
+     * 相机监听
+     */
+    private var cameraListener: CameraListener = object : CameraListener() {
+        /**
+         * 拍照监听
+         */
+        override fun onPictureTaken(result: PictureResult) {
+            super.onPictureTaken(result)
+            val photoFile = File(
+                requireActivity().getExternalFilesDir("photos"),
+                "${System.currentTimeMillis()}.jpg"
+            )
+            result.toFile(photoFile) { file: File? ->
+                callFaceMatchingApi(file)
+            }
         }
-        mFotoapparat.start()
-        myHandler.start()
-        isMatching = false
     }
 
     override fun onPause() {
         super.onPause()
-//        mFotoapparat.stop()
-        RcLog.info("removeCallbacksAndMessages===================")
-//        mTakePictureHandler.removeCallbacksAndMessages(null)
+        viewBinding.mlCameraView.removeCameraListener(cameraListener)
+        viewBinding.mlCameraView.removeFrameProcessor(frameProcessor)
+        viewBinding.mlCameraView.close()
     }
 
-    private fun callFaceMatchingApi(photoFile: File) {
-        if (!photoFile.exists()) return
+    private fun callFaceMatchingApi(photoFile: File?) {
+        // 没有人脸文件则重新发起
+        if (photoFile == null || !photoFile.exists()) {
+            isInComparison = Pair(true, false)
+            return
+        }
+
         val disposable = ApiRepository.authFace(photoFile, LabApp.sLabConfig!!.labId)
             .subscribe({ userVo ->
                 MediaUtils.deleteFile(photoFile)
@@ -168,15 +198,14 @@ class FaceAuthFragment :
                 val activity = requireActivity()
                 if (activity is OnAuthResultListener) {
                     if (!activity.onAuthSuccess(AuthType.FACE, userVo)) {
-                        isMatching = false
+                        isInComparison = Pair(false, false)
                     }
                 }
             }, { throwable ->
                 MediaUtils.deleteFile(photoFile)
                 if (!isResumed) return@subscribe
-
+                isInComparison = Pair(true, false)
                 if (!pretreatmentError(throwable)) {
-                    isMatching = false
                     throwable.printStackTrace()
                     showNetError(throwable)
                 }
@@ -195,13 +224,11 @@ class FaceAuthFragment :
                     .setTitle("提示")
                     .setMessage(throwable.message)
                     .setPositiveButton("确定") { _, _ ->
-                        isMatching = false
                     }.show()
                 return true
             } else if ("500" == throwable.code
                 && throwable.message == "识别中"
             ) {
-                isMatching = false
                 return true
             }
         }
@@ -210,7 +237,8 @@ class FaceAuthFragment :
 
     override fun onDestroy() {
         super.onDestroy()
-        myHandler.stop()
+        viewBinding.mlCameraView.clearCameraListeners();
+        viewBinding.mlCameraView.destroy();
     }
 
 }

+ 9 - 1
app/src/main/java/com/dlc/eboard/ui/common/BaseCountDownActivity.kt

@@ -66,9 +66,18 @@ abstract class BaseCountDownActivity<VB : ViewBinding> :
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+    }
+
+    override fun onStart() {
+        super.onStart()
         EventBus.getDefault().register(this)
     }
 
+    override fun onStop() {
+        EventBus.getDefault().unregister(this)
+        super.onStop()
+    }
+
     override fun onResume() {
         super.onResume()
         startCountDown()
@@ -80,7 +89,6 @@ abstract class BaseCountDownActivity<VB : ViewBinding> :
     }
 
     override fun onDestroy() {
-        EventBus.getDefault().unregister(this)
         mCountDownHandler.removeCallbacksAndMessages(null)
         super.onDestroy()
     }

+ 9 - 1
app/src/main/java/com/dlc/eboard/ui/settings/SettingsActivity.kt

@@ -6,6 +6,7 @@ import android.os.Looper
 import android.os.Message
 import android.provider.Settings
 import androidx.appcompat.app.AlertDialog
+import com.blankj.utilcode.util.AppUtils
 import com.dlc.eboard.common.CommonUtils
 import com.dlc.eboard.common.Constants
 import com.dlc.eboard.databinding.ActivitySettingsBinding
@@ -144,7 +145,9 @@ class SettingsActivity : RcBaseActivity<ActivitySettingsBinding>() {
         viewBinding.androidId.text = CommonUtils.getAndroidId()
         viewBinding.versionName.text = DeviceUtils.getVersionName(this)
         viewBinding.curEnv.text = HttpConfig.API_BASE_URL
+        viewBinding.curEnvInput.setText(HttpConfig.API_BASE_URL)
         viewBinding.curSafetyEnv.text = HttpConfig.SIGN_IN_CHECK_BASE_URL
+        viewBinding.curEnvSafetyInput.setText(HttpConfig.SIGN_IN_CHECK_BASE_URL)
 
         val apiVersion = EnvSp.loadEnv(this)?.apiVersion ?: Constants.NetExtra.API_VERSION
         viewBinding.apiVersion.text =
@@ -152,8 +155,13 @@ class SettingsActivity : RcBaseActivity<ActivitySettingsBinding>() {
         viewBinding.apiVersion.tag = apiVersion
 
         viewBinding.curMqttEnv.text = Constants.MqttConfig.SERVER_URI
+        viewBinding.curMqttEnvInput.setText(Constants.MqttConfig.SERVER_URI)
+
         viewBinding.curMqttName.text = Constants.MqttConfig.U_NAME
+        viewBinding.curMqttNameInput.setText(Constants.MqttConfig.U_NAME)
+
         viewBinding.curMqttPwd.text = Constants.MqttConfig.U_PWD
+        viewBinding.curMqttPwdInput.setText(Constants.MqttConfig.U_PWD)
 
         viewBinding.curSettingPwd.text =
             EnvSp.loadEnv(this)?.settingPwd ?: Constants.Mock.SETTING_PWD
@@ -182,7 +190,7 @@ class SettingsActivity : RcBaseActivity<ActivitySettingsBinding>() {
 
         override fun handleMessage(msg: Message) {
             mRef.get()?.run {
-                CommonUtils.restartApp(this)
+                AppUtils.relaunchApp(true)
             }
         }
     }

+ 58 - 0
app/src/main/java/com/dlc/eboard/ui/widget/DetectView.java

@@ -0,0 +1,58 @@
+package com.dlc.eboard.ui.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DetectView extends View {
+    private Paint mPaint;
+    private List<RectF> rects = new ArrayList<>();
+
+    public DetectView(Context context) {
+        this(context, null);
+    }
+
+    public DetectView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mPaint.setColor(Color.GREEN);
+        float mStrokeWidth = 4;
+        mPaint.setStrokeWidth(mStrokeWidth);
+        mPaint.setDither(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        try {
+            for (RectF rect : rects) {
+                canvas.drawRect(rect, mPaint);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void onDetectFace(List<RectF> rects) {
+        this.rects = rects;
+        invalidate();
+    }
+
+    public void onDetectFace(RectF rect) {
+        this.rects.clear();
+        this.rects.add(rect);
+        invalidate();
+    }
+}

+ 2 - 2
app/src/main/res/layout/activity_auth_four_choice.xml

@@ -47,8 +47,8 @@
 
         <com.rc.core.ui.widget.SwipeViewPager
             android:id="@+id/viewPager"
-            android:layout_width="570dp"
-            android:layout_height="0dp"
+            android:layout_width="800px"
+            android:layout_height="600px"
             android:layout_marginBottom="5dp"
             app:layout_constraintBottom_toTopOf="@id/tabLabel"
             app:layout_constraintEnd_toEndOf="parent"

+ 4 - 3
app/src/main/res/layout/activity_splash.xml

@@ -83,13 +83,13 @@
             app:layout_constraintTop_toTopOf="@+id/text_check_count" />
 
         <LinearLayout
-            android:visibility="gone"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:layout_marginTop="30dp"
-            android:gravity="center_vertical"
-            android:orientation="horizontal">
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:visibility="visible">
 
             <ProgressBar
                 android:layout_width="30dp"
@@ -111,6 +111,7 @@
                 android:layout_marginStart="5dp"
                 android:textColor="@color/white"
                 android:textSize="14sp"
+                android:visibility="gone"
                 tools:text="(1%)" />
 
         </LinearLayout>

+ 15 - 1
app/src/main/res/layout/fragment_auth_face_matching.xml

@@ -22,6 +22,20 @@
             app:rectanglesStrokeWidth="2dp" />
     </io.fotoapparat.facedetector.view.CameraOverlayLayout>
 
+    <com.otaliastudios.cameraview.CameraView
+        android:id="@+id/ml_camera_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:cameraDrawHardwareOverlays="true"
+        app:cameraEngine="camera1">
+
+        <com.dlc.eboard.ui.widget.DetectView
+            android:id="@+id/detectView"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center" />
+    </com.otaliastudios.cameraview.CameraView>
+
     <androidx.constraintlayout.widget.Guideline
         android:id="@+id/middle_line"
         android:layout_width="wrap_content"
@@ -49,7 +63,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="17dp"
-        android:text="请将脸部对准摄像头"
+        android:text="请正视摄像头"
         android:textColor="@android:color/white"
         android:textSize="17sp"
         app:layout_constraintEnd_toEndOf="parent"

+ 1 - 1
build.gradle

@@ -17,7 +17,7 @@ buildscript {
 //    apply from: 'config/config.gradle'
     dependencies {
         classpath 'com.android.tools.build:gradle:8.6.0'
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files