Browse Source

图层控制功能完成

不会爬树的猴 2 years ago
parent
commit
44413c08a2
56 changed files with 1758 additions and 108 deletions
  1. 0 1
      .idea/gradle.xml
  2. 3 3
      app/libs/android-sdk-v5-uxsdk/build.gradle
  3. 7 3
      app/src/main/AndroidManifest.xml
  4. 204 0
      app/src/main/java/com/cr/adapter/LayerAdapter.kt
  5. 43 0
      app/src/main/java/com/cr/common/CrUnitManager.kt
  6. 82 26
      app/src/main/java/com/cr/common/DataManager.kt
  7. 45 0
      app/src/main/java/com/cr/common/DatabaseAppManager.kt
  8. 118 0
      app/src/main/java/com/cr/common/DatabaseBaseManager.kt
  9. 43 0
      app/src/main/java/com/cr/common/DatabaseConfigManager.kt
  10. 11 28
      app/src/main/java/com/cr/cruav/AvLogin.kt
  11. 27 17
      app/src/main/java/com/cr/cruav/AvMain.kt
  12. 40 14
      app/src/main/java/com/cr/data/utils.kt
  13. 78 0
      app/src/main/java/com/cr/map/EventMapAction.kt
  14. 29 0
      app/src/main/java/com/cr/map/EventMarkChange.kt
  15. 36 0
      app/src/main/java/com/cr/map/LayerConfigModel.kt
  16. 107 0
      app/src/main/java/com/cr/map/LayerManager.kt
  17. 55 0
      app/src/main/java/com/cr/map/LayerModel.kt
  18. 30 0
      app/src/main/java/com/cr/map/LayerType.kt
  19. 17 0
      app/src/main/java/com/cr/map/SketchGraphicsOverlay.kt
  20. 69 0
      app/src/main/java/com/cr/pages/FragmentLayerControl.kt
  21. 464 6
      app/src/main/java/com/cr/pages/FragmentMap.kt
  22. 4 4
      app/src/main/java/com/cr/pages/FragmentSetDataDownload.kt
  23. 1 1
      app/src/main/res/drawable/shape_back_fragment.xml
  24. 34 0
      app/src/main/res/drawable/switch_smart_thumb.xml
  25. 19 0
      app/src/main/res/drawable/switch_smart_track.xml
  26. 1 1
      app/src/main/res/layout/av_main.xml
  27. 28 0
      app/src/main/res/layout/frag_layer_control.xml
  28. 58 0
      app/src/main/res/layout/item_layercontrol.xml
  29. 3 0
      app/src/main/res/values-sw1024dp/dimens.xml
  30. 3 0
      app/src/main/res/values-sw1280dp/dimens.xml
  31. 3 0
      app/src/main/res/values-sw1365dp/dimens.xml
  32. 3 0
      app/src/main/res/values-sw240dp/dimens.xml
  33. 3 0
      app/src/main/res/values-sw320dp/dimens.xml
  34. 3 0
      app/src/main/res/values-sw384dp/dimens.xml
  35. 3 0
      app/src/main/res/values-sw392dp/dimens.xml
  36. 3 0
      app/src/main/res/values-sw400dp/dimens.xml
  37. 3 0
      app/src/main/res/values-sw410dp/dimens.xml
  38. 3 0
      app/src/main/res/values-sw411dp/dimens.xml
  39. 3 0
      app/src/main/res/values-sw432dp/dimens.xml
  40. 3 0
      app/src/main/res/values-sw480dp/dimens.xml
  41. 3 0
      app/src/main/res/values-sw533dp/dimens.xml
  42. 3 0
      app/src/main/res/values-sw592dp/dimens.xml
  43. 3 0
      app/src/main/res/values-sw600dp/dimens.xml
  44. 3 0
      app/src/main/res/values-sw640dp/dimens.xml
  45. 3 0
      app/src/main/res/values-sw662dp/dimens.xml
  46. 3 0
      app/src/main/res/values-sw720dp/dimens.xml
  47. 3 0
      app/src/main/res/values-sw768dp/dimens.xml
  48. 3 0
      app/src/main/res/values-sw800dp/dimens.xml
  49. 3 0
      app/src/main/res/values-sw811dp/dimens.xml
  50. 3 0
      app/src/main/res/values-sw820dp/dimens.xml
  51. 3 0
      app/src/main/res/values-sw960dp/dimens.xml
  52. 3 0
      app/src/main/res/values-sw961dp/dimens.xml
  53. 4 0
      app/src/main/res/values/dimens.xml
  54. 1 1
      app/src/main/res/values/strings.xml
  55. 27 0
      app/src/main/res/values/themes.xml
  56. 1 3
      settings.gradle

+ 0 - 1
.idea/gradle.xml

@@ -12,7 +12,6 @@
           <set>
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/app" />
-            <option value="$PROJECT_DIR$/app/libs/android-sdk-v5-uxsdk" />
           </set>
         </option>
       </GradleProjectSettings>

+ 3 - 3
app/libs/android-sdk-v5-uxsdk/build.gradle

