ソースを参照

1、DJI SDK版本升级到5.5.0
2、遥控器硬件的代码控制(必须控制采有反应)初步测试成功

不会爬树的猴 1 年間 前
コミット
ebbeedc785
38 ファイル変更1513 行追加160 行削除
  1. 2 3
      .idea/deploymentTargetDropDown.xml
  2. 18 19
      app/build.gradle
  3. 7 11
      app/src/main/AndroidManifest.xml
  4. 39 0
      app/src/main/java/com/cr/common/CrAudioUtil.kt
  5. 52 0
      app/src/main/java/com/cr/common/CrCameraInfo.kt
  6. 20 0
      app/src/main/java/com/cr/common/CrMediaInfo.kt
  7. 15 0
      app/src/main/java/com/cr/common/CrUnitManager.kt
  8. 1 1
      app/src/main/java/com/cr/cruav/AvLogin.kt
  9. 10 5
      app/src/main/java/com/cr/cruav/AvMain.kt
  10. 440 3
      app/src/main/java/com/cr/data/utils.kt
  11. 38 24
      app/src/main/java/com/cr/map/MapTouch.kt
  12. 3 1
      app/src/main/java/com/cr/pages/CrFragment.kt
  13. 8 8
      app/src/main/java/com/cr/pages/FragmentCaseTools.kt
  14. 6 6
      app/src/main/java/com/cr/pages/FragmentDoodle.kt
  15. 136 3
      app/src/main/java/com/cr/pages/FragmentDynamicInfo.kt
  16. 56 4
      app/src/main/java/com/cr/pages/FragmentFPV.kt
  17. 6 7
      app/src/main/java/com/cr/pages/FragmentMark.kt
  18. 1 1
      app/src/main/java/com/cr/pages/FragmentSetIpAndCom.kt
  19. 7 7
      app/src/main/java/com/cr/pages/FragmentTools.kt
  20. 2 2
      app/src/main/java/com/cr/pages/FragmentTopInfo.kt
  21. 9 9
      app/src/main/java/com/cr/view/CrImageEditor.kt
  22. 166 0
      app/src/main/java/com/cr/viewmodel/CrCameraVM.kt
  23. 33 0
      app/src/main/java/com/cr/viewmodel/CrRemoteControlVM.kt
  24. 7 0
      app/src/main/java/com/cr/viewmodel/CrVideoChannelVM.kt
  25. 86 0
      app/src/main/java/com/cr/widget/CrBaseDrawWidget.kt
  26. 1 1
      app/src/main/java/com/cr/widget/CrButtonWidget.kt
  27. 246 0
      app/src/main/java/com/cr/widget/CrCompassWidget.kt
  28. 4 4
      app/src/main/java/com/cr/widget/CrSpeedWidget.kt
  29. 5 0
      app/src/main/res/drawable/shape_back_circle.xml
  30. 6 6
      app/src/main/res/layout/frag_case_tools.xml
  31. 4 4
      app/src/main/res/layout/frag_doodle.xml
  32. 46 18
      app/src/main/res/layout/frag_dynamic_info.xml
  33. 10 0
      app/src/main/res/layout/frag_fpv.xml
  34. 4 4
      app/src/main/res/layout/frag_mark.xml
  35. 5 5
      app/src/main/res/layout/frag_tools.xml
  36. 11 2
      app/src/main/res/values/themes.xml
  37. 2 1
      build.gradle
  38. 1 1
      gradle/wrapper/gradle-wrapper.properties

+ 2 - 3
.idea/deploymentTargetDropDown.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="deploymentTargetDropDown">
-    <runningDeviceTargetSelectedWithDropDown>
+    <runningDeviceTargetsSelectedWithDialog>
       <Target>
         <type value="RUNNING_DEVICE_TARGET" />
         <deviceKey>
@@ -11,7 +11,6 @@
           </Key>
         </deviceKey>
       </Target>
-    </runningDeviceTargetSelectedWithDropDown>
-    <timeTargetWasSelectedWithDropDown value="2023-07-31T08:53:58.640102Z" />
+    </runningDeviceTargetsSelectedWithDialog>
   </component>
 </project>

+ 18 - 19
app/build.gradle

