Browse Source

1.重写监控功能

JaycePC 1 week ago
parent
commit
089a20cdba
62 changed files with 632 additions and 290 deletions
  1. 18 9
      app/build.gradle
  2. BIN
      app/libs/HatomPlayerCore.jar
  3. 5 0
      app/src/main/AndroidManifest.xml
  4. 4 7
      app/src/main/java/http/client/ApiRepository.kt
  5. 1 5
      app/src/main/java/http/client/LabClient.kt
  6. 13 7
      app/src/main/java/http/client/retrofit/ApiService.java
  7. 2 10
      app/src/main/java/http/client/retrofit/LabRetrofit.kt
  8. 3 2
      app/src/main/java/http/vo/response/LabBulletinBoardVo.java
  9. 1 0
      app/src/main/java/xn/xxp/HomeActivity.java
  10. 2 0
      app/src/main/java/xn/xxp/app/LabApp.java
  11. 26 7
      app/src/main/java/xn/xxp/home/adapter/HomeBoardAdapter.kt
  12. 15 1
      app/src/main/java/xn/xxp/home/auth/ChoiceAuthActivity.java
  13. 6 4
      app/src/main/java/xn/xxp/home/auth/fragment/LzFaceAuthFragment.java
  14. 6 2
      app/src/main/java/xn/xxp/home/auth/fragment/QrAuthFragment.java
  15. 2 8
      app/src/main/java/xn/xxp/main/MainActivity.kt
  16. 3 3
      app/src/main/java/xn/xxp/main/MainBoardAdapter.java
  17. 225 10
      app/src/main/java/xn/xxp/main/monitor/MonitorActivity.java
  18. 141 0
      app/src/main/java/xn/xxp/main/monitor/MonitorDialog.java
  19. 46 0
      app/src/main/java/xn/xxp/main/monitor/MonitorInfo.java
  20. 0 174
      app/src/main/java/xn/xxp/main/monitor/MonitorListActivity.kt
  21. 0 12
      app/src/main/java/xn/xxp/main/risk/VideoDialogFragment.java
  22. 11 7
      app/src/main/java/xn/xxp/main/rule/RuleActivity.java
  23. 11 3
      app/src/main/java/xn/xxp/main/rule/RuleDetailActivity.java
  24. 7 2
      app/src/main/java/xn/xxp/mqtt/MqttManager.kt
  25. 3 0
      app/src/main/java/xn/xxp/utils/Tool.java
  26. 7 2
      app/src/main/java/xn/xxp/widget/ItemBoardView.kt
  27. BIN
      app/src/main/jniLibs/arm64-v8a/libAudioEngine.so
  28. BIN
      app/src/main/jniLibs/arm64-v8a/libFormatConversion.so
  29. BIN
      app/src/main/jniLibs/arm64-v8a/libFormatConversionSDK.so
  30. BIN
      app/src/main/jniLibs/arm64-v8a/libHPSClient.so
  31. BIN
      app/src/main/jniLibs/arm64-v8a/libHPSClientSDK.so
  32. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaACodec.so
  33. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaAssistant.so
  34. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaExtractor.so
  35. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaMuxer.so
  36. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaPostProc.so
  37. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaVDecode.so
  38. BIN
      app/src/main/jniLibs/arm64-v8a/libMediaVEncode.so
  39. BIN
      app/src/main/jniLibs/arm64-v8a/libPlayCtrl.so
  40. BIN
      app/src/main/jniLibs/arm64-v8a/libSystemTransform.so
  41. BIN
      app/src/main/jniLibs/arm64-v8a/libcrypto.so
  42. BIN
      app/src/main/jniLibs/arm64-v8a/libssl.so
  43. BIN
      app/src/main/jniLibs/armeabi-v7a/libAudioEngine.so
  44. BIN
      app/src/main/jniLibs/armeabi-v7a/libFormatConversion.so
  45. BIN
      app/src/main/jniLibs/armeabi-v7a/libFormatConversionSDK.so
  46. BIN
      app/src/main/jniLibs/armeabi-v7a/libHPSClient.so
  47. BIN
      app/src/main/jniLibs/armeabi-v7a/libHPSClientSDK.so
  48. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaACodec.so
  49. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaAssistant.so
  50. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaExtractor.so
  51. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaMuxer.so
  52. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaPostProc.so
  53. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaVDecode.so
  54. BIN
      app/src/main/jniLibs/armeabi-v7a/libMediaVEncode.so
  55. BIN
      app/src/main/jniLibs/armeabi-v7a/libPlayCtrl.so
  56. BIN
      app/src/main/jniLibs/armeabi-v7a/libSystemTransform.so
  57. BIN
      app/src/main/jniLibs/armeabi-v7a/libcrypto.so
  58. BIN
      app/src/main/jniLibs/armeabi-v7a/libssl.so
  59. 0 13
      app/src/main/res/layout/activity_main.xml
  60. 33 2
      app/src/main/res/layout/activity_monitor.xml
  61. 33 0
      app/src/main/res/layout/dialog_monitor.xml
  62. 8 0
      gradle/libs.versions.toml

+ 18 - 9
app/build.gradle