@@ -34,9 +34,9 @@ dependencies {
     androidTestImplementation 'androidx.test.ext:junit:1.1.1'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
 
-    implementation "com.dji:dji-sdk-v5-aircraft:5.2.0"
-    implementation "com.dji:dji-sdk-v5-networkImp:5.2.0"
-    compileOnly "com.dji:dji-sdk-v5-aircraft-provided:5.2.0"
+    implementation "com.dji:dji-sdk-v5-aircraft:5.3.0"
+    implementation "com.dji:dji-sdk-v5-networkImp:5.3.0"
+    compileOnly "com.dji:dji-sdk-v5-aircraft-provided:5.3.0"
 
     implementation 'com.squareup.okio:okio:1.15.0'
     implementation 'com.squareup.wire:wire-runtime:2.2.0'

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

@@ -35,20 +35,24 @@
         android:name=".CrApplication"
         android:allowBackup="true"
         android:icon="@drawable/app_icon"
-        android:label="@string/app_name"
+        android:label="@string/cr_app_name"
         android:roundIcon="@drawable/app_icon"
         android:supportsRtl="true"
         android:networkSecurityConfig="@xml/network_security_config"
         android:theme="@style/Theme.CrUAV">
         <activity
             android:name=".AvMain"
-            android:exported="false" />
+            android:exported="false"
+            android:configChanges="orientation|screenSize"
+            android:screenOrientation="reverseLandscape"/>
 
         <meta-data
             android:name="com.dji.sdk.API_KEY"
             android:value="9ca142bd221858778ce319da" />
 
-        <activity android:name=".AvLogin">
+        <activity android:name=".AvLogin"
+            android:configChanges="orientation|screenSize"
+            android:screenOrientation="reverseLandscape">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />

+ 204 - 0
app/src/main/java/com/cr/adapter/LayerAdapter.kt

@@ -0,0 +1,204 @@
+package com.cr.adapter
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CompoundButton
+import android.widget.CompoundButton.OnCheckedChangeListener
+import android.widget.ImageView
+import android.widget.Switch
+import android.widget.TextView
+import com.cr.cruav.R
+import com.cr.map.LayerModel
+import com.cr.map.LayerType
+import com.esri.arcgisruntime.layers.ArcGISMapImageSublayer
+import com.esri.arcgisruntime.layers.ArcGISTiledLayer
+import com.esri.arcgisruntime.layers.FeatureLayer
+import com.esri.arcgisruntime.mapping.view.GraphicsOverlay
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/14 14:27
+ * 描述:图层控制适配器
+ */
+class LayerAdapter@JvmOverloads constructor(
+    context: Context,
+    dataList:MutableList<LayerModel>
+) : CrAdapter<LayerModel>(context, dataList) {
+    companion object {
+        class ViewHolder {
+            var lblGroupName: TextView? = null
+            var imgIco: ImageView? = null
+            var lblName: TextView? = null
+            var sVisible: Switch? = null
+            var sLabel: Switch? = null
+            var lblLabel: TextView? = null
+        }
+    }
+
+    /**
+     * 重写获取视图方法
+     * @param position Int
+     * @param convertView View?
+     * @param viewGroup ViewGroup?
+     * @return View?
+     */
+    override fun getView(position: Int, convertView: View?, viewGroup: ViewGroup?): View? {
+        var holder:ViewHolder ?=null
+        var view = convertView
+        if(convertView == null){
+            holder = ViewHolder()
+            view = inflater?.inflate(R.layout.item_layercontrol,null)
+            holder.lblGroupName = view?.findViewById(R.id.item_layer_group_name)
+            holder.imgIco = view?.findViewById(R.id.item_layer_img)
+            holder.lblName = view?.findViewById(R.id.item_layer_name)
+            holder.sVisible = view?.findViewById(R.id.item_layer_on_visible)
+            holder.sLabel = view?.findViewById(R.id.item_layer_on_label)
+            holder.lblLabel = view?.findViewById(R.id.item_layer_lbl)
+            view?.tag = holder
+        }else{
+            holder = view?.tag as ViewHolder
+        }
+        val model = dataList!![position]
+        // todo: 2023/4/14 设置组标题
+        if (model.groupName == "") {
+            holder.lblGroupName!!.visibility = View.GONE
+        } else {
+            holder.lblGroupName!!.visibility = View.VISIBLE
+            holder.lblGroupName!!.text = model.groupName
+        }
+        // todo: 2023/4/14 设置名称
+        holder.lblName?.text = model.name
+        // todo: 2023/4/14 设置是否可见
+        holder.sVisible!!.isChecked = getLayerVisible(position)
+        holder.sLabel!!.isChecked = getLayerLabelVisible(position)
+        // todo: 2023/4/14 设置标注是否显示
+        if (model.lyrType === LayerType.LAYER_TYPE_FEATURE || model.lyrType === LayerType.LAYER_TYPE_SERVER) {
+            holder.lblLabel!!.visibility = View.VISIBLE
+            holder.sLabel!!.visibility = View.VISIBLE
+        } else {
+            holder.lblLabel!!.visibility = View.GONE
+            holder.sLabel!!.visibility = View.GONE
+        }
+        // todo: 2023/4/14 设置监听
+        holder.sLabel!!.tag = position
+        holder.sVisible!!.tag = position
+        holder.sVisible!!.setOnCheckedChangeListener(checkedChangeListener)
+        holder.sLabel!!.setOnCheckedChangeListener(checkedChangeListener)
+
+        return view
+    }
+
+    /**
+     * 监听
+     */
+    private var checkedChangeListener = object:OnCheckedChangeListener{
+        override fun onCheckedChanged(view: CompoundButton?, isChecked: Boolean) {
+            // todo: 2023/4/14 这段代码是为了保证不会通过setChecked方法激活该方法
+            if (!view!!.isPressed) return
+            val index: Int = Integer.valueOf(view.tag.toString())
+            when (view.id) {
+                R.id.item_layer_on_label -> setLabelVisible(index)
+                R.id.item_layer_on_visible -> setLayerVisible(index)
+            }
+        }
+
+    }
+
+    /**
+     * 设置图层是否显示
+     * @param index Int
+     */
+    private fun setLayerVisible(index: Int) {
+        val layerModel = dataList!![index]
+        when (layerModel.lyrType) {
+            LayerType.LAYER_TYPE_TILED -> {
+                val tLayer = layerModel.layer as ArcGISTiledLayer
+                layerModel.isVisible = !layerModel.isVisible
+                tLayer.isVisible = layerModel.isVisible
+            }
+            LayerType.LAYER_TYPE_FEATURE, LayerType.LAYER_TYPE_FEATURE_EDIT -> {
+                val fLayer = layerModel.layer as FeatureLayer
+                layerModel.isVisible = !layerModel.isVisible
+                fLayer.isVisible = layerModel.isVisible
+            }
+            LayerType.LAYER_TYPE_GRAPHIC -> {
+                val gLayer = layerModel.layer as GraphicsOverlay
+                layerModel.isVisible = !layerModel.isVisible
+                gLayer.isVisible = layerModel.isVisible
+            }
+            LayerType.LAYER_TYPE_SERVER -> {
+                val sLayer = layerModel.layer as ArcGISMapImageSublayer
+                layerModel.isVisible = !layerModel.isVisible
+                sLayer.isVisible = layerModel.isVisible
+            }
+        }
+    }
+
+    /**
+     * 获取图层是否显示
+     * @param index Int 图层Index
+     * @return Boolean
+     */
+    private fun getLayerVisible(index: Int): Boolean {
+        val layerModel = dataList!![index]
+        return when (layerModel.lyrType) {
+            LayerType.LAYER_TYPE_TILED -> {
+                val tLayer = layerModel.layer as ArcGISTiledLayer
+                tLayer.isVisible
+            }
+            LayerType.LAYER_TYPE_FEATURE, LayerType.LAYER_TYPE_FEATURE_EDIT -> {
+                val fLayer = layerModel.layer as FeatureLayer
+                fLayer.isVisible
+            }
+            LayerType.LAYER_TYPE_GRAPHIC -> {
+                val gLayer = layerModel.layer as GraphicsOverlay
+                gLayer.isVisible
+            }
+            LayerType.LAYER_TYPE_SERVER -> {
+                val sLayer = layerModel.layer as ArcGISMapImageSublayer
+                sLayer.isVisible
+            }
+            else -> false
+        }
+    }
+
+    /**
+     * 获取图层标注是否显示
+     * @param index Int 图层Index
+     * @return Boolean
+     */
+    private fun getLayerLabelVisible(index: Int): Boolean {
+        val layerModel = dataList!![index]
+        return when (layerModel.lyrType) {
+            LayerType.LAYER_TYPE_FEATURE -> {
+                val fLayer = layerModel.layer as FeatureLayer
+                fLayer.isLabelsEnabled
+            }
+            LayerType.LAYER_TYPE_SERVER -> {
+                val sLayer = layerModel.layer as ArcGISMapImageSublayer
+                sLayer.isLabelsEnabled
+            }
+            else -> false
+        }
+    }
+
+    /**
+     * 控制图层是否显示标注
+     * @param index Int 图层Index
+     */
+    private fun setLabelVisible(index: Int) {
+        val layerModel: LayerModel = dataList!![index]
+        when (layerModel.lyrType) {
+            LayerType.LAYER_TYPE_FEATURE -> {
+                val fLayer = layerModel.layer as FeatureLayer
+                fLayer.isLabelsEnabled = !fLayer.isLabelsEnabled
+            }
+            LayerType.LAYER_TYPE_SERVER -> {
+                val sLayer = layerModel.layer as ArcGISMapImageSublayer
+                sLayer.isLabelsEnabled = !sLayer.isLabelsEnabled
+            }
+        }
+    }
+}

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

@@ -0,0 +1,43 @@
+package com.cr.common
+
+import android.content.res.Resources
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/14 11:37
+ * 描述:单位管理类
+ */
+class CrUnitManager {
+    companion object{
+        /**
+         * dp转像素
+         * @param dp Float dp值
+         * @return Float 像素值
+         */
+        fun dp2px(dp: Float): Float {
+            val metrics = Resources.getSystem().displayMetrics
+            return dp * metrics.density
+        }
+
+        /**
+         * dp转像素
+         * @param dp Int dp值
+         * @return Float 像素值
+         */
+        fun dp2px(dp: Int): Int {
+            val metrics = Resources.getSystem().displayMetrics
+            return (dp * metrics.density).toInt()
+        }
+
+        /**
+         * 像素转dp
+         * @param px Int 像素
+         * @return Int dp值
+         */
+        fun px2dp(px: Int): Int {
+            val metrics = Resources.getSystem().displayMetrics
+            return (px / metrics.density + 0.5f).toInt()
+        }
+    }
+}

+ 82 - 26
app/src/main/java/com/cr/common/DataManager.kt

@@ -1,5 +1,7 @@
 package com.cr.common
 
+import com.cr.map.LayerConfigModel
+import com.cr.map.LayerModel
 import com.cr.models.IPAndComModel
 import com.cr.models.UserModel
 
@@ -11,15 +13,15 @@ import com.cr.models.UserModel
  */
 class DataManager {
     // todo: 2023/4/3 静态方法及属性封装
-    companion object{
+    companion object {
 
         /**
          * 获取网络服务连接信息
          * @return IPAndComModel
          */
-        fun getNetworkLinkInfo():IPAndComModel{
-            var sql:String = "SELECT * FROM ipcom where CHECKED = '1'"
-            var res:List<HashMap<String,String>> = DatabaseManager.getInstance().query(sql)
+        fun getNetworkLinkInfo(): IPAndComModel {
+            var sql: String = "SELECT * FROM ipcom where CHECKED = '1'"
+            var res: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
             var map = res[0]
             map.let {
                 return IPAndComModel.initByMap(it)
@@ -30,11 +32,11 @@ class DataManager {
          * 获取网络连接列表
          * @return List<IPAndComModel>
          */
-        fun getNetworkLinks():List<IPAndComModel>{
+        fun getNetworkLinks(): List<IPAndComModel> {
             var res = mutableListOf<IPAndComModel>()
-            var sql:String = "SELECT * FROM ipcom order by id"
-            var qList:List<HashMap<String,String>> = DatabaseManager.getInstance().query(sql)
-            for(map in qList){
+            var sql: String = "SELECT * FROM ipcom order by id"
+            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            for (map in qList) {
                 var item = IPAndComModel.initByMap(map)
                 res.add(item)
             }
@@ -46,9 +48,10 @@ class DataManager {
          * @param queryItem IPAndComModel 连接信息
          * @return Boolean
          */
-        fun queryNetworkLink(queryItem:IPAndComModel):Boolean{
-            var sql = "select * from ipcom where ip='${queryItem.ip}' and com='${queryItem.com}' and server='${queryItem.serverName}'"
-            var qList:List<HashMap<String,String>> = DatabaseManager.getInstance().query(sql)
+        fun queryNetworkLink(queryItem: IPAndComModel): Boolean {
+            var sql =
+                "select * from ipcom where ip='${queryItem.ip}' and com='${queryItem.com}' and server='${queryItem.serverName}'"
+            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
             return qList != null && qList.isNotEmpty()
         }
 
@@ -58,11 +61,11 @@ class DataManager {
          * @param isChecked Boolean 选中状态
          * @return Boolean
          */
-        fun updateNetworkChecked(item:IPAndComModel,isChecked:Boolean):Boolean{
+        fun updateNetworkChecked(item: IPAndComModel, isChecked: Boolean): Boolean {
             var where = "ip='${item.ip}' and com='${item.com}' and server='${item.serverName}'"
             var checkedValue = if (isChecked) "1" else "0"
             var values = hashMapOf("checked" to checkedValue)
-            return DatabaseManager.getInstance().update("ipcom",values,where)
+            return DatabaseAppManager.getInstance().update("ipcom", values, where)
         }
 
         /**
@@ -70,18 +73,23 @@ class DataManager {
          * @param item IPAndComModel 网络连接
          * @return Boolean
          */
-        fun insertNetworkLink(item:IPAndComModel):Boolean{
-            var values = hashMapOf("checked" to "1","ip" to item.ip,"com" to item.com,"server" to item.serverName)
-            return DatabaseManager.getInstance().insert("ipcom",values)
+        fun insertNetworkLink(item: IPAndComModel): Boolean {
+            var values = hashMapOf(
+                "checked" to "1",
+                "ip" to item.ip,
+                "com" to item.com,
+                "server" to item.serverName
+            )
+            return DatabaseAppManager.getInstance().insert("ipcom", values)
         }
 
         /**
          * 取消所有连接的选中状态
          * @return Boolean
          */
-        fun cancelNetworkChecked():Boolean{
+        fun cancelNetworkChecked(): Boolean {
             var values = hashMapOf("checked" to "0")
-            return DatabaseManager.getInstance().update("ipcom",values,"")
+            return DatabaseAppManager.getInstance().update("ipcom", values, "")
         }
 
         /**
@@ -90,38 +98,86 @@ class DataManager {
          * @param password String 密码
          * @return Boolean
          */
-        fun saveUser(userName:String,password:String):Boolean{
+        fun saveUser(userName: String, password: String): Boolean {
             // todo: 2023/4/6 由于只保留一条数据 保存前先删除
             deleteUser()
             // todo: 2023/4/6 定义插入数据
-            var userMap:HashMap<String,String> = hashMapOf()
+            var userMap: HashMap<String, String> = hashMapOf()
             userMap["name"] = userName
             userMap["password"] = password
             userMap["issave"] = "1"
-            return DatabaseManager.getInstance().insert("user",userMap)
+            return DatabaseAppManager.getInstance().insert("user", userMap)
         }
 
         /**
          * 删除账号和密码
          * @return Boolean
          */
-        fun deleteUser():Boolean{
-            return DatabaseManager.getInstance().delete("user","")
+        fun deleteUser(): Boolean {
+            return DatabaseAppManager.getInstance().delete("user", "")
         }
 
         /**
          * 获取存储的账号信息
          * @return UserModel
          */
-        fun getUser():UserModel{
+        fun getUser(): UserModel {
             var user = UserModel()
             var sql = "SELECT * FROM user"
-            var qList:List<HashMap<String,String>> = DatabaseManager.getInstance().query(sql)
-            if (qList != null && qList.isNotEmpty()){
+            var qList: List<HashMap<String, String>> = DatabaseAppManager.getInstance().query(sql)
+            if (qList != null && qList.isNotEmpty()) {
                 user.userId = qList[0]["name"]
                 user.userPwd = qList[0]["password"]
             }
             return user
         }
+
+        /**
+         * 获取切片图层配置
+         * @return MutableList<LayerModel>
+         */
+        fun getTileLayerConfig(): MutableList<LayerModel> {
+            // todo: 2023/4/13 返回的图层
+            var layers: MutableList<LayerModel> = mutableListOf()
+            var sql = "select * from TileLayerConfig order by id"
+            var qList: List<HashMap<String, String>> =
+                DatabaseConfigManager.getInstance().query(sql)
+            if (qList != null && qList.isNotEmpty()) {
+                for (map in qList) {
+                    var lyrName = map["lyrname"]
+                    var lyrIsVisible = map["isvisible"].equals("1")
+                    var lyrUrl = map["lyrurl"]?.replace("/tile/", "")
+                    var model: LayerModel = LayerModel(lyrName!!, lyrIsVisible, lyrUrl!!)
+                    layers.add(model)
+                }
+            }
+            // todo: 2023/4/13 返回
+            return layers
+        }
+
+        /**
+         * 获取矢量数据配置
+         * @return MutableList<LayerConfigModel>
+         */
+        fun getVectorLayerConfig(): MutableList<LayerConfigModel> {
+            // todo: 2023/4/13 定义数据集
+            var layerList: MutableList<LayerConfigModel> = mutableListOf()
+            var sql = "SELECT * FROM BaseLayerConfig"
+            var qList: List<HashMap<String, String>> =
+                DatabaseConfigManager.getInstance().query(sql)
+            if (qList != null && qList.isNotEmpty()) {
+                for (map in qList) {
+                    var model = LayerConfigModel(
+                        map["name"]!!,
+                        map["lyrname"]!!,
+                        map["idx"]!!.toInt(),
+                        map["isvisible"].equals("1")
+                    )
+                    layerList.add(model)
+                }
+            }
+            // todo: 2023/4/13 返回数据集合
+            return layerList
+        }
     }
 }

+ 45 - 0
app/src/main/java/com/cr/common/DatabaseAppManager.kt

@@ -0,0 +1,45 @@
+package com.cr.common
+
+import android.content.ContentValues
+import android.database.Cursor
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
+import com.cr.data.CrUtil
+import java.io.File
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/3/31 09:09
+ * 描述:数据管理类
+ */
+open class DatabaseAppManager :DatabaseBaseManager(){
+    /**
+     * 在此代码块中加入静态方法
+     */
+    companion object {
+        /**
+         * 获取静态实例 单例
+         * @return DatabaseManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    object InstanceHelper {
+        var self = DatabaseAppManager()
+    }
+
+    /**
+     * 打开配置库
+     * @return Boolean
+     */
+    override fun openConfigDatabase(): Boolean {
+        var filePath: String = CrUtil.DATABASE_PATH
+        var file: File = File(filePath)
+        if (!file.exists()) return false
+        if (sqLiteDatabaseConfig == null) {
+            sqLiteDatabaseConfig = SQLiteDatabase.openDatabase(filePath, null, OPEN_READWRITE)
+        }
+        return sqLiteDatabaseConfig!!.isOpen
+    }
+}

+ 118 - 0
app/src/main/java/com/cr/common/DatabaseBaseManager.kt

@@ -0,0 +1,118 @@
+package com.cr.common
+
+import android.content.ContentValues
+import android.database.Cursor
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
+import com.cr.data.CrUtil
+import java.io.File
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/3/31 09:09
+ * 描述:数据管理类
+ */
+open class DatabaseBaseManager {
+    // define: 2023/3/31 配置库
+    var sqLiteDatabaseConfig: SQLiteDatabase? = null
+
+    /**
+     * 在此代码块中加入静态方法
+     */
+    companion object {
+        /**
+         * 获取静态实例 单例
+         * @return DatabaseManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    object InstanceHelper {
+        var self = DatabaseBaseManager()
+    }
+
+    /**
+     * 打开配置库
+     * @return Boolean
+     */
+    open fun openConfigDatabase(): Boolean {
+        var filePath: String = CrUtil.DATABASE_PATH
+        var file: File = File(filePath)
+        if (!file.exists()) return false
+        if (sqLiteDatabaseConfig == null) {
+            sqLiteDatabaseConfig = SQLiteDatabase.openDatabase(filePath, null, OPEN_READWRITE)
+        }
+        return sqLiteDatabaseConfig!!.isOpen
+    }
+
+    /**
+     * 通用查询方法
+     * @param sql String SQL
+     * @return List<HashMap<String,String>>
+     */
+    fun query(sql: String): List<HashMap<String, String>> {
+        var res = mutableListOf<HashMap<String, String>>()
+        var cursor: Cursor? = sqLiteDatabaseConfig?.rawQuery(sql, null)
+        // todo: 2023/4/3 获取列
+        cursor?.let {
+            var columns = it.columnNames
+            while (it.moveToNext()) {
+                var map = hashMapOf<String, String>()
+                for (column in columns) {
+                    var columnName = column.toLowerCase()
+                    try{
+                        map[columnName] = it.getString(it.getColumnIndex(column))
+                    }catch (e:java.lang.Exception){
+                        map[columnName] = ""
+                    }
+
+                }
+                res.add(map)
+            }
+        }
+        return res
+    }
+
+    /**
+     * 更新数据
+     * @param tabName String 待更新表名
+     * @param values HashMap<String, String> 更新值集合
+     * @param where String 条件
+     * @return Boolean 是否更新成功
+     */
+    fun update(tabName: String, values: HashMap<String, String>, where: String): Boolean {
+        var uValues = ContentValues()
+        for (value in values) {
+            uValues.put(value.key, value.value)
+        }
+        var resInt = sqLiteDatabaseConfig?.update(tabName, uValues, where, null)
+        return resInt!! > 0
+    }
+
+    /**
+     * 删除数据
+     * @param tabName String 表名
+     * @param where String 条件
+     * @return Boolean
+     */
+    fun delete(tabName:String,where:String):Boolean{
+        var resInt = sqLiteDatabaseConfig?.delete(tabName,where,null)
+        return resInt!! > 0
+    }
+
+    /**
+     * 插入数据
+     * @param tabName String 表名
+     * @param values HashMap<String, String> 插入集合
+     * @return Boolean
+     */
+    fun insert(tabName: String, values: HashMap<String, String>):Boolean{
+        var uValues = ContentValues()
+        for (value in values) {
+            uValues.put(value.key, value.value)
+        }
+        var resInt = sqLiteDatabaseConfig?.insert(tabName, null,uValues)
+        return resInt!! > 0
+    }
+}

+ 43 - 0
app/src/main/java/com/cr/common/DatabaseConfigManager.kt

@@ -0,0 +1,43 @@
+package com.cr.common
+
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteDatabase.OPEN_READWRITE
+import com.cr.data.CrUtil
+import java.io.File
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/3/31 09:09
+ * 描述:管理数据库操作类 网络下载的配置库
+ */
+class DatabaseConfigManager : DatabaseBaseManager() {
+    /**
+     * 在此代码块中加入静态方法
+     */
+    companion object {
+        /**
+         * 获取静态实例 单例
+         * @return DatabaseManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    object InstanceHelper {
+        var self = DatabaseConfigManager()
+    }
+
+    /**
+     * 打开配置库
+     * @return Boolean
+     */
+    override fun openConfigDatabase(): Boolean {
+        var filePath: String = CrUtil.DATABASE_PATH_CONFIG
+        var file: File = File(filePath)
+        if (!file.exists()) return false
+        if (sqLiteDatabaseConfig == null) {
+            sqLiteDatabaseConfig = SQLiteDatabase.openDatabase(filePath, null, OPEN_READWRITE)
+        }
+        return sqLiteDatabaseConfig!!.isOpen
+    }
+}

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

@@ -15,14 +15,14 @@ import android.widget.TextView
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import com.cr.common.DataManager
-import com.cr.common.DatabaseManager
+import com.cr.common.DatabaseAppManager
+import com.cr.common.DatabaseConfigManager
 import com.cr.common.FileManager
 import com.cr.data.CrConfig
 import com.cr.data.CrUtil
 import com.cr.data.CrUtil.Companion.onStart
 import com.cr.dialog.DialogNormal
 import com.cr.dialog.DialogNormal.DialogNormalListener
-import com.cr.dialog.DialogProgressUtil
 import com.cr.event.EventFragmentBarAction
 import com.cr.models.UserModel
 import com.cr.network.NetManager
@@ -163,31 +163,10 @@ class AvLogin : CrActivity(), OnClickListener {
                 context!!.onStart<AvMain>()
             }
             R.id.login_btn_set -> {
-//                fragIpAndCom?.let {
-//                    it.setBarVisible(isVisible = true)
-//                    showFragment(it)
-//                }
-                // todo: 2023/4/12 下载测试文件
-                TCPDataTask.getInstance().sendDownloadFile(context!!,"","http://218.59.194.74:8088/lqz_service/download/demo.rar",object:TCPDataTask.OnDownloadListener{
-                    override fun onStart() {
-                        DialogProgressUtil.show(context!!)
-                    }
-
-                    override fun onFailed(message: String) {
-                        DialogProgressUtil.dismiss()
-                    }
-
-                    override fun onProgress(progress: Int, total: Int) {
-                        DialogProgressUtil.setMax(total)
-                        var pValue = String.format("%.2f",(progress/total.toDouble())*100) + "%"
-                        DialogProgressUtil.update("1/1",pValue,progress)
-                    }
-
-                    override fun onComplete() {
-                        DialogProgressUtil.dismiss()
-                    }
-
-                })
+                fragIpAndCom?.let {
+                    it.setBarVisible(isVisible = true)
+                    showFragment(it)
+                }
             }
 
         }
@@ -304,7 +283,7 @@ class AvLogin : CrActivity(), OnClickListener {
         // todo: 2023/4/3 拷贝配置库
         FileManager.MoveDataBase(this)
         // todo: 2023/4/3 判断数据库是否存在 存在则启动
-        var databaseIsOpen: Boolean = DatabaseManager.getInstance().openConfigDatabase()
+        var databaseIsOpen: Boolean = DatabaseAppManager.getInstance().openConfigDatabase()
         // todo: 2023/4/3 最终判断是否可以正常使用App
         if (FileManager.isExists(CrUtil.PROJECT_PATH) && FileManager.isExists(CrUtil.IMAGE_PATH) && FileManager.isExists(
                 CrUtil.PROJECT_CACHE_PATH
@@ -312,6 +291,10 @@ class AvLogin : CrActivity(), OnClickListener {
         ) {
             // todo: 2023/4/3 自检通过 可正常使用
             DialogNormal(this, "操作提示", "系统自检通过,可正常使用!").show()
+            // todo: 2023/4/13 启动配置库
+            DatabaseConfigManager.getInstance().openConfigDatabase()
+            // todo: 2023/4/13 启动无人机库
+
             // todo: 2023/4/6 页面初始化显示
             initPage()
         } else {

+ 27 - 17
app/src/main/java/com/cr/cruav/AvMain.kt

@@ -16,10 +16,7 @@ import androidx.fragment.app.commitNow
 import com.cr.data.CrConfig
 import com.cr.data.CrUtil
 import com.cr.event.EventFragmentBarAction
-import com.cr.pages.FragmentFPV
-import com.cr.pages.FragmentMap
-import com.cr.pages.FragmentSet
-import com.cr.pages.FragmentTopInfo
+import com.cr.pages.*
 import com.cr.viewmodel.*
 import com.squareup.otto.Subscribe
 import dji.v5.common.error.IDJIError
@@ -43,7 +40,7 @@ class AvMain : CrActivity(), View.OnClickListener {
     private val flightControlVm: CrFlightControlVM by viewModels()
 
     // define: 2023/3/14 将链路视图绑定到模型
-    private val linkVm:CrLinkVM by viewModels()
+    private val linkVm: CrLinkVM by viewModels()
 
     // define: 2023/3/13 顶部视图容器
     private var fragmentTopInfo: FragmentTopInfo? = null
@@ -52,13 +49,16 @@ class AvMain : CrActivity(), View.OnClickListener {
     private var fragmentFPV: FragmentFPV? = null
 
     // define: 2023/3/14 地图容器
-    private var fragmentMap:FragmentMap? = null
+    private var fragmentMap: FragmentMap? = null
 
     // define: 2023/3/14 图传窗口是不是小窗口
-    private var isFpvSmallWindow:Boolean = true
+    private var isFpvSmallWindow: Boolean = true
 
     // define: 2023/4/11 初始化设置页面
-    private var fragmentSet:FragmentSet? = null
+    private var fragmentSet: FragmentSet? = null
+
+    // define: 2023/4/14 图层控制页面
+    private var fragmentLayerControl: FragmentLayerControl? = null
 
 
     /**
@@ -81,6 +81,7 @@ class AvMain : CrActivity(), View.OnClickListener {
     override fun joinControls() {
         // todo: 2023/4/11 设置点击事件
         tools_set.setOnClickListener(this)
+        tools_layer.setOnClickListener(this)
     }
 
     /**
@@ -98,12 +99,18 @@ class AvMain : CrActivity(), View.OnClickListener {
     /**
      * 初始化页面
      */
-    private fun initPage(){
+    private fun initPage() {
         // todo: 2023/4/10 显示登录账号
         av_main_lbl_user.text = CrConfig.user?.userName
         // todo: 2023/4/11 初始化设置页面
         fragmentSet = FragmentSet()
         fragmentSet?.let {
+            addFragment(it, R.id.av_frm_right_panel)
+            hideFragment(it)
+        }
+        // todo: 2023/4/14 初始化图层控制页面
+        fragmentLayerControl = FragmentLayerControl()
+        fragmentLayerControl?.let {
             addFragment(it,R.id.av_frm_right_panel)
             hideFragment(it)
         }
@@ -127,11 +134,11 @@ class AvMain : CrActivity(), View.OnClickListener {
                 CrUtil.print("切换图传窗口")
                 av_fragment_fpv.removeAllViews()
                 av_fragment_map.removeAllViews()
-                if(isFpvSmallWindow){
+                if (isFpvSmallWindow) {
                     isFpvSmallWindow = false
                     av_fragment_map.addView(fragmentFPV!!.view)
                     av_fragment_fpv.addView(fragmentMap!!.view)
-                }else{
+                } else {
                     isFpvSmallWindow = true
                     av_fragment_map.addView(fragmentMap!!.view)
                     av_fragment_fpv.addView(fragmentFPV!!.view)
@@ -144,8 +151,8 @@ class AvMain : CrActivity(), View.OnClickListener {
         }
         // todo: 2023/3/14 加入地图视图
         fragmentMap = FragmentMap()
-        supportFragmentManager.commit{
-            replace(R.id.av_fragment_map,fragmentMap!!)
+        supportFragmentManager.commit {
+            replace(R.id.av_fragment_map, fragmentMap!!)
         }
 
     }
@@ -200,10 +207,14 @@ class AvMain : CrActivity(), View.OnClickListener {
      * @param view View
      */
     override fun onClick(view: View?) {
-        when(view?.id){
-            R.id.tools_set->{
+        when (view?.id) {
+            R.id.tools_set -> {
                 showFragment(fragmentSet!!)
             }
+            R.id.tools_layer->{
+                showFragment(fragmentLayerControl!!)
+                fragmentLayerControl?.initPage()
+            }
         }
     }
 
@@ -224,13 +235,12 @@ class AvMain : CrActivity(), View.OnClickListener {
     }
 
 
-
     /**
      * 订阅Fragment管理事件
      * @param event EventFragmentBarAction
      */
     @Subscribe
     fun onFragmentBar(event: EventFragmentBarAction) {
-        hideFragment(fragmentSet!!)
+        hideFragment(event.fragment!!)
     }
 }

+ 40 - 14
app/src/main/java/com/cr/data/utils.kt

@@ -68,9 +68,34 @@ class CrUtil {
         // define: 2023/3/31 配置文件存储路径
         val CONFIG_PATH: String = "$PROJECT_PATH/config/"
 
-         // define: 2023/4/3 数据库路径
+        // define: 2023/4/3 数据库路径
         val DATABASE_PATH = "$CONFIG_PATH/dinfo.db"
 
+        // define: 2023/4/13 网络下载的飞行库文件名称
+        val DATA_FILE_NAME = "data.sqlite"
+
+        // define: 2023/4/13 网络下载的配置库文件名称
+        val CONFIG_FILE_NAME = "config.sqlite"
+
+        // define: 2023/4/13 可编辑地图数据集文件名称
+        val MAP_EDIT_FILE_NAME = "map.geodatabase"
+
+        // define: 2023/4/13 基础地图数据集文件名称
+        val MAP_BASE_FILE_NAME = "base.geodatabase"
+
+        // define: 2023/4/13 配置库文件路径
+        val DATABASE_PATH_CONFIG = "${CONFIG_PATH}/${CONFIG_FILE_NAME}"
+
+        // define: 2023/4/13 飞行库文件路径
+        val DATABASE_PATH_AIR = "${CONFIG_PATH}/${DATA_FILE_NAME}"
+
+        // define: 2023/4/13 基础地图数据集完整路径
+        val MAP_PATH_BASE = "${CONFIG_PATH}/${MAP_BASE_FILE_NAME}"
+
+        // define: 2023/4/13 可编辑地图数据集完整路径
+        val MAP_PATH_EDIT = "${CONFIG_PATH}/${MAP_EDIT_FILE_NAME}"
+
+
         /**
          * 根据等级数值获取等级
          * @param level Int
@@ -200,8 +225,8 @@ class CrUtil {
          * @param context Context 上下文
          * @return String
          */
-        fun getVersionName(context: Context):String{
-            var packageInfo:PackageInfo = getPackageInfo(context)
+        fun getVersionName(context: Context): String {
+            var packageInfo: PackageInfo = getPackageInfo(context)
             return packageInfo.versionName
         }
 
@@ -211,8 +236,8 @@ class CrUtil {
          * @return Long
          */
         @RequiresApi(Build.VERSION_CODES.P)
-        fun getVersionCode(context: Context):Long{
-            var packageInfo:PackageInfo = getPackageInfo(context)
+        fun getVersionCode(context: Context): Long {
+            var packageInfo: PackageInfo = getPackageInfo(context)
             return packageInfo.longVersionCode
         }
 
@@ -221,9 +246,10 @@ class CrUtil {
          * @param context Context 上下文
          * @return PackageInfo
          */
-        fun getPackageInfo(context: Context):PackageInfo{
-            var pm:PackageManager = context.packageManager
-            var packageInfo:PackageInfo = pm.getPackageInfo(context.packageName,PackageManager.GET_CONFIGURATIONS)
+        fun getPackageInfo(context: Context): PackageInfo {
+            var pm: PackageManager = context.packageManager
+            var packageInfo: PackageInfo =
+                pm.getPackageInfo(context.packageName, PackageManager.GET_CONFIGURATIONS)
             return packageInfo
         }
 
@@ -233,12 +259,12 @@ class CrUtil {
          * @param message String 错误消息
          * @return String?
          */
-        fun TextView.checkBlank(message: String):String?{
+        fun TextView.checkBlank(message: String): String? {
             val text = this.text.toString()
-            if(text.isBlank()){
-                DialogNormal(this.context,"警告",message).show()
+            if (text.isBlank()) {
+                DialogNormal(this.context, "警告", message).show()
                 return null
-            }else{
+            } else {
                 return text
             }
         }
@@ -248,8 +274,8 @@ class CrUtil {
          * 启动窗体
          * @receiver Context
          */
-        inline fun <reified T: Activity> Context.onStart(){
-            startActivity(Intent(this,T::class.java))
+        inline fun <reified T : Activity> Context.onStart() {
+            startActivity(Intent(this, T::class.java))
         }
     }
 }

+ 78 - 0
app/src/main/java/com/cr/map/EventMapAction.kt

@@ -0,0 +1,78 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 15:31
+ * 描述:地图动作
+ */
+enum class EventMapAction {
+    /**
+     * 没有任何动作
+     */
+    MapTapNon,
+    /**
+     * 涂鸦动作
+     */
+    MapTapSelectTy,
+    /**
+     * 微信分享上传动作
+     */
+    MapTapCaseWxAndUpload,
+    /**
+     * 添加标志动作
+     */
+    MapTapAppendICO,
+    /**
+     * 选择标志动作
+     */
+    MapTapSelectICO,
+    /**
+     * 添加违建点动作
+     */
+    MapTapAddWaypoint,
+    /**
+     * 选择违建点动作
+     */
+    MapTapSelectWaypoint,
+    /**
+     * 长度测量动作
+     */
+    MapTapSurveyLength,
+    /**
+     * 面积测量动作
+     */
+    MapTapSurveyArea,
+    /**
+     * 删除违建点动作
+     */
+    MapTapDeleteWaypoing,
+    /**
+     * 移动违建点动作
+     */
+    MapTapMoveWaypoing,
+    /**
+     * 移动中动作
+     */
+    MapTapMovingWaypoint,
+    /**
+     * 创建违建面动作
+     */
+    MapTapCreateCasePolygon,
+    /**
+     * 查询网络案件动作
+     */
+    MapTapQueryNetCase,
+    /**
+     * 查询本地案件动作
+     */
+    MapTapQueryLocalCase,
+    /**
+     * 添加复飞点动作
+     */
+    MapTapAddRepeatFlight,
+    /**
+     * 查询位置动作
+     */
+    MapTapGetLocation,
+}

+ 29 - 0
app/src/main/java/com/cr/map/EventMarkChange.kt

@@ -0,0 +1,29 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 15:32
+ * 描述:标志事件
+ */
+class EventMarkChange constructor() {
+    // define: 2023/4/13 符号名称
+    var markName: String = ""
+
+    // define: 2023/4/13 符号资源
+    var markDrawable: Int = -1
+
+    // define: 2023/4/13 符号旋转角度
+    var markAngle:Float = 0f
+
+    /**
+     * 初始化方法
+     * @param name String 符号名称
+     * @param drawable Int 符号资源
+     * @constructor
+     */
+    constructor(name:String,drawable:Int):this(){
+        this.markName = name
+        this.markDrawable = drawable
+    }
+}

+ 36 - 0
app/src/main/java/com/cr/map/LayerConfigModel.kt

@@ -0,0 +1,36 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 17:20
+ * 描述:配置图层模型
+ */
+class LayerConfigModel @JvmOverloads constructor(
+    name: String,
+    layerName: String,
+    layerIndex: Int = 0,
+    isVisible: Boolean = false
+) {
+    // define: 2023/4/13 显示名称
+    var name = ""
+
+    // define: 2023/4/13 图层名称
+    var lyrName = ""
+
+    // define: 2023/4/13 图层索引
+    var lyrIdx = 0
+
+    // define: 2023/4/13 是否显示
+    var isVisible = false
+
+    /**
+     * 初始化
+     */
+    init {
+        this.name = name
+        this.lyrName = layerName
+        this.lyrIdx = layerIndex
+        this.isVisible = isVisible
+    }
+}

+ 107 - 0
app/src/main/java/com/cr/map/LayerManager.kt

@@ -0,0 +1,107 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 15:50
+ * 描述:地图图层管理器
+ */
+class LayerManager {
+    /**
+     * 图层分组枚举
+     */
+    enum class LayerGroup{
+        /**
+         * 常用图层
+         */
+        LAYER_NAME_DAILY,
+        /**
+         * 绘制图层
+         */
+        LAYER_NAME_DRAW,
+        /**
+         * 历史图层
+         */
+        LAYER_NAME_HISTORY,
+        /**
+         * 基础图层
+         */
+        LAYER_NAME_BASE,
+        /**
+         * 飞行图层
+         */
+        LAYER_NAME_AIR
+    }
+
+    // define: 2023/4/13 常量定义
+    val LAYER_NAME_DAILY = "常用图层"
+    val LAYER_NAME_DRAW = "绘制图层"
+    val LAYER_NAME_HISTORY = "历史图层"
+    val LAYER_NAME_BASE = "基础图层"
+    val LAYER_NAME_AIR = "飞行图层"
+
+    // define: 2023/4/13 图层集合
+    private var mapLayers:HashMap<String,MutableList<LayerModel>> = hashMapOf()
+
+    companion object {
+        /**
+         * 获取静态实例 单例
+         * @return LayerManager
+         */
+        fun getInstance() = InstanceHelper.self
+    }
+
+    /**
+     * 单例必备
+     */
+    object InstanceHelper{
+        var self = LayerManager()
+    }
+
+    /**
+     * 初始化
+     */
+    init {
+        mapLayers?.put(LAYER_NAME_DAILY, mutableListOf())
+        mapLayers?.put(LAYER_NAME_BASE, mutableListOf())
+        mapLayers?.put(LAYER_NAME_HISTORY, mutableListOf())
+        mapLayers?.put(LAYER_NAME_DRAW, mutableListOf())
+        mapLayers?.put(LAYER_NAME_AIR, mutableListOf())
+    }
+
+    // todo: 2023/4/13 添加图层
+    fun addLayer(layer:LayerModel,group:LayerGroup){
+        when(group){
+            LayerGroup.LAYER_NAME_BASE->
+                mapLayers[LAYER_NAME_BASE]?.add(layer)
+            LayerGroup.LAYER_NAME_DRAW->
+                mapLayers[LAYER_NAME_DRAW]?.add(layer)
+            LayerGroup.LAYER_NAME_DAILY->
+                mapLayers[LAYER_NAME_DAILY]?.add(layer)
+            LayerGroup.LAYER_NAME_HISTORY->
+                mapLayers[LAYER_NAME_HISTORY]?.add(layer)
+            LayerGroup.LAYER_NAME_AIR->
+                mapLayers[LAYER_NAME_AIR]?.add(layer)
+        }
+    }
+
+    /**
+     * 获取图层集合
+     * @return List<LayerModel>?
+     */
+    fun getLayers(): MutableList<LayerModel>? {
+        val resList: MutableList<LayerModel> = mutableListOf()
+        // TODO: 4/15/21 循环所有的数据
+        for (key in mapLayers.keys) {
+            val models: MutableList<LayerModel>? = mapLayers[key]
+            for (i in models!!.indices) {
+                val model = models[i]
+                if (i == 0) {
+                    model.groupName = key!!
+                }
+                resList.add(model)
+            }
+        }
+        return resList
+    }
+}

+ 55 - 0
app/src/main/java/com/cr/map/LayerModel.kt

@@ -0,0 +1,55 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 15:50
+ * 描述:地图图层模型
+ */
+class LayerModel constructor(){
+    // define: 2023/4/13 图层名称
+    var name: String? = null
+
+    // define: 2023/4/13 图层
+    var layer: Any? = null
+
+    // todo: 2023/4/13 图层是否可见
+    var isVisible = false
+
+    // define: 2023/4/13 图层分组名称
+    var groupName = ""
+
+    // define: 2023/4/13 图层类型
+    var lyrType: LayerType? = null
+
+    // define: 2023/4/13 图层地址
+    var url:String? = null
+
+    /**
+     * 初始化方法
+     * @param name String 图层名称
+     * @param isVisible Boolean 图层是否可见
+     * @param layerType LayerType 图层类型
+     * @param layer Any 图层
+     * @constructor
+     */
+    constructor(name:String,isVisible:Boolean,layerType:LayerType,layer:Any):this(){
+        this.name = name
+        this.isVisible = isVisible
+        this.lyrType = layerType
+        this.layer = layer
+    }
+
+    /**
+     * 初始化方法
+     * @param name String 图层名称
+     * @param isVisible Boolean 图层是否可见
+     * @param url String 图层地址
+     * @constructor
+     */
+    constructor(name:String,isVisible:Boolean,url:String):this(){
+        this.name = name
+        this.isVisible = isVisible
+        this.url = url
+    }
+}

+ 30 - 0
app/src/main/java/com/cr/map/LayerType.kt

@@ -0,0 +1,30 @@
+package com.cr.map
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 16:01
+ * 描述:地图图层类型
+ */
+enum class LayerType {
+    /**
+     * 矢量图层
+     */
+    LAYER_TYPE_FEATURE,
+    /**
+     * 切片图层
+     */
+    LAYER_TYPE_TILED,
+    /**
+     * 绘制图层
+     */
+    LAYER_TYPE_GRAPHIC,
+    /**
+     * 可编辑图层
+     */
+    LAYER_TYPE_FEATURE_EDIT,
+    /**
+     * 服务图层
+     */
+    LAYER_TYPE_SERVER,
+}

+ 17 - 0
app/src/main/java/com/cr/map/SketchGraphicsOverlay.kt

@@ -0,0 +1,17 @@
+package com.cr.map
+
+import com.esri.arcgisruntime.geometry.SpatialReference
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/13 16:59
+ * 描述:草图编辑工具
+ */
+class SketchGraphicsOverlay {
+    // todo: 2023/4/13 静态
+    companion object{
+        // define: 2023/4/13 WGS84坐标系框架
+        val wgs84SpatialReference:SpatialReference = SpatialReference.create(4326)
+    }
+}

+ 69 - 0
app/src/main/java/com/cr/pages/FragmentLayerControl.kt

@@ -0,0 +1,69 @@
+package com.cr.pages
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ListView
+import com.cr.adapter.LayerAdapter
+import com.cr.cruav.CrApplication
+import com.cr.cruav.R
+import com.cr.event.BarAction
+import com.cr.event.EventFragmentBarAction
+import com.cr.map.LayerManager
+
+/**
+ * 操作系统:MAC系统
+ * 创建者:王成
+ * 创建日期:2023/4/14 14:16
+ * 描述:图层控制页面
+ */
+class FragmentLayerControl :CrNavigationFragment(){
+    private var listView:ListView ?= null // define: 2023/4/14 视图
+
+    /**
+     * 创建视图
+     * @param inflater LayoutInflater
+     * @param container ViewGroup?
+     * @param savedInstanceState Bundle?
+     * @return View?
+     */
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // todo: 2023/4/11 设置动画方向
+        setAnimationDirection(AnimationDirection.RIGHT)
+        self = this
+        mainView = inflater.inflate(R.layout.frag_layer_control,null)
+        // todo: 2023/4/14 挂载控件
+        joinControls()
+        // todo: 2023/4/14 设置导航栏
+        setBar(R.id.nv)
+        return mainView
+    }
+
+    /**
+     * 重写挂载控件
+     */
+    override fun joinControls() {
+        // todo: 2023/4/14 挂载视图控件
+        listView = mainView?.findViewById(R.id.list_view)
+    }
+
+    /**
+     * 初始化页面
+     */
+    override fun initPage() {
+        var adapter = LayerAdapter(context!!,LayerManager.getInstance().getLayers()!!)
+        listView?.adapter = adapter
+    }
+
+    /**
+     * 重写关闭事件
+     */
+    override fun dismiss() {
+        CrApplication.getEventBus().post(EventFragmentBarAction(self!!,BarAction.ACTION_DISMISS))
+    }
+}

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

@@ -1,14 +1,38 @@
 package com.cr.pages
 
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import com.cr.common.CrUnitManager
+import com.cr.common.DataManager
+import com.cr.common.FileManager
 import com.cr.cruav.R
+import com.cr.data.CrUtil
+import com.cr.map.*
 import com.esri.arcgisruntime.ArcGISRuntimeEnvironment
+import com.esri.arcgisruntime.arcgisservices.LabelDefinition
+import com.esri.arcgisruntime.data.Feature
+import com.esri.arcgisruntime.data.FeatureTable
+import com.esri.arcgisruntime.data.Geodatabase
+import com.esri.arcgisruntime.data.ServiceFeatureTable
+import com.esri.arcgisruntime.geometry.Point
+import com.esri.arcgisruntime.geometry.PointBuilder
+import com.esri.arcgisruntime.geometry.PolylineBuilder
+import com.esri.arcgisruntime.layers.ArcGISMapImageLayer
 import com.esri.arcgisruntime.layers.ArcGISTiledLayer
+import com.esri.arcgisruntime.layers.FeatureLayer
 import com.esri.arcgisruntime.mapping.ArcGISMap
+import com.esri.arcgisruntime.mapping.view.Graphic
+import com.esri.arcgisruntime.mapping.view.GraphicsOverlay
 import com.esri.arcgisruntime.mapping.view.MapView
+import com.esri.arcgisruntime.mapping.view.SketchEditor
+import com.esri.arcgisruntime.symbology.*
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import com.google.gson.JsonPrimitive
 
 /**
  * 操作系统:MAC系统
@@ -18,9 +42,110 @@ import com.esri.arcgisruntime.mapping.view.MapView
  */
 class FragmentMap : CrAnimationFragment() {
     // define: 2023/3/14 地图容器
-    private var mapView: MapView?= null
+    private var mapView: MapView? = null
+
     // define: 2023/3/14 地图
-    private var mMap:ArcGISMap? = null
+    private var mMap: ArcGISMap? = null
+
+    // todo: 2023/4/13 常量定义
+    val ONLINE_LAYER_NAME = "底图"
+    val ONLINE_LABEL_LAYER_NAME = "标签"
+
+    // todo: 2023/4/13 图层名称定义
+    val LAYER_NAME_ICO = "永久标志"
+    val LAYER_NAME_DOODLE = "永久涂鸦"
+    val LAYER_NAME_MEDIA = "案件点"
+    val LAYER_NAME_CASE = "绘制案件图斑"
+    val LAYER_NAME_YX = "影像图"
+    val LAYER_NAME_GH = "规划图"
+    val LAYER_NAME_XZ = "现状图"
+    val LAYER_NAME_NET_CASE = "在线案件图斑"
+    val LAYER_NAME_TEMP_ICO = "临时标志"
+    val LAYER_NAME_TEMP_DOODLE = "临时涂鸦"
+    val LAYER_NAME_CONFIG_VILLAGE = "行政区(村界)"
+    val LAYER_NAME_CONFIG_TOWNS = "行政区(镇界)"
+
+    val LAYER_NAME_AIR_LINE = "飞行航线"
+    val LAYER_NAME_AIR_HISTORY_LINE = "历史航线"
+    val LAYER_NAME_AIR_LOCATION = "飞行器"
+    val LAYER_NAME_AIR_HOME = "返航点"
+
+    // todo: 2023/4/14 符号相关常量
+    val SYMBOL_WIDTH = 25.0f;  //  define: 2023/4/13 图片符号的宽度
+    val SYMBOL_HEIGHT = 25.0f;  //  define: 2023/4/13 图片符号的高度
+    val R_LABEL_WJ_NO = "wj_no";  //  define: 2023/4/13 未上传违建标识
+    val R_LABEL_WJ_YES = "wj_yes"; //  define: 2023/4/13 已上传违建标识
+    val R_LABEL_REPEAT_NO = "repeat_no";  //  define: 2023/4/13 为上传复飞点标识
+    val R_LABEL_REPEAT_YES = "repeat_yes"; //  define: 2023/4/13 已上传复飞点标识
+
+    // todo: 2023/4/14 媒体点相关常量
+    val MEDIA_TYPE_WJ_NO = "0";    //  define: 2023/4/13 未上传的违建点
+    val MEDIA_TYPE_WJ_YES = "1";  //  define: 2023/4/13 已上传的违建点
+    val MEDIA_TYPE_REPEAT_NO = "4";   //  define: 2023/4/13 未上传的复飞案件
+    val MEDIA_TYPE_REPEAT_YES = "5";   //  define: 2023/4/13 已上传的复飞案件
+
+    // todo: 2023/4/14 字段相关常量
+    val FIELD_NET_CASE_POLYGON_AJH = "AJH";   //  define: 2023/4/13 网络案件的案件编号
+    val FIELD_CASE_POLYGON_ANJID = "ANJID";   //  define: 2023/4/13 案件ID
+    val FIELD_CASE_POLYGON_MJ = "MJ";   //  define: 2023/4/13 面积
+    val FIELD_CASE_POLYGON_BZ = "BZ";   //  define: 2023/4/13 违建面的类型 0--代表未匹配 1--代表已匹配
+    val FIELD_CASE_POLYGON_BZ_VALUE_NO = "0";   //  define: 2023/4/13 未匹配
+    val FIELD_CASE_POLYGON_BZ_VALUE_YES = "1";   //  define: 2023/4/13 已匹配
+    val FIELD_CASE_NAME = "NAME";   //  define: 2023/4/13 名称字段
+    val FIELD_CASE_IMAGES = "IMAGES";   //  define: 2023/4/13 图片集合字段
+    val FIELD_CASE_RQ = "RQ";   //  define: 2023/4/13 日期字段
+    val FIELD_CASE_LAT = "LAT";   //  define: 2023/4/13 纬度字段
+    val FIELD_CASE_LNG = "LNG";   //  define: 2023/4/13 经度字段
+    val FIELD_CASE_ISUP = "ISUP";   //  define: 2023/4/13 是否上传
+    val FIELD_CASE_ALT = "ALT";   //  define: 2023/4/13 高度字段
+    val FIELD_CASE_ANG = "ANG";   //  define: 2023/4/13 角度字段
+    val FIELD_CASE_TYPE = "TYPE";   //  define: 2023/4/13 类型字段
+    val FIELD_CASE_ISDOWN = "ISDOWN";   //  define: 2023/4/13 是否下载
+
+
+    // todo: 2023/4/13 标志相关
+    private var markChange: EventMarkChange? = null
+
+    // todo: 2023/4/13 动作相关
+    private var mapAction: EventMapAction? = null
+
+    // todo: 2023/4/14 绘制图层
+    private var gLayerIco: GraphicsOverlay? = null // define: 2023/4/13 标志图层
+    private var gLayerDoodle: GraphicsOverlay? = null // define: 2023/4/13 涂鸦图层
+    private var gLayerAirplaneLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器位置图层
+    private var gLayerAirplaneHomeLocation: GraphicsOverlay? = null // define: 2023/4/13 飞行器返航点位置图层
+    private var gLayerAirplaneLine: GraphicsOverlay? = null // define: 2023/4/13 飞行航线图层
+    private var gLayerHistoryAirplaneLine: GraphicsOverlay? = null // define: 2023/4/13 历史航线图层
+
+    // todo: 2023/4/13 样式相关
+    private var symbolAirplaneLine: SimpleLineSymbol? = null // define: 2023/4/13 飞行航线样式
+    private var symbolAirplaneLink: SimpleLineSymbol? = null // define: 2023/4/13 飞行器与返航点连接线样式
+    private var symbolAirplaneLocation: PictureMarkerSymbol? = null // define: 2023/4/13 飞行器符号样式
+
+    // todo: 2023/4/13 要素相关
+    private var builderAirplaneLine: PolylineBuilder? = null // define: 2023/4/13 航线点集
+    private var builderAirplaneLink: PolylineBuilder? = null // define: 2023/4/13 飞行器与返航点连接线点集
+    private var builderAirplaneLocation: PointBuilder? = null // define: 2023/4/13 飞行器位置点
+    private var builderAirplaneHomeLocation: PointBuilder? = null // define: 2023/4/13 返航点位置
+    private var graAirplaneLine: Graphic? = null // define: 2023/4/13 航线图形
+    private var graAirplaneLink: Graphic? = null // define: 2023/4/13 飞行器与返航点连接线图形
+    private var graAirplaneLocation: Graphic? = null // define: 2023/4/13 飞行器位置图形
+    private var graAirplaneHomeLocation: Graphic? = null // define: 2023/4/13 返航点位置图形
+    private var sketchEditor: SketchEditor? = null // define: 2023/4/13 草图编辑器
+    private var feaSelectCase: Feature? = null // define: 2023/4/13 选中的案件点
+
+    // todo: 2023/4/14 编辑图层
+    private var fTableICO: FeatureTable? = null // define: 2023/4/14 永久标志表
+    private var fLayerICO: FeatureLayer? = null // define: 2023/4/14 永久标志图层
+    private var fTableMedia: FeatureTable? = null // define: 2023/4/14 媒体表
+    private var fLayerMedia: FeatureLayer? = null // define: 2023/4/14 媒体图层
+    private var fTableDoodle: FeatureTable? = null // define: 2023/4/14 永久涂鸦表
+    private var fLayerDoodle: FeatureLayer? = null // define: 2023/4/14 永久涂鸦图层
+    private var fTableCasePolygon: FeatureTable? = null // define: 2023/4/14 永久案件表
+    private var fLayerCasePolygon: FeatureLayer? = null // define: 2023/4/14 永久案件图层
+    private var fTableNetCasePolygon: ServiceFeatureTable? = null // define: 2023/4/14 网路案件表
+    private var fLayerNetCasePolygon: ArcGISMapImageLayer? = null // define: 2023/4/14 网络案件图层
+
     /**
      * 重写创建View方法
      * @param inflater LayoutInflater
@@ -33,7 +158,7 @@ class FragmentMap : CrAnimationFragment() {
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        mainView = inflater.inflate(R.layout.frag_map,container,false)
+        mainView = inflater.inflate(R.layout.frag_map, container, false)
         return mainView
     }
 
@@ -50,18 +175,351 @@ class FragmentMap : CrAnimationFragment() {
     /**
      * 初始化UI
      */
-    private fun initUI(){
+    private fun initUI() {
         ArcGISRuntimeEnvironment.setLicense("runtimelite,1000,rud4449636536,none,NKMFA0PL4S0DRJE15166");
         // todo: 2023/3/14 初始化控件
         mapView = mainView?.findViewById(R.id.map_mapView)
         mapView?.let {
+            // todo: 2023/4/13 设置底部标识是否显示
             it.isAttributionTextVisible = false
             mMap = ArcGISMap()
             it.map = mMap
+            // todo: 2023/4/13 地图控件初始化
+            it.backgroundGrid.color = Color.argb(255, 216, 216, 216)
+            it.backgroundGrid.gridLineColor = Color.argb(0, 255, 255, 255)
         }
+        // todo: 2023/4/13 地图初始化
+        mapInit()
+    }
+
+    /**
+     * 地图初始化
+     */
+    private fun mapInit() {
+        // todo: 2023/4/13 加载在线底图
+        addOnlineRasterLayer()
+        // todo: 2023/4/13 添加切片图层
+        addTiledToMap()
+        // todo: 2023/4/13 添加基础矢量地图
+        addBaseGeoDatabaseToMap()
+        // todo: 2023/4/14 添加可编辑矢量数据
+        addEditGeoDatabaseToMap()
+
+        // todo: 2023/4/13 定位地图中心点
+        setMapCenter(118.709, 35.219, 5000.0);
+    }
 
-        var url:String = "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer";
-        var layer:ArcGISTiledLayer = ArcGISTiledLayer(url)
+    /**
+     * 添加在线地图
+     */
+    private fun addOnlineRasterLayer() {
+        var url: String =
+            "https://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer";
+        var layer = ArcGISTiledLayer(url)
+        layer.name = ONLINE_LAYER_NAME
         mMap?.operationalLayers?.add(layer)
     }
+
+    /**
+     * 添加切片图层
+     */
+    private fun addTiledToMap() {
+        var tileLayers = DataManager.getTileLayerConfig()
+        for (model in tileLayers) {
+            var layer = ArcGISTiledLayer(model.url)
+            layer.name = model.name
+            layer.isVisible = model.isVisible
+            mMap?.operationalLayers?.add(layer)
+            // todo: 2023/4/13 添加到配置
+            LayerManager.getInstance().addLayer(
+                LayerModel(
+                    model.name!!,
+                    model.isVisible,
+                    LayerType.LAYER_TYPE_TILED,
+                    layer
+                ), LayerManager.LayerGroup.LAYER_NAME_DAILY
+            )
+        }
+    }
+
+    /**
+     * 添加基础矢量地图集合
+     */
+    private fun addBaseGeoDatabaseToMap() {
+        if (!FileManager.isExists(CrUtil.MAP_PATH_BASE)) return
+        var geoDatabase = Geodatabase(CrUtil.MAP_PATH_BASE)
+        // todo: 2023/4/13 加载完成监听
+        geoDatabase.addDoneLoadingListener(Runnable {
+            var vLayers = DataManager.getVectorLayerConfig()
+            var tables = geoDatabase.geodatabaseFeatureTables
+            for (vLayer in vLayers) {
+                var table = tables[vLayer.lyrIdx]
+                var layer = FeatureLayer(table)
+                layer.name = vLayer.lyrName
+                layer.isVisible = vLayer.isVisible
+                mMap?.operationalLayers?.add(layer)
+                // todo: 2023/4/13 添加到配置信息
+                LayerManager.getInstance().addLayer(
+                    LayerModel(
+                        vLayer.lyrName,
+                        vLayer.isVisible,
+                        LayerType.LAYER_TYPE_FEATURE,
+                        layer
+                    ), LayerManager.LayerGroup.LAYER_NAME_BASE
+                )
+            }
+        })
+        // todo: 2023/4/13 加载数据集
+        geoDatabase.loadAsync()
+    }
+
+    /**
+     * 加载可编辑数据
+     */
+    private fun addEditGeoDatabaseToMap() {
+        if (!FileManager.isExists(CrUtil.MAP_PATH_EDIT)) return
+        var geoDatabase = Geodatabase(CrUtil.MAP_PATH_EDIT)
+        // todo: 2023/4/14 数据加载完监听
+        geoDatabase.addDoneLoadingListener(Runnable {
+            // todo: 2023/4/14 初始化标志图层
+            fTableICO = geoDatabase.getGeodatabaseFeatureTable("ico84")
+            fLayerICO = FeatureLayer(fTableICO)
+            fLayerICO!!.name = LAYER_NAME_ICO
+            fLayerICO!!.isVisible = true
+            mMap!!.operationalLayers.add(fLayerICO)
+            LayerManager.getInstance().addLayer(
+                LayerModel(
+                    fLayerICO!!.name,
+                    fLayerICO!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerICO!!
+                ), LayerManager.LayerGroup.LAYER_NAME_DAILY
+            )
+            // todo: 2023/4/14  初始化涂鸦图层
+            fTableDoodle = geoDatabase.getGeodatabaseFeatureTable("ty84")
+            fLayerDoodle = FeatureLayer(fTableDoodle)
+            fLayerDoodle!!.name = LAYER_NAME_DOODLE
+            fLayerDoodle!!.isVisible = true
+            mMap!!.operationalLayers.add(fLayerDoodle)
+            LayerManager.getInstance().addLayer(
+                LayerModel(
+                    fLayerDoodle!!.name,
+                    fLayerDoodle!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerDoodle!!
+                ), LayerManager.LayerGroup.LAYER_NAME_DAILY
+            )
+            // todo: 2023/4/14  初始化媒体点图层
+            fTableMedia = geoDatabase.getGeodatabaseFeatureTable("media84")
+            fLayerMedia = FeatureLayer(fTableMedia)
+            fLayerMedia!!.name = LAYER_NAME_MEDIA
+            fLayerMedia!!.isVisible = true
+            mMap!!.operationalLayers.add(fLayerMedia)
+            LayerManager.getInstance().addLayer(
+                LayerModel(
+                    fLayerMedia!!.name,
+                    fLayerMedia!!.isVisible, LayerType.LAYER_TYPE_FEATURE_EDIT, fLayerMedia!!
+                ), LayerManager.LayerGroup.LAYER_NAME_DAILY
+            )
+            // todo: 2023/4/14  初始化违建面图层
+            fTableCasePolygon = geoDatabase.getGeodatabaseFeatureTable("sbwj84")
+            fLayerCasePolygon = FeatureLayer(fTableCasePolygon)
+            fLayerCasePolygon!!.name = LAYER_NAME_CASE
+            fLayerCasePolygon!!.isVisible = true
+            // todo: 2023/4/14 给图层添加标注
+            val labelDefinition: LabelDefinition =
+                createLabelDefinition(Color.BLUE, 12.0f, "round(\$feature.MJ,2) + '亩';")
+            fLayerCasePolygon!!.labelDefinitions.add(labelDefinition)
+            fLayerCasePolygon!!.isLabelsEnabled = true
+            mMap!!.operationalLayers.add(fLayerCasePolygon)
+            LayerManager.getInstance().addLayer(
+                LayerModel(
+                    fLayerCasePolygon!!.name,
+                    fLayerCasePolygon!!.isVisible,
+                    LayerType.LAYER_TYPE_FEATURE_EDIT,
+                    fLayerCasePolygon!!
+                ), LayerManager.LayerGroup.LAYER_NAME_DAILY
+            )
+            // todo: 2023/4/14 可编辑数据符号化
+            editLayerRenderer()
+        })
+        // todo: 2023/4/14 异步加载
+        geoDatabase.loadAsync()
+    }
+
+    /**
+     * 编辑图层符号话
+     */
+    private fun editLayerRenderer() {
+        // todo: 2023/4/14  永久涂鸦图层符号化
+        val doodleSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.BLUE, 2.5f)
+        val doodleRenderer = SimpleRenderer(doodleSymbol)
+        fLayerDoodle?.renderer = doodleRenderer
+        // todo: 2023/4/14  永久标志图层符号化
+        val icoSymbol: PictureMarkerSymbol =
+            createPictureMarkerSymbol(R.drawable.ico_ty1, 30f, 30f)
+        val icoRenderer = SimpleRenderer(icoSymbol)
+        fLayerICO?.renderer = icoRenderer
+        // todo: 2023/4/14  违建符号化
+        val mediaRenderer = UniqueValueRenderer()
+        val mediaSymbolYes: PictureMarkerSymbol = createPictureMarkerSymbol(
+            R.drawable.ico_wj_upload_yes,
+            SYMBOL_WIDTH,
+            SYMBOL_HEIGHT
+        )
+        val mediaSymbolNo: PictureMarkerSymbol = createPictureMarkerSymbol(
+            R.drawable.ico_wj_no,
+            SYMBOL_WIDTH,
+            SYMBOL_HEIGHT
+        )
+        val mediaSymbolRepeatYes: PictureMarkerSymbol = createPictureMarkerSymbol(
+            R.drawable.ico_repeatflight_yes,
+            SYMBOL_WIDTH,
+            SYMBOL_HEIGHT
+        )
+        val mediaSymbolRepeatNo: PictureMarkerSymbol = createPictureMarkerSymbol(
+            R.drawable.ico_repeatflight_no,
+            SYMBOL_WIDTH,
+            SYMBOL_HEIGHT
+        )
+        mediaRenderer.defaultSymbol = mediaSymbolNo
+        mediaRenderer.defaultLabel = R_LABEL_WJ_NO
+        mediaRenderer.fieldNames.add(FIELD_CASE_ISUP)
+        val cValueNo: MutableList<Any> = ArrayList()
+        cValueNo.add(MEDIA_TYPE_WJ_NO)
+        mediaRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                R_LABEL_WJ_NO,
+                R_LABEL_WJ_NO,
+                mediaSymbolNo,
+                cValueNo
+            )
+        )
+        val cValueYes: MutableList<Any> = ArrayList()
+        cValueYes.add(MEDIA_TYPE_WJ_YES)
+        mediaRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                R_LABEL_WJ_YES,
+                R_LABEL_WJ_YES,
+                mediaSymbolYes,
+                cValueYes
+            )
+        )
+        val cValueRepeatNo: MutableList<Any> = ArrayList()
+        cValueRepeatNo.add(MEDIA_TYPE_REPEAT_NO)
+        mediaRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                R_LABEL_REPEAT_NO,
+                R_LABEL_REPEAT_NO,
+                mediaSymbolRepeatNo,
+                cValueRepeatNo
+            )
+        )
+        val cValueRepeatYes: List<Any> = ArrayList()
+        cValueNo.add(MEDIA_TYPE_REPEAT_YES)
+        mediaRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                R_LABEL_REPEAT_YES,
+                R_LABEL_REPEAT_YES,
+                mediaSymbolRepeatYes,
+                cValueRepeatYes
+            )
+        )
+        fLayerMedia?.renderer = mediaRenderer
+        // todo: 2023/4/14  绘制违建面符号化
+        val colorClear = Color.argb(0, 255, 255, 255)
+        val caseNoLineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.DASH_DOT, Color.BLUE, 2.5f)
+        val caseYesLineSymbol = SimpleLineSymbol(SimpleLineSymbol.Style.DASH_DOT, Color.RED, 2.5f)
+        val caseNoFillSymbol =
+            SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, colorClear, caseNoLineSymbol)
+        val caseYesFillSymbol =
+            SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, colorClear, caseYesLineSymbol)
+        val casePolygonRenderer = UniqueValueRenderer()
+        casePolygonRenderer.fieldNames.add(FIELD_CASE_POLYGON_BZ)
+        casePolygonRenderer.defaultSymbol = caseNoFillSymbol
+        casePolygonRenderer.defaultLabel = FIELD_CASE_POLYGON_BZ_VALUE_NO
+        val cValueCaseNo: MutableList<Any> = ArrayList()
+        cValueCaseNo.add(FIELD_CASE_POLYGON_BZ_VALUE_NO)
+        casePolygonRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                FIELD_CASE_POLYGON_BZ_VALUE_NO,
+                FIELD_CASE_POLYGON_BZ_VALUE_NO,
+                caseNoFillSymbol,
+                cValueCaseNo
+            )
+        )
+        val cValueCaseYes: MutableList<Any> = ArrayList()
+        cValueCaseYes.add(FIELD_CASE_POLYGON_BZ_VALUE_YES)
+        casePolygonRenderer.uniqueValues.add(
+            UniqueValueRenderer.UniqueValue(
+                FIELD_CASE_POLYGON_BZ_VALUE_YES,
+                FIELD_CASE_POLYGON_BZ_VALUE_YES,
+                caseYesFillSymbol,
+                cValueCaseYes
+            )
+        )
+        fLayerCasePolygon?.renderer = casePolygonRenderer
+    }
+
+    /**
+     * 创建图片符号
+     * @param drawable Int 图片资源Id
+     * @param width Float 宽度
+     * @param height Float 高度
+     * @return PictureMarkerSymbol?
+     */
+    private fun createPictureMarkerSymbol(
+        drawable: Int,
+        width: Float,
+        height: Float
+    ): PictureMarkerSymbol {
+        val tDrawable = context!!.resources.getDrawable(drawable) as BitmapDrawable
+        val symbol = PictureMarkerSymbol(tDrawable)
+        if (width > 0) symbol.width = width else symbol.width =
+            CrUnitManager.px2dp(tDrawable.bitmap.width).toFloat()
+        if (height > 0) symbol.height = height else symbol.height =
+            CrUnitManager.px2dp(tDrawable.bitmap.height).toFloat()
+        return symbol
+    }
+
+    /**
+     * 创建标注
+     * @param txtColor Int 文字颜色
+     * @param txtSize Float 文字大小
+     * @param expression String 表达式
+     * @return LabelDefinition? 标注
+     */
+    private fun createLabelDefinition(
+        txtColor: Int,
+        txtSize: Float,
+        expression: String
+    ): LabelDefinition {
+        val textSymbol = TextSymbol()
+        textSymbol.color = txtColor
+        textSymbol.fontWeight = TextSymbol.FontWeight.BOLD
+        textSymbol.haloColor = Color.WHITE
+        textSymbol.haloWidth = 2.0f
+        textSymbol.fontFamily = "Arial"
+        textSymbol.size = txtSize
+        val label = JsonObject()
+        val labelExpression = JsonObject()
+        labelExpression.add("expression", JsonPrimitive(expression))
+        label.add("labelExpressionInfo", labelExpression)
+        label.add("labelPlacement", JsonPrimitive("esriServerPolygonPlacementAlwaysHorizontal"))
+        label.add("symbol", JsonParser().parse(textSymbol.toJson()))
+        return LabelDefinition.fromJson(label.toString())
+    }
+
+    /**
+     * 定位地图中心
+     * @param longitude Double 中心经度
+     * @param latitude Double 中心纬度
+     * @param scale Double 缩放比例
+     */
+    private fun setMapCenter(longitude: Double, latitude: Double, scale: Double) {
+        // todo: 2023/4/13 创建中心点
+        var centerPoint: Point =
+            Point(longitude, latitude, SketchGraphicsOverlay.wgs84SpatialReference)
+        if (scale > 0) {
+            mapView?.setViewpointCenterAsync(centerPoint, scale)
+        } else {
+            mapView?.setViewpointCenterAsync(centerPoint)
+        }
+    }
 }

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

@@ -58,10 +58,10 @@ class FragmentSetDataDownload:CrNavigationFragment() {
      */
     override fun initPage() {
         dataList.clear()
-        dataList.add(DownloadDataModel("矢量地图集", "base.geodatabase", false))
-        dataList.add(DownloadDataModel("编辑地图集", "map.geodatabase", false))
-        dataList.add(DownloadDataModel("飞行数据库", "data.sqlite", false))
-        dataList.add(DownloadDataModel("基础配置库", "config.sqlite", false))
+        dataList.add(DownloadDataModel("矢量地图集", CrUtil.MAP_BASE_FILE_NAME, false))
+        dataList.add(DownloadDataModel("编辑地图集", CrUtil.MAP_EDIT_FILE_NAME, false))
+        dataList.add(DownloadDataModel("飞行数据库", CrUtil.DATA_FILE_NAME, false))
+        dataList.add(DownloadDataModel("基础配置库", CrUtil.CONFIG_FILE_NAME, false))
         downloadAdapter?.notifyUpdate(dataList)
     }
 

+ 1 - 1
app/src/main/res/drawable/shape_back_fragment.xml

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#B0000000"/>
+    <solid android:color="#E0000000"/>
 </shape>

+ 34 - 0
app/src/main/res/drawable/switch_smart_thumb.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="false">
+        <layer-list>
+            <item android:width="@dimen/switch_smart_height" android:height="@dimen/switch_smart_height">
+                <shape android:shape="oval">
+                    <!--                                <solid android:color="#b3536673"></solid>-->
+                </shape>
+            </item>
+
+            <item android:bottom="@dimen/switch_smart_offset" android:left="@dimen/switch_smart_offset" android:right="@dimen/switch_smart_offset" android:top="@dimen/switch_smart_offset">
+                <shape android:shape="oval">
+                    <solid android:color="#d9ffffff"></solid>
+                </shape>
+            </item>
+        </layer-list>
+    </item>
+
+    <item android:state_checked="true">
+        <layer-list>
+            <item android:width="@dimen/switch_smart_height" android:height="@dimen/switch_smart_height">
+                <shape android:shape="oval">
+<!--                    <solid android:color="#b3536673"></solid>-->
+                </shape>
+            </item>
+
+            <item android:bottom="@dimen/switch_smart_offset" android:left="@dimen/switch_smart_offset" android:right="@dimen/switch_smart_offset" android:top="@dimen/switch_smart_offset">
+                <shape android:shape="oval">
+                    <solid android:color="#1aa01b"></solid>
+                </shape>
+            </item>
+        </layer-list>
+    </item>
+</selector>

+ 19 - 0
app/src/main/res/drawable/switch_smart_track.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--开关按钮关闭时的导轨样式-->
+    <item android:state_checked="false">
+        <shape>
+            <size android:height="@dimen/switch_smart_height" android:width="@dimen/switch_smart_width"></size>
+            <corners android:radius="@dimen/switch_smart_height"></corners>
+            <solid android:color="#9e9e9e"></solid>
+        </shape>
+    </item>
+    <!--开关按钮打开时的导轨样式-->
+    <item android:state_checked="true">
+        <shape>
+            <size android:height="@dimen/switch_smart_height" android:width="@dimen/switch_smart_width"></size>
+            <corners android:radius="@dimen/switch_smart_height"></corners>
+            <solid android:color="#409eff"></solid>
+        </shape>
+    </item>
+</selector>

+ 1 - 1
app/src/main/res/layout/av_main.xml

@@ -29,7 +29,7 @@
         android:layout_width="@dimen/cr_200_dp"
         android:layout_height="@dimen/cr_160_dp"
         android:id="@+id/av_fragment_fpv"
-        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/av_main_panel_bottom"
         app:layout_constraintRight_toRightOf="parent"
         android:layout_marginBottom="@dimen/cr_6_dp"
         android:layout_marginRight="@dimen/cr_6_dp"

+ 28 - 0
app/src/main/res/layout/frag_layer_control.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:clickable="true">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/shape_back_fragment"
+        android:orientation="vertical">
+        <com.cr.widget.CrNavigationBarWidget
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:crTitle="@string/nv_title_layer"
+            app:isGotoBack="false"
+            app:isDismiss="true"
+            android:id="@+id/nv"
+            android:layout_weight="0"/>
+        <ListView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:divider="@null"
+            android:dividerHeight="0dp"
+            android:id="@+id/list_view"/>
+    </LinearLayout>
+</RelativeLayout>

+ 58 - 0
app/src/main/res/layout/item_layercontrol.xml

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textSize="@dimen/sp_12"
+        android:text="分组"
+        android:layout_margin="8dp"
+        android:textStyle="bold"
+        android:textColor="@color/yellow"
+        android:id="@+id/item_layer_group_name"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/cr_22_dp"
+        android:orientation="vertical"
+        android:layout_marginLeft="@dimen/cr_5_dp">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:layout_weight="1">
+            <ImageView
+                style="@style/item_layer_base"
+                android:layout_width="@dimen/cr_14_dp"
+                android:layout_height="@dimen/cr_14_dp"
+                android:src="@drawable/ico_layer"
+                android:id="@+id/item_layer_img"/>
+            <TextView
+                style="@style/item_layer_name"
+                android:text="影像图"
+                android:layout_weight="1"
+                android:id="@+id/item_layer_name"
+                android:layout_marginLeft="@dimen/cr_5_dp"/>
+            <TextView
+                style="@style/item_layer_label"
+                android:text="显示/隐藏"/>
+            <Switch
+                style="@style/item_layer_padding"
+                android:track="@drawable/switch_smart_track"
+                android:thumb="@drawable/switch_smart_thumb"
+                android:id="@+id/item_layer_on_visible"/>
+            <TextView
+                style="@style/item_layer_label"
+                android:text="标注"
+                android:id="@+id/item_layer_lbl"/>
+            <Switch
+                style="@style/item_layer_padding"
+                android:track="@drawable/switch_smart_track"
+                android:thumb="@drawable/switch_smart_thumb"
+                android:id="@+id/item_layer_on_label"/>
+        </LinearLayout>
+        <View style="@style/view_split_h1"/>
+    </LinearLayout>
+</LinearLayout>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">73.9556dp</dimen>
 	<dimen name="switch_height">51.2000dp</dimen>
 	<dimen name="switch_offset">3.4133dp</dimen>
+	<dimen name="switch_smart_width">39.8222dp</dimen>
+	<dimen name="switch_smart_height">22.7556dp</dimen>
+	<dimen name="switch_smart_offset">3.4133dp</dimen>
 	<dimen name="common_padding">5.6889dp</dimen>
 	<dimen name="common_margin">8.5333dp</dimen>
 	<dimen name="common_button_height">73.9556dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">92.4444dp</dimen>
 	<dimen name="switch_height">64.0000dp</dimen>
 	<dimen name="switch_offset">4.2667dp</dimen>
+	<dimen name="switch_smart_width">49.7778dp</dimen>
+	<dimen name="switch_smart_height">28.4444dp</dimen>
+	<dimen name="switch_smart_offset">4.2667dp</dimen>
 	<dimen name="common_padding">7.1111dp</dimen>
 	<dimen name="common_margin">10.6667dp</dimen>
 	<dimen name="common_button_height">92.4444dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">98.5833dp</dimen>
 	<dimen name="switch_height">68.2500dp</dimen>
 	<dimen name="switch_offset">4.5500dp</dimen>
+	<dimen name="switch_smart_width">53.0833dp</dimen>
+	<dimen name="switch_smart_height">30.3333dp</dimen>
+	<dimen name="switch_smart_offset">4.5500dp</dimen>
 	<dimen name="common_padding">7.5833dp</dimen>
 	<dimen name="common_margin">11.3750dp</dimen>
 	<dimen name="common_button_height">98.5833dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">17.3333dp</dimen>
 	<dimen name="switch_height">12.0000dp</dimen>
 	<dimen name="switch_offset">0.8000dp</dimen>
+	<dimen name="switch_smart_width">9.3333dp</dimen>
+	<dimen name="switch_smart_height">5.3333dp</dimen>
+	<dimen name="switch_smart_offset">0.8000dp</dimen>
 	<dimen name="common_padding">1.3333dp</dimen>
 	<dimen name="common_margin">2.0000dp</dimen>
 	<dimen name="common_button_height">17.3333dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">23.1111dp</dimen>
 	<dimen name="switch_height">16.0000dp</dimen>
 	<dimen name="switch_offset">1.0667dp</dimen>
+	<dimen name="switch_smart_width">12.4444dp</dimen>
+	<dimen name="switch_smart_height">7.1111dp</dimen>
+	<dimen name="switch_smart_offset">1.0667dp</dimen>
 	<dimen name="common_padding">1.7778dp</dimen>
 	<dimen name="common_margin">2.6667dp</dimen>
 	<dimen name="common_button_height">23.1111dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">27.7333dp</dimen>
 	<dimen name="switch_height">19.2000dp</dimen>
 	<dimen name="switch_offset">1.2800dp</dimen>
+	<dimen name="switch_smart_width">14.9333dp</dimen>
+	<dimen name="switch_smart_height">8.5333dp</dimen>
+	<dimen name="switch_smart_offset">1.2800dp</dimen>
 	<dimen name="common_padding">2.1333dp</dimen>
 	<dimen name="common_margin">3.2000dp</dimen>
 	<dimen name="common_button_height">27.7333dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">28.3111dp</dimen>
 	<dimen name="switch_height">19.6000dp</dimen>
 	<dimen name="switch_offset">1.3067dp</dimen>
+	<dimen name="switch_smart_width">15.2444dp</dimen>
+	<dimen name="switch_smart_height">8.7111dp</dimen>
+	<dimen name="switch_smart_offset">1.3067dp</dimen>
 	<dimen name="common_padding">2.1778dp</dimen>
 	<dimen name="common_margin">3.2667dp</dimen>
 	<dimen name="common_button_height">28.3111dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">28.8889dp</dimen>
 	<dimen name="switch_height">20.0000dp</dimen>
 	<dimen name="switch_offset">1.3333dp</dimen>
+	<dimen name="switch_smart_width">15.5556dp</dimen>
+	<dimen name="switch_smart_height">8.8889dp</dimen>
+	<dimen name="switch_smart_offset">1.3333dp</dimen>
 	<dimen name="common_padding">2.2222dp</dimen>
 	<dimen name="common_margin">3.3333dp</dimen>
 	<dimen name="common_button_height">28.8889dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">29.6111dp</dimen>
 	<dimen name="switch_height">20.5000dp</dimen>
 	<dimen name="switch_offset">1.3667dp</dimen>
+	<dimen name="switch_smart_width">15.9444dp</dimen>
+	<dimen name="switch_smart_height">9.1111dp</dimen>
+	<dimen name="switch_smart_offset">1.3667dp</dimen>
 	<dimen name="common_padding">2.2778dp</dimen>
 	<dimen name="common_margin">3.4167dp</dimen>
 	<dimen name="common_button_height">29.6111dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">29.6833dp</dimen>
 	<dimen name="switch_height">20.5500dp</dimen>
 	<dimen name="switch_offset">1.3700dp</dimen>
+	<dimen name="switch_smart_width">15.9833dp</dimen>
+	<dimen name="switch_smart_height">9.1333dp</dimen>
+	<dimen name="switch_smart_offset">1.3700dp</dimen>
 	<dimen name="common_padding">2.2833dp</dimen>
 	<dimen name="common_margin">3.4250dp</dimen>
 	<dimen name="common_button_height">29.6833dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">31.2000dp</dimen>
 	<dimen name="switch_height">21.6000dp</dimen>
 	<dimen name="switch_offset">1.4400dp</dimen>
+	<dimen name="switch_smart_width">16.8000dp</dimen>
+	<dimen name="switch_smart_height">9.6000dp</dimen>
+	<dimen name="switch_smart_offset">1.4400dp</dimen>
 	<dimen name="common_padding">2.4000dp</dimen>
 	<dimen name="common_margin">3.6000dp</dimen>
 	<dimen name="common_button_height">31.2000dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">34.6667dp</dimen>
 	<dimen name="switch_height">24.0000dp</dimen>
 	<dimen name="switch_offset">1.6000dp</dimen>
+	<dimen name="switch_smart_width">18.6667dp</dimen>
+	<dimen name="switch_smart_height">10.6667dp</dimen>
+	<dimen name="switch_smart_offset">1.6000dp</dimen>
 	<dimen name="common_padding">2.6667dp</dimen>
 	<dimen name="common_margin">4.0000dp</dimen>
 	<dimen name="common_button_height">34.6667dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">38.4944dp</dimen>
 	<dimen name="switch_height">26.6500dp</dimen>
 	<dimen name="switch_offset">1.7767dp</dimen>
+	<dimen name="switch_smart_width">20.7278dp</dimen>
+	<dimen name="switch_smart_height">11.8444dp</dimen>
+	<dimen name="switch_smart_offset">1.7767dp</dimen>
 	<dimen name="common_padding">2.9611dp</dimen>
 	<dimen name="common_margin">4.4417dp</dimen>
 	<dimen name="common_button_height">38.4944dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">42.7556dp</dimen>
 	<dimen name="switch_height">29.6000dp</dimen>
 	<dimen name="switch_offset">1.9733dp</dimen>
+	<dimen name="switch_smart_width">23.0222dp</dimen>
+	<dimen name="switch_smart_height">13.1556dp</dimen>
+	<dimen name="switch_smart_offset">1.9733dp</dimen>
 	<dimen name="common_padding">3.2889dp</dimen>
 	<dimen name="common_margin">4.9333dp</dimen>
 	<dimen name="common_button_height">42.7556dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">43.3333dp</dimen>
 	<dimen name="switch_height">30.0000dp</dimen>
 	<dimen name="switch_offset">2.0000dp</dimen>
+	<dimen name="switch_smart_width">23.3333dp</dimen>
+	<dimen name="switch_smart_height">13.3333dp</dimen>
+	<dimen name="switch_smart_offset">2.0000dp</dimen>
 	<dimen name="common_padding">3.3333dp</dimen>
 	<dimen name="common_margin">5.0000dp</dimen>
 	<dimen name="common_button_height">43.3333dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">46.2222dp</dimen>
 	<dimen name="switch_height">32.0000dp</dimen>
 	<dimen name="switch_offset">2.1333dp</dimen>
+	<dimen name="switch_smart_width">24.8889dp</dimen>
+	<dimen name="switch_smart_height">14.2222dp</dimen>
+	<dimen name="switch_smart_offset">2.1333dp</dimen>
 	<dimen name="common_padding">3.5556dp</dimen>
 	<dimen name="common_margin">5.3333dp</dimen>
 	<dimen name="common_button_height">46.2222dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">47.8111dp</dimen>
 	<dimen name="switch_height">33.1000dp</dimen>
 	<dimen name="switch_offset">2.2067dp</dimen>
+	<dimen name="switch_smart_width">25.7444dp</dimen>
+	<dimen name="switch_smart_height">14.7111dp</dimen>
+	<dimen name="switch_smart_offset">2.2067dp</dimen>
 	<dimen name="common_padding">3.6778dp</dimen>
 	<dimen name="common_margin">5.5167dp</dimen>
 	<dimen name="common_button_height">47.8111dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">52.0000dp</dimen>
 	<dimen name="switch_height">36.0000dp</dimen>
 	<dimen name="switch_offset">2.4000dp</dimen>
+	<dimen name="switch_smart_width">28.0000dp</dimen>
+	<dimen name="switch_smart_height">16.0000dp</dimen>
+	<dimen name="switch_smart_offset">2.4000dp</dimen>
 	<dimen name="common_padding">4.0000dp</dimen>
 	<dimen name="common_margin">6.0000dp</dimen>
 	<dimen name="common_button_height">52.0000dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">55.4667dp</dimen>
 	<dimen name="switch_height">38.4000dp</dimen>
 	<dimen name="switch_offset">2.5600dp</dimen>
+	<dimen name="switch_smart_width">29.8667dp</dimen>
+	<dimen name="switch_smart_height">17.0667dp</dimen>
+	<dimen name="switch_smart_offset">2.5600dp</dimen>
 	<dimen name="common_padding">4.2667dp</dimen>
 	<dimen name="common_margin">6.4000dp</dimen>
 	<dimen name="common_button_height">55.4667dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">57.7778dp</dimen>
 	<dimen name="switch_height">40.0000dp</dimen>
 	<dimen name="switch_offset">2.6667dp</dimen>
+	<dimen name="switch_smart_width">31.1111dp</dimen>
+	<dimen name="switch_smart_height">17.7778dp</dimen>
+	<dimen name="switch_smart_offset">2.6667dp</dimen>
 	<dimen name="common_padding">4.4444dp</dimen>
 	<dimen name="common_margin">6.6667dp</dimen>
 	<dimen name="common_button_height">57.7778dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">58.5722dp</dimen>
 	<dimen name="switch_height">40.5500dp</dimen>
 	<dimen name="switch_offset">2.7033dp</dimen>
+	<dimen name="switch_smart_width">31.5389dp</dimen>
+	<dimen name="switch_smart_height">18.0222dp</dimen>
+	<dimen name="switch_smart_offset">2.7033dp</dimen>
 	<dimen name="common_padding">4.5056dp</dimen>
 	<dimen name="common_margin">6.7583dp</dimen>
 	<dimen name="common_button_height">58.5722dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">59.2222dp</dimen>
 	<dimen name="switch_height">41.0000dp</dimen>
 	<dimen name="switch_offset">2.7333dp</dimen>
+	<dimen name="switch_smart_width">31.8889dp</dimen>
+	<dimen name="switch_smart_height">18.2222dp</dimen>
+	<dimen name="switch_smart_offset">2.7333dp</dimen>
 	<dimen name="common_padding">4.5556dp</dimen>
 	<dimen name="common_margin">6.8333dp</dimen>
 	<dimen name="common_button_height">59.2222dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">69.3333dp</dimen>
 	<dimen name="switch_height">48.0000dp</dimen>
 	<dimen name="switch_offset">3.2000dp</dimen>
+	<dimen name="switch_smart_width">37.3333dp</dimen>
+	<dimen name="switch_smart_height">21.3333dp</dimen>
+	<dimen name="switch_smart_offset">3.2000dp</dimen>
 	<dimen name="common_padding">5.3333dp</dimen>
 	<dimen name="common_margin">8.0000dp</dimen>
 	<dimen name="common_button_height">69.3333dp</dimen>

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

@@ -3,6 +3,9 @@
 	<dimen name="switch_width">69.4056dp</dimen>
 	<dimen name="switch_height">48.0500dp</dimen>
 	<dimen name="switch_offset">3.2033dp</dimen>
+	<dimen name="switch_smart_width">37.3722dp</dimen>
+	<dimen name="switch_smart_height">21.3556dp</dimen>
+	<dimen name="switch_smart_offset">3.2033dp</dimen>
 	<dimen name="common_padding">5.3389dp</dimen>
 	<dimen name="common_margin">8.0083dp</dimen>
 	<dimen name="common_button_height">69.4056dp</dimen>

+ 4 - 0
app/src/main/res/values/dimens.xml

@@ -5,6 +5,10 @@
     <dimen name="switch_height">18dp</dimen>
     <dimen name="switch_offset">1.2dp</dimen>
 
+    <dimen name="switch_smart_width">14dp</dimen>
+    <dimen name="switch_smart_height">8dp</dimen>
+    <dimen name="switch_smart_offset">1.2dp</dimen>
+
     <dimen name="common_padding">2dp</dimen>
     <dimen name="common_margin">3dp</dimen>
     <dimen name="common_button_height">26dp</dimen>

+ 1 - 1
app/src/main/res/values/strings.xml

@@ -1,5 +1,5 @@
 <resources>
-    <string name="app_name">无人机巡查</string>
+    <string name="cr_app_name">无人机巡查</string>
 
     <string name="unregistered">Err</string>
     <string name="registered">Cr</string>

+ 27 - 0
app/src/main/res/values/themes.xml

@@ -215,6 +215,33 @@
         <item name="android:scaleType">fitCenter</item>
     </style>
 
+    <!--图层控制页面基础组件-->
+    <style name="item_layer_base">
+        <item name="android:layout_weight">0</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:textColor">@color/white</item>
+    </style>
+    <!--图层控制页面Padding样式-->
+    <style name="item_layer_padding" parent="item_layer_base">
+        <item name="android:layout_marginRight">@dimen/cr_8_dp</item>
+    </style>
+    <!--图层名称样式-->
+    <style name="item_layer_name" parent="item_layer_base">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:textSize">@dimen/sp_10</item>
+        <item name="android:gravity">center_vertical</item>
+    </style>
+    <!--图层控制小标签样式-->
+    <style name="item_layer_label" parent="item_layer_padding">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:textSize">@dimen/sp_9</item>
+        <item name="android:textColor">@color/yellow</item>
+        <item name="android:gravity">center_vertical</item>
+    </style>
+
     <!--自定义文本框属性-->
     <declare-styleable name="ViewEditTextProperty">
         <attr name="crHint"></attr>

+ 1 - 3
settings.gradle

@@ -1,4 +1,2 @@
-include ':android-sdk-v5-uxsdk'
 include ':app'
-project(':android-sdk-v5-uxsdk').projectDir = new File(rootDir, 'app/libs/android-sdk-v5-uxsdk/')
-rootProject.name = "DJIV5Demo"
+rootProject.name = "UAVApp"