diff --git a/app/build.gradle b/app/build.gradle
index f09e43bd..199d51c4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,7 +35,7 @@ android {
         targetCompatibility JavaVersion.VERSION_11
     }
     kotlinOptions {
-        jvmTarget = '1.8'
+        jvmTarget = '11'
     }
     buildFeatures {
         viewBinding true
@@ -91,7 +91,6 @@ dependencies {
 
     // 读取spatialite文件
     implementation 'com.github.sevar83:android-spatialite:2.0.1'
-
 }
 //允许引用生成的代码
 kapt {
diff --git a/app/src/main/java/com/navinfo/omqs/OMQSApplication.kt b/app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
index ae704354..d6d09a80 100644
--- a/app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
+++ b/app/src/main/java/com/navinfo/omqs/OMQSApplication.kt
@@ -16,7 +16,6 @@ class OMQSApplication : Application() {
         Util.getInstance().init(applicationContext)
         NetUtils.getInstance().init(this)
         TakePhotoManager.getInstance().init(this, 1)
-        FileManager.initRootDir(this)
     }
 
     private fun getKey(inputString: String): String {
diff --git a/app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt b/app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt
index d4ae318e..86265253 100644
--- a/app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt
+++ b/app/src/main/java/com/navinfo/omqs/bean/TaskBean.kt
@@ -5,6 +5,7 @@ import com.navinfo.omqs.Constant
 import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
 import io.realm.RealmList
 import io.realm.RealmObject
+import io.realm.annotations.Ignore
 import io.realm.annotations.PrimaryKey
 import io.realm.annotations.RealmClass
 
@@ -55,9 +56,11 @@ open class TaskBean @JvmOverloads constructor(
     /**
      * 当前下载状态
      */
-    var status: Int = FileDownloadStatus.NONE
-) : RealmObject(){
-    fun getDownLoadUrl():String{
+    var status: Int = FileDownloadStatus.NONE,
+    @Ignore
+    var message: String = ""
+) : RealmObject() {
+    fun getDownLoadUrl(): String {
         return "${Constant.SERVER_ADDRESS}devcp/download?fileStr=26"
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt
index a3d18999..ea70906b 100644
--- a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt
+++ b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt
@@ -30,13 +30,24 @@ import kotlin.streams.toList
 /**
  * 导入omdb数据的帮助类
  * */
-class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val context: Context,@Assisted("omdbFile") val omdbFile: File) {
+class ImportOMDBHelper @AssistedInject constructor(
+    @Assisted("context") val context: Context,
+    @Assisted("omdbFile") val omdbFile: File
+) {
     @Inject
     lateinit var omdbHiltFactory: OMDBDataBaseHiltFactory
+
     @Inject
     lateinit var gson: Gson
-    private val database by lazy { omdbHiltFactory.obtainOmdbDataBaseHelper(context, omdbFile.absolutePath, 1).writableDatabase }
-    private val configFile: File = File("${Constant.USER_DATA_PATH}", Constant.OMDB_CONFIG)
+    private val database by lazy {
+        omdbHiltFactory.obtainOmdbDataBaseHelper(
+            context,
+            omdbFile.absolutePath,
+            1
+        ).writableDatabase
+    }
+    private val configFile: File =
+        File("${Constant.DATA_PATH}/${Constant.CURRENT_USER_ID}", Constant.OMDB_CONFIG)
 
     /**
      * 读取config的配置文件
@@ -67,8 +78,10 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
                         }
                     }.toList()
 
-                    val cursor = database.query(table, finalColumns.toTypedArray(), "1=1",
-                        mutableListOf<String>().toTypedArray(), null, null, null, null)
+                    val cursor = database.query(
+                        table, finalColumns.toTypedArray(), "1=1",
+                        mutableListOf<String>().toTypedArray(), null, null, null, null
+                    )
                     with(cursor) {
                         if (moveToFirst()) {
                             while (moveToNext()) {
@@ -76,13 +89,17 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
                                 for (columnIndex in 0 until columnCount) {
                                     var columnName = getColumnName(columnIndex)
                                     if (columnName.startsWith("ST_AsText(")) {
-                                        columnName = columnName.replace("ST_AsText(", "").substringBeforeLast(")")
+                                        columnName = columnName.replace("ST_AsText(", "")
+                                            .substringBeforeLast(")")
                                     }
-                                    when(getType(columnIndex)) {
+                                    when (getType(columnIndex)) {
                                         FIELD_TYPE_NULL -> rowMap[columnName] = ""
-                                        FIELD_TYPE_INTEGER -> rowMap[columnName] = getInt(columnIndex)
-                                        FIELD_TYPE_FLOAT -> rowMap[columnName] = getFloat(columnIndex)
-                                        FIELD_TYPE_BLOB -> rowMap[columnName] = String(getBlob(columnIndex), Charsets.UTF_8)
+                                        FIELD_TYPE_INTEGER -> rowMap[columnName] =
+                                            getInt(columnIndex)
+                                        FIELD_TYPE_FLOAT -> rowMap[columnName] =
+                                            getFloat(columnIndex)
+                                        FIELD_TYPE_BLOB -> rowMap[columnName] =
+                                            String(getBlob(columnIndex), Charsets.UTF_8)
                                         else -> rowMap[columnName] = getString(columnIndex)
                                     }
                                 }
@@ -104,54 +121,60 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
     suspend fun importOmdbZipFile(omdbZipFile: File): Flow<String> = withContext(Dispatchers.IO) {
         val importConfig = openConfigFile()
         val unZipFolder = File(omdbZipFile.parentFile, "result")
-        flow<String> {
+        flow {
             if (unZipFolder.exists()) {
                 unZipFolder.deleteRecursively()
             }
             unZipFolder.mkdirs()
             // 开始解压zip文件
             val unZipFiles = ZipUtils.unzipFile(omdbZipFile, unZipFolder)
+            // 将listResult数据插入到Realm数据库中
+            Realm.getDefaultInstance().beginTransaction()
             // 遍历解压后的文件,读取该数据返回
             for ((index, currentConfig) in importConfig.tables.withIndex()) {
                 val txtFile = unZipFiles.find {
                     it.name == currentConfig.table
                 }
 
-                val listResult: MutableList<Map<String, Any>> = mutableListOf()
+                val listResult = mutableListOf<Map<String, Any?>>()
                 currentConfig?.let {
                     val list = FileIOUtils.readFile2List(txtFile, "UTF-8")
-                    if (list!=null) {
+                    if (list != null) {
                         // 将list数据转换为map
                         for (line in list) {
-                            val map = gson.fromJson<Map<String, Any>>(line, object : TypeToken<MutableMap<String, Any>>() {}.type)
+                            val map = gson.fromJson<Map<String, Any?>>(line, object:TypeToken<Map<String, Any?>>(){}.getType())
                                 .toMutableMap()
-                            map["QItable"] = currentConfig.table
-                            map["QIname"] = currentConfig.name
-                            map["QIcode"] = currentConfig.code
+                            map["qi_table"] = currentConfig.table
+                            map["qi_name"] = currentConfig.name
+                            map["qi_code"] = currentConfig.code
                             listResult.add(map)
                         }
                     }
                 }
-                // 将listResult数据插入到Realm数据库中
-                Realm.getDefaultInstance().beginTransaction()
                 for (map in listResult) { // 每一个map就是Realm的一条数据
                     // 先查询这个mesh下有没有数据,如果有则跳过即可
 //                    val meshEntity = Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("properties['mesh']", map["mesh"].toString()).findFirst()
                     val renderEntity = RenderEntity()
-                    renderEntity.code = map["QIcode"].toString().toInt()
-                    renderEntity.name = map["QIname"].toString()
-                    renderEntity.table = map["QItable"].toString()
+                    renderEntity.code = map["qi_code"].toString().toInt()
+                    renderEntity.name = map["qi_name"].toString()
+                    renderEntity.table = map["qi_table"].toString()
                     // 其他数据插入到Properties中
                     renderEntity.geometry = map["geometry"].toString()
-                    for (entry in map) {
-                        renderEntity.properties[entry.key] = entry.value.toString()
+                    for ((key, value) in map) {
+                        when (value) {
+                            is String -> renderEntity.properties[key.toString()] = value
+                            is Int -> renderEntity.properties[key.toString()] = value.toInt().toString()
+                            is Double -> renderEntity.properties[key.toString()] = value.toDouble().toString()
+                            else -> renderEntity.properties[key.toString()] = value.toString()
+                        }
                     }
                     Realm.getDefaultInstance().insert(renderEntity)
                 }
-                Realm.getDefaultInstance().commitTransaction()
                 // 1个文件发送一次flow流
-                emit("${index+1}/${importConfig.tables.size}")
+                emit("${index + 1}/${importConfig.tables.size}")
             }
+            Realm.getDefaultInstance().commitTransaction()
+            emit("OK")
         }
     }
 
@@ -160,7 +183,15 @@ class ImportOMDBHelper @AssistedInject constructor(@Assisted("context") val cont
         val columns = mutableListOf<String>()
 
         // 查询 sqlite_master 表获取指定数据表的元数据信息
-        val cursor = db.query("sqlite_master", arrayOf("sql"), "type='table' AND name=?", arrayOf(tableName), null, null, null)
+        val cursor = db.query(
+            "sqlite_master",
+            arrayOf("sql"),
+            "type='table' AND name=?",
+            arrayOf(tableName),
+            null,
+            null,
+            null
+        )
 
         // 从元数据信息中解析出列名
         if (cursor.moveToFirst()) {
diff --git a/app/src/main/java/com/navinfo/omqs/db/MyRealmModule.kt b/app/src/main/java/com/navinfo/omqs/db/MyRealmModule.kt
index 15350948..cab1956b 100644
--- a/app/src/main/java/com/navinfo/omqs/db/MyRealmModule.kt
+++ b/app/src/main/java/com/navinfo/omqs/db/MyRealmModule.kt
@@ -1,9 +1,9 @@
 package com.navinfo.omqs.db
 
-import com.navinfo.collect.library.data.entity.QsRecordBean
 import com.navinfo.omqs.bean.HadLinkDvoBean
 import com.navinfo.omqs.bean.TaskBean
+import io.realm.annotations.RealmModule
 
-@io.realm.annotations.RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
+@RealmModule(classes = [TaskBean::class, HadLinkDvoBean::class])
 class MyRealmModule {
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/hilt/ActivityModule.kt b/app/src/main/java/com/navinfo/omqs/hilt/ActivityModule.kt
new file mode 100644
index 00000000..aa4e2a56
--- /dev/null
+++ b/app/src/main/java/com/navinfo/omqs/hilt/ActivityModule.kt
@@ -0,0 +1,66 @@
+package com.navinfo.omqs.hilt
+
+import android.content.Context
+import com.navinfo.collect.library.map.NIMapController
+import com.navinfo.omqs.db.RealmOperateHelper
+import com.navinfo.omqs.db.RoomAppDatabase
+import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
+import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
+import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityRetainedComponent
+import dagger.hilt.android.qualifiers.ActivityContext
+import dagger.hilt.android.scopes.ActivityRetainedScoped
+
+@InstallIn(ActivityRetainedComponent::class)
+@Module
+class ActivityModule {
+
+    /**
+     * 注入地图控制器,在activity范围内使用,单例
+     */
+    @ActivityRetainedScoped
+    @Provides
+    fun providesMapController(): NIMapController = NIMapController()
+
+    /**
+     * 注入离线地图下载管理,在activity范围内使用,单例
+     */
+    @ActivityRetainedScoped
+    @Provides
+    fun providesOfflineMapDownloadManager(
+        networkServiceAPI: RetrofitNetworkServiceAPI,
+        roomAppDatabase: RoomAppDatabase,
+        mapController: NIMapController
+    ): OfflineMapDownloadManager =
+        OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
+
+    /**
+     * 注入任务下载
+     */
+    @ActivityRetainedScoped
+    @Provides
+    fun providesTaskListDownloadManager(
+        networkServiceAPI: RetrofitNetworkServiceAPI,
+        importFactory: ImportOMDBHiltFactory,
+    ): TaskDownloadManager =
+        TaskDownloadManager(importFactory, networkServiceAPI)
+
+    /**
+     * 实验失败,这样创建,viewmodel不会在activity销毁的时候同时销毁
+     * 4-14:因为没有传入activity的 owner,无法检测生命周期,
+     */
+//    @ActivityRetainedScoped
+//    @Provides
+//    fun providesMainViewModel(mapController: NIMapController): MainViewModel {
+//        return MainViewModel(mapController)
+//    }
+
+    @ActivityRetainedScoped
+    @Provides
+    fun providesRealmOperateHelper(): RealmOperateHelper {
+        return RealmOperateHelper()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt b/app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt
index 907043db..25cc9516 100644
--- a/app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt
+++ b/app/src/main/java/com/navinfo/omqs/hilt/GlobalModule.kt
@@ -1,20 +1,23 @@
 package com.navinfo.omqs.hilt
 
 import android.app.Application
-import android.content.Context
 import android.util.Log
 import androidx.room.Room
 import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.google.gson.reflect.TypeToken
 import com.navinfo.omqs.Constant
 import com.navinfo.omqs.OMQSApplication
 import com.navinfo.omqs.db.RoomAppDatabase
 import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
+import com.navinfo.omqs.tools.IntTypeAdapter
 import com.tencent.wcdb.database.SQLiteCipherSpec
 import com.tencent.wcdb.room.db.WCDBOpenHelperFactory
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
 import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
 import dagger.hilt.components.SingletonComponent
 import io.realm.Realm
 import kotlinx.coroutines.*
@@ -34,7 +37,7 @@ class GlobalModule {
 
     @Singleton
     @Provides
-    fun provideApplication(application: Application): OMQSApplication {
+    fun provideApplication(@ApplicationContext application: Application): OMQSApplication {
         return application as OMQSApplication
     }
 
@@ -86,7 +89,12 @@ class GlobalModule {
 
     @Provides
     @Singleton
-    fun provideGson(): Gson = Gson()
+    fun provideGson(): Gson = GsonBuilder()
+            // 解决解析Json时将int类型自动转换为Double的问题
+        .registerTypeAdapter(object : TypeToken<Map<String, Any?>>() {}.getType(), IntTypeAdapter())
+        .registerTypeAdapter(object : TypeToken<Map<String, Any>>() {}.getType(), IntTypeAdapter())
+        .registerTypeAdapter(object : TypeToken<Map<Any, Any>>() {}.getType(), IntTypeAdapter())
+        .create()
 
     @Provides
     @Singleton
diff --git a/app/src/main/java/com/navinfo/omqs/hilt/MainActivityModule.kt b/app/src/main/java/com/navinfo/omqs/hilt/MainActivityModule.kt
index 7d353b88..8a855745 100644
--- a/app/src/main/java/com/navinfo/omqs/hilt/MainActivityModule.kt
+++ b/app/src/main/java/com/navinfo/omqs/hilt/MainActivityModule.kt
@@ -1,63 +1,21 @@
 package com.navinfo.omqs.hilt
 
+import android.content.Context
 import com.navinfo.collect.library.map.NIMapController
-import com.navinfo.omqs.db.RealmOperateHelper
-import com.navinfo.omqs.db.RoomAppDatabase
-import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
-import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
-import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
 import dagger.Module
 import dagger.Provides
 import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityRetainedComponent
-import dagger.hilt.android.scopes.ActivityRetainedScoped
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.qualifiers.ActivityContext
+import dagger.hilt.android.scopes.ActivityScoped
 
-@InstallIn(ActivityRetainedComponent::class)
+@InstallIn(ActivityComponent::class)
 @Module
 class MainActivityModule {
-
     /**
      * 注入地图控制器,在activity范围内使用,单例
      */
-    @ActivityRetainedScoped
+    @ActivityScoped
     @Provides
-    fun providesMapController(): NIMapController = NIMapController()
-
-    /**
-     * 注入离线地图下载管理,在activity范围内使用,单例
-     */
-    @ActivityRetainedScoped
-    @Provides
-    fun providesOfflineMapDownloadManager(
-        networkServiceAPI: RetrofitNetworkServiceAPI,
-        roomAppDatabase: RoomAppDatabase,
-        mapController: NIMapController
-    ): OfflineMapDownloadManager =
-        OfflineMapDownloadManager(networkServiceAPI, roomAppDatabase, mapController)
-
-    /**
-     * 注入任务下载
-     */
-    @ActivityRetainedScoped
-    @Provides
-    fun providesTaskListDownloadManager(
-        networkServiceAPI: RetrofitNetworkServiceAPI,
-    ): TaskDownloadManager =
-        TaskDownloadManager(networkServiceAPI)
-
-    /**
-     * 实验失败,这样创建,viewmodel不会在activity销毁的时候同时销毁
-     * 4-14:因为没有传入activity的 owner,无法检测生命周期,
-     */
-//    @ActivityRetainedScoped
-//    @Provides
-//    fun providesMainViewModel(mapController: NIMapController): MainViewModel {
-//        return MainViewModel(mapController)
-//    }
-
-    @ActivityRetainedScoped
-    @Provides
-    fun providesRealmOperateHelper(): RealmOperateHelper {
-        return RealmOperateHelper()
-    }
+    fun providesContext(@ActivityContext context: Context): Context = context
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/hilt/Qualifiers.kt b/app/src/main/java/com/navinfo/omqs/hilt/Qualifiers.kt
new file mode 100644
index 00000000..ab9d81cd
--- /dev/null
+++ b/app/src/main/java/com/navinfo/omqs/hilt/Qualifiers.kt
@@ -0,0 +1,7 @@
+//package com.navinfo.omqs.hilt
+//
+//import javax.inject.Qualifier
+//
+//@Qualifier
+//@Retention(AnnotationRetention.RUNTIME)
+//annotation class ActivityContext
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadManager.kt b/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadManager.kt
index 57da8cd8..8c5c1b5c 100644
--- a/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadManager.kt
+++ b/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadManager.kt
@@ -1,23 +1,32 @@
 package com.navinfo.omqs.http.taskdownload
 
+import android.content.Context
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.Observer
 import com.navinfo.omqs.bean.TaskBean
+import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
+import com.navinfo.omqs.hilt.OMDBDataBaseHiltFactory
 import com.navinfo.omqs.http.RetrofitNetworkServiceAPI
+import dagger.hilt.android.qualifiers.ActivityContext
 import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
 
 
 /**
  * 管理任务数据下载
  */
 
-class TaskDownloadManager(
+class TaskDownloadManager constructor(
+    val importFactory: ImportOMDBHiltFactory,
     val netApi: RetrofitNetworkServiceAPI,
 ) {
+
+    lateinit var context: Context
+
     /**
      * 最多同时下载数量
      */
-    private val MAX_SCOPE = 3
+    private val MAX_SCOPE = 1
 
     /**
      * 存储有哪些城市需要下载的队列
@@ -33,6 +42,9 @@ class TaskDownloadManager(
         ConcurrentHashMap<Int, TaskDownloadScope>()
     }
 
+    fun init(context: Context) {
+        this.context = context
+    }
 
     /**
      * 启动下载任务
@@ -92,7 +104,7 @@ class TaskDownloadManager(
 
     fun addTask(taskBean: TaskBean) {
         if (!scopeMap.containsKey(taskBean.id)) {
-            scopeMap[taskBean.id] = TaskDownloadScope(this, taskBean)
+            scopeMap[taskBean.id] = TaskDownloadScope( this, taskBean)
         }
     }
 
diff --git a/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadScope.kt b/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadScope.kt
index 15694cb1..f15902d7 100644
--- a/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadScope.kt
+++ b/app/src/main/java/com/navinfo/omqs/http/taskdownload/TaskDownloadScope.kt
@@ -1,23 +1,34 @@
 package com.navinfo.omqs.http.taskdownload
 
+import android.content.Context
 import android.util.Log
+import androidx.core.content.ContentProviderCompat.requireContext
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.Observer
 import com.navinfo.omqs.Constant
 import com.navinfo.omqs.bean.TaskBean
+import com.navinfo.omqs.db.ImportOMDBHelper
+import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
+import com.navinfo.omqs.tools.FileManager
 import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
+import io.realm.Realm
 import kotlinx.coroutines.*
 import java.io.File
 import java.io.IOException
 import java.io.InputStream
 import java.io.RandomAccessFile
+import javax.inject.Inject
 
 class TaskDownloadScope(
     private val downloadManager: TaskDownloadManager,
     val taskBean: TaskBean,
 ) :
     CoroutineScope by CoroutineScope(Dispatchers.IO + CoroutineName("OfflineMapDownLoad")) {
+
+    @Inject
+    lateinit var importOMDBHiltFactory: ImportOMDBHiltFactory
+
     /**
      *下载任务,用来取消的
      */
@@ -59,7 +70,12 @@ class TaskDownloadScope(
      */
     fun launch() {
         downloadJob = launch() {
-            download()
+            FileManager.checkOMDBFileInfo(taskBean)
+            if (taskBean.status == FileDownloadStatus.IMPORT) {
+                importData()
+            } else {
+                download()
+            }
             downloadManager.launchNext(taskBean.id)
         }
     }
@@ -76,14 +92,17 @@ class TaskDownloadScope(
      * 更新任务
      * @param status [OfflineMapCityBean.Status]
      */
-    private fun change(status: Int) {
-        if (taskBean.status != status || status == FileDownloadStatus.LOADING) {
+    private fun change(status: Int, message: String = "") {
+        if (taskBean.status != status || status == FileDownloadStatus.LOADING || status == FileDownloadStatus.IMPORTING) {
             taskBean.status = status
+            taskBean.message = message
             downloadData.postValue(taskBean)
-            launch(Dispatchers.IO) {
-//                downloadManager.roomDatabase.getOfflineMapDao().update(taskBean)
+            launch {
+                val realm = Realm.getDefaultInstance()
+                realm.executeTransaction {
+                    it.copyToRealmOrUpdate(taskBean)
+                }
             }
-
         }
     }
 
@@ -96,36 +115,75 @@ class TaskDownloadScope(
         downloadData.observe(owner, ob)
     }
 
+    /**
+     * 导入数据
+     */
+    private suspend fun importData(file: File? = null) {
+        try {
+            Log.e("jingo", "importData SSS")
+            change(FileDownloadStatus.IMPORTING)
+            var fileNew = file
+                ?: File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
+            val importOMDBHelper: ImportOMDBHelper =
+                downloadManager.importFactory.obtainImportOMDBHelper(
+                    downloadManager.context,
+                    fileNew
+                )
+            importOMDBHelper.importOmdbZipFile(importOMDBHelper.omdbFile).collect {
+                Log.e("jingo", "数据安装 $it")
+                if (it == "OK") {
+                    change(FileDownloadStatus.DONE)
+                } else {
+                    change(FileDownloadStatus.IMPORTING, it)
+                }
+            }
+        } catch (e: Exception) {
+            Log.e("jingo", "数据安装失败 ${e.toString()}")
+            change(FileDownloadStatus.ERROR)
+        }
+
+        Log.e("jingo", "importData EEE")
+    }
+
     /**
      * 下载文件
      */
     private suspend fun download() {
+        //如果文件下载安装已经完毕
+        if (taskBean.status == FileDownloadStatus.DONE) {
+            return
+        }
         var inputStream: InputStream? = null
         var randomAccessFile: RandomAccessFile? = null
         try {
             //创建离线地图 下载文件夹,.map文件夹的下一级
-            val fileDir = File("${Constant.DOWNLOAD_PATH}download")
+            val fileDir = File("${Constant.DOWNLOAD_PATH}")
             if (!fileDir.exists()) {
                 fileDir.mkdirs()
             }
 
             val fileTemp =
-                File("${Constant.DOWNLOAD_PATH}${taskBean.id}_${taskBean.dataVersion}")
+                File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip")
             val startPosition = taskBean.currentSize
-            //验证断点有效性
-            if (startPosition < 0) throw IOException("jingo Start position less than zero")
+
+            if (fileTemp.length() > 0 && taskBean.fileSize > 0 && fileTemp.length() == taskBean.fileSize) {
+                importData(fileTemp)
+                return
+            }
+
             val response = downloadManager.netApi.retrofitDownLoadFile(
                 start = "bytes=$startPosition-",
                 url = taskBean.getDownLoadUrl()
             )
             val responseBody = response.body()
 
-            change(FileDownloadStatus.LOADING)
-            responseBody ?: throw IOException("jingo ResponseBody is null")
 
+            responseBody ?: throw IOException("jingo ResponseBody is null")
             if (startPosition == 0L) {
                 taskBean.fileSize = responseBody.contentLength()
+                Log.e("jingo", "当前文件大小 ${taskBean.fileSize}")
             }
+            change(FileDownloadStatus.LOADING)
             //写入文件
             randomAccessFile = RandomAccessFile(fileTemp, "rwd")
             randomAccessFile.seek(startPosition)
@@ -146,17 +204,14 @@ class TaskDownloadScope(
                 }
             }
 
-            Log.e("jingo", "文件下载完成 ${taskBean.currentSize} == ${taskBean.fileSize}")
             if (taskBean.currentSize == taskBean.fileSize) {
-                val res =
-                    fileTemp.renameTo(File("${Constant.DOWNLOAD_PATH}${taskBean.evaluationTaskName}.zip"))
-                Log.e("jingo", "文件下载完成 修改文件 $res")
-                change(FileDownloadStatus.DONE)
+                importData(fileTemp)
             } else {
                 change(FileDownloadStatus.PAUSE)
             }
         } catch (e: Throwable) {
             change(FileDownloadStatus.ERROR)
+            Log.e("jingo","数据下载出错 ${e.message}")
         } finally {
             inputStream?.close()
             randomAccessFile?.close()
diff --git a/app/src/main/java/com/navinfo/omqs/tools/FileManager.kt b/app/src/main/java/com/navinfo/omqs/tools/FileManager.kt
index 4b0aa70d..754d2a7f 100644
--- a/app/src/main/java/com/navinfo/omqs/tools/FileManager.kt
+++ b/app/src/main/java/com/navinfo/omqs/tools/FileManager.kt
@@ -16,8 +16,10 @@ class FileManager {
             const val LOADING = 2 //下载中
             const val PAUSE = 3 //暂停
             const val ERROR = 4 //错误
-            const val DONE = 5 //完成
-            const val UPDATE = 6 //有新版本要更新
+            const val IMPORT = 5 //安装
+            const val IMPORTING = 6 //安装中
+            const val UPDATE = 7 //有新版本要更新
+            const val DONE = 8 //完成
         }
 
         //初始化数据文件夹
@@ -109,60 +111,28 @@ class FileManager {
          * 检查离线地图文件
          */
         suspend fun checkOMDBFileInfo(taskBean: TaskBean) {
+            if (taskBean.status == FileDownloadStatus.DONE)
+                return
             //访问离线地图文件夹
             val fileDir = File("${Constant.DOWNLOAD_PATH}")
             //如果连本地文件夹还没有,就不用修改任何数据了
             if (!fileDir.exists()) {
                 return
             }
-            //访问离线地图临时下载文件夹
-            val fileTempDir = File(Constant.DOWNLOAD_PATH)
-            //是否有一份.map文件了
-            var mapFile: File? = null
             //文件夹里文件挨个访问
             for (item in fileDir.listFiles()) {
                 //先找到对应的省市文件,例如:540000_西藏自治区_20230401195018.map",以id开头
-                if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
-                    //如果本地文件与从网络获取到版本号一致,表示这个文件已经下载完毕,不用处理了
-                    if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
-                        taskBean.status = FileDownloadStatus.DONE
-                        return
-                    }
-                    //文件存在,版本号不对应,留给下面流程处理
-                    mapFile = item
-                    break
-                }
-            }
-            //临时下载文件夹
-            if (fileTempDir.exists()) {
-                for (item in fileTempDir.listFiles()) {
-                    //先找到对应的省市文件,例如:540000_20230401195018",以id开头
-                    if (item.isFile && item.name.startsWith("${taskBean.id}_")) {
-                        //如果本地文件与从网络获取到版本号一致,表示这个文件已经在下载列表中
-                        if (item.name == "${taskBean.id}_${taskBean.dataVersion}") {
-                            //如果这个临时文件的大小和下载大小是一致的,说明已经下载完了,但是在下载环节没有更名移动成功,需要重命名和移动文件夹
-                            if (item.length() == taskBean.fileSize) {
-                                //移动更名文件后删除旧数据,修改状态
-                                if (item.renameTo(File("${Constant.OFFLINE_MAP_PATH}${taskBean.evaluationTaskName}.zip"))) {
-                                    //删除旧版本数据
-                                    mapFile?.delete()
-                                    taskBean.status = FileDownloadStatus.DONE
-                                    return
-                                }
-                            } else { // 临时文件大小和目标不一致,说明下载了一半
-                                taskBean.status = FileDownloadStatus.PAUSE
-                                taskBean.currentSize = item.length()
-                                return
-                            }
-                        } else { //虽然省市id开头一致,但是版本号不一致,说明之前版本下载了一部分,现在要更新了,原来下载的文件直接删除
-                            taskBean.status = FileDownloadStatus.UPDATE
-                            item.delete()
-                            return
-                        }
-                        break
+                if (item.isFile && item.name == "${taskBean.evaluationTaskName}_${taskBean.dataVersion}.zip") {
+                    taskBean.currentSize = item.length()
+                    if (taskBean.fileSize > 0 && taskBean.fileSize == item.length()) {
+                        taskBean.status = FileDownloadStatus.IMPORT
+                    } else {
+                        taskBean.status = FileDownloadStatus.PAUSE
                     }
+                    return
                 }
             }
+            taskBean.status = FileDownloadStatus.NONE
         }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/tools/IntTypeAdapter.kt b/app/src/main/java/com/navinfo/omqs/tools/IntTypeAdapter.kt
new file mode 100644
index 00000000..894053f4
--- /dev/null
+++ b/app/src/main/java/com/navinfo/omqs/tools/IntTypeAdapter.kt
@@ -0,0 +1,69 @@
+package com.navinfo.omqs.tools
+
+import com.google.gson.Gson
+import com.google.gson.TypeAdapter
+import com.google.gson.internal.LinkedTreeMap
+import com.google.gson.stream.JsonReader
+import com.google.gson.stream.JsonToken
+import com.google.gson.stream.JsonWriter
+import java.io.IOException
+
+class IntTypeAdapter : TypeAdapter<Any>() {
+    private val delegate: TypeAdapter<Any> = Gson().getAdapter(Any::class.java)
+
+    @Throws(IOException::class)
+    override fun read(`in`: JsonReader): Any? {
+        val token = `in`.peek()
+        when (token) {
+            JsonToken.BEGIN_ARRAY -> {
+                val list: MutableList<Any?> = ArrayList()
+                `in`.beginArray()
+                while (`in`.hasNext()) {
+                    list.add(read(`in`))
+                }
+                `in`.endArray()
+                return list
+            }
+            JsonToken.BEGIN_OBJECT -> {
+                val map: MutableMap<String, Any?> = LinkedTreeMap()
+                `in`.beginObject()
+                while (`in`.hasNext()) {
+                    map[`in`.nextName()] = read(`in`)
+                }
+                `in`.endObject()
+                return map
+            }
+            JsonToken.STRING -> return `in`.nextString()
+            JsonToken.NUMBER -> {
+                // 改写数字的处理逻辑,将数字值分为整型与浮点型。
+                val dbNum = `in`.nextDouble()
+                // 数字超过long的最大值,返回浮点类型
+                if (dbNum > Long.MAX_VALUE) {
+                    return dbNum
+                }
+                // 判断数字是否为整数值
+                val lngNum = dbNum.toLong()
+                return if (dbNum == lngNum.toDouble()) {
+                    try {
+                        lngNum.toInt()
+                    } catch (e: Exception) {
+                        lngNum
+                    }
+                } else {
+                    dbNum
+                }
+            }
+            JsonToken.BOOLEAN -> return `in`.nextBoolean()
+            JsonToken.NULL -> {
+                `in`.nextNull()
+                return null
+            }
+            else -> throw IllegalStateException()
+        }
+    }
+
+    @Throws(IOException::class)
+    override fun write(out: JsonWriter, value: Any?) {
+        delegate.write(out, value)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/login/LoginViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/login/LoginViewModel.kt
index e241cb99..94d4f611 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/activity/login/LoginViewModel.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/activity/login/LoginViewModel.kt
@@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
 import com.blankj.utilcode.util.ResourceUtils
 import com.navinfo.omqs.Constant
 import com.navinfo.omqs.bean.LoginUserBean
+import com.navinfo.omqs.db.MyRealmModule
 import com.navinfo.omqs.db.RoomAppDatabase
 import com.navinfo.omqs.http.NetResult
 import com.navinfo.omqs.http.NetworkService
@@ -159,7 +160,8 @@ class LoginViewModel @Inject constructor(
         Constant.VERSION_ID = userId
         Constant.USER_DATA_PATH = Constant.DATA_PATH + Constant.USER_ID + "/" + Constant.VERSION_ID
         // 在SD卡创建用户目录,解压资源等
-        val userFolder = File("${Constant.DATA_PATH}/${userId}")
+        val userFolder = File(Constant.USER_DATA_PATH)
+        if (!userFolder.exists()) userFolder.mkdirs()
         // 初始化Realm
         Realm.init(context.applicationContext)
         val password = "encryp".encodeToByteArray().copyInto(ByteArray(64))
@@ -169,7 +171,7 @@ class LoginViewModel @Inject constructor(
             .directory(userFolder)
             .name("OMQS.realm")
             .encryptionKey(password)
-//            .modules(Realm.getDefaultModule(), MyRealmModule())
+            .modules(Realm.getDefaultModule(), MyRealmModule())
             .schemaVersion(1)
             .build()
         Realm.setDefaultConfiguration(config)
diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt
index 14d6015c..51273fb5 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt
@@ -4,10 +4,8 @@ import android.os.Bundle
 import androidx.activity.viewModels
 import androidx.core.view.WindowCompat
 import androidx.databinding.DataBindingUtil
-import androidx.lifecycle.ViewModelProvider
-import com.blankj.utilcode.util.ToastUtils
-import androidx.lifecycle.lifecycleScope
 import androidx.navigation.findNavController
+import com.blankj.utilcode.util.ToastUtils
 import com.navinfo.collect.library.map.NIMapController
 import com.navinfo.collect.library.map.handler.NiLocationListener
 import com.navinfo.omqs.Constant
@@ -34,10 +32,10 @@ class MainActivity : BaseActivity() {
     @Inject
     lateinit var offlineMapDownloadManager: OfflineMapDownloadManager
 
+
     override fun onCreate(savedInstanceState: Bundle?) {
         WindowCompat.setDecorFitsSystemWindows(window, false)
         super.onCreate(savedInstanceState)
-
         binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
         //初始化地图
         mapController.init(
diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt
index 49a4603f..4f7cd21f 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/personalcenter/PersonalCenterFragment.kt
@@ -3,38 +3,24 @@ package com.navinfo.omqs.ui.fragment.personalcenter
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
-import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import androidx.fragment.app.Fragment
 import androidx.fragment.app.viewModels
-import androidx.lifecycle.lifecycleScope
 import androidx.navigation.fragment.findNavController
 import com.blankj.utilcode.util.UriUtils
 import com.github.k1rakishou.fsaf.FileChooser
 import com.github.k1rakishou.fsaf.callback.FSAFActivityCallbacks
 import com.github.k1rakishou.fsaf.callback.FileChooserCallback
-import com.navinfo.collect.library.data.RealmUtils
-import com.navinfo.collect.library.data.entity.OMDBEntity
 import com.navinfo.collect.library.map.NIMapController
 import com.navinfo.omqs.R
 import com.navinfo.omqs.databinding.FragmentPersonalCenterBinding
 import com.navinfo.omqs.db.ImportOMDBHelper
 import com.navinfo.omqs.hilt.ImportOMDBHiltFactory
 import com.navinfo.omqs.tools.CoroutineUtils
-import com.navinfo.omqs.ui.activity.BaseActivity
 import com.navinfo.omqs.ui.fragment.BaseFragment
 import dagger.hilt.android.AndroidEntryPoint
-import io.realm.Realm
-import io.realm.RealmDictionary
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.FlowCollector
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
 import org.oscim.core.GeoPoint
-import java.io.File
-import java.util.UUID
 import javax.inject.Inject
 
 /**
@@ -104,13 +90,6 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
                                     file
                                 )
                                 viewModel.importOMDBData(importOMDBHelper)
-//                            // 开始导入数据
-//                            CoroutineUtils.launchWithLoading(
-//                                requireContext(),
-//                                loadingMessage = "导入数据..."
-//                            ) {
-//
-//                            }
                         }
                     })
                 }
@@ -122,14 +101,13 @@ class PersonalCenterFragment : BaseFragment(), FSAFActivityCallbacks {
 
                         override fun onResult(uri: Uri) {
                             viewModel.importScProblemData(uri)
-
                         }
                     })
                 }
                 R.id.personal_center_menu_test -> {
                     viewModel.readRealmData()
                     // 定位到指定位置
-                    niMapController.mMapView.vtmMap.animator().animateTo(GeoPoint(28.608398, 115.67901))
+                    niMapController.mMapView.vtmMap.animator().animateTo(GeoPoint(30.270367985798032, 113.83513667119433))
                 }
                 R.id.personal_center_menu_task_list -> {
                     findNavController().navigate(R.id.TaskListFragment)
diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt
index 8e3ab8f8..692404ca 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt
@@ -13,6 +13,8 @@ import com.navinfo.omqs.http.taskdownload.TaskDownloadManager
 import com.navinfo.omqs.tools.FileManager.Companion.FileDownloadStatus
 import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter
 import com.navinfo.omqs.ui.other.BaseViewHolder
+import java.io.File
+import javax.inject.Inject
 
 /**
  * 离线地图城市列表 RecyclerView 适配器
@@ -31,7 +33,7 @@ class TaskListAdapter(
         if (it.tag != null) {
             val taskBean = data[it.tag as Int]
             when (taskBean.status) {
-                FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.ERROR -> {
+                FileDownloadStatus.NONE, FileDownloadStatus.UPDATE, FileDownloadStatus.PAUSE, FileDownloadStatus.IMPORT, FileDownloadStatus.ERROR -> {
                     Log.e("jingo", "开始下载 ${taskBean.status}")
                     downloadManager.start(taskBean.id)
                 }
@@ -125,6 +127,29 @@ class TaskListAdapter(
                     View.INVISIBLE
                 binding.taskDownloadBtn.text = "更新"
             }
+            FileDownloadStatus.IMPORTING -> {
+                if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
+                    View.VISIBLE
+                binding.taskDownloadBtn.text = "安装中"
+                val split = taskBean.message.split("/")
+                if (split.size == 2) {
+                    try {
+                        val index = split[0].toInt()
+                        val count = split[1].toInt()
+                        binding.taskProgress.progress =
+                            index * 100 / count
+                    } catch (e: Exception) {
+                        Log.e("jingo", "更新进度条 $e")
+                    }
+                } else {
+                    binding.taskProgress.progress = 0
+                }
+            }
+            FileDownloadStatus.IMPORT -> {
+                if (binding.taskProgress.visibility != View.VISIBLE) binding.taskProgress.visibility =
+                    View.INVISIBLE
+                binding.taskDownloadBtn.text = "安装"
+            }
         }
     }
 
diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt
index 55e149d9..9ec1ab92 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt
@@ -30,6 +30,7 @@ class TaskListFragment : BaseFragment(){
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View {
+        downloadManager.init(requireContext())
         _binding = FragmentTaskListBinding.inflate(inflater, container, false)
         return binding.root
 
diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListViewModel.kt
index d8825811..f3175363 100644
--- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListViewModel.kt
+++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListViewModel.kt
@@ -27,12 +27,28 @@ class TaskListViewModel @Inject constructor(
     fun getTaskList(context: Context) {
         viewModelScope.launch(Dispatchers.IO) {
             val realm = Realm.getDefaultInstance()
-            Log.e("jingo","realm hashCOde ${realm.hashCode()}")
+            Log.e("jingo", "realm hashCOde ${realm.hashCode()}")
+            var taskList: List<TaskBean> = mutableListOf()
             when (val result = networkService.getTaskList("02911")) {
                 is NetResult.Success -> {
                     if (result.data != null) {
                         realm.executeTransaction {
-                            realm.copyToRealmOrUpdate(result.data.obj)
+                            result.data.obj?.let { list ->
+                                for (task in list) {
+                                    val item = realm.where(TaskBean::class.java).equalTo(
+                                        "id", task.id
+                                    ).findFirst()
+                                    if (item != null) {
+                                        task.fileSize = item.fileSize
+                                        Log.e("jingo", "当前文件大小 ${task.fileSize}")
+                                        task.status = item.status
+                                        task.currentSize = item.currentSize
+                                    }
+                                    realm.copyToRealmOrUpdate(task)
+                                }
+                            }
+                            val objects = realm.where(TaskBean::class.java).findAll()
+                            taskList = realm.copyFromRealm(objects)
                         }
                     }
                 }
@@ -51,9 +67,8 @@ class TaskListViewModel @Inject constructor(
                 is NetResult.Loading -> {}
                 else -> {}
             }
-            val objects = realm.where(TaskBean::class.java).findAll()
-            val taskList = realm.copyFromRealm(objects)
-            for(item in taskList){
+
+            for (item in taskList) {
                 FileManager.checkOMDBFileInfo(item)
             }
             liveDataTaskList.postValue(taskList)
diff --git a/app/src/main/res/layout/adapter_task_list.xml b/app/src/main/res/layout/adapter_task_list.xml
index c64c31cf..f83eb5c1 100644
--- a/app/src/main/res/layout/adapter_task_list.xml
+++ b/app/src/main/res/layout/adapter_task_list.xml
@@ -8,6 +8,7 @@
     android:paddingLeft="10dp"
     android:paddingTop="5dp"
     android:paddingRight="10dp"
+    android:paddingBottom="5dp"
     tools:context="com.navinfo.omqs.ui.fragment.tasklist.TaskListAdapter">
 
     <TextView
diff --git a/collect-library/build.gradle b/collect-library/build.gradle
index 63bc27c2..d61972fa 100644
--- a/collect-library/build.gradle
+++ b/collect-library/build.gradle
@@ -38,8 +38,8 @@ android {
         }
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_8
-        targetCompatibility JavaVersion.VERSION_1_8
+        sourceCompatibility JavaVersion.VERSION_11
+        targetCompatibility JavaVersion.VERSION_11
     }
 
     sourceSets {
diff --git a/collect-library/src/main/assets/editormarker.xml b/collect-library/src/main/assets/editormarker.xml
index 7ca48369..aa009d1b 100644
--- a/collect-library/src/main/assets/editormarker.xml
+++ b/collect-library/src/main/assets/editormarker.xml
@@ -1549,4 +1549,104 @@
             <symbol src="assets:symbols/dot_blue.svg" />
         </m>
     </m>
+
+    <m k="qi_table">
+        <!-- 道路线 -->
+        <m v="OMDB_RD_LINK">
+            <line stroke="#9c9c9c" width="1"/>
+        </m>
+        <!--道路方向-->
+        <m v="OMDB_RD_LINK_DIRECT">
+            <m k="direct">
+                <m v="2">
+                    <lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
+                </m>
+                <m v="3">
+                    <lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
+                </m>
+            </m>
+        </m>
+        <!--道路种别-->
+        <m v="OMDB_RD_LINK_KIND">
+            <m k="kind">
+                <m v="1">
+                    <line stroke="#fcacd4" width="1"/>
+                </m>
+                <m v="2">
+                    <line stroke="#dcacfc" width="1"/>
+                </m>
+                <m v="3">
+                    <line stroke="#fc9c9c" width="1"/>
+                </m>
+                <m v="4">
+                    <line stroke="#fcd484" width="1"/>
+                </m>
+                <m v="5">
+                    <line stroke="#ecfccc" width="1"/>
+                </m>
+                <m v="6">
+                    <line stroke="#acec84" width="1"/>
+                </m>
+                <m v="7">
+                    <line stroke="#806048" width="1"/>
+                </m>
+                <m v="8">
+                    <line stroke="#fcfc7c" width="1"/>
+                </m>
+                <m v="9">
+                    <line stroke="#acc4fc" width="1"/>
+                </m>
+                <m v="10">
+                    <line stroke="#8cc8e0" width="1"/>
+                </m>
+                <m v="11">
+                    <line stroke="#64ecdc" width="1"/>
+                </m>
+                <m v="13">
+                    <line stroke="#585080" width="1"/>
+                </m>
+                <m v="15">
+                    <line stroke="#647430" width="1"/>
+                </m>
+            </m>
+        </m>
+
+        <!--常规点限速-->
+        <m v="OMDB_SPEEDLIMIT">
+            <m k="speedFlag">
+                <m v="0">
+                    <circle fill="#0000ff" radius="30" scale-radius="true" />
+                    <text k="maxSpeed" use="road"></text>
+                    <text k="minSpeed" dy="30" bg-fill="#00ff00" use="road"></text>
+                </m>
+                <m v="1">
+<!--                    <circle fill="#0000ff" radius="30" scale-radius="true" />-->
+                    <text k="maxSpeed" use="road"></text>
+                    <text k="minSpeed" dy="30" bg-fill="#00ff00" use="road"></text>
+                </m>
+            </m>
+        </m>
+        <!--条件点限速-->
+        <m v="OMDB_SPEEDLIMIT_COND">
+            <m k="direct">
+                <m v="2">
+                    <lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
+                </m>
+                <m v="3">
+                    <lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
+                </m>
+            </m>
+        </m>
+        <!--可变点限速-->
+        <m v="OMDB_SPEEDLIMIT_VAR">
+            <m k="direct">
+                <m v="2">
+                    <lineSymbol src="assets:omdb/oneway_left.svg"></lineSymbol>
+                </m>
+                <m v="3">
+                    <lineSymbol src="assets:omdb/oneway_right.svg"></lineSymbol>
+                </m>
+            </m>
+        </m>
+    </m>
 </rendertheme>
\ No newline at end of file
diff --git a/collect-library/src/main/assets/omdb/oneway_left.svg b/collect-library/src/main/assets/omdb/oneway_left.svg
new file mode 100644
index 00000000..9acd8dbe
--- /dev/null
+++ b/collect-library/src/main/assets/omdb/oneway_left.svg
@@ -0,0 +1,11 @@
+<svg width="580" height="580" xmlns="http://www.w3.org/2000/svg" version="1.0">
+ <metadata id="metadata10"/>
+
+ <g>
+  <title>Layer 1</title>
+  <g transform="rotate(-179.925 290 290)" id="svg_1">
+   <path stroke="#ffffff" shape-rendering="auto" filter-blend-mode="normal" stroke-linejoin="round" fill="none" solid-opacity="1" color-interpolation="sRGB" isolation="auto" stroke-width="64" color-rendering="auto" image-rendering="auto" color="#000000" filter-gaussianBlur-deviation="0" color-interpolation-filters="linearRGB" opacity="0.8" solid-color="#000000" mix-blend-mode="normal" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" id="path4151"/>
+   <path fill="#6a6a6a" id="path4136" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z"/>
+  </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/collect-library/src/main/assets/omdb/oneway_right.svg b/collect-library/src/main/assets/omdb/oneway_right.svg
new file mode 100644
index 00000000..b289a043
--- /dev/null
+++ b/collect-library/src/main/assets/omdb/oneway_right.svg
@@ -0,0 +1,11 @@
+<svg width="580" height="580" xmlns="http://www.w3.org/2000/svg" version="1.0">
+ <metadata id="metadata10"/>
+
+ <g>
+  <title>Layer 1</title>
+  <g id="svg_1" transform="rotate(-0.400407 290 290)">
+   <path id="path4151" d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" mix-blend-mode="normal" solid-color="#000000" opacity="0.8" color-interpolation-filters="linearRGB" filter-gaussianBlur-deviation="0" color="#000000" image-rendering="auto" color-rendering="auto" stroke-width="64" isolation="auto" color-interpolation="sRGB" solid-opacity="1" fill="none" stroke-linejoin="round" filter-blend-mode="normal" shape-rendering="auto" stroke="#ffffff"/>
+   <path d="m30,261l286,0l0,-72.5l234,101.85l-234,101.15l0,-72.5l-286,0l0,-58z" id="path4136" fill="#6a6a6a"/>
+  </g>
+ </g>
+</svg>
\ No newline at end of file
diff --git a/collect-library/src/main/java/com/navinfo/collect/library/data/entity/QsRecordBean.kt b/collect-library/src/main/java/com/navinfo/collect/library/data/entity/QsRecordBean.kt
index 58d4bb8a..42adfd2a 100644
--- a/collect-library/src/main/java/com/navinfo/collect/library/data/entity/QsRecordBean.kt
+++ b/collect-library/src/main/java/com/navinfo/collect/library/data/entity/QsRecordBean.kt
@@ -4,7 +4,6 @@ import com.navinfo.collect.library.utils.GeometryToolsKt
 import io.realm.RealmObject
 import io.realm.RealmSet
 import io.realm.annotations.PrimaryKey
-import io.realm.annotations.RealmClass
 
 
 /**
diff --git a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LayerManagerHandler.kt b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LayerManagerHandler.kt
index 3b419ed5..f3524706 100644
--- a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LayerManagerHandler.kt
+++ b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LayerManagerHandler.kt
@@ -116,6 +116,18 @@ open class LayerManagerHandler(context: AppCompatActivity, mapView: NIMapView,tr
         mMapView.updateMap()
 //        initMapLifeSource()
 
+        // 设置矢量图层均在12级以上才显示
+        mMapView.vtmMap.events.bind(UpdateListener { e, mapPosition ->
+            if (e == org.oscim.map.Map.SCALE_EVENT) {
+                // 测评数据图层在指定Zoom后开始显示
+                val isOmdbZoom = mapPosition.zoomLevel>=Constant.OMDB_MIN_ZOOM
+                baseGroupLayer?.layers?.forEach {
+                    it.isEnabled = !isOmdbZoom
+                }
+                omdbVectorTileLayer.isEnabled = isOmdbZoom
+                omdbLabelLayer.isEnabled = isOmdbZoom
+            }
+        })
     }
 
     private fun initOMDBVectorTileLayer() {
diff --git a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryToolsKt.kt b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryToolsKt.kt
index 3d5fd4a5..888e0afd 100644
--- a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryToolsKt.kt
+++ b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryToolsKt.kt
@@ -42,7 +42,7 @@ class GeometryToolsKt {
                     val tileY1 = MercatorProjection.latitudeToTileY(minMaxY[1], Constant.OVER_ZOOM.toByte())
                     val minTileY = if (tileY0 <= tileY1) tileY0 else tileY1
                     val maxTileY = if (tileY0 <= tileY1) tileY1 else tileY0
-                    println("getTileYByGeometry$envelope===$minTileY===$maxTileY")
+//                    println("getTileYByGeometry$envelope===$minTileY===$maxTileY")
 
                     for (i in minTileY..maxTileY) {
                         tileYSet.add(i)
@@ -86,7 +86,7 @@ class GeometryToolsKt {
                         val tileX1 = MercatorProjection.longitudeToTileX(minMaxX[1], Constant.OVER_ZOOM.toByte())
                         val minTileX = if (tileX0 <= tileX1) tileX0 else tileX1
                         val maxTileX = if (tileX0 <= tileX1) tileX1 else tileX0
-                        println("getTileXByGeometry$envelope$minTileX===$maxTileX")
+//                        println("getTileXByGeometry$envelope$minTileX===$maxTileX")
                         for (i in minTileX..maxTileX) {
                             tileXSet.add(i)
                         }
diff --git a/collect-library/src/main/res/resources/rendertheme.xsd b/collect-library/src/main/res/resources/rendertheme.xsd
new file mode 100644
index 00000000..b28e722a
--- /dev/null
+++ b/collect-library/src/main/res/resources/rendertheme.xsd
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:tns="http://opensciencemap.org/rendertheme"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
+           targetNamespace="http://opensciencemap.org/rendertheme" xml:lang="en">
+
+    <!-- attribute types -->
+    <xs:simpleType name="cap">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="butt"/>
+            <xs:enumeration value="round"/>
+            <xs:enumeration value="square"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="closed">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="yes"/>
+            <xs:enumeration value="no"/>
+            <xs:enumeration value="any"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="color">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="elementList">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="node"/>
+            <xs:enumeration value="way"/>
+            <xs:enumeration value="any"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="selectorList">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="first"/>
+            <xs:enumeration value="any"/>
+            <xs:enumeration value="when-matched"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="fontFamily">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="default"/>
+            <xs:enumeration value="default_bold"/>
+            <xs:enumeration value="monospace"/>
+            <xs:enumeration value="sans_serif"/>
+            <xs:enumeration value="serif"/>
+            <xs:enumeration value="thin"/>
+            <xs:enumeration value="light"/>
+            <xs:enumeration value="medium"/>
+            <xs:enumeration value="black"/>
+            <xs:enumeration value="condensed"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="fontStyle">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="bold"/>
+            <xs:enumeration value="bold_italic"/>
+            <xs:enumeration value="italic"/>
+            <xs:enumeration value="normal"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="nonNegativeFloat">
+        <xs:restriction base="xs:float">
+            <xs:minInclusive value="0"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="src">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="((file|assets):)?.+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="strokeDasharray">
+        <xs:restriction base="xs:string">
+            <xs:pattern
+                    value="([0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)? *, *)*[0-9]+(\.[0-9]+)? *, *[0-9]+(\.[0-9]+)?"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="textKey">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="ele"/>
+            <xs:enumeration value="addr:housenumber"/>
+            <xs:enumeration value="addr_housenumber"/> <!-- Mapzen -->
+            <xs:enumeration value="housenumber"/> <!-- OpenMapTiles -->
+            <xs:enumeration value="name"/>
+            <xs:enumeration value="maxSpeed"/><!--最高速度-->
+            <xs:enumeration value="minSpeed"/><!--最低速度-->
+            <xs:enumeration value="ref"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- style menu cat element -->
+    <xs:complexType name="cat">
+        <xs:attribute name="id" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <!-- style menu name element -->
+    <xs:complexType name="name">
+        <xs:attribute name="lang" type="xs:string" use="required"/>
+        <xs:attribute name="value" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <!-- style menu overlay element -->
+    <xs:complexType name="overlay">
+        <xs:attribute name="id" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <!-- style menu layer element -->
+    <xs:complexType name="layer">
+        <xs:sequence maxOccurs="1" minOccurs="0">
+            <xs:element name="name" maxOccurs="unbounded" minOccurs="0" type="tns:name"/>
+            <xs:element name="cat" maxOccurs="unbounded" minOccurs="0" type="tns:cat"/>
+            <xs:element name="overlay" maxOccurs="unbounded" minOccurs="0" type="tns:overlay"/>
+        </xs:sequence>
+        <xs:attribute name="id" type="xs:string" use="required"/>
+        <xs:attribute name="parent" type="xs:string" use="optional"/>
+        <xs:attribute name="visible" default="false" type="xs:boolean" use="optional"/>
+        <xs:attribute name="enabled" default="false" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+
+    <!-- rendering instructions -->
+    <xs:complexType name="area">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+        <xs:attribute name="id" default="0" type="xs:string" use="optional"/>
+        <xs:attribute name="use" default="0" type="xs:string" use="optional"/>
+        <xs:attribute name="src" type="tns:src" use="optional"/>
+        <xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke" default="#00000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <xs:attribute name="fade" default="-1" type="xs:integer" use="optional"/>
+        <xs:attribute name="blend" default="-1" type="xs:integer" use="optional"/>
+        <xs:attribute name="blend-fill" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="mesh" default="false" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="caption">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+        <xs:attribute name="k" type="tns:textKey" use="required"/>
+        <xs:attribute name="dy" default="0" type="xs:float" use="optional"/>
+        <xs:attribute name="font-family" default="default" type="tns:fontFamily" use="optional"/>
+        <xs:attribute name="style" default="normal" type="tns:fontStyle" use="optional"/>
+        <xs:attribute name="size" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <xs:attribute name="bg-fill" default="#00000000" type="tns:color" use="optional"/>
+        <xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <!-- polygon area expressed as a ratio to tile area, e.g. 0.1 for 10% of tile area -->
+        <xs:attribute name="area-size" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <!-- priority for label placement, 0 = highest priority -->
+        <xs:attribute name="priority" default="0" type="xs:integer" use="optional"/>
+        <!-- symbol src name -->
+        <xs:attribute name="symbol" type="tns:src" use="optional"/>
+        <xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="circle">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+        <xs:attribute name="radius" type="tns:nonNegativeFloat" use="required"/>
+        <xs:attribute name="scale-radius" default="false" type="xs:boolean" use="optional"/>
+        <xs:attribute name="fill" default="#00000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke" default="#00000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="line">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+
+        <!-- style: TODO only in style-line-->
+        <xs:attribute name="id" default="0" type="xs:string" use="optional"/>
+
+        <!-- inherited style -->
+        <xs:attribute name="use" default="0" type="xs:string" use="optional"/>
+
+        <xs:attribute name="src" type="tns:src" use="optional"/>
+        <xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="width" default="0" type="xs:float" use="optional"/>
+        <!-- minimum scaled width to draw outline -->
+        <xs:attribute name="min" default="0" type="xs:float" use="optional"/>
+        <xs:attribute name="dasharray" type="tns:strokeDasharray" use="optional"/>
+        <xs:attribute name="cap" default="round" type="tns:cap" use="optional"/>
+        <xs:attribute name="outline" default="" type="xs:string" use="optional"/>
+        <xs:attribute name="fade" default="-1" type="xs:integer" use="optional"/>
+        <xs:attribute name="blur" default="-1" type="xs:float" use="optional"/>
+        <xs:attribute name="fix" default="false" type="xs:boolean" use="optional"/>
+        <xs:attribute name="repeat-gap" default="200" type="xs:float" use="optional"/>
+        <xs:attribute name="repeat-start" default="30" type="xs:float" use="optional"/>
+
+        <!-- stipple repeat in 'pixel' -->
+        <xs:attribute name="stipple" default="0" type="xs:integer" use="optional"/>
+        <!-- stipple color -->
+        <xs:attribute name="stipple-stroke" default="#000000" type="tns:color" use="optional"/>
+        <!-- stipple width relative to line width, i.e 0.0-1.0 -->
+        <xs:attribute name="stipple-width" default="0" type="xs:float" use="optional"/>
+
+    </xs:complexType>
+
+    <xs:complexType name="text">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+
+        <xs:attribute name="id" default="0" type="xs:string" use="optional"/>
+        <xs:attribute name="use" default="0" type="xs:string" use="optional"/>
+
+        <xs:attribute name="k" default="name" type="tns:textKey" use="optional"/>
+        <xs:attribute name="dy" default="0" type="xs:float" use="optional"/>
+        <xs:attribute name="font-family" default="default" type="tns:fontFamily" use="optional"/>
+        <xs:attribute name="style" default="normal" type="tns:fontStyle" use="optional"/>
+        <xs:attribute name="size" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <xs:attribute name="bg-fill" default="#00000000" type="tns:color" use="optional"/>
+        <xs:attribute name="fill" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke" default="#000000" type="tns:color" use="optional"/>
+        <xs:attribute name="stroke-width" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <xs:attribute name="caption" default="false" type="xs:boolean" use="optional"/>
+        <!-- polygon area expressed as a ratio to tile area, e.g. 0.1 for 10% of tile area -->
+        <xs:attribute name="area-size" default="0" type="tns:nonNegativeFloat" use="optional"/>
+        <!-- priority for label placement, 0 = highest priority -->
+        <xs:attribute name="priority" default="0" type="xs:integer" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="symbol">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+
+        <xs:attribute name="id" default="0" type="xs:string" use="optional"/>
+        <xs:attribute name="use" default="0" type="xs:string" use="optional"/>
+
+        <xs:attribute name="src" type="tns:src" use="optional"/>
+        <xs:attribute name="symbol-width" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-height" type="xs:positiveInteger" use="optional"/>
+        <xs:attribute name="symbol-percent" type="xs:positiveInteger" use="optional"/>
+
+        <!-- symbols on lines -->
+        <xs:attribute name="billboard" default="false" type="xs:boolean" use="optional"/>
+        <xs:attribute name="repeat" default="false" type="xs:boolean" use="optional"/>
+        <xs:attribute name="repeat-gap" default="200" type="xs:float" use="optional"/>
+        <xs:attribute name="repeat-start" default="30" type="xs:float" use="optional"/>
+        <xs:attribute name="rotate" default="true" type="xs:boolean" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="extrusion">
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+        <xs:attribute name="line-color" type="tns:color" use="optional"/>
+        <xs:attribute name="side-color" type="tns:color" use="required"/>
+        <xs:attribute name="top-color" type="tns:color" use="required"/>
+        <xs:attribute name="hsv-h" default="0" type="xs:double" use="optional"/>
+        <xs:attribute name="hsv-s" default="1" type="xs:double" use="optional"/>
+        <xs:attribute name="hsv-v" default="1" type="xs:double" use="optional"/>
+        <!-- 12m default -->
+        <xs:attribute name="default-height" default="12" type="xs:positiveInteger" use="optional"/>
+    </xs:complexType>
+
+    <!-- match elements -->
+    <xs:complexType name="m">
+        <xs:choice maxOccurs="unbounded" minOccurs="0">
+            <!-- recursion to allow for nested m -->
+            <xs:element name="m" type="tns:m"/>
+
+            <xs:element name="area" type="tns:area"/>
+            <xs:element name="caption" type="tns:caption"/>
+            <xs:element name="circle" type="tns:circle"/>
+            <xs:element name="line" type="tns:line"/>
+            <xs:element name="outline" type="tns:line"/>
+            <xs:element name="lineSymbol" type="tns:line"/>
+            <xs:element name="text" type="tns:text"/>
+            <xs:element name="extrusion" type="tns:extrusion"/>
+            <xs:element name="symbol" type="tns:symbol"/>
+
+            <!-- outline is defined within rules to match layering -->
+            <xs:element name="outline-layer" type="tns:line"/>
+        </xs:choice>
+
+        <xs:attribute name="select" default="any" type="tns:selectorList" use="optional"/>
+        <xs:attribute name="e" type="tns:elementList" use="optional"/>
+        <xs:attribute name="k" type="xs:string" use="optional"/>
+        <xs:attribute name="v" type="xs:string" use="optional"/>
+        <xs:attribute name="cat" type="xs:string" use="optional"/>
+        <xs:attribute name="closed" default="any" type="tns:closed" use="optional"/>
+        <xs:attribute name="zoom-min" default="0" type="xs:unsignedByte" use="optional"/>
+        <xs:attribute name="zoom-max" default="127" type="xs:unsignedByte" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="atlasRect">
+        <xs:attribute name="id" type="xs:string" use="required"/>
+        <xs:attribute name="pos" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="atlas">
+        <xs:choice maxOccurs="unbounded" minOccurs="0">
+            <xs:element name="rect" type="tns:atlasRect"/>
+        </xs:choice>
+        <xs:attribute name="img" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <!-- stylemenu element -->
+    <xs:complexType name="stylemenu">
+        <xs:sequence maxOccurs="1" minOccurs="0">
+            <xs:element name="layer" maxOccurs="unbounded" minOccurs="0" type="tns:layer"/>
+        </xs:sequence>
+        <xs:attribute name="defaultvalue" type="xs:string" use="required"/>
+        <xs:attribute name="defaultlang" type="xs:string" use="required"/>
+        <xs:attribute name="id" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <!-- tag-transform element -->
+    <xs:complexType name="tag-transform">
+        <xs:attribute name="k" type="xs:string" use="required"/>
+        <xs:attribute name="v" type="xs:string" use="optional"/>
+        <xs:attribute name="k-lib" type="xs:string" use="required"/>
+        <xs:attribute name="v-lib" type="xs:string" use="optional"/>
+    </xs:complexType>
+
+    <!-- rendertheme element -->
+    <xs:complexType name="rendertheme">
+        <xs:sequence maxOccurs="1" minOccurs="0">
+            <xs:element name="stylemenu" maxOccurs="1" minOccurs="0" type="tns:stylemenu"/>
+
+            <!-- tag definitions -->
+            <xs:choice maxOccurs="unbounded" minOccurs="0">
+                <xs:element name="tag-transform" type="tns:tag-transform"/>
+            </xs:choice>
+
+            <!-- style definitions -->
+            <xs:sequence maxOccurs="256" minOccurs="0">
+                <xs:choice maxOccurs="unbounded" minOccurs="0">
+                    <xs:element name="style-text" type="tns:text"/>
+                    <xs:element name="style-symbol" type="tns:symbol"/>
+                    <xs:element name="style-area" type="tns:area"/>
+                    <xs:element name="style-line" type="tns:line"/>
+                    <!-- <xs:element name="style-outline" type="tns:line" /> -->
+                </xs:choice>
+            </xs:sequence>
+
+            <xs:choice maxOccurs="1" minOccurs="0">
+                <xs:element name="atlas" type="tns:atlas"/>
+            </xs:choice>
+
+            <!-- matching rules -->
+            <xs:sequence maxOccurs="unbounded" minOccurs="0">
+                <xs:element name="m" type="tns:m"/>
+            </xs:sequence>
+        </xs:sequence>
+        <xs:attribute name="version" type="xs:positiveInteger" use="required"/>
+        <xs:attribute name="map-background" default="#ffffff" type="tns:color" use="optional"/>
+        <xs:attribute name="base-stroke-width" default="1" type="tns:nonNegativeFloat"
+                      use="optional"/>
+        <xs:attribute name="base-text-scale" default="1" type="tns:nonNegativeFloat"
+                      use="optional"/>
+    </xs:complexType>
+
+    <!-- root element -->
+    <xs:element name="rendertheme" type="tns:rendertheme"/>
+</xs:schema>