@@ -6,6 +6,11 @@ plugins {
 }
 
 android {
+    sourceSets {
+        main {
+            jniLibs.srcDirs = ['src/main/jniLibs']
+        }
+    }
     namespace 'xn.xxp'
     compileSdk 35
 
@@ -13,13 +18,17 @@ android {
         applicationId "xn.xxp"
         minSdk 31
         targetSdk 35
-        versionCode 1
-        versionName "1.0"
+        versionCode 2
+        versionName "2.0"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         room {
             schemaDirectory("$projectDir/schemas")
         }
+        ndk {
+            //noinspection ChromeOsAbiSupport
+            abiFilters 'arm64-v8a', 'armeabi-v7a'
+        }
     }
 
     buildTypes {
@@ -118,11 +127,11 @@ dependencies {
     implementation libs.coil.svg
     // fotoapparat
     implementation libs.fotoapparat
-
-    implementation 'com.shuyu:gsyVideoPlayer-java:8.1.0'
-    implementation 'com.shuyu:gsyVideoPlayer-armv7a:8.1.0'
-
-    implementation 'org.jsoup:jsoup:1.16.2'
-
-    implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'
+    // gsPlayer
+    implementation libs.gsyvideoplayer.java
+    implementation libs.gsyvideoplayer.armv7a
+    // jsoup
+    implementation libs.jsoup
+    // pdfView
+    implementation libs.android.pdf.viewer
 }

BIN
app/libs/HatomPlayerCore.jar


+ 5 - 0
app/src/main/AndroidManifest.xml

@@ -34,8 +34,13 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.西农电子信息牌"
         android:usesCleartextTraffic="true">
+        <activity
+            android:name=".home.leave.LeaveActivity"
+            android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
+            android:exported="false" />
         <activity
             android:name=".main.monitor.MonitorActivity"
+            android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
             android:exported="false" />
         <activity
             android:name=".main.rule.RuleDetailActivity"

+ 4 - 7
app/src/main/java/http/client/ApiRepository.kt

@@ -14,7 +14,8 @@ import java.lang.StringBuilder
 
 object ApiRepository {
 
-    private val mLibClient by lazy { RetrofitFactory().createLabClient()
+    private val mLibClient by lazy {
+        RetrofitFactory().createLabClient()
     }
 
     /**
@@ -185,8 +186,8 @@ object ApiRepository {
      *
      * @param type 1:学校制度 2:学院制度 3: 中心制度
      */
-    fun safeBookList(safetyListReq: SafetyListReq): Observable<List<SafeBook>> {
-        return mLibClient.safeBookList(safetyListReq).schedulers()
+    fun safeBookList(type: String): Observable<List<SafeBook>> {
+        return mLibClient.safeBookList(type).schedulers()
     }
 
     /**
@@ -611,10 +612,6 @@ object ApiRepository {
     }
 
 
-    fun terminalAuth(param: TerminalAuthReq): Observable<String> {
-        return mLibClient.terminalAuth(param).schedulers()
-    }
-
 }
 
 fun <T : Any> Observable<T>.schedulers(): Observable<T> {

+ 1 - 5
app/src/main/java/http/client/LabClient.kt

@@ -126,7 +126,7 @@ interface LabClient {
      *
      * @param type 1:学校制度 2:学院制度 3: 中心制度
      */
-    fun safeBookList(safetyListReq: SafetyListReq): Observable<List<SafeBook>>
+    fun safeBookList(type: String): Observable<List<SafeBook>>
 
     /**
      * 获取实验室安全制度详细信息
@@ -298,8 +298,4 @@ interface LabClient {
      */
     fun newMsgGroup(param: NoticeReq): Observable<List<NoticeSummary>>
 
-    /**
-     * 鉴权
-     */
-    fun terminalAuth(param: TerminalAuthReq): Observable<String>
 }

+ 13 - 7
app/src/main/java/http/client/retrofit/ApiService.java

@@ -1,5 +1,8 @@
 package http.client.retrofit;
 
+import java.util.List;
+import java.util.Map;
+
 import http.vo.CommonDataResponse;
 import http.vo.CommonResponse;
 import http.vo.CommonRowsResponse;
@@ -24,24 +27,18 @@ import http.vo.response.HomeMiddleResp;
 import http.vo.response.HomeRightResp;
 import http.vo.response.HomeTopResp;
 import http.vo.response.LabBulletinBoardVo;
-import xn.xxp.room.bean.LabConfig;
 import http.vo.response.LabHazardVo;
 import http.vo.response.LabPersonVo;
 import http.vo.response.LabWarnVo;
 import http.vo.response.LaboratoryVo;
 import http.vo.response.LotDeviceVo;
 import http.vo.response.MonitorVo;
-import xn.xxp.room.bean.NoticeSummary;
 import http.vo.response.RecordsResponse;
 import http.vo.response.SafeBook;
 import http.vo.response.SignInCheckResp;
 import http.vo.response.SpeakInfo;
 import http.vo.response.UserFingerVo;
 import http.vo.response.UserVo;
-
-import java.util.List;
-import java.util.Map;
-
 import io.reactivex.rxjava3.core.Observable;
 import okhttp3.MultipartBody;
 import okhttp3.RequestBody;
@@ -56,6 +53,8 @@ import retrofit2.http.PartMap;
 import retrofit2.http.Path;
 import retrofit2.http.Query;
 import retrofit2.http.QueryMap;
+import xn.xxp.room.bean.LabConfig;
+import xn.xxp.room.bean.NoticeSummary;
 
 public interface ApiService {
 
@@ -113,6 +112,13 @@ public interface ApiService {
     @POST("terminal/lab/signIn/check/checkInXxpAll")
     Observable<CommonDataResponse<String>> checkInXxpAll(@PartMap Map<String, RequestBody> params, @Part MultipartBody.Part file);
 
+    /**
+     * ZD-A010: 签到-安全准入检测三合一
+     */
+    @Multipart
+    @POST("terminal/lab/signIn/check/checkInXxpAll")
+    Observable<CommonDataResponse<String>> checkInXxpNewAll(@QueryMap Map<String, String> params, @Part MultipartBody.Part file);
+
     /**
      * ZD-A011: 签到提交
      */
@@ -183,7 +189,7 @@ public interface ApiService {
      * ZD-A022: 查询实验室安全制度列表
      */
     @POST("terminal/lab/safeBook/queryOptionList")
-    Observable<CommonDataResponse<List<SafeBook>>> safeBookList(@Body SafetyListReq safetyListReq);
+    Observable<CommonDataResponse<List<SafeBook>>> safeBookList(@Query("type") String type);
 
     /**
      * ZD-A023: 获取实验室安全制度详细信息

+ 2 - 10
app/src/main/java/http/client/retrofit/LabRetrofit.kt

@@ -257,8 +257,8 @@ open class LabRetrofit : LabClient {
      *
      * @param type 1:学校制度 2:学院制度 3: 中心制度
      */
-    override fun safeBookList(safetyListReq: SafetyListReq): Observable<List<SafeBook>> {
-        return apiService.safeBookList(safetyListReq)
+    override fun safeBookList(type: String): Observable<List<SafeBook>> {
+        return apiService.safeBookList(type)
             .map(this::dataConvert)
     }
 
@@ -548,14 +548,6 @@ open class LabRetrofit : LabClient {
             .map(this::recordsConvert)
     }
 
-    /**
-     * 鉴权
-     */
-    override fun terminalAuth(param: TerminalAuthReq): Observable<String> {
-        return apiService.terminalAuth(param)
-            .map(this::dataConvert)
-    }
-
     @Throws(NetException::class)
     private fun <T> recordsConvert(response: CommonDataResponse<RecordsResponse<T>>): List<T> {
         requireSuccess(response)

+ 3 - 2
app/src/main/java/http/vo/response/LabBulletinBoardVo.java

@@ -32,6 +32,8 @@ public class LabBulletinBoardVo {
     public String icon;
     // ("异常图标")
     public String exceptionIcon;
+    // 属性名称
+    public String attributeName;
     public String funNum; // 功能编码
     public String code; // 设备Code
 
@@ -41,7 +43,6 @@ public class LabBulletinBoardVo {
         String unit_ = null == unit ? "" : unit;
         return String.format("%s:%s%s", describe_, val_, unit_);
     }
-    
-    
+
 
 }

+ 1 - 0
app/src/main/java/xn/xxp/HomeActivity.java

@@ -348,6 +348,7 @@ public class HomeActivity extends BaseCountDownActivity<ActivityHomeBinding> imp
 
     @Subscribe(threadMode = ThreadMode.MAIN)
     public void onWarningEvent(WarningEvent event) {
+        LogUtils.json("预案", event);
         if (null != event) {
             List<LabWarnVo> labWarnVos = event.getData();
             if (!labWarnVos.isEmpty()) {

+ 2 - 0
app/src/main/java/xn/xxp/app/LabApp.java

@@ -18,6 +18,7 @@ import com.bumptech.glide.Glide;
 import com.github.anrwatchdog.ANRWatchDog;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
+import com.hikvision.hatomplayer.HatomPlayerSDK;
 import com.kongzue.dialogx.DialogX;
 import com.tencent.smtt.export.external.TbsCoreSettings;
 import com.tencent.smtt.sdk.QbSdk;
@@ -54,6 +55,7 @@ public class LabApp extends Application {
     @Override
     public void onCreate() {
         super.onCreate();
+        HatomPlayerSDK.init(this, "", true);
         Tool.INSTANCE.openAdb();
         gson = GsonUtils.getGson().newBuilder().serializeNulls().registerTypeAdapter(String.class, new StringNullAdapter()).create();
         GsonUtils.setGsonDelegate(gson);

+ 26 - 7
app/src/main/java/xn/xxp/home/adapter/HomeBoardAdapter.kt

@@ -69,13 +69,32 @@ public class HomeBoardAdapter :
     override fun convert(holder: BaseViewHolder, item: LabBulletinBoardVo) {
         val itemView = holder.itemView as ItemBoardView
         val itemVal = mValueMap[item.deviceNo]
-        itemView.setSensorInfo(item.deviceName, item.icon)
-        itemView.setSensorValue(
-            itemVal?.value,
-            itemVal?.unit,
-            mWarningSet.contains(item.deviceNo),
-            item.online
-        )
+        itemView.setSensorInfo(item.attributeName, item.icon)
+        if ("烟感" == item.attributeName) {
+            if (itemVal?.value == "0") {
+                itemView.setSensorValue(
+                    "正常",
+                    itemVal.unit,
+                    mWarningSet.contains(item.deviceNo),
+                    item.online
+                )
+            } else {
+                itemView.setSensorValue(
+                    "异常",
+                    itemVal?.unit,
+                    mWarningSet.contains(item.deviceNo),
+                    item.online
+                )
+            }
+        } else {
+            itemView.setSensorValue(
+                itemVal?.value,
+                itemVal?.unit,
+                mWarningSet.contains(item.deviceNo),
+                item.online
+            )
+        }
+
     }
 
     private data class BoardValue(val value: String?, val unit: String?, val formatVal: String?)

+ 15 - 1
app/src/main/java/xn/xxp/home/auth/ChoiceAuthActivity.java

@@ -8,6 +8,9 @@ import androidx.fragment.app.FragmentManager;
 import com.blankj.utilcode.util.ActivityUtils;
 import com.blankj.utilcode.util.FragmentUtils;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import core.ui.activity.BaseSignActivity;
 import http.vo.response.UserVo;
 import xn.xxp.HomeActivity;
@@ -19,10 +22,13 @@ import xn.xxp.home.AccessVerify;
 import xn.xxp.home.auth.fragment.CardAuthFragment;
 import xn.xxp.home.auth.fragment.LzFaceAuthFragment;
 import xn.xxp.home.auth.fragment.QrAuthFragment;
+import xn.xxp.home.notice.NoticeListActivity;
 import xn.xxp.main.MainActivity;
 import xn.xxp.room.RoomTool;
 import xn.xxp.room.bean.DeviceConfig;
 import xn.xxp.room.bean.LabConfig;
+import xn.xxp.room.bean.NoticeSummary;
+import xn.xxp.room.dao.NoticeSummaryDao;
 import xn.xxp.utils.Tool;
 import xn.xxp.widget.ITitleBar;
 import xn.xxp.widget.NavViewCompat;
@@ -36,7 +42,7 @@ public class ChoiceAuthActivity extends BaseSignActivity<ActivityAuthChoiceBindi
 
     @Override
     public ITitleBar getMTitleBar() {
-        return binding.titleBar;
+        return null;
     }
 
     @Override
@@ -57,6 +63,14 @@ public class ChoiceAuthActivity extends BaseSignActivity<ActivityAuthChoiceBindi
     @Override
     protected void initViews(Bundle savedInstanceState) {
         super.initViews(savedInstanceState);
+        binding.titleBar.setTitleInfoFromSp();
+        NoticeSummaryDao noticeSummaryDao = RoomTool.getInstance().noticeSummaryDao();
+        List<NoticeSummary> noticeSummaryList = noticeSummaryDao.getAll();
+        if (null == noticeSummaryList) {
+            noticeSummaryList = new ArrayList<>();
+        }
+        binding.titleBar.updateNotice(noticeSummaryList);
+        
         deviceConfig = RoomTool.getInstance().deviceConfigDao().getDeviceConfig();
         labConfig = RoomTool.getInstance().labConfigDao().getLabConfig();
         String access = getIntent().getStringExtra("access");

+ 6 - 4
app/src/main/java/xn/xxp/home/auth/fragment/LzFaceAuthFragment.java

@@ -245,7 +245,7 @@ public class LzFaceAuthFragment extends RcBaseFragment<FragmentAuthLzFaceBinding
                                             if (null == result) {
                                                 showToast("查询异常,请重试!");
                                                 ThreadUtils.runOnUiThreadDelayed(() -> {
-                                                    if (!isDetached()) {
+                                                    if (!isDetached() && isAdded() && getActivity() != null) {
                                                         checking = false;
                                                         FaceUtils.getInstance().startFaceRecog();
                                                     }
@@ -254,15 +254,17 @@ public class LzFaceAuthFragment extends RcBaseFragment<FragmentAuthLzFaceBinding
                                             }
                                             if (result.getFirst() != 200) {
                                                 ThreadUtils.runOnUiThreadDelayed(() -> {
-                                                    if (!isDetached()) {
+                                                    if (!isDetached() && isAdded() && getActivity() != null) {
                                                         checking = false;
                                                         FaceUtils.getInstance().startFaceRecog();
                                                     }
                                                 }, 1000);
                                                 showToast(result.getSecond());
                                             } else {
-                                                ChoiceAuthActivity fourChoiceAuthActivity = (ChoiceAuthActivity) LzFaceAuthFragment.this.requireActivity();
-                                                fourChoiceAuthActivity.authSuccess(AuthType.FACE, result.getThird());
+                                                if (isAdded() && getActivity() != null) {
+                                                    ChoiceAuthActivity fourChoiceAuthActivity = (ChoiceAuthActivity) LzFaceAuthFragment.this.requireActivity();
+                                                    fourChoiceAuthActivity.authSuccess(AuthType.FACE, result.getThird());
+                                                }
                                             }
                                         }
                                     }

+ 6 - 2
app/src/main/java/xn/xxp/home/auth/fragment/QrAuthFragment.java

@@ -13,6 +13,7 @@ import androidx.annotation.Nullable;
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.GsonUtils;
 import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ShellUtils;
 import com.blankj.utilcode.util.ThreadUtils;
 import com.blankj.utilcode.util.TimeUtils;
 import com.google.zxing.BarcodeFormat;
@@ -35,6 +36,7 @@ import xn.xxp.home.auth.ChoiceAuthActivity;
 import xn.xxp.room.RoomTool;
 import xn.xxp.room.bean.DeviceConfig;
 import xn.xxp.room.bean.LabConfig;
+import xn.xxp.utils.Tool;
 
 /**
  * 览众人脸识别
@@ -158,8 +160,10 @@ public class QrAuthFragment extends RcBaseFragment<FragmentAuthQrBinding> {
 
     @Override
     public void onDestroyView() {
-        qrTimer.cancel();
-        qrTimer = null;
+        if (null != qrTimer) {
+            qrTimer.cancel();
+            qrTimer = null;
+        }
         super.onDestroyView();
 
     }

+ 2 - 8
app/src/main/java/xn/xxp/main/MainActivity.kt

@@ -46,7 +46,7 @@ import xn.xxp.app.LabApp
 import xn.xxp.app.SettingActivity
 import xn.xxp.databinding.ActivityMainBinding
 import xn.xxp.home.lab_info.LabDetailActivity
-import xn.xxp.main.monitor.MonitorListActivity
+import xn.xxp.main.monitor.MonitorActivity
 import xn.xxp.main.person.LaboratoryPersonActivity
 import xn.xxp.main.risk.RiskListActivity
 import xn.xxp.main.rule.RuleActivity
@@ -338,14 +338,9 @@ class MainActivity :
 
             true
         }
-        // 信息牌
-        binding.labDetail.setOnClickListener(FastClickDelegate {
-            val intent = Intent(this, LabDetailActivity::class.java)
-            startActivity(intent)
-        })
         // 视频监控
         binding.monitor.setOnClickListener(FastClickDelegate {
-            val intent = Intent(this, MonitorListActivity::class.java)
+            val intent = Intent(this, MonitorActivity::class.java)
             startActivity(intent)
         })
         // 人员信息(老师)/实验人员(学生)
@@ -355,7 +350,6 @@ class MainActivity :
         })
         // 规章制度
         binding.safetyRegulation.setOnClickListener(FastClickDelegate {
-            // TODO 规章制度需要手动用java重写
             val intent = Intent(this, RuleActivity::class.java)
             startActivity(intent)
         })

+ 3 - 3
app/src/main/java/xn/xxp/main/MainBoardAdapter.java

@@ -121,10 +121,10 @@ public class MainBoardAdapter extends BaseQuickAdapter<LabBulletinBoardVo, BaseV
     protected void convert(@NonNull BaseViewHolder baseViewHolder, LabBulletinBoardVo labBulletinBoardVo) {
         ItemBoardView itemView = (ItemBoardView) baseViewHolder.itemView;
         BoardValue itemVal = mValueMap.get(labBulletinBoardVo.deviceNo);
-        itemView.setSensorInfo(labBulletinBoardVo.deviceName, labBulletinBoardVo.icon);
+        itemView.setSensorInfo(labBulletinBoardVo.attributeName, labBulletinBoardVo.icon);
         itemView.setSensorValue(
-                itemVal != null ? itemVal.value() : null,
-                itemVal != null ? itemVal.unit() : null,
+                itemVal != null ? itemVal.value() : "",
+                itemVal != null ? itemVal.unit() : "",
                 mWarningSet.contains(labBulletinBoardVo.deviceNo),
                 labBulletinBoardVo.online
         );

+ 225 - 10
app/src/main/java/xn/xxp/main/monitor/MonitorActivity.java

@@ -1,20 +1,235 @@
 package xn.xxp.main.monitor;
 
+import android.content.DialogInterface;
+import android.graphics.SurfaceTexture;
 import android.os.Bundle;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.GridLayout;
 
-import androidx.activity.EdgeToEdge;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
 
-import xn.xxp.R;
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+import com.hikvision.hatomplayer.DefaultHatomPlayer;
+import com.hikvision.hatomplayer.HatomPlayer;
+import com.hikvision.hatomplayer.PlayCallback;
+import com.hikvision.hatomplayer.PlayConfig;
+import com.hikvision.hatomplayer.core.Quality;
 
-public class MonitorActivity extends AppCompatActivity {
+import java.util.ArrayList;
+import java.util.List;
+
+import core.ui.activity.BaseCountDownActivity;
+import core.util.FastClickDelegate;
+import http.client.ApiRepository;
+import http.vo.response.MonitorVo;
+import io.reactivex.rxjava3.functions.Consumer;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+import xn.xxp.app.LabApp;
+import xn.xxp.databinding.ActivityMonitorBinding;
+import xn.xxp.main.risk.VideoDialogFragment;
+import xn.xxp.room.RoomTool;
+import xn.xxp.room.bean.LabConfig;
+import xn.xxp.widget.ITitleBar;
+import xn.xxp.widget.NavViewCompat;
+
+public class MonitorActivity extends BaseCountDownActivity<ActivityMonitorBinding> {
+
+    private ActivityMonitorBinding binding;
+    private List<MonitorInfo> monitorInfoList = new ArrayList<>();
+    private MonitorDialog monitorDialog;
+
+    @Override
+    public ITitleBar getMTitleBar() {
+        return binding.titleBar;
+    }
+
+    @Override
+    public NavViewCompat getMNavView() {
+        return null;
+    }
+
+    @Override
+    protected ActivityMonitorBinding createViewBinding() {
+        return binding = ActivityMonitorBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected void initViews(Bundle savedInstanceState) {
+        super.initViews(savedInstanceState);
+        binding.navView.setNavListener(new NavViewCompat.NavListener() {
+            @Override
+            public void onHomeViewClicked() {
+                logoutCountDownFinish();
+            }
+
+            @Override
+            public void onBackViewClicked() {
+                showLoading("正在退出...");
+                ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Object>() {
+                    @Override
+                    public Object doInBackground() throws Throwable {
+                        if (null != monitorInfoList) {
+                            for (int i = 0; i < monitorInfoList.size(); i++) {
+                                MonitorInfo monitorInfo = monitorInfoList.get(i);
+                                HatomPlayer hatomPlayer = monitorInfo.getHatomPlayer();
+                                if (null != hatomPlayer) {
+                                    hatomPlayer.stop();
+                                }
+                            }
+                        }
+                        return null;
+                    }
+
+                    @Override
+                    public void onSuccess(Object result) {
+                        dismissLoading();
+                        finish();
+                    }
+                });
+            }
+
+            @Override
+            public void onFingerEnrollViewClicked() {
+
+            }
+        });
+
+
+        LabConfig labConfig = RoomTool.getInstance().labConfigDao().getLabConfig();
+        showLoading("加载中...");
+        addDisposable(ApiRepository.INSTANCE.cameraBySubjectId(String.valueOf(labConfig.getLabId()), LabApp.userVo.userId, LabApp.userVo.userName, 3).subscribe(new Consumer<List<MonitorVo>>() {
+            @Override
+            public void accept(List<MonitorVo> monitorVos) throws Throwable {
+                if (null != monitorVos && !monitorVos.isEmpty()) {
+                    binding.gridLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+                        @Override
+                        public void onGlobalLayout() {
+                            binding.gridLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                            int width = binding.gridLayout.getWidth();
+                            int height = binding.gridLayout.getHeight();
+
+                            for (int i = 0; i < monitorVos.size(); i++) {
+                                MonitorVo monitorVo = monitorVos.get(i);
+                                MonitorInfo monitorInfo = new MonitorInfo();
+                                TextureView textureView = new TextureView(MonitorActivity.this);
+                                GridLayout.LayoutParams params = new GridLayout.LayoutParams();
+                                params.width = width / 3;
+                                params.height = height / 3;
+                                params.setMargins(5, 5, 5, 5); // 设置间距
+                                textureView.setLayoutParams(params);
+                                textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
+                                    @Override
+                                    public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
+                                        for (int j = 0; j < monitorInfoList.size(); j++) {
+                                            MonitorInfo monitorInfo = monitorInfoList.get(j);
+                                            SurfaceTexture surfaceTexture = monitorInfo.getTextureView().getSurfaceTexture();
+                                            if (surfaceTexture == surface) {
+                                                play(monitorInfo.getHatomPlayer(), surface, monitorInfo.getMonitorVo().streamUrl);
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    @Override
+                                    public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
+
+                                    }
+
+                                    @Override
+                                    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+                                        return false;
+                                    }
+
+                                    @Override
+                                    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+
+                                    }
+                                });
+
+                                textureView.setOnClickListener(new FastClickDelegate(new Function1<View, Unit>() {
+                                    @Override
+                                    public Unit invoke(View view) {
+                                        for (int j = 0; j < monitorInfoList.size(); j++) {
+                                            MonitorInfo monitorInfo = monitorInfoList.get(j);
+                                            if (monitorInfo.getTextureView() == view) {
+                                                monitorDialog = new MonitorDialog(MonitorActivity.this, monitorInfo, new DialogInterface.OnDismissListener() {
+                                                    @Override
+                                                    public void onDismiss(DialogInterface dialog) {
+                                                        dialog.dismiss();
+                                                        monitorDialog = null;
+                                                    }
+                                                });
+                                                monitorDialog.show();
+                                                break;
+                                            }
+                                        }
+                                        return null;
+                                    }
+                                }));
+
+                                HatomPlayer hatomPlayer = new DefaultHatomPlayer();
+                                PlayConfig playConfig = new PlayConfig();
+                                playConfig.hardDecode = true;
+                                playConfig.privateData = true;
+                                hatomPlayer.setPlayConfig(playConfig);
+                                hatomPlayer.setPlayStatusCallback(new PlayCallback.PlayStatusCallback() {
+                                    @Override
+                                    public void onPlayerStatus(@NonNull PlayCallback.Status status, String s) {
+                                        LogUtils.d(status, s);
+                                    }
+                                });
+
+                                monitorInfo.setTextureView(textureView);
+                                monitorInfo.setMonitorVo(monitorVo);
+                                monitorInfo.setHatomPlayer(hatomPlayer);
+
+                                monitorInfoList.add(monitorInfo);
+
+                                binding.gridLayout.addView(textureView);
+                            }
+
+                            dismissLoading();
+                        }
+                    });
+                }
+            }
+        }, new Consumer<Throwable>() {
+            @Override
+            public void accept(Throwable throwable) throws Throwable {
+                dismissLoading();
+            }
+        }));
+    }
+
+    private void play(HatomPlayer hatomPlayer, SurfaceTexture surfaceTexture, String url) {
+        ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Object>() {
+            @Override
+            public Object doInBackground() throws Throwable {
+                hatomPlayer.setSurfaceTexture(surfaceTexture);
+                hatomPlayer.setDataSource(url, null);
+                hatomPlayer.changeStream(Quality.SUB_STREAM_LOW);
+                hatomPlayer.start();
+                return null;
+            }
+
+            @Override
+            public void onSuccess(Object result) {
+
+            }
+        });
+    }
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_monitor);
+    protected void onDestroy() {
+        Fragment fragment = getSupportFragmentManager().findFragmentByTag("video_dialog");
+        if (fragment instanceof VideoDialogFragment) {
+            ((VideoDialogFragment) fragment).dismissAllowingStateLoss();
+        }
+        super.onDestroy();
     }
 }

+ 141 - 0
app/src/main/java/xn/xxp/main/monitor/MonitorDialog.java

@@ -0,0 +1,141 @@
+package xn.xxp.main.monitor;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.view.TextureView;
+import android.view.View;
+import android.view.Window;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ThreadUtils;
+import com.hikvision.hatomplayer.DefaultHatomPlayer;
+import com.hikvision.hatomplayer.HatomPlayer;
+import com.hikvision.hatomplayer.PlayCallback;
+import com.hikvision.hatomplayer.PlayConfig;
+import com.hikvision.hatomplayer.core.Quality;
+
+import core.util.FastClickDelegate;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+import xn.xxp.R;
+
+
+public class MonitorDialog extends Dialog {
+
+    private final MonitorInfo monitorInfo;
+    private HatomPlayer hatomPlayer;
+    private TextView textView;
+
+    public MonitorDialog(@NonNull Context context, MonitorInfo monitorInfo, OnDismissListener dismissListener) {
+        super(context, R.style.FullScreenDialog);
+        this.monitorInfo = monitorInfo;
+        setOnDismissListener(dismissListener);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.dialog_monitor);
+        Window window = getWindow();
+        if (window != null) {
+            window.setWindowAnimations(R.style.DialogAnimation);
+        }
+        initVideoPlayer();
+    }
+
+    private void initVideoPlayer() {
+        TextureView textureView = findViewById(R.id.textureView);
+        textView = findViewById(R.id.back);
+        textView.setOnClickListener(new FastClickDelegate(new Function1<View, Unit>() {
+            @Override
+            public Unit invoke(View view) {
+                textView.setText("正在退出...");
+                releasePlayer();
+                return null;
+            }
+        }));
+        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
+            @Override
+            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
+                ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Object>() {
+                    @Override
+                    public Object doInBackground() throws Throwable {
+                        hatomPlayer = new DefaultHatomPlayer();
+                        PlayConfig playConfig = new PlayConfig();
+                        playConfig.hardDecode = true;
+                        playConfig.privateData = true;
+                        hatomPlayer.setPlayConfig(playConfig);
+                        hatomPlayer.setPlayStatusCallback(new PlayCallback.PlayStatusCallback() {
+                            @Override
+                            public void onPlayerStatus(@NonNull PlayCallback.Status status, String s) {
+                                LogUtils.d(status, s);
+                            }
+                        });
+                        hatomPlayer.setSurfaceTexture(surface);
+                        hatomPlayer.setDataSource(monitorInfo.getMonitorVo().streamUrl, null);
+                        hatomPlayer.changeStream(Quality.STREAM_SUPER_CLEAR);
+                        hatomPlayer.start();
+                        return null;
+                    }
+
+                    @Override
+                    public void onSuccess(Object result) {
+
+                    }
+                });
+            }
+
+            @Override
+            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
+
+            }
+
+            @Override
+            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+                return false;
+            }
+
+            @Override
+            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+
+            }
+        });
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        releasePlayer();
+    }
+
+    /**
+     * 释放播放器资源
+     */
+    private void releasePlayer() {
+        if (hatomPlayer != null) {
+            dismiss();
+            ThreadUtils.executeByCached(new ThreadUtils.SimpleTask<Object>() {
+                @Override
+                public Object doInBackground() throws Throwable {
+                    hatomPlayer.stop(); // 释放播放器
+                    return null;
+                }
+
+                @Override
+                public void onSuccess(Object result) {
+                    dismiss();
+                }
+            });
+            textView.setOnClickListener(null);
+            hatomPlayer = null; // 置空防止内存泄漏
+        } else {
+            dismiss();
+        }
+    }
+}

+ 46 - 0
app/src/main/java/xn/xxp/main/monitor/MonitorInfo.java

@@ -0,0 +1,46 @@
+package xn.xxp.main.monitor;
+
+import android.view.TextureView;
+
+import com.hikvision.hatomplayer.HatomPlayer;
+
+import http.vo.response.MonitorVo;
+
+public class MonitorInfo {
+    private TextureView textureView;
+    private HatomPlayer hatomPlayer;
+    private MonitorVo monitorVo;
+    private boolean isFull;
+
+    public boolean isFull() {
+        return isFull;
+    }
+
+    public void setFull(boolean full) {
+        isFull = full;
+    }
+
+    public TextureView getTextureView() {
+        return textureView;
+    }
+
+    public void setTextureView(TextureView textureView) {
+        this.textureView = textureView;
+    }
+
+    public HatomPlayer getHatomPlayer() {
+        return hatomPlayer;
+    }
+
+    public void setHatomPlayer(HatomPlayer hatomPlayer) {
+        this.hatomPlayer = hatomPlayer;
+    }
+
+    public MonitorVo getMonitorVo() {
+        return monitorVo;
+    }
+
+    public void setMonitorVo(MonitorVo monitorVo) {
+        this.monitorVo = monitorVo;
+    }
+}

+ 0 - 174
app/src/main/java/xn/xxp/main/monitor/MonitorListActivity.kt

@@ -1,174 +0,0 @@
-package xn.xxp.main.monitor
-
-import android.os.Bundle
-import android.view.View
-import android.view.ViewGroup
-import com.hikvision.open.ui.preview.PlayWindowView
-import core.ui.activity.BaseCountDownActivity
-import http.client.ApiRepository
-import http.vo.response.MonitorVo
-import play.model.PlayStatus
-import play.widget.window.WindowGroup
-import xn.xxp.app.LabApp
-import xn.xxp.databinding.ActivityMonitorListBinding
-import xn.xxp.room.RoomTool
-import xn.xxp.room.bean.LabConfig
-import xn.xxp.utils.Tool
-import xn.xxp.widget.ITitleBar
-import xn.xxp.widget.NavViewCompat
-
-/**
- * 视频监控
- *
- * @author ReiChin_
- */
-class MonitorListActivity :
-    BaseCountDownActivity<ActivityMonitorListBinding>() {
-
-    lateinit var labConfig: LabConfig
-    override fun getMTitleBar(): ITitleBar {
-        return binding.titleBar
-    }
-
-    override fun getMNavView(): NavViewCompat {
-        return binding.navView
-    }
-
-    private val groupAdapter by lazy {
-        binding.windowGroup.windowGroupAdapter
-    }
-
-    override fun createViewBinding() = ActivityMonitorListBinding.inflate(layoutInflater)
-
-    private var mFullScreen = false
-
-    override fun initViews(savedInstanceState: Bundle?) {
-        super.initViews(savedInstanceState)
-        labConfig = RoomTool.getInstance().labConfigDao().labConfig
-        initWindowGroup()
-        binding.autoHideView.setOnFullScreenListener {
-            mFullScreen = !mFullScreen
-            if (mFullScreen) {
-                binding.titleBar.visibility = View.GONE
-                binding.navView.visibility = View.GONE
-
-                val layoutParams = binding.content.layoutParams as ViewGroup.MarginLayoutParams
-                layoutParams.leftMargin = 0
-                layoutParams.rightMargin = 0
-                layoutParams.topMargin = 0
-                layoutParams.bottomMargin = 0
-                binding.content.setPadding(0, 0, 0, 0)
-            } else {
-                binding.titleBar.visibility = View.VISIBLE
-                binding.navView.visibility = View.VISIBLE
-
-                val layoutParams = binding.content.layoutParams as ViewGroup.MarginLayoutParams
-                layoutParams.leftMargin = Tool.INSTANCE.dip2px(17f)
-                layoutParams.rightMargin = Tool.INSTANCE.dip2px(17f)
-                layoutParams.topMargin = Tool.INSTANCE.dip2px(7f)
-                layoutParams.bottomMargin = Tool.INSTANCE.dip2px(50f)
-                val paddingH = Tool.INSTANCE.dip2px(45f)
-                val paddingV = Tool.INSTANCE.dip2px(26f)
-                binding.content.setPadding(paddingH, paddingV, paddingH, paddingV)
-            }
-            return@setOnFullScreenListener mFullScreen
-        }
-    }
-
-    private fun initWindowGroup() {
-        //默认选中第一个窗口
-        binding.windowGroup.selectedCurrFirstWindow()
-        groupAdapter.windowItemStructAllList.forEach {
-            //设置点击事件
-            it.setOnSingleClickListener { lastWindowSerial, currentWindowSerial ->
-                //上一次选中的窗口序列号和当前选中窗口序列号不一致
-                if (lastWindowSerial != currentWindowSerial) {
-                    return@setOnSingleClickListener
-                }
-                //判断是否展示
-                if (binding.autoHideView.isVisible) {
-                    binding.autoHideView.hide()
-                } else {
-                    binding.autoHideView.show()
-                }
-            }
-        }
-        groupAdapter.setWindowForbidMove(true)
-    }
-
-    override fun onRestart() {
-        super.onRestart()
-        //界面重新展示时,通知窗口可见了
-        groupAdapter.setPageChangeEvent(groupAdapter.currentPage, groupAdapter.windowMode)
-    }
-
-
-    override fun onStop() {
-        super.onStop()
-        //界面到后台时,通知窗口不可见了
-        groupAdapter.windowItemStructAllList.forEach {
-            if (it.userVisibleHint) {
-                it.userVisibleHint = false
-            }
-        }
-    }
-
-    override fun initData() {
-        showLoading("请稍等...")
-        val disposable = ApiRepository.cameraBySubjectId(
-            labConfig.labId.toString(),
-            LabApp.userVo.userId,
-            LabApp.userVo.userName,
-            3
-        )
-            .subscribe({ data ->
-                dismissLoading()
-                dispatchLoadDataSuccess(data)
-            }, { throwable ->
-                dismissLoading()
-                showNetError(throwable)
-                throwable.printStackTrace()
-            })
-        addDisposable(disposable)
-    }
-
-    private var mMonitorData: List<MonitorVo>? = null
-
-    private fun dispatchLoadDataSuccess(data: List<MonitorVo>?) {
-        if (data.isNullOrEmpty()) {
-            showToast("暂无数据")
-            return
-        }
-        mMonitorData = data
-
-        groupAdapter.windowMode = calcWindowMode(data.size)
-        groupAdapter.setCurrentNeedWindowCount(data.size)
-        groupAdapter.notifyDataSetChanged()
-        groupAdapter.allDoubleClickEnable = WindowGroup.WINDOW_MODE_ONE != groupAdapter.windowMode
-
-        groupAdapter.windowItemStructAllList.forEachIndexed { index, item ->
-            if (mMonitorData.isNullOrEmpty() || index >= mMonitorData!!.size) return@forEachIndexed
-
-            val monitorVo: MonitorVo = mMonitorData!![index % mMonitorData!!.size]
-            val playWindowView = item as PlayWindowView
-            if (playWindowView.getPlayStatus() != PlayStatus.PLAYING) {
-                playWindowView.setHardDecodePlay(true)
-                playWindowView.setSmartDetect(true)
-                playWindowView.startPlay(monitorVo.streamUrl)
-            } else {
-                playWindowView.changeStream(monitorVo.streamUrl)
-            }
-        }
-    }
-
-    private fun calcWindowMode(size: Int): Int {
-        return when {
-            size == 1 -> WindowGroup.WINDOW_MODE_ONE
-            size <= 4 -> WindowGroup.WINDOW_MODE_FOUR
-            size <= 9 -> WindowGroup.WINDOW_MODE_NINE
-            size <= 16 -> WindowGroup.WINDOW_MODE_SIXTEEN
-            else -> WindowGroup.WINDOW_MODE_FOUR
-        }
-    }
-
-}

+ 0 - 12
app/src/main/java/xn/xxp/main/risk/VideoDialogFragment.java

@@ -40,14 +40,11 @@ import xn.xxp.R;
  */
 public class VideoDialogFragment extends DialogFragment {
 
-    // region 成员变量
     private StandardGSYVideoPlayer videoPlayer; // 视频播放器核心组件
     private String videoUrl;                    // 当前播放视频URL
     private String videoTitle;                  // 视频标题
     private LifecycleObserver lifecycleObserver;// Activity生命周期观察者
-    // endregion
 
-    // region 单例管理
     /**
      * 使用弱引用管理实例,防止内存泄漏
      * WeakReference在内存不足时会被GC回收,避免DialogFragment无法释放
@@ -72,9 +69,6 @@ public class VideoDialogFragment extends DialogFragment {
         instance.setVideoData(url, title); // 更新数据
         return instance;
     }
-    // endregion
-
-    // region 数据配置
 
     /**
      * 设置视频数据(用于实例复用)
@@ -86,9 +80,7 @@ public class VideoDialogFragment extends DialogFragment {
         this.videoUrl = url;
         this.videoTitle = title;
     }
-    // endregion
 
-    // region 生命周期管理
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -201,9 +193,6 @@ public class VideoDialogFragment extends DialogFragment {
         }
         super.onDestroy();
     }
-    // endregion
-
-    // region 播放器管理
 
     /**
      * 初始化视频播放器
@@ -259,5 +248,4 @@ public class VideoDialogFragment extends DialogFragment {
             videoPlayer = null; // 置空防止内存泄漏
         }
     }
-    // endregion
 }

+ 11 - 7
app/src/main/java/xn/xxp/main/rule/RuleActivity.java

@@ -21,6 +21,8 @@ import http.client.ApiRepository;
 import http.net.UrlValidator;
 import http.vo.request.SafetyListReq;
 import http.vo.response.SafeBook;
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.disposables.Disposable;
 import io.reactivex.rxjava3.functions.Consumer;
 import kotlin.Unit;
 import kotlin.jvm.functions.Function1;
@@ -73,7 +75,7 @@ public class RuleActivity extends BaseCountDownActivity<ActivityRuleBinding> {
             }
         }));
         // 中心制度
-        binding.schoolSystem.setOnClickListener(new FastClickDelegate(new Function1<View, Unit>() {
+        binding.centerSystem.setOnClickListener(new FastClickDelegate(new Function1<View, Unit>() {
             @Override
             public Unit invoke(View view) {
                 mSystemFlag = "3";
@@ -86,7 +88,6 @@ public class RuleActivity extends BaseCountDownActivity<ActivityRuleBinding> {
             @Override
             public void onRefresh() {
                 queryData();
-
             }
         });
         ruleAdapter = new RuleAdapter(safeBookList);
@@ -143,11 +144,13 @@ public class RuleActivity extends BaseCountDownActivity<ActivityRuleBinding> {
         queryData();
     }
 
+    private Disposable disposable;
+
     private void queryData() {
-        SafetyListReq safetyListReq = new SafetyListReq();
-        safetyListReq.type = mSystemFlag;
-        LogUtils.json(safetyListReq);
-        addDisposable(ApiRepository.INSTANCE.safeBookList(safetyListReq).subscribe(new Consumer<List<SafeBook>>() {
+        if (null != disposable) {
+            removeDisposable(disposable);
+        }
+        disposable = ApiRepository.INSTANCE.safeBookList(mSystemFlag).subscribe(new Consumer<List<SafeBook>>() {
             @Override
             public void accept(List<SafeBook> safeBooks) throws Throwable {
                 dispatchLoadDataSuccess(safeBooks);
@@ -158,7 +161,8 @@ public class RuleActivity extends BaseCountDownActivity<ActivityRuleBinding> {
                 LogUtils.e(Log.getStackTraceString(throwable));
                 dispatchLoadDataFailure(throwable);
             }
-        }));
+        });
+        addDisposable(disposable);
     }
 
     private void dispatchLoadDataFailure(Throwable throwable) {

+ 11 - 3
app/src/main/java/xn/xxp/main/rule/RuleDetailActivity.java

@@ -4,6 +4,7 @@ import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 
@@ -74,7 +75,12 @@ public class RuleDetailActivity extends BaseCountDownActivity<ActivityRuleDetail
     @Override
     protected void initData() {
         super.initData();
-        binding.titleText.setText(safeBook.name);
+        if (null == safeBook || TextUtils.isEmpty(safeBook.content)) {
+            showToast("无法预览,请重新上传文件!");
+            finish();
+            return;
+        }
+        binding.titleText.setText(TextUtils.isEmpty(safeBook.name) ? "" : safeBook.name);
         showLoading("加载中...");
         downloadHelper = new DownloadHelper(this);
         downloadHelper.startDownload(safeBook.content, "pdf.pdf", 3399, new DownloadHelper.DownloadCallback() {
@@ -158,8 +164,10 @@ public class RuleDetailActivity extends BaseCountDownActivity<ActivityRuleDetail
 
     @Override
     protected void onDestroy() {
-        downloadHelper.cancelDownload(3399);
-        downloadHelper.release();
+        if (null != downloadHelper) {
+            downloadHelper.cancelDownload(3399);
+            downloadHelper.release();
+        }
         super.onDestroy();
     }
 

+ 7 - 2
app/src/main/java/xn/xxp/mqtt/MqttManager.kt

@@ -51,7 +51,12 @@ class MqttManager private constructor() {
         deviceConfig = RoomTool.getInstance().deviceConfigDao().deviceConfig
         labConfig = RoomTool.getInstance().labConfigDao().labConfig
         this.clientId = "${deviceConfig.devId}#${System.nanoTime()}"
-        LogUtils.d("MQTT配置", deviceConfig.mqttAddress, deviceConfig.mqttName, deviceConfig.mqttPas)
+        LogUtils.d(
+            "MQTT配置",
+            deviceConfig.mqttAddress,
+            deviceConfig.mqttName,
+            deviceConfig.mqttPas
+        )
         mMqttWorker = MqttWorker(
             deviceConfig.mqttAddress,
             clientId,
@@ -77,7 +82,7 @@ class MqttManager private constructor() {
             }
 
             override fun messageArrived(topic: String?, message: MqttMessage?) {
-                LogUtils.d("MQTT接收", topic, message)
+                LogUtils.d("MQTT接收", mMqttWorker, topic, message)
                 dispatchMessage(topic, message.toString())
             }
         })

+ 3 - 0
app/src/main/java/xn/xxp/utils/Tool.java

@@ -2,12 +2,15 @@ package xn.xxp.utils;
 
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.LogUtils;
+import com.blankj.utilcode.util.ShellUtils;
 import com.blankj.utilcode.util.ThreadUtils;
 import com.blankj.utilcode.util.ToastUtils;
 import com.blankj.utilcode.util.Utils;
 import com.hikvision.dmb.system.InfoSystemApi;
 import com.njlz.card.DeviceUtils;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 public enum Tool {

+ 7 - 2
app/src/main/java/xn/xxp/widget/ItemBoardView.kt

@@ -9,6 +9,7 @@ import android.graphics.drawable.AnimationDrawable
 import android.graphics.drawable.PictureDrawable
 import android.text.SpannableString
 import android.text.Spanned
+import android.text.TextUtils
 import android.text.style.RelativeSizeSpan
 import android.util.AttributeSet
 import android.view.LayoutInflater
@@ -46,12 +47,12 @@ class ItemBoardView @JvmOverloads constructor(
     }
 
     fun setSensorInfo(sensorName: String?, drawableResId: Int) {
-        viewBinding.sensorName.text = sensorName
+        viewBinding.sensorName.text = if (TextUtils.isEmpty(sensorName)) "" else (sensorName)
         viewBinding.sensorIcon.setImageResource(drawableResId)
     }
 
     fun setSensorInfo(sensorName: String?, url: String) {
-        viewBinding.sensorName.text = sensorName
+        viewBinding.sensorName.text = if (TextUtils.isEmpty(sensorName)) "" else (sensorName)
 
 //        val tintPaint = Paint().apply {
 //            colorFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
@@ -77,11 +78,15 @@ class ItemBoardView @JvmOverloads constructor(
         }
         viewBinding.sensorValue.text = formatVal
         if (warning) {
+            if (value == "异常") {
+                viewBinding.sensorValue.setTextColor(Color.RED)
+            }
             if (viewBinding.root.background != mAnimDrawable) {
                 viewBinding.root.background = mAnimDrawable
             }
             if (!mAnimDrawable.isRunning) mAnimDrawable.start()
         } else {
+            viewBinding.sensorValue.setTextColor(Color.WHITE)
             if (mAnimDrawable.isRunning) mAnimDrawable.stop()
             viewBinding.root.setBackgroundResource(R.mipmap.icon_sensor_none)
         }

BIN
app/src/main/jniLibs/arm64-v8a/libAudioEngine.so


BIN
app/src/main/jniLibs/arm64-v8a/libFormatConversion.so


BIN
app/src/main/jniLibs/arm64-v8a/libFormatConversionSDK.so


BIN
app/src/main/jniLibs/arm64-v8a/libHPSClient.so


BIN
app/src/main/jniLibs/arm64-v8a/libHPSClientSDK.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaACodec.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaAssistant.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaExtractor.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaMuxer.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaPostProc.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaVDecode.so


BIN
app/src/main/jniLibs/arm64-v8a/libMediaVEncode.so


BIN
app/src/main/jniLibs/arm64-v8a/libPlayCtrl.so


BIN
app/src/main/jniLibs/arm64-v8a/libSystemTransform.so


BIN
app/src/main/jniLibs/arm64-v8a/libcrypto.so


BIN
app/src/main/jniLibs/arm64-v8a/libssl.so


BIN
app/src/main/jniLibs/armeabi-v7a/libAudioEngine.so


BIN
app/src/main/jniLibs/armeabi-v7a/libFormatConversion.so


BIN
app/src/main/jniLibs/armeabi-v7a/libFormatConversionSDK.so


BIN
app/src/main/jniLibs/armeabi-v7a/libHPSClient.so


BIN
app/src/main/jniLibs/armeabi-v7a/libHPSClientSDK.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaACodec.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaAssistant.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaExtractor.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaMuxer.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaPostProc.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaVDecode.so


BIN
app/src/main/jniLibs/armeabi-v7a/libMediaVEncode.so


BIN
app/src/main/jniLibs/armeabi-v7a/libPlayCtrl.so


BIN
app/src/main/jniLibs/armeabi-v7a/libSystemTransform.so


BIN
app/src/main/jniLibs/armeabi-v7a/libcrypto.so


BIN
app/src/main/jniLibs/armeabi-v7a/libssl.so


+ 0 - 13
app/src/main/res/layout/activity_main.xml

@@ -222,7 +222,6 @@
                 android:textColor="#ffffffff"
                 android:textSize="18sp"
                 app:layout_constraintBottom_toBottomOf="parent"
-                app:layout_constraintEnd_toStartOf="@id/labDetail"
                 app:layout_constraintStart_toEndOf="@id/labLevel"
                 app:layout_constraintTop_toTopOf="parent"
                 tools:text="大气污染控制工程实验室" />
@@ -240,18 +239,6 @@
                 app:round="6dp"
                 tools:src="@mipmap/img_sy_ewm" />
 
-            <TextView
-                android:id="@+id/labDetail"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="16dp"
-                android:text="信息牌 >>"
-                android:textColor="@android:color/white"
-                android:textSize="14sp"
-                app:layout_constraintBottom_toBottomOf="parent"
-                app:layout_constraintEnd_toStartOf="@id/qrCode"
-                app:layout_constraintTop_toTopOf="parent" />
-
         </androidx.constraintlayout.widget.ConstraintLayout>
 
         <ImageView

+ 33 - 2
app/src/main/res/layout/activity_monitor.xml

@@ -1,10 +1,41 @@
 <?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/main"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@mipmap/img_bg"
+    android:orientation="vertical"
     tools:context=".main.monitor.MonitorActivity">
 
-</androidx.constraintlayout.widget.ConstraintLayout>
+    <xn.xxp.widget.TitleBar
+        android:id="@+id/titleBar"
+        android:layout_width="match_parent"
+        android:layout_height="56dp"
+        android:background="@mipmap/img_navigation_bg"
+        app:showNotice="true"
+        app:signed="true" />
+
+    <xn.xxp.widget.NavViewCompat
+        android:id="@+id/nav_view"
+        android:layout_width="match_parent"
+        android:layout_height="42dp"
+        app:location="视频监控"
+        app:showBack="true"
+        app:showHome="true" />
+
+    <GridLayout
+        android:id="@+id/gridLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="20dp"
+        android:background="@drawable/shape_rect_round_11_solid_white_20p"
+        android:columnCount="3"
+        android:orientation="horizontal"
+        android:padding="8dp"
+        android:rowCount="3">
+
+    </GridLayout>
+
+</LinearLayout>

+ 33 - 0
app/src/main/res/layout/dialog_monitor.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#073388">
+
+    <ProgressBar
+        android:layout_width="100px"
+        android:layout_height="100px"
+        android:layout_centerInParent="true" />
+
+    <TextureView
+        android:id="@+id/textureView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:keepScreenOn="true" />
+
+    <TextView
+        android:id="@+id/back"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_margin="20dp"
+        android:background="@drawable/shape_rect_round_5_solid"
+        android:drawablePadding="10dp"
+        android:gravity="center"
+        android:paddingHorizontal="10dp"
+        android:paddingVertical="5dp"
+        android:text="返回"
+        android:textColor="@color/white"
+        app:drawableStartCompat="@mipmap/icon_sys_return" />
+</RelativeLayout>

+ 8 - 0
gradle/libs.versions.toml

@@ -1,9 +1,13 @@
 [versions]
 agp = "8.6.1"
+androidPdfViewer = "3.2.0-beta.1"
 annotation = "1.9.1"
 coil = "2.7.0"
 coilSvg = "2.7.0"
 fotoapparat = "2.7.0"
+gsyvideoplayerJava = "8.1.0"
+gsyvideoplayerArmv7a = "8.1.0"
+jsoup = "1.16.2"
 zxing-core = "3.5.3"
 zxing-android-core = "3.3.0"
 dialogx = "0.0.49"
@@ -40,6 +44,7 @@ xxpermissions = "20.0"
 
 [libraries]
 adapter-rxjava3 = { module = "com.squareup.retrofit2:adapter-rxjava3", version.ref = "retrofit" }
+android-pdf-viewer = { module = "com.github.barteksc:android-pdf-viewer", version.ref = "androidPdfViewer" }
 androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
 androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
 androidx-lifecycle-extensions = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "lifecycleExtensions" }
@@ -53,6 +58,9 @@ coil = { module = "io.coil-kt:coil", version.ref = "coil" }
 converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
 converter-scalars = { module = "com.squareup.retrofit2:converter-scalars", version.ref = "retrofit" }
 fotoapparat = { module = "io.fotoapparat:fotoapparat", version.ref = "fotoapparat" }
+gsyvideoplayer-armv7a = { module = "com.shuyu:gsyVideoPlayer-armv7a", version.ref = "gsyvideoplayerArmv7a" }
+gsyvideoplayer-java = { module = "com.shuyu:gsyVideoPlayer-java", version.ref = "gsyvideoplayerJava" }
+jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
 zxing-core = { module = "com.google.zxing:core", version.ref = "zxing-core" }
 zxing-android-core = { module = "com.google.zxing:android-core", version.ref = "zxing-android-core" }
 dialogx = { module = "com.github.kongzue.DialogX:DialogX", version.ref = "dialogx" }