@@ -5,16 +5,15 @@ plugins {
 apply plugin: 'kotlin-android-extensions'
 
 android {
-    compileSdkVersion 30
-    buildToolsVersion "30.0.2"
+    compileSdkVersion 33
+//    buildToolsVersion "30.0.2"
 
     defaultConfig {
         applicationId "com.cr.cruav"
-        minSdkVersion 24
-        targetSdkVersion 30
+        minSdkVersion 23
+        targetSdkVersion 33
         versionCode 1
         versionName "V1.0.0"
-        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         multiDexEnabled true
         ndk {
             abiFilters 'arm64-v8a'
@@ -41,6 +40,11 @@ android {
         pickFirst 'lib/arm64-v8a/libc++_shared.so'
         pickFirst 'lib/armeabi-v7a/libc++_shared.so'
     }
+    //关闭lint
+    lintOptions {
+        checkReleaseBuilds false
+        abortOnError false
+    }
 
     packagingOptions {
         doNotStrip "*/*/libconstants.so"
@@ -71,41 +75,36 @@ android {
         doNotStrip "*/*/libmrtc_onvif.so"
         doNotStrip "*/*/libmrtc_rtmp.so"
         doNotStrip "*/*/libmrtc_rtsp.so"
-        exclude 'META-INF/DEPENDENCIES'
-        pickFirst 'lib/arm64-v8a/libc++_shared.so'
-        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
     }
 }
 
 dependencies {
 
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    implementation 'androidx.core:core-ktx:1.2.0'
-    implementation 'androidx.appcompat:appcompat:1.1.0'
+    implementation 'androidx.core:core-ktx:1.3.2'
+    implementation 'androidx.appcompat:appcompat:1.3.1'
     implementation 'com.google.android.material:material:1.1.0'
-    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
-    testImplementation 'junit:junit:4.+'
-    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
-    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
 
     implementation "com.dji:dji-sdk-v5-aircraft:$djisdk_version"
     implementation "com.dji:dji-sdk-v5-networkImp:$djisdk_version"
     compileOnly "com.dji:dji-sdk-v5-aircraft-provided:$djisdk_version"
 
-    implementation 'com.squareup.okio:okio:1.15.0'
+    implementation 'com.squareup.okio:okio:1.17.2'
     implementation 'com.squareup.wire:wire-runtime:2.2.0'
     implementation 'com.airbnb.android:lottie:3.3.1'
 
-    implementation 'com.esri.arcgisruntime:arcgis-android:100.8.0'
+    implementation "com.esri.arcgisruntime:arcgis-android:100.8.0"
     api 'com.contrarywind:Android-PickerView:4.1.9'
 
-    api 'androidx.activity:activity-ktx:1.2.0-alpha01'
+//    api 'androidx.activity:activity-ktx:1.2.0-alpha01'
     api 'androidx.fragment:fragment-ktx:1.2.0-alpha01'
     api 'com.squareup:otto:1.3.8'
     api 'com.squareup.okhttp3:okhttp:4.2.0'
 
     //TODO 引入屏幕适配框架
     implementation 'me.jessyan:autosize:1.2.1'
-    //TODO 引入轮播器支持
-    implementation 'com.github.ryanlijianchang:AdPlayBanner:v0.7'
 }

+ 7 - 11
app/src/main/AndroidManifest.xml

@@ -2,6 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.cr.cruav">
 
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
@@ -9,20 +10,12 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.VIBRATE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 
     <uses-feature
         android:name="android.hardware.usb.host"
@@ -40,6 +33,7 @@
         android:supportsRtl="true"
         android:networkSecurityConfig="@xml/network_security_config"
         xmlns:tools="http://schemas.android.com/tools"  tools:replace="label"
+        android:requestLegacyExternalStorage="true"
         android:theme="@style/Theme.CrUAV">
         <!--注册provider 用于文件路径解析-->
         <provider
@@ -53,7 +47,7 @@
         </provider>
         <activity
             android:name=".AvMain"
-            android:exported="false"
+            android:exported="true"
             android:configChanges="orientation|screenSize"
             android:screenOrientation="reverseLandscape"/>
 
@@ -62,8 +56,10 @@
             android:value="9ca142bd221858778ce319da" />
 
         <activity android:name=".AvLogin"
-            android:configChanges="orientation|screenSize"
-            android:screenOrientation="reverseLandscape">
+            android:launchMode="singleTask"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:screenOrientation="reverseLandscape"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

+ 39 - 0
app/src/main/java/com/cr/common/CrAudioUtil.kt

@@ -0,0 +1,39 @@
+package com.cr.common
+
+import android.content.Context
+import android.media.MediaPlayer
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/4 09:11
+ * 描述:音频播放类
+ */
+class CrAudioUtil {
+    /**
+     * 静态方法
+     */
+    companion object{
+        private var MIN_RATIO:Float = 0.3f
+        // define: 2023/8/4 播放器
+        private var player:MediaPlayer?=null
+        private fun playSound(context: Context,resID:Int,ignoreWhenBusy:Boolean){
+            try{
+                if(player != null){
+                    player?.let {
+                        // todo: 2023/8/4 如果正在播放则停止
+                        if(it.isPlaying){
+                            if(ignoreWhenBusy){
+                                return
+                            }
+                            it.stop()
+                        }
+                        it.release()
+                    }
+                }
+            }catch (e:java.lang.Exception){
+
+            }
+        }
+    }
+}

+ 52 - 0
app/src/main/java/com/cr/common/CrCameraInfo.kt

@@ -0,0 +1,52 @@
+package com.cr.common
+
+import com.cr.data.DEFAULT_STR
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/2 10:11
+ * 描述:相机模型信息
+ */
+data class CrCameraInfo(var isConnection: Boolean = false) {
+    // define: 2023/8/2 iso
+    var iso: String = DEFAULT_STR
+
+    // define: 2023/8/2 快门速度
+    var speed: String = DEFAULT_STR
+
+    // define: 2023/8/2 焦距
+    var focal: String = DEFAULT_STR
+
+    // define: 2023/8/2 补偿值
+    var ev: String = DEFAULT_STR
+
+    // define: 2023/8/2 拍照数量
+    var photoCount: String = DEFAULT_STR
+
+    // define: 2023/8/2 视频时长
+    var videoTime: String = DEFAULT_STR
+
+    // define: 2023/8/3 相机模式
+    var cameraModel: CrCameraMode = CrCameraMode.NON
+
+    /**
+     * 模式定义
+     */
+    enum class CrCameraMode {
+        /**
+         * 拍照模式
+         */
+        PHOTO,
+
+        /**
+         * 视频模式
+         */
+        VIDEO,
+
+        /**
+         * 未知模式
+         */
+        NON,
+    }
+}

+ 20 - 0
app/src/main/java/com/cr/common/CrMediaInfo.kt

@@ -0,0 +1,20 @@
+package com.cr.common
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/2 17:05
+ * 描述:大疆媒体信息
+ */
+data class CrMediaInfo(var name: String? = null) {
+    // define: 2023/8/3 大小
+    var size: String? = null
+
+    // define: 2023/8/3 创建时间
+    var time: String? = null
+
+    init {
+        this.size = "0K"
+        this.time = "00:00:00"
+    }
+}

+ 15 - 0
app/src/main/java/com/cr/common/CrUnitManager.kt

@@ -150,6 +150,21 @@ class CrUnitManager {
         }
 
         /**
+         * 文件大小转字符串表示
+         * @param size Int 文件大小
+         * @return String 字符串表示
+         */
+        fun toFileSize(size:Int):String{
+            return if(size<1024){
+                "${size}K"
+            }else if(size >=1024 && size < 1024*1024){
+                "${String.format("%.2fM",size/1024)}"
+            }else{
+                ""
+            }
+        }
+
+        /**
          * 像素转dp
          * @param px Float 像素值
          * @return Float

+ 1 - 1
app/src/main/java/com/cr/cruav/AvLogin.kt

@@ -92,7 +92,7 @@ class AvLogin : CrActivity(), OnClickListener {
         super.joinControls()
         // todo: 2023/4/6 初始化版本信息
         lblVersion = findViewById(R.id.login_version)
-        lblVersion?.text = "{${CrUtil.getVersionName(this)}}"
+        //lblVersion?.text = "{${CrUtil.getVersionName(this)}}"
         // todo: 2023/4/6 初始化账号密码
         txtUserName = findViewById(R.id.login_username)
         txtPassword = findViewById(R.id.login_password)

+ 10 - 5
app/src/main/java/com/cr/cruav/AvMain.kt

@@ -38,6 +38,9 @@ class AvMain : CrActivity(), View.OnClickListener {
     // define: 2023/3/14 将链路视图绑定到模型
     private val linkVm: CrLinkVM by viewModels()
 
+    // define: 2023/8/2 绑定相机视图到模型
+    private val cameraVm:CrCameraVM by viewModels()
+
     // define: 2023/3/13 顶部视图容器
     private var fragmentTopInfo: FragmentTopInfo? = null
 
@@ -232,6 +235,8 @@ class AvMain : CrActivity(), View.OnClickListener {
                 flightControlVm.initListener()
                 // todo: 2023/3/14 初始化链路监听
                 linkVm.initListener()
+                // todo: 2023/8/2 相机监听初始化
+                cameraVm.initListener()
             }
 
             // todo: 2023/3/13 App注册失败回调
@@ -240,23 +245,23 @@ class AvMain : CrActivity(), View.OnClickListener {
             }
 
             override fun onProductDisconnect(productId: Int) {
-                ToastUtils.showToast("Not yet implemented")
+
             }
 
             override fun onProductConnect(productId: Int) {
-                ToastUtils.showToast("Not yet implemented")
+
             }
 
             override fun onProductChanged(productId: Int) {
-                ToastUtils.showToast("Not yet implemented")
+
             }
 
             override fun onInitProcess(event: DJISDKInitEvent?, totalProcess: Int) {
-                ToastUtils.showToast("Not yet implemented")
+
             }
 
             override fun onDatabaseDownloadProgress(current: Long, total: Long) {
-                ToastUtils.showToast("Not yet implemented")
+
             }
         })
     }

+ 440 - 3
app/src/main/java/com/cr/data/utils.kt

@@ -13,7 +13,11 @@ import android.util.Log
 import android.widget.TextView
 import android.widget.Toast
 import androidx.annotation.RequiresApi
+import com.cr.cruav.CrApplication
 import com.cr.dialog.DialogNormal
+import dji.sdk.keyvalue.value.camera.CameraExposureCompensation
+import dji.sdk.keyvalue.value.camera.CameraISO
+import dji.sdk.keyvalue.value.camera.CameraShutterSpeed
 import dji.v5.utils.common.ContextUtil
 import dji.v5.utils.common.StringUtils
 import java.text.SimpleDateFormat
@@ -21,6 +25,7 @@ import java.util.*
 import java.util.regex.Pattern
 
 const val DEFAULT_STR = "N/A"
+const val DEFAULT_TIME = "00:00:00"
 const val DEFAULT_RES_ID = -1
 const val IN_INNER_NETWORK_STR = "IN_INNER"
 const val IN_OUT_NETWORK_STR = "IN_OUT"
@@ -54,7 +59,7 @@ class CrUtil {
         val PROJECT_NAME: String = "lsquav"
 
         // define: 2023/3/31 存储主目录 随着App卸载删除
-        val CARD_PATH: String = ContextUtil.getContext().getExternalFilesDir(null).toString()
+        val CARD_PATH: String = CrApplication.getContext().getExternalFilesDir(null).toString()
 
         // define: 2023/3/31 工程目录
         val PROJECT_PATH: String = "$CARD_PATH/$PROJECT_NAME"
@@ -134,6 +139,426 @@ class CrUtil {
         }
 
         /**
+         * 获取ISO
+         * @param iso CameraISO
+         * @return String
+         */
+        fun getISO(iso: CameraISO): String {
+            when (iso) {
+                CameraISO.ISO_50 -> {
+                    return "50"
+                }
+                CameraISO.ISO_100 -> {
+                    return "100"
+                }
+                CameraISO.ISO_200 -> {
+                    return "200"
+                }
+                CameraISO.ISO_400 -> {
+                    return "400"
+                }
+                CameraISO.ISO_800 -> {
+                    return "800"
+                }
+                CameraISO.ISO_1600 -> {
+                    return "1600"
+                }
+                CameraISO.ISO_3200 -> {
+                    return "3200"
+                }
+                CameraISO.ISO_6400 -> {
+                    return "6400"
+                }
+                CameraISO.ISO_12800 -> {
+                    return "12800"
+                }
+                CameraISO.ISO_25600 -> {
+                    return "25600"
+                }
+                CameraISO.ISO_102400 -> {
+                    return "102400"
+                }
+                CameraISO.ISO_AUTO -> {
+                    return "AUTO"
+                }
+                CameraISO.UNKNOWN -> {
+                    return "UNKNOWN"
+                }
+                CameraISO.ISO_FIXED -> {
+                    return "FIXED"
+                }
+            }
+            return DEFAULT_STR
+        }
+
+        /**
+         * 获取补偿值
+         * @param ev CameraExposureCompensation
+         * @return String
+         */
+        fun getEv(ev: CameraExposureCompensation): String {
+            when (ev) {
+                CameraExposureCompensation.NEG_5P0EV -> {
+                    return "-5.0"
+                }
+                CameraExposureCompensation.NEG_4P7EV -> {
+                    return "-4.7"
+                }
+                CameraExposureCompensation.NEG_4P3EV -> {
+                    return "-4.3"
+                }
+                CameraExposureCompensation.NEG_4P0EV -> {
+                    return "-4.0"
+                }
+                CameraExposureCompensation.NEG_3P7EV -> {
+                    return "-3.7"
+                }
+                CameraExposureCompensation.NEG_3P3EV -> {
+                    return "-3.3"
+                }
+                CameraExposureCompensation.NEG_3P0EV -> {
+                    return "-3.0"
+                }
+                CameraExposureCompensation.NEG_2P7EV -> {
+                    return "-2.7"
+                }
+                CameraExposureCompensation.NEG_2P3EV -> {
+                    return "-2.3"
+                }
+                CameraExposureCompensation.NEG_2P0EV -> {
+                    return "-2.0"
+                }
+                CameraExposureCompensation.NEG_1P7EV -> {
+                    return "-1.7"
+                }
+                CameraExposureCompensation.NEG_1P3EV -> {
+                    return "-1.3"
+                }
+                CameraExposureCompensation.NEG_1P0EV -> {
+                    return "-1.0"
+                }
+                CameraExposureCompensation.NEG_0P7EV -> {
+                    return "-0.7"
+                }
+                CameraExposureCompensation.NEG_0P3EV -> {
+                    return "-0.3"
+                }
+                CameraExposureCompensation.NEG_0EV -> {
+                    return "0.0"
+                }
+                CameraExposureCompensation.POS_0P3EV -> {
+                    return "0.3"
+                }
+                CameraExposureCompensation.POS_0P7EV -> {
+                    return "0.7"
+                }
+                CameraExposureCompensation.POS_1P0EV -> {
+                    return "1.0"
+                }
+                CameraExposureCompensation.POS_1P3EV -> {
+                    return "1.3"
+                }
+                CameraExposureCompensation.POS_1P7EV -> {
+                    return "1.7"
+                }
+                CameraExposureCompensation.POS_2P0EV -> {
+                    return "2.0"
+                }
+                CameraExposureCompensation.POS_2P3EV -> {
+                    return "2.3"
+                }
+                CameraExposureCompensation.POS_2P7EV -> {
+                    return "2.7"
+                }
+                CameraExposureCompensation.POS_3P0EV -> {
+                    return "3.0"
+                }
+                CameraExposureCompensation.POS_3P3EV -> {
+                    return "3.3"
+                }
+                CameraExposureCompensation.POS_3P7EV -> {
+                    return "3.7"
+                }
+                CameraExposureCompensation.POS_4P0EV -> {
+                    return "4.0"
+                }
+                CameraExposureCompensation.POS_4P3EV -> {
+                    return "4.3"
+                }
+                CameraExposureCompensation.POS_4P7EV -> {
+                    return "4.7"
+                }
+                CameraExposureCompensation.POS_5P0EV -> {
+                    return "5.0"
+                }
+                CameraExposureCompensation.FIXED -> {
+                    return "FIXED"
+                }
+                CameraExposureCompensation.UNKNOWN -> {
+                    return "UNKNOWN"
+                }
+            }
+            return DEFAULT_STR
+        }
+
+        /**
+         * 获取快门速度
+         * @param shutterSpeed CameraShutterSpeed
+         * @return String
+         */
+        fun getShutterSpeed(shutterSpeed: CameraShutterSpeed): String {
+            when (shutterSpeed) {
+                CameraShutterSpeed.SHUTTER_SPEED_AUTO -> {
+                    return "AUTO"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_20000 -> {
+                    return "1/20000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_16000 -> {
+                    return "1/16000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_12800 -> {
+                    return "1/12800"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_10000 -> {
+                    return "1/10000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_8000 -> {
+                    return "1/8000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_6400 -> {
+                    return "1/6400"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_6000 -> {
+                    return "1/6000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_5000 -> {
+                    return "1/5000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_4000 -> {
+                    return "1/4000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_3200 -> {
+                    return "1/3200"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_3000 -> {
+                    return "1/3000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_2500 -> {
+                    return "1/2500"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_2000 -> {
+                    return "1/2000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1600 -> {
+                    return "1/1600"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1500 -> {
+                    return "1/1500"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1250 -> {
+                    return "1/1250"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1000 -> {
+                    return "1/1000"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_800 -> {
+                    return "1/800"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_725 -> {
+                    return "1/725"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_640 -> {
+                    return "1/640"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_500 -> {
+                    return "1/500"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_400 -> {
+                    return "1/400"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_350 -> {
+                    return "1/350"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_320 -> {
+                    return "1/320"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_250 -> {
+                    return "1/250"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_240 -> {
+                    return "1/240"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_200 -> {
+                    return "1/200"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_180 -> {
+                    return "1/180"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_160 -> {
+                    return "1/160"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_125 -> {
+                    return "1/125"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_120 -> {
+                    return "1/120"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_100 -> {
+                    return "1/100"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_90 -> {
+                    return "1/90"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_80 -> {
+                    return "1/80"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_60 -> {
+                    return "1/60"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_50 -> {
+                    return "1/50"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_40 -> {
+                    return "1/40"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_30 -> {
+                    return "1/30"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_25 -> {
+                    return "1/25"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_20 -> {
+                    return "1/20"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_15 -> {
+                    return "1/15"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_12DOT5 -> {
+                    return "1/12.5"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_10 -> {
+                    return "1/10"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_8 -> {
+                    return "1/8"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_6DOT25 -> {
+                    return "1/6.25"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_5 -> {
+                    return "1/5"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_4 -> {
+                    return "1/4"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_3 -> {
+                    return "1/3"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_2DOT5 -> {
+                    return "1/2.5"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_2 -> {
+                    return "1/2"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1DOT67 -> {
+                    return "1/1.67"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1_1DOT25 -> {
+                    return "1/1.25"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1 -> {
+                    return "1.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1DOT3 -> {
+                    return "1.3"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED1DOT6 -> {
+                    return "1.6"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED2 -> {
+                    return "2.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED2DOT5 -> {
+                    return "2.5"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED3 -> {
+                    return "3.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED3DOT2 -> {
+                    return "3.2"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED4 -> {
+                    return "4.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED5 -> {
+                    return "5.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED6 -> {
+                    return "6.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED7 -> {
+                    return "7.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED8 -> {
+                    return "8.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED9 -> {
+                    return "9.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED10 -> {
+                    return "10.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED11 -> {
+                    return "11.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED13 -> {
+                    return "13.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED15 -> {
+                    return "15.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED16 -> {
+                    return "16.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED20 -> {
+                    return "20.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED23 -> {
+                    return "23.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED25 -> {
+                    return "25.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED30 -> {
+                    return "30.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED40 -> {
+                    return "40.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED50 -> {
+                    return "50.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED60 -> {
+                    return "60.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED80 -> {
+                    return "80.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED100 -> {
+                    return "100.0"
+                }
+                CameraShutterSpeed.SHUTTER_SPEED120 -> {
+                    return "120.0"
+                }
+                CameraShutterSpeed.UNKNOWN->{
+                    return "UNKNOWN"
+                }
+            }
+            return DEFAULT_STR
+        }
+
+        /**
          * Logcat输出消息
          * @param message String
          */
@@ -152,7 +577,7 @@ class CrUtil {
         fun setFont(context: Context, textView: TextView, fontId: Int) {
             var font: Typeface? = Typeface.createFromAsset(context.assets, CrUtil.FontPath)
             textView!!.typeface = font
-            textView!!.text = StringUtils.getResStr(fontId)
+            textView!!.text = context.resources.getString(fontId)
         }
 
         /**
@@ -190,7 +615,7 @@ class CrUtil {
          */
         @JvmStatic
         fun getDimens(dimenId: Int): Float {
-            return ContextUtil.getContext().resources.getDimension(dimenId)
+            return CrApplication.getContext().resources.getDimension(dimenId)
         }
 
         /**
@@ -277,6 +702,18 @@ class CrUtil {
         inline fun <reified T : Activity> Context.onStart() {
             startActivity(Intent(this, T::class.java))
         }
+
+        /**
+         * 秒转时分秒
+         * @param seconds Int 秒
+         * @return String 时:分:秒
+         */
+        fun secondsToHMS(seconds:Int):String{
+            var hours = seconds/3600
+            var minutes = (seconds % 3600)/60
+            var rSeconds = seconds % 60
+            return String.format("%d:%02d:%02d",hours,minutes,rSeconds)
+        }
     }
 }
 

+ 38 - 24
app/src/main/java/com/cr/map/MapTouch.kt

@@ -79,48 +79,62 @@ class MapTouch constructor(context: Context, mapView: MapView) :
         return false
     }
 
-    // todo: 2023/4/18 重写点击事件
-    override fun onSingleTapUp(e: MotionEvent?): Boolean {
+    // todo: 2023/8/4 重写点击事件
+    override fun onSingleTapUp(e: MotionEvent): Boolean {
         when (action) {
             // todo: 2023/4/19 选择涂鸦
             MapAction.MapTapSelectDoodle,
-            MapAction.MapTapSelectMark-> {
+            MapAction.MapTapSelectMark -> {
                 identifyLayer(e!!.x.toInt(), e.y.toInt())
             }
             // todo: 2023/4/19 添加标志
-            MapAction.MapTapAppendMark->{
-                var mapPoint = mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(),e.y.toInt()))
-                if(listener != null) listener?.onMarkAppend(mapPoint!!)
+            MapAction.MapTapAppendMark -> {
+                var mapPoint =
+                    mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(), e.y.toInt()))
+                if (listener != null) listener?.onMarkAppend(mapPoint!!)
             }
             // todo: 2023/6/7 查询地理位置
-            MapAction.MapTapGetLocation->{
-                var mapPoint = mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(),e.y.toInt()))
-                var queryPoint = GeometryEngine.project(mapPoint, SpatialReference.create(4326)) as Point
-                var format:DecimalFormat = DecimalFormat("#.######")
-                if(listener != null) listener?.onQueryLocation(mapPoint!!,format.format(queryPoint.x),format.format(queryPoint.y))
+            MapAction.MapTapGetLocation -> {
+                var mapPoint =
+                    mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(), e.y.toInt()))
+                var queryPoint =
+                    GeometryEngine.project(mapPoint, SpatialReference.create(4326)) as Point
+                var format: DecimalFormat = DecimalFormat("#.######")
+                if (listener != null) listener?.onQueryLocation(
+                    mapPoint!!,
+                    format.format(queryPoint.x),
+                    format.format(queryPoint.y)
+                )
             }
             // todo: 2023/6/12 添加案件点
-            MapAction.MapTapAddWaypoint->{
-                var mapPoint = mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(),e.y.toInt()))
-                var queryPoint = GeometryEngine.project(mapPoint, SpatialReference.create(4326)) as Point
-                var format:DecimalFormat = DecimalFormat("#.######")
-                if(listener != null) listener?.onAppendWaypoint(mapPoint!!,format.format(queryPoint.x),format.format(queryPoint.y))
+            MapAction.MapTapAddWaypoint -> {
+                var mapPoint =
+                    mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(), e.y.toInt()))
+                var queryPoint =
+                    GeometryEngine.project(mapPoint, SpatialReference.create(4326)) as Point
+                var format: DecimalFormat = DecimalFormat("#.######")
+                if (listener != null) listener?.onAppendWaypoint(
+                    mapPoint!!,
+                    format.format(queryPoint.x),
+                    format.format(queryPoint.y)
+                )
                 this.action = MapAction.MapTapNon
             }
             // todo: 2023/6/14 删除案件点
-            MapAction.MapTapDeleteWaypoint->{
-                var screenPoint = android.graphics.Point(e!!.x.toInt(),e.y.toInt())
-                if(listener != null) listener?.onRemoveWaypoint(screenPoint!!)
+            MapAction.MapTapDeleteWaypoint -> {
+                var screenPoint = android.graphics.Point(e!!.x.toInt(), e.y.toInt())
+                if (listener != null) listener?.onRemoveWaypoint(screenPoint!!)
                 this.action = MapAction.MapTapNon
             }
             // todo: 2023/6/14 移动案件点
-            MapAction.MapTapStartMoveWaypoing->{
-                var mapPoint = mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(),e.y.toInt()))
-                if(listener != null) listener?.onMoveWaypointBySelect(mapPoint!!)
+            MapAction.MapTapStartMoveWaypoing -> {
+                var mapPoint =
+                    mapView?.screenToLocation(android.graphics.Point(e!!.x.toInt(), e.y.toInt()))
+                if (listener != null) listener?.onMoveWaypointBySelect(mapPoint!!)
             }
             // todo: 2023/6/15 案件分享及上传选择
-            MapAction.MapTapCaseWxAndUpload->{
-                var screenPoint = android.graphics.Point(e!!.x.toInt(),e.y.toInt())
+            MapAction.MapTapCaseWxAndUpload -> {
+                var screenPoint = android.graphics.Point(e!!.x.toInt(), e.y.toInt())
                 var mapPoint = mapView?.screenToLocation(screenPoint)
                 if (listener != null) listener?.onCaseUploadBySelect(screenPoint)
             }

+ 3 - 1
app/src/main/java/com/cr/pages/CrFragment.kt

@@ -51,7 +51,9 @@ open class CrFragment :Fragment(){
      * @param warning String 警告消息
      */
     protected fun showWarning(warning: String) {
-        DialogNormal(context!!, "警告", warning).show()
+        mainHandler.post(Runnable {
+            DialogNormal(context!!, "警告", warning).show()
+        })
     }
 
     /**

+ 8 - 8
app/src/main/java/com/cr/pages/FragmentCaseTools.kt

@@ -11,7 +11,7 @@ import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.event.BarAction
 import com.cr.event.EventFragmentBarAction
-import com.cr.widget.CrButton
+import com.cr.widget.CrButtonWidget
 import com.squareup.otto.Subscribe
 
 /**
@@ -20,7 +20,7 @@ import com.squareup.otto.Subscribe
  * 创建日期:2023/6/9 17:12
  * 描述:案件图斑编辑页面
  */
-class FragmentCaseTools : CrNavigationFragment(), CrButton.OnClickListener,
+class FragmentCaseTools : CrNavigationFragment(), CrButtonWidget.OnClickListener,
     OnCheckedChangeListener {
     /**
      * 操作监听接口
@@ -51,13 +51,13 @@ class FragmentCaseTools : CrNavigationFragment(), CrButton.OnClickListener,
         fun onRemoveCasePoint()
     }
 
-    private var btnSave: CrButton? = null  // define: 2023/6/9 保存
-    private var btnDelete: CrButton? = null  // define: 2023/6/9 删除
-    private var btnUndo: CrButton? = null  // define: 2023/6/9 回退一步
-    private var btnReset: CrButton? = null  // define: 2023/6/9 重新绘制
-    private var btnMovePoint: CrButton? = null // define: 2023/6/9 移动案件点
+    private var btnSave: CrButtonWidget? = null  // define: 2023/6/9 保存
+    private var btnDelete: CrButtonWidget? = null  // define: 2023/6/9 删除
+    private var btnUndo: CrButtonWidget? = null  // define: 2023/6/9 回退一步
+    private var btnReset: CrButtonWidget? = null  // define: 2023/6/9 重新绘制
+    private var btnMovePoint: CrButtonWidget? = null // define: 2023/6/9 移动案件点
     private var switchDraw: Switch? = null // define: 2023/6/9 开启绘制
-    private var btnRemoveCasePoint:CrButton?=null  // define: 2023/6/13 删除违建点
+    private var btnRemoveCasePoint:CrButtonWidget?=null  // define: 2023/6/13 删除违建点
 
     // todo: 2023/6/9 操作监听
     private var listener: OnOperationListener? = null

+ 6 - 6
app/src/main/java/com/cr/pages/FragmentDoodle.kt

@@ -11,7 +11,7 @@ import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.event.BarAction
 import com.cr.event.EventFragmentBarAction
-import com.cr.widget.CrButton
+import com.cr.widget.CrButtonWidget
 import com.squareup.otto.Subscribe
 
 /**
@@ -20,7 +20,7 @@ import com.squareup.otto.Subscribe
  * 创建日期:2023/4/17 09:12
  * 描述:涂鸦操作页面
  */
-class FragmentDoodle : CrNavigationFragment(), CrButton.OnClickListener, OnCheckedChangeListener {
+class FragmentDoodle : CrNavigationFragment(), CrButtonWidget.OnClickListener, OnCheckedChangeListener {
     /**
      * 操作监听接口
      */
@@ -50,10 +50,10 @@ class FragmentDoodle : CrNavigationFragment(), CrButton.OnClickListener, OnCheck
         fun onDelete()
     }
 
-    private var btnClear: CrButton? = null // define: 2023/4/17 清除临时绘制的涂鸦
-    private var btnSave: CrButton? = null  // define: 2023/4/17 保存临时绘制的涂鸦
-    private var btnRemove: CrButton? = null // define: 2023/4/17 全部删除永久保存的涂鸦
-    private var btnDelete: CrButton? = null // define: 2023/4/17 删除选择的涂鸦
+    private var btnClear: CrButtonWidget? = null // define: 2023/4/17 清除临时绘制的涂鸦
+    private var btnSave: CrButtonWidget? = null  // define: 2023/4/17 保存临时绘制的涂鸦
+    private var btnRemove: CrButtonWidget? = null // define: 2023/4/17 全部删除永久保存的涂鸦
+    private var btnDelete: CrButtonWidget? = null // define: 2023/4/17 删除选择的涂鸦
     private var switchDraw: Switch? = null  // define: 2023/4/17 开启绘制
     private var switchSelect: Switch? = null // define: 2023/4/17 开启选择
 

+ 136 - 3
app/src/main/java/com/cr/pages/FragmentDynamicInfo.kt

@@ -4,7 +4,18 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.activityViewModels
+import androidx.transition.Visibility
+import com.cr.common.CrCameraInfo
 import com.cr.cruav.R
+import com.cr.data.CrUtil
+import com.cr.viewmodel.CrCameraVM
+import dji.sdk.keyvalue.key.CameraKey
+import dji.sdk.keyvalue.key.KeyTools
+import dji.sdk.keyvalue.value.common.EmptyMsg
+import dji.v5.common.callback.CommonCallbacks
+import dji.v5.common.error.IDJIError
 
 /**
  * 操作系统:MAC系统
@@ -12,7 +23,22 @@ import com.cr.cruav.R
  * 创建日期:2023/7/29 16:30
  * 描述:大疆动态数据页面
  */
-class FragmentDynamicInfo:CrFragment() {
+class FragmentDynamicInfo : CrFragment(), View.OnClickListener {
+    // todo: 2023/8/2 绑定模型
+    private val cameraVm: CrCameraVM by activityViewModels()
+
+    // todo: 2023/8/2 组件定义
+    private var lblCameraISO: TextView? = null // define: 2023/8/2 ISO值
+    private var lblCameraSpeed: TextView? = null // define: 2023/8/2 快门速度
+    private var lblCameraFocal: TextView? = null // define: 2023/8/2 相机焦距
+    private var lblCameraEv: TextView? = null // define: 2023/8/2 补偿值
+    private var lblSDPhotoCount: TextView? = null // define: 2023/8/2 SD卡中可存储的照片数量
+    private var lblSDVideoTime: TextView? = null // define: 2023/8/2 SD卡中可以录制的视频时间
+    private var lblDJILogin: TextView? = null // define: 2023/8/2 是否登录大疆账户
+
+    private var flagPhoto: TextView? = null  // define: 2023/8/3 照片模式标志
+    private var flagVideo: TextView? = null // define: 2023/8/3 视频模式标志
+
     /**
      * 初始化
      * @param inflater LayoutInflater
@@ -26,7 +52,114 @@ class FragmentDynamicInfo:CrFragment() {
         savedInstanceState: Bundle?
     ): View? {
         self = this;
-        mainView = inflater.inflate(R.layout.frag_dynamic_info,null)
+        mainView = inflater.inflate(R.layout.frag_dynamic_info, null)
+        // todo: 2023/8/2 挂载控件
+        joinControls()
         return mainView
     }
-}
+
+    /**
+     * 覆写挂载控件
+     */
+    override fun joinControls() {
+        super.joinControls()
+        // todo: 2023/8/2 挂载控件
+        mainView?.let {
+            lblCameraISO = it.findViewById(R.id.camera_iso)
+            lblCameraSpeed = it.findViewById(R.id.camera_speed)
+            lblCameraFocal = it.findViewById(R.id.camera_focal)
+            lblCameraEv = it.findViewById(R.id.camera_ev)
+
+            lblSDPhotoCount = it.findViewById(R.id.sd_photo_count)
+            lblSDVideoTime = it.findViewById(R.id.sd_video_time)
+
+            lblDJILogin = it.findViewById(R.id.dji_login)
+
+            // todo: 2023/8/3 挂载相机模式标志
+            flagPhoto = it.findViewById(R.id.camera_model_photo)
+            flagPhoto?.visibility = View.GONE
+            flagVideo = it.findViewById(R.id.camera_model_video)
+            flagVideo?.visibility = View.GONE
+
+            // todo: 2023/8/2 挂载事件
+            lblSDPhotoCount?.setOnClickListener(this)
+        }
+    }
+
+    /**
+     * 生命周期
+     * 后台转前台运行时调用
+     */
+    override fun onResume() {
+        super.onResume()
+        // todo: 2023/8/2 初始化订阅
+        initObserver()
+    }
+
+    /**
+     * 生命周期
+     * 销毁
+     */
+    override fun onDestroy() {
+        super.onDestroy()
+    }
+
+    /**
+     * 初始化订阅
+     */
+    private fun initObserver() {
+        // todo: 2023/8/2 订阅相机信息
+        cameraVm.cameraInfo.observe(requireActivity()) {
+            it?.let {
+                // todo: 2023/8/4 相机基本参数
+                lblCameraISO?.text = it.iso
+                lblCameraSpeed?.text = it.speed
+                lblCameraFocal?.text = it.focal
+                lblCameraEv?.text = it.ev
+
+                // todo: 2023/8/4 可拍照数量或可录制视频时长
+                lblSDPhotoCount?.text = it.photoCount
+                lblSDVideoTime?.text = it.videoTime
+
+                // todo: 2023/8/4 相机模式
+                when(it.cameraModel){
+                    CrCameraInfo.CrCameraMode.NON->{
+                        flagVideo?.visibility = View.GONE
+                        flagPhoto?.visibility = View.GONE
+                    }
+                    CrCameraInfo.CrCameraMode.PHOTO->{
+                        flagVideo?.visibility = View.GONE
+                        flagPhoto?.visibility = View.VISIBLE
+                    }
+                    CrCameraInfo.CrCameraMode.VIDEO->{
+                        flagVideo?.visibility = View.VISIBLE
+                        flagPhoto?.visibility = View.GONE
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 视图点击事件
+     * @param view View
+     */
+    override fun onClick(view: View?) {
+        when (view?.id) {
+            R.id.sd_photo_count -> {
+                CrUtil.print("拍照")
+                dji.v5.manager.KeyManager.getInstance()
+                    .performAction(KeyTools.createKey(CameraKey.KeyStartShootPhoto),
+                        object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg> {
+                            override fun onSuccess(t: EmptyMsg?) {
+                                CrUtil.print("拍照成功${t.toString()}")
+                            }
+
+                            override fun onFailure(error: IDJIError) {
+                                CrUtil.print("拍照失败${error.description()}}")
+                            }
+                        })
+            }
+        }
+    }
+}

+ 56 - 4
app/src/main/java/com/cr/pages/FragmentFPV.kt

@@ -7,6 +7,7 @@ import android.view.SurfaceView
 import android.view.View
 import android.view.ViewGroup
 import android.widget.Button
+import android.widget.TextView
 import androidx.fragment.app.activityViewModels
 import com.cr.cruav.R
 import com.cr.viewmodel.CrFlightControlVM
@@ -16,9 +17,7 @@ import dji.v5.common.video.channel.VideoChannelType
 import dji.v5.common.video.decoder.DecoderOutputMode
 import dji.v5.common.video.decoder.DecoderState
 import dji.v5.common.video.decoder.VideoDecoder
-import dji.v5.common.video.interfaces.DecoderStateChangeListener
-import dji.v5.common.video.interfaces.IVideoChannel
-import dji.v5.common.video.interfaces.IVideoDecoder
+import dji.v5.common.video.interfaces.*
 
 
 /**
@@ -44,6 +43,7 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
     // define: 2023/3/10 延迟初始化一个视频画布
     private lateinit var surfaceView: SurfaceView
     private var btnTrigger: Button? = null
+    private var lblInfo:TextView?=null // define: 2023/8/4 显示信息
 
     // define: 2023/3/11 视频通道
     private var curVideoChannel: IVideoChannel? = null
@@ -51,6 +51,13 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
     // define: 2023/3/10 定义视频解码器
     private var videoDecoder: IVideoDecoder? = null
 
+    // todo: 2023/8/4 视频相关参数
+    private var videoWidth:Int = -1
+    private var videoHeight:Int = -1
+    private var widthChanged:Boolean = false
+    private var heightChange:Boolean = false
+    private var fps:Int = -1
+
     // todo: 2023/3/13 监听
     lateinit var listener:FPVListener
 
@@ -67,12 +74,16 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
         savedInstanceState: Bundle?
     ): View? {
         var view = inflater.inflate(R.layout.frag_fpv, container, false)
+        // todo: 2023/8/4 关闭 View Layer。 View Layer 可以加速无 invalidate() 时的刷新效率,但对于需要调用 invalidate() 的刷新无法加速
+        view.setLayerType(View.LAYER_TYPE_NONE,null)
         // todo: 2023/3/13 给View挂接事件
         view.setOnClickListener(clickListener)
         // todo: 2023/3/10 挂接图传视图控件
         surfaceView = view.findViewById(R.id.surface_fpv)
         btnTrigger = view.findViewById(R.id.fpv_trigger)
         btnTrigger?.setOnClickListener(clickListener)
+        // todo: 2023/8/4 挂接信息显示组件
+        lblInfo = view.findViewById(R.id.fpv_info)
         // todo: 2023/3/10 设置视图控件监听
         surfaceView.holder.addCallback(this)
         return view
@@ -109,11 +120,20 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
      * 初始化
      */
     private fun init() {
+        // todo: 2023/8/4 注册订阅
+        videoChannelVM.videoChannelInfo.observe(viewLifecycleOwner){
+            it?.let {
+                val videoStreamInfo = "fps:[${it.fps}] width:[${videoWidth}] height:[${videoHeight}]"
+                lblInfo?.text = videoStreamInfo
+            }
+        }
         // todo: 2023/3/11 绑定视频通道变化监听
         videoChannelVM.listener = object : CrVideoChannelListener {
             // todo: 2023/3/13 变更通道
             override fun initVideoChannel(videoChannel: IVideoChannel) {
                 curVideoChannel = videoChannel
+                // todo: 2023/8/4 添加组针变化监听
+                curVideoChannel?.addStreamDataListener(streamDataListener)
                 setChannelToSurface()
             }
 
@@ -172,11 +192,42 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
                 // todo: 2023/3/10 更新编码状态
                 videoChannelVM.videoChannelInfo.value?.decoderState = newState
                 // todo: 2023/3/10 刷新数据
-                videoChannelVM.refresh(videoChannelVM.videoChannelInfo)
+                videoChannelVM.refreshVideoChannelInfo()
             }
         }
 
     /**
+     * 组针后数据的监听
+     */
+    private val streamDataListener = StreamDataListener {
+        it?.let {
+            if(fps != it.fps){
+                fps = it.fps
+                mainHandler.post{
+                    videoChannelVM.videoChannelInfo.value?.fps = fps
+                    videoChannelVM.refreshVideoChannelInfo()
+                }
+            }
+            if(videoWidth != it.width){
+                videoWidth = it.width
+                widthChanged = true
+            }
+            if(videoHeight != it.height){
+                videoHeight = it.height
+                heightChange = true
+            }
+            if(widthChanged || heightChange){
+                widthChanged = false
+                heightChange = false
+                mainHandler.post{
+                    videoChannelVM.videoChannelInfo.value?.resolution = "${videoWidth}*${videoHeight}"
+                    videoChannelVM.refreshVideoChannelInfo()
+                }
+            }
+        }
+    }
+
+    /**
      * surfaceView 创建监听
      * @param p0 SurfaceHolder
      */
@@ -209,6 +260,7 @@ class FragmentFPV : CrAnimationFragment(), SurfaceHolder.Callback {
      */
     override fun onDestroyView() {
         super.onDestroyView()
+        curVideoChannel?.removeStreamDataListener(streamDataListener)
         // todo: 2023/3/10 释放编码资源
         if (videoDecoder != null) {
             videoDecoder?.destroy()

+ 6 - 7
app/src/main/java/com/cr/pages/FragmentMark.kt

@@ -5,7 +5,6 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.view.ViewTreeObserver.OnGlobalLayoutListener
 import android.widget.CompoundButton
 import android.widget.CompoundButton.OnCheckedChangeListener
 import android.widget.ImageView
@@ -19,7 +18,7 @@ import com.cr.event.BarAction
 import com.cr.event.EventFragmentBarAction
 import com.cr.map.EventMarkChange
 import com.cr.view.CrViewWheel
-import com.cr.widget.CrButton
+import com.cr.widget.CrButtonWidget
 import com.squareup.otto.Subscribe
 import dji.v5.utils.common.ContextUtil
 
@@ -29,7 +28,7 @@ import dji.v5.utils.common.ContextUtil
  * 创建日期:2023/4/17 09:12
  * 描述:标志操作页面
  */
-class FragmentMark : CrNavigationFragment(), CrButton.OnClickListener, OnCheckedChangeListener{
+class FragmentMark : CrNavigationFragment(), CrButtonWidget.OnClickListener, OnCheckedChangeListener{
     /**
      * 操作监听接口
      */
@@ -59,10 +58,10 @@ class FragmentMark : CrNavigationFragment(), CrButton.OnClickListener, OnChecked
         fun onDelete()
     }
 
-    private var btnClear: CrButton? = null // define: 2023/4/17 清除临时绘制的涂鸦
-    private var btnSave: CrButton? = null  // define: 2023/4/17 保存临时绘制的涂鸦
-    private var btnRemove: CrButton? = null // define: 2023/4/17 全部删除永久保存的涂鸦
-    private var btnDelete: CrButton? = null // define: 2023/4/17 删除选择的涂鸦
+    private var btnClear: CrButtonWidget? = null // define: 2023/4/17 清除临时绘制的涂鸦
+    private var btnSave: CrButtonWidget? = null  // define: 2023/4/17 保存临时绘制的涂鸦
+    private var btnRemove: CrButtonWidget? = null // define: 2023/4/17 全部删除永久保存的涂鸦
+    private var btnDelete: CrButtonWidget? = null // define: 2023/4/17 删除选择的涂鸦
     private var switchDraw: Switch? = null  // define: 2023/4/17 开启绘制
     private var switchSelect: Switch? = null // define: 2023/4/17 开启选择
     private var imageView:ImageView?= null  // define: 2023/4/18 图片

+ 1 - 1
app/src/main/java/com/cr/pages/FragmentSetIpAndCom.kt

@@ -87,7 +87,7 @@ class FragmentSetIpAndCom : CrNavigationFragment(),View.OnClickListener{
         wheelSelectIpAndCom?.setTextColorCenter(Color.YELLOW) // TODO: 4/17/21 设置选中项颜色
         wheelSelectIpAndCom?.setItemsVisibleCount(8)
         wheelSelectIpAndCom?.setTextSize(CrUtil.getDimens(R.dimen.sp_6))
-        wheelSelectIpAndCom?.setTypeface(CrUtil.getFont(ContextUtil.getContext()))
+        wheelSelectIpAndCom?.setTypeface(CrUtil.getFont(CrApplication.getContext()))
         wheelSelectIpAndCom?.setCyclic(false) // TODO: 6/9/21 禁止循环
         wheelSelectIpAndCom?.setOnItemSelectedListener(onItemSelectedListener)
 

+ 7 - 7
app/src/main/java/com/cr/pages/FragmentTools.kt

@@ -8,7 +8,7 @@ import com.cr.cruav.CrApplication
 import com.cr.cruav.R
 import com.cr.event.BarAction
 import com.cr.event.EventFragmentBarAction
-import com.cr.widget.CrButton
+import com.cr.widget.CrButtonWidget
 
 /**
  * 操作系统:MAC系统
@@ -16,7 +16,7 @@ import com.cr.widget.CrButton
  * 创建日期:2023/4/21 10:08
  * 描述:工具箱页面
  */
-class FragmentTools:CrNavigationFragment() ,CrButton.OnClickListener{
+class FragmentTools:CrNavigationFragment() ,CrButtonWidget.OnClickListener{
     /**
      * 监听接口
      */
@@ -37,11 +37,11 @@ class FragmentTools:CrNavigationFragment() ,CrButton.OnClickListener{
         fun onToLocation()
     }
     // todo: 2023/4/21 控件定义
-    private var btnMeasureLength:CrButton? = null // define: 2023/4/21 长度测量按钮
-    private var btnMeasureArea:CrButton? = null // define: 2023/4/21 面积测量按钮
-    private var btnMeasureClear:CrButton? = null // define: 2023/4/21 清除测量内容按钮
-    private var btnGetLocation:CrButton? = null // define: 2023/4/21 获取经纬度按钮
-    private var btnToLocation:CrButton? = null // define: 2023/4/21 经纬度定位按钮
+    private var btnMeasureLength:CrButtonWidget? = null // define: 2023/4/21 长度测量按钮
+    private var btnMeasureArea:CrButtonWidget? = null // define: 2023/4/21 面积测量按钮
+    private var btnMeasureClear:CrButtonWidget? = null // define: 2023/4/21 清除测量内容按钮
+    private var btnGetLocation:CrButtonWidget? = null // define: 2023/4/21 获取经纬度按钮
+    private var btnToLocation:CrButtonWidget? = null // define: 2023/4/21 经纬度定位按钮
 
     // todo: 2023/4/21 定义监听 自行实现
     private var listener:OnOperationListener? = null

+ 2 - 2
app/src/main/java/com/cr/pages/FragmentTopInfo.kt

@@ -168,8 +168,8 @@ open class FragmentTopInfo : Fragment() {
     private fun observerLink(){
         linkVm.linkInfo.observe(requireActivity()){
             if (msdkRegisterVm.registerInfo.value?.isRegister == true) {
-                dji_link_symbol.setImageDrawable(linkSignalQualityIcon[CrUtil.getLinkSignalQuality(it.signalQuality)])
-                dji_link_value.text = it.frequencyBand
+                dji_link_symbol?.setImageDrawable(linkSignalQualityIcon[CrUtil.getLinkSignalQuality(it.signalQuality)])
+                dji_link_value?.text = it.frequencyBand
             }
         }
     }

+ 9 - 9
app/src/main/java/com/cr/view/CrImageEditor.kt

@@ -47,12 +47,12 @@ class CrImageEditor @JvmOverloads constructor(
      */
     private val mScaleListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
         // todo: 2023/6/20 缩放开始
-        override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
+        override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
             return true
         }
 
         // todo: 2023/6/20 缩放中
-        override fun onScale(detector: ScaleGestureDetector?): Boolean {
+        override fun onScale(detector: ScaleGestureDetector): Boolean {
             var scaleFactor = detector?.scaleFactor
             if (mCenterX == 0f) {
                 // todo: 2023/6/20 最小X轴缩放
@@ -69,8 +69,8 @@ class CrImageEditor @JvmOverloads constructor(
         }
 
         // todo: 2023/6/20 缩放结束
-        override fun onScaleEnd(detector: ScaleGestureDetector?) {
-
+        override fun onScaleEnd(detector: ScaleGestureDetector) {
+            super.onScaleEnd(detector)
         }
     }
 
@@ -80,7 +80,7 @@ class CrImageEditor @JvmOverloads constructor(
      */
     private val mTranslationListener = object : GestureDetector.SimpleOnGestureListener() {
         // todo: 2023/6/20 单击确认
-        override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
+        override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
             // todo: 2023/6/20 单击绘制一个点 试试
             e?.let {
                 var point = PointF(it.x, it.y)
@@ -94,8 +94,8 @@ class CrImageEditor @JvmOverloads constructor(
 
         // todo: 2023/6/20 移动
         override fun onScroll(
-            e1: MotionEvent?,
-            e2: MotionEvent?,
+            e1: MotionEvent,
+            e2: MotionEvent,
             distanceX: Float,
             distanceY: Float
         ): Boolean {
@@ -208,9 +208,9 @@ class CrImageEditor @JvmOverloads constructor(
      */
     override fun onTouchEvent(event: MotionEvent?): Boolean {
         // todo: 2023/6/20 这里将触摸事件转接给ScaleGestureDetector与GestureDetector
-        mScaleGestureDetector?.onTouchEvent(event)
+        mScaleGestureDetector?.onTouchEvent(event!!)
         if (mScaleGestureDetector?.isInProgress == false) {
-            mGestureDetector?.onTouchEvent(event)
+            mGestureDetector?.onTouchEvent(event!!)
         }
         return true
     }

+ 166 - 0
app/src/main/java/com/cr/viewmodel/CrCameraVM.kt

@@ -0,0 +1,166 @@
+package com.cr.viewmodel
+
+import androidx.lifecycle.MutableLiveData
+import com.cr.common.CrCameraInfo
+import com.cr.common.CrMediaInfo
+import com.cr.common.CrUnitManager
+import com.cr.data.CrUtil
+import com.cr.data.DEFAULT_STR
+import com.cr.data.DEFAULT_TIME
+import dji.sdk.keyvalue.key.CameraKey
+import dji.sdk.keyvalue.value.camera.CameraMode
+import dji.sdk.keyvalue.value.camera.CameraStorageInfo
+import dji.sdk.keyvalue.value.camera.MediaFileType
+import dji.v5.et.create
+import dji.v5.et.listen
+import okhttp3.internal.notifyAll
+import java.text.SimpleDateFormat
+import java.time.format.DateTimeFormatter
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/2 10:10
+ * 描述:相机模型
+ */
+class CrCameraVM : CrViewModel() {
+    // define: 2023/8/2 相机信息
+    var cameraInfo = MutableLiveData<CrCameraInfo>()
+
+    // define: 2023/8/3 媒体信息
+    var mediaInfo = MutableLiveData<CrMediaInfo>()
+
+    /**
+     * 初始化
+     */
+    init {
+        // todo: 2023/8/3 初始化相机信息
+        cameraInfo.postValue(CrCameraInfo())
+        cameraInfo.value?.let {
+            it.isConnection = false
+            it.iso = DEFAULT_STR
+            it.speed = DEFAULT_STR
+            it.focal = DEFAULT_STR
+            it.ev = DEFAULT_STR
+            it.photoCount = DEFAULT_STR
+            it.videoTime = DEFAULT_TIME
+            it.cameraModel = CrCameraInfo.CrCameraMode.NON
+        }
+        // todo: 2023/8/3 初始化媒体信息
+        mediaInfo.postValue(CrMediaInfo(name = ""))
+        mediaInfo.value?.let {
+            it.time = DEFAULT_TIME
+            it.size = DEFAULT_STR
+            it.name = DEFAULT_STR
+        }
+    }
+
+
+    /**
+     * 覆写注册监听
+     */
+    override fun initListener() {
+        // todo: 2023/8/2 相机连接
+        CameraKey.KeyConnection.create().listen(this) { key ->
+            key?.let { itKey ->
+                if (itKey) {
+                    cameraInfo.value?.isConnection = true
+                    // todo: 2023/8/2 相机连接后 注册其他
+                    listenerOther()
+                    refresh(cameraInfo)
+                } else {
+                    cameraInfo.value?.let {
+                        it.isConnection = false
+                        it.iso = DEFAULT_STR
+                        it.speed = DEFAULT_STR
+                        it.focal = DEFAULT_STR
+                        it.ev = DEFAULT_STR
+                        it.videoTime = DEFAULT_TIME
+                        it.photoCount = DEFAULT_STR
+                        it.cameraModel = CrCameraInfo.CrCameraMode.NON
+                        refresh(cameraInfo)
+                    }
+                    mediaInfo.value?.let {
+                        it.time = DEFAULT_TIME
+                        it.size = DEFAULT_STR
+                        it.name = DEFAULT_STR
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * 注册其他
+     */
+    private fun listenerOther() {
+        // todo: 2023/8/2 ISO监听
+        CameraKey.KeyISO.create().listen(this) {
+            it?.let {
+                cameraInfo.value?.iso = CrUtil.getISO(it)
+                refresh(cameraInfo)
+            }
+        }
+        // todo: 2023/8/2 焦距
+        CameraKey.KeyCameraZoomFocalLength.create().listen(this) {
+            it?.let {
+                cameraInfo.value?.focal = it.toString()
+                refresh(cameraInfo)
+            }
+        }
+        // todo: 2023/8/2 补偿值
+        CameraKey.KeyExposureCompensation.create().listen(this) {
+            it?.let {
+                cameraInfo.value?.ev = CrUtil.getEv(it)
+                refresh(cameraInfo)
+            }
+        }
+        // todo: 2023/8/2 快门
+        CameraKey.KeyShutterSpeed.create().listen(this) {
+            it?.let {
+                cameraInfo.value?.speed = CrUtil.getShutterSpeed(it)
+                refresh(cameraInfo)
+            }
+        }
+        // todo: 2023/8/2 存储卡
+        CameraKey.KeyCameraStorageInfos.create().listen(this) {
+            it?.let {
+                var info: List<CameraStorageInfo> = it.cameraStorageInfoList
+                if (info != null && info.isNotEmpty()) {
+                    cameraInfo.value?.photoCount = info?.get(0).availablePhotoCount.toString()
+                    cameraInfo.value?.videoTime =
+                        CrUtil.secondsToHMS(info?.get(0).availableVideoDuration)
+                    refresh(cameraInfo)
+                }
+            }
+        }
+        // todo: 2023/8/2 创建新媒体
+        CameraKey.KeyNewlyGeneratedMediaFile.create().listen(this) {
+            it?.let {
+                if (it.type == MediaFileType.JPEG) {
+                    mediaInfo.value?.name = "FX_${CrUnitManager.toSystemDate()}"
+                    mediaInfo.value?.size = CrUnitManager.toFileSize(it.fileSize)
+                    mediaInfo.value?.time =
+                        "${it.createTime.year}-${it.createTime.month}-${it.createTime.day} ${it.createTime.hour}:${it.createTime.minute}:${it.createTime.second}"
+                }
+            }
+        }
+        // todo: 2023/8/3 相机模式
+        CameraKey.KeyCameraMode.create().listen(this){
+            it?.let {
+                when(it){
+                    CameraMode.VIDEO_NORMAL->{
+                        cameraInfo.value?.cameraModel = CrCameraInfo.CrCameraMode.VIDEO
+                    }
+                    CameraMode.UNKNOWN->{
+                        cameraInfo.value?.cameraModel = CrCameraInfo.CrCameraMode.NON
+                    }
+                    else->{
+                        cameraInfo.value?.cameraModel = CrCameraInfo.CrCameraMode.PHOTO
+                    }
+                }
+            }
+        }
+    }
+}

+ 33 - 0
app/src/main/java/com/cr/viewmodel/CrRemoteControlVM.kt

@@ -3,7 +3,13 @@ package com.cr.viewmodel
 import androidx.lifecycle.MutableLiveData
 import com.cr.common.CrRemoteControlInfo
 import com.cr.cruav.R
+import com.cr.data.CrUtil
+import dji.sdk.keyvalue.key.CameraKey
+import dji.sdk.keyvalue.key.KeyTools
 import dji.sdk.keyvalue.key.RemoteControllerKey
+import dji.sdk.keyvalue.value.common.EmptyMsg
+import dji.v5.common.callback.CommonCallbacks
+import dji.v5.common.error.IDJIError
 import dji.v5.et.create
 import dji.v5.et.listen
 import dji.v5.utils.common.ContextUtil
@@ -57,5 +63,32 @@ class CrRemoteControlVM : CrViewModel(){
                 refresh(remoteControlInfo)
             }
         }
+        // todo: 2023/8/4 拍照按钮按下
+        RemoteControllerKey.KeyShutterButtonDown.create().listen(this){
+            it?.let {
+                if(it){
+                    CrUtil.print("拍照按钮按下");
+                    dji.v5.manager.KeyManager.getInstance()
+                        .performAction(
+                            KeyTools.createKey(CameraKey.KeyStartShootPhoto),
+                            object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg> {
+                                override fun onSuccess(t: EmptyMsg?) {
+                                    CrUtil.print("拍照成功${t.toString()}")
+                                }
+
+                                override fun onFailure(error: IDJIError) {
+                                    CrUtil.print("拍照失败${error.description()}}")
+                                }
+                            })
+                }
+            }
+        }
+        RemoteControllerKey.KeyRCSwitchButtonDown.create().listen(this){
+            it?.let {
+                if(it){
+                    CrUtil.print("切换")
+                }
+            }
+        }
     }
 }

+ 7 - 0
app/src/main/java/com/cr/viewmodel/CrVideoChannelVM.kt

@@ -228,4 +228,11 @@ class CrVideoChannelVM : CrViewModel() {
             }
         }
     }
+
+    /**
+     * 刷新信息
+     */
+    fun refreshVideoChannelInfo(){
+        videoChannelInfo.postValue(videoChannelInfo.value)
+    }
 }

+ 86 - 0
app/src/main/java/com/cr/widget/CrBaseDrawWidget.kt

@@ -0,0 +1,86 @@
+package com.cr.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import com.cr.common.CrColorManager
+import com.cr.common.CrUnitManager
+import com.cr.cruav.R
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/1 09:38
+ * 描述:基础绘制组件 继承自View 共需要动态绘制内容的视图继承使用
+ */
+open class CrBaseDrawWidget @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+    // todo: 2023/8/1 视图大小定义
+    protected var viewWidth: Int = 0   // define: 2023/8/1 视图宽度
+    protected var viewHeight: Int = 0  // define: 2023/8/1 视图高度
+    protected var canvasSize: Int = 0  // define: 2023/8/1 视图大小
+
+    // todo: 2023/8/1 画布
+    protected var canvas: Canvas? = null
+
+    /**
+     * 生命周期函数
+     * 当xml加载完成后会调用此方法
+     */
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        setBackgroundColor(Color.argb(0,70,71,81))
+    }
+
+    /**
+     * 生命周期函数
+     * 视图加入窗口
+     */
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+    }
+
+    /**
+     * 重绘
+     * @param widthMeasureSpec Int
+     * @param heightMeasureSpec Int
+     */
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        // todo: 2023/7/31 获取视图宽度和高度 单位是像素
+        this.viewWidth = MeasureSpec.getSize(widthMeasureSpec)
+        this.viewHeight = MeasureSpec.getSize(heightMeasureSpec)
+        // todo: 2023/7/31 取小的那个值作为画布大小
+        canvasSize = if (viewWidth > viewHeight) viewHeight else viewWidth
+    }
+
+    /**
+     * 重绘
+     * @param canvas Canvas
+     */
+    override fun draw(canvas: Canvas?) {
+        super.draw(canvas)
+        this.canvas = canvas
+    }
+
+    /**
+     * 初始化线类型画笔
+     * @param paint Paint
+     */
+    protected fun crPaintInit(paint:Paint){
+        paint?.let {
+            it.isAntiAlias = true  // todo: 2023/8/1 抗锯齿
+            it.color = CrColorManager.getColor(context, R.color.white)
+            it.alpha = 100
+            it.strokeJoin = Paint.Join.ROUND
+            it.strokeCap = Paint.Cap.BUTT
+            it.style = Paint.Style.STROKE  // define: 2023/8/1 画笔类型
+        }
+    }
+}

+ 1 - 1
app/src/main/java/com/cr/widget/CrButton.kt → app/src/main/java/com/cr/widget/CrButtonWidget.kt

@@ -15,7 +15,7 @@ import com.cr.common.CrFontManager
  * 创建日期:2023/4/14 16:13
  * 描述:通用按钮
  */
-class CrButton @JvmOverloads constructor(
+class CrButtonWidget @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttr: Int = 0

+ 246 - 0
app/src/main/java/com/cr/widget/CrCompassWidget.kt

@@ -0,0 +1,246 @@
+package com.cr.widget
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import android.util.AttributeSet
+import com.cr.common.CrColorManager
+import com.cr.common.CrUnitManager
+import com.cr.cruav.R
+import com.cr.data.CrUtil
+import java.util.*
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/8/1 09:33
+ * 描述:指南针组件
+ */
+class CrCompassWidget @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAtr: Int = 0
+) : CrBaseDrawWidget(context, attrs, defStyleAtr), SensorEventListener {
+    // todo: 2023/8/1 画笔定义
+    private var mLinePaint: Paint? = null  // define: 2023/8/1 线画笔
+    private var mCirclePaint: Paint? = null // define: 2023/8/1 圆画笔
+    private var mCircleCenterPaint: Paint? = null  // define: 2023/8/1 圆心画笔
+    private var mArcScanPaint: Paint? = null // define: 2023/8/1 扫描圆弧画笔
+
+    // todo: 2023/8/1 宽度定义
+    private var mStrokeWith: Int = 1  // define: 2023/8/1 描边宽度
+    private var mScanAngle: Float = 90f // define: 2023/8/1 扫描角度
+
+    // todo: 2023/8/1 传感器
+    private var sensorManger: SensorManager? = null // define: 2023/8/1 传感器管理器
+    private var magneticSensor: Sensor? = null  // define: 2023/8/1 磁场传感器
+    private var accelerometerSensor: Sensor? = null  // define: 2023/8/1 加速度传感器
+    private var values: FloatArray = FloatArray(3) // define: 2023/8/1 计算值
+    private var r: FloatArray = FloatArray(9)  // define: 2023/8/1 旋转矩阵
+    private var gravity: FloatArray = FloatArray(3)  // define: 2023/8/1 磁场传感器数据
+    private var geomagnetic: FloatArray = FloatArray(3)  // define: 2023/8/1 加速度传感器数据
+
+    /**
+     * 初始还
+     */
+    init {
+        // todo: 2023/8/1 初始化画笔
+        initPaint()
+    }
+
+    /**
+     * 加入窗体
+     */
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        // todo: 2023/8/1 初始化传感器
+        sensorManger = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
+        sensorManger?.let { itSensorManager ->
+            // todo: 2023/8/1 获取传感器
+            magneticSensor = itSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)
+            accelerometerSensor = itSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
+
+            // todo: 2023/8/2 SensorManager.SENSOR_DELAY_GAME 代表更新速率 指最高的速率
+
+            // todo: 2023/8/1 注册地磁传感器事件
+            magneticSensor?.let {
+                itSensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_GAME)
+            }
+
+            // todo: 2023/8/1 注册加速度传感器事件
+            accelerometerSensor?.let {
+                itSensorManager.registerListener(this, it, SensorManager.SENSOR_DELAY_GAME)
+            }
+        }
+    }
+
+    /**
+     * 移除窗体
+     */
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        // todo: 2023/8/1 移除注册的监听事件
+        sensorManger?.let {
+            it.unregisterListener(this)
+        }
+    }
+
+    /**
+     * 绘制
+     * @param canvas Canvas
+     */
+    override fun draw(canvas: Canvas?) {
+        // todo: 2023/8/1 继承超类的方法 即可获取全局画布
+        super.draw(canvas)
+        // todo: 2023/8/1 绘制线
+        drawLine()
+        // todo: 2023/8/1 绘制圆
+        drawCircle()
+        // todo: 2023/8/1 绘制扫描圆弧
+        drawScanArc()
+        // todo: 2023/8/1 绘制圆心
+        drawCircleCenter()
+    }
+
+    /**
+     * 绘制扫描圆弧
+     */
+    private fun drawScanArc() {
+        var paddingPixel: Float = CrUnitManager.dp2px(2f)
+        // todo: 2023/8/1 圆弧绘制区域
+        var mRectF: RectF = RectF(
+            paddingPixel,
+            paddingPixel,
+            canvasSize - paddingPixel,
+            canvasSize - paddingPixel
+        )
+        mArcScanPaint?.alpha = 80
+        canvas?.drawArc(mRectF, mScanAngle - 15, 30f, true, mArcScanPaint!!)
+    }
+
+    /**
+     * 绘制圆心
+     */
+    private fun drawCircleCenter() {
+        var centerX: Float = canvasSize / 2f
+        var centerY: Float = canvasSize / 2f
+        var radius: Float = CrUnitManager.dp2px(3f)
+        canvas?.drawCircle(centerX, centerY, radius, mCircleCenterPaint!!)
+    }
+
+    /**
+     * 绘制线
+     */
+    private fun drawLine() {
+        // todo: 2023/8/1 画横线
+        var hStartX: Float = 0f
+        var hStartY: Float = canvasSize / 2f
+        var hEndX: Float = canvasSize * 1f
+        var hEndY: Float = canvasSize / 2f
+        canvas?.drawLine(hStartX, hStartY, hEndX, hEndY, mLinePaint!!)
+
+        // todo: 2023/8/1 画竖线
+        var vStartX: Float = canvasSize / 2f
+        var vStartY: Float = 0f
+        var vEndX: Float = canvasSize / 2f
+        var vEndY: Float = canvasSize * 1f
+        canvas?.drawLine(vStartX, vStartY, vEndX, vEndY, mLinePaint!!)
+    }
+
+    /**
+     * 绘制圆
+     */
+    private fun drawCircle() {
+        var radius: Float = (canvasSize / 2f - 20) / 5f
+        var centerX: Float = canvasSize / 2f
+        var centerY: Float = canvasSize / 2f
+        for (index in 1 until 6) {
+            mCirclePaint?.alpha = 255 - ((255 - 30) / 5) * index
+            canvas?.drawCircle(centerX, centerY, radius * index, mCirclePaint!!)
+        }
+    }
+
+    /**
+     * 初始化画笔
+     */
+    private fun initPaint() {
+        // todo: 2023/8/1 初始化线画笔
+        mLinePaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        mLinePaint?.let {
+            crPaintInit(it)
+            it.strokeWidth = CrUnitManager.dp2px(mStrokeWith).toFloat()
+        }
+        // todo: 2023/8/1 初始化圆画笔
+        mCirclePaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        mCirclePaint?.let {
+            crPaintInit(it)
+            it.strokeWidth = CrUnitManager.dp2px(mStrokeWith).toFloat()
+        }
+        // todo: 2023/8/1 初始化圆心画笔
+        mCircleCenterPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        mCircleCenterPaint?.let {
+            crPaintInit(it)
+            it.style = Paint.Style.FILL
+            it.color = CrColorManager.getColor(context, R.color.white)
+            it.alpha = 255
+            it.strokeWidth = CrUnitManager.dp2px(3f)
+        }
+        // todo: 2023/8/1 扫描圆弧画笔
+        mArcScanPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+        mArcScanPaint?.let {
+            crPaintInit(it)
+            it.alpha = 80
+            it.color = CrColorManager.getColor(context, R.color.palegreen)
+            it.style = Paint.Style.FILL
+        }
+    }
+
+    /**
+     * 传感器变化监听
+     * @param event SensorEvent
+     */
+    override fun onSensorChanged(event: SensorEvent?) {
+        // todo: 2023/8/2 地磁传感器
+        if (event?.sensor?.type == Sensor.TYPE_MAGNETIC_FIELD) {
+            geomagnetic = event?.values
+        }
+        // todo: 2023/8/2 加速度传感器
+        if (event?.sensor?.type == Sensor.TYPE_ACCELEROMETER) {
+            gravity = event?.values
+            getValue()
+        }
+    }
+
+    /**
+     * 精度变化监听
+     * @param p0 Sensor
+     * @param p1 Int
+     */
+    override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
+
+    }
+
+    /**
+     * 获取值
+     */
+    private fun getValue() {
+        // todo: 2023/8/1 传入地磁数据和加速度数据 计算旋转矩阵r
+        SensorManager.getRotationMatrix(r, null, gravity, geomagnetic)
+        // todo: 2023/8/1 根据旋转矩阵r计算方向数据
+        // todo: 2023/8/1 values[0] 记录手机绕 Z 轴旋转角度
+        // todo: 2023/8/1 values[1] 记录手机绕 X 轴旋转角度
+        // todo: 2023/8/1 values[2] 记录手机绕 Y 轴旋转角度
+        SensorManager.getOrientation(r, values)
+        var z: Double = Math.toDegrees(values!![0].toDouble()) - 90
+        var x: Double = Math.toDegrees(values!![1].toDouble())
+        var y: Double = Math.toDegrees(values!![2].toDouble())
+//        CrUtil.print(String.format("方位角:%.2f x方向:%.2f y方向:%.2f", z, x, y))
+        mScanAngle = z.toFloat()
+        invalidate()
+    }
+}

+ 4 - 4
app/src/main/java/com/cr/widget/CrSpeed.kt → app/src/main/java/com/cr/widget/CrSpeedWidget.kt

@@ -19,7 +19,7 @@ import com.cr.cruav.R
  * 创建日期:2023/7/31 09:06
  * 描述:飞行器速度View
  */
-class CrSpeed @JvmOverloads constructor(
+class CrSpeedWidget @JvmOverloads constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAtr: Int = 0
@@ -68,16 +68,16 @@ class CrSpeed @JvmOverloads constructor(
     init {
         this.mStrokeWith = CrUnitManager.getDimens(context, R.dimen.cr_5_dp).toInt()
         // todo: 2023/7/31 属性初始化
-        val attributes = context.obtainStyledAttributes(attrs, R.styleable.CrSpeed)
+        val attributes = context.obtainStyledAttributes(attrs, R.styleable.CrSpeedWidget)
         if(attributes != null){
             // todo: 2023/7/31 设置标题
-            val strTitle = attributes.getString(R.styleable.CrSpeed_speedTitle)
+            val strTitle = attributes.getString(R.styleable.CrSpeedWidget_speedTitle)
             title = if(strTitle != null && strTitle != ""){
                 strTitle
             }else{
                 "**速度"
             }
-            val floatProgress = attributes.getInt(R.styleable.CrSpeed_speedProgress,0)
+            val floatProgress = attributes.getInt(R.styleable.CrSpeedWidget_speedProgress,0)
             progressAngle = floatProgress
             progressValue = floatProgress
         }

+ 5 - 0
app/src/main/res/drawable/shape_back_circle.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/yellow"/>
+    <corners android:radius="@dimen/cr_50_dp"/>
+</shape>

+ 6 - 6
app/src/main/res/layout/frag_case_tools.xml

@@ -27,35 +27,35 @@
             android:id="@+id/case_on_draw"/>
     </LinearLayout>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_save"
         app:crLeftResource = "@string/ico_save"
         android:id="@+id/case_save"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_delete"
         app:crLeftResource = "@string/ico_delete"
         android:id="@+id/cases_delete"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_back"
         app:crLeftResource = "@string/ico_undo"
         android:id="@+id/case_undo"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_reset"
         app:crLeftResource = "@string/ico_remove"
         android:id="@+id/case_reset"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_remove_case"
         app:crLeftResource = "@string/ico_delete"
         android:id="@+id/case_remove_point"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_case_title_move_case"
         app:crLeftResource = "@string/ico_move"

+ 4 - 4
app/src/main/res/layout/frag_doodle.xml

@@ -25,19 +25,19 @@
             android:id="@+id/doodle_on_draw"/>
     </LinearLayout>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_doodle_title_clear"
         app:crLeftResource = "@string/ico_clear"
         android:id="@+id/doodle_clear"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_doodle_title_save"
         app:crLeftResource = "@string/ico_save"
         android:id="@+id/doodle_save"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_doodle_title_remove"
         app:crLeftResource = "@string/ico_remove"
@@ -55,7 +55,7 @@
             android:id="@+id/doodle_on_select"/>
     </LinearLayout>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_doodle_title_on_delete"
         app:crLeftResource = "@string/ico_delete"

+ 46 - 18
app/src/main/res/layout/frag_dynamic_info.xml

@@ -19,7 +19,8 @@
                     android:text="@string/title_camera_iso"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/camera_iso"/>
             </LinearLayout>
         </LinearLayout>
         <LinearLayout
@@ -32,7 +33,8 @@
                     android:text="@string/title_camera_speed"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/camera_speed"/>
             </LinearLayout>
         </LinearLayout>
         <LinearLayout
@@ -44,7 +46,8 @@
                     android:text="@string/title_camera_focal"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/camera_focal"/>
             </LinearLayout>
         </LinearLayout>
         <LinearLayout
@@ -56,16 +59,26 @@
                     android:text="@string/title_camera_ev"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/camera_ev"/>
             </LinearLayout>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
         <LinearLayout
             style="@style/dji_camera_component"
             android:layout_width="@dimen/cr_80_dp">
-            <ImageView
-                style="@style/dji_top_component_img"
-                android:src="@drawable/sd_zpsl"/>
+            <RelativeLayout
+                style="@style/dji_top_component_panel">
+                <ImageView
+                    style="@style/dji_top_component_img"
+                    android:src="@drawable/sd_zpsl"/>
+                <TextView
+                    android:layout_width="@dimen/cr_10_dp"
+                    android:layout_height="@dimen/cr_10_dp"
+                    android:background="@drawable/shape_back_circle"
+                    android:id="@+id/camera_model_photo"
+                    android:visibility="gone"/>
+            </RelativeLayout>
             <LinearLayout
                 style="@style/dji_top_component_lbl_panel">
                 <TextView
@@ -73,15 +86,25 @@
                     android:text="@string/title_camera_photo"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/sd_photo_count"/>
             </LinearLayout>
         </LinearLayout>
         <LinearLayout
             style="@style/dji_camera_component"
             android:layout_width="@dimen/cr_80_dp">
-            <ImageView
-                style="@style/dji_top_component_img"
-                android:src="@drawable/sd_spsj"/>
+            <RelativeLayout
+                style="@style/dji_top_component_panel">
+                <ImageView
+                    style="@style/dji_top_component_img"
+                    android:src="@drawable/sd_spsj"/>
+                <TextView
+                    android:layout_width="@dimen/cr_10_dp"
+                    android:layout_height="@dimen/cr_10_dp"
+                    android:background="@drawable/shape_back_circle"
+                    android:id="@+id/camera_model_video"
+                    android:visibility="gone"/>
+            </RelativeLayout>
             <LinearLayout
                 style="@style/dji_top_component_lbl_panel">
                 <TextView
@@ -89,7 +112,8 @@
                     android:text="@string/title_camera_video"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/value_camera_video"/>
+                    android:text="@string/value_camera_video"
+                    android:id="@+id/sd_video_time"/>
             </LinearLayout>
         </LinearLayout>
         <View style="@style/view_split_v1"/>
@@ -103,7 +127,8 @@
                     android:text="@string/title_login_dji"/>
                 <TextView
                     style="@style/dji_top_text_value_style"
-                    android:text="@string/cr_string_default_value"/>
+                    android:text="@string/cr_string_default_value"
+                    android:id="@+id/dji_login"/>
             </LinearLayout>
         </LinearLayout>
     </LinearLayout>
@@ -116,8 +141,11 @@
         <LinearLayout
             android:layout_width="@dimen/cr_100_dp"
             android:layout_height="match_parent"
-            android:layout_margin="@dimen/common_margin"
-            android:background="@color/white"/>
+            android:layout_margin="@dimen/common_margin">
+            <com.cr.widget.CrCompassWidget
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
+        </LinearLayout>
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -132,7 +160,7 @@
                     android:layout_width="@dimen/cr_70_dp"
                     android:layout_height="match_parent"
                     android:layout_margin="@dimen/common_margin">
-                    <com.cr.widget.CrSpeed
+                    <com.cr.widget.CrSpeedWidget
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
                         app:speedProgress="30"
@@ -142,7 +170,7 @@
                     android:layout_width="@dimen/cr_70_dp"
                     android:layout_height="match_parent"
                     android:layout_margin="@dimen/common_margin">
-                    <com.cr.widget.CrSpeed
+                    <com.cr.widget.CrSpeedWidget
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
                         app:speedProgress="30"
@@ -152,7 +180,7 @@
                     android:layout_width="@dimen/cr_70_dp"
                     android:layout_height="match_parent"
                     android:layout_margin="@dimen/common_margin">
-                    <com.cr.widget.CrSpeed
+                    <com.cr.widget.CrSpeedWidget
                         android:layout_width="match_parent"
                         android:layout_height="match_parent"
                         app:speedProgress="30"

+ 10 - 0
app/src/main/res/layout/frag_fpv.xml

@@ -9,6 +9,16 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:id="@+id/surface_fpv"/>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="****"
+        android:gravity="center"
+        android:id="@+id/fpv_info"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:textColor="@color/blue"
+        android:textSize="@dimen/sp_14"/>
     <Button
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"

+ 4 - 4
app/src/main/res/layout/frag_mark.xml

@@ -52,7 +52,7 @@
 
                         <View style="@style/view_split_h2" />
 
-                        <com.cr.widget.CrButton
+                        <com.cr.widget.CrButtonWidget
                             android:id="@+id/mark_clear"
                             style="@style/view_tools_line_row_button"
                             app:crLeftResource="@string/ico_clear"
@@ -60,7 +60,7 @@
 
                         <View style="@style/view_split_h2" />
 
-                        <com.cr.widget.CrButton
+                        <com.cr.widget.CrButtonWidget
                             android:id="@+id/mark_save"
                             style="@style/view_tools_line_row_button"
                             app:crLeftResource="@string/ico_save"
@@ -68,7 +68,7 @@
 
                         <View style="@style/view_split_h2" />
 
-                        <com.cr.widget.CrButton
+                        <com.cr.widget.CrButtonWidget
                             android:id="@+id/mark_remove"
                             style="@style/view_tools_line_row_button"
                             app:crLeftResource="@string/ico_remove"
@@ -93,7 +93,7 @@
 
                         <View style="@style/view_split_h2" />
 
-                        <com.cr.widget.CrButton
+                        <com.cr.widget.CrButtonWidget
                             android:id="@+id/mark_delete"
                             style="@style/view_tools_line_row_button"
                             app:crLeftResource="@string/ico_delete"

+ 5 - 5
app/src/main/res/layout/frag_tools.xml

@@ -13,31 +13,31 @@
         app:crTitle="@string/nv_title_tools"
         app:isDismiss="true"
         app:isGotoBack="false" />
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_tools_measure_length"
         app:crLeftResource = "@string/ico_clear"
         android:id="@+id/tools_measure_length"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_tools_measure_area"
         app:crLeftResource = "@string/ico_save"
         android:id="@+id/tools_measure_area"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_tools_measure_clear"
         app:crLeftResource = "@string/ico_remove"
         android:id="@+id/tools_measure_clear"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_tools_get_location"
         app:crLeftResource = "@string/ico_remove"
         android:id="@+id/tools_get_location"/>
     <View style="@style/view_split_h2"/>
-    <com.cr.widget.CrButton
+    <com.cr.widget.CrButtonWidget
         style="@style/view_tools_line_row_button"
         app:crTitle="@string/frag_tools_to_location"
         app:crLeftResource = "@string/ico_remove"

+ 11 - 2
app/src/main/res/values/themes.xml

@@ -1,6 +1,6 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- Base application theme. -->
-    <style name="Theme.CrUAV" parent="Theme.AppCompat.Light.NoActionBar">
+    <style name="Theme.CrUAV" parent="Theme.Design.NoActionBar">
         <!-- Primary brand color. -->
         <item name="colorPrimary">@color/colorPrimary</item>
         <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
@@ -78,6 +78,13 @@
         <item name="android:layout_weight">0</item>
     </style>
 
+    <!--大疆顶部视图-组件-容器样式-->
+    <style name="dji_top_component_panel">
+        <item name="android:layout_width">@dimen/cr_30_dp</item>
+        <item name="android:layout_height">@dimen/cr_30_dp</item>
+        <item name="android:layout_weight">0</item>
+    </style>
+
     <!--大疆顶部视图-组件-文字-容器样式-->
     <style name="dji_top_component_lbl_panel">
         <item name="android:layout_width">wrap_content</item>
@@ -378,6 +385,8 @@
         <item name="android:layout_weight">1</item>
     </style>
 
+    <style name="Theme">Theme.NoTitleBar.Fullscreen</style>
+
     <!--自定义文本框属性-->
     <declare-styleable name="ViewEditTextProperty">
         <attr name="crHint" />
@@ -404,7 +413,7 @@
     </declare-styleable>
 
     <!--速度控件属性-->
-    <declare-styleable name="CrSpeed">
+    <declare-styleable name="CrSpeedWidget">
         <attr name="speedTitle" format="string"/>
         <attr name="speedProgress" format="integer"/>
     </declare-styleable>

+ 2 - 1
build.gradle

@@ -1,7 +1,8 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 buildscript {
     ext.kotlin_version = '1.6.10'
-    ext.djisdk_version = '5.4.0'
+    ext.djisdk_version = '5.5.0'
+    ext.arcgissdk_version = '100.8.0'
     repositories {
         google()
         jcenter()

+ 1 - 1
gradle/wrapper/gradle-wrapper.properties

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip