From c4881e713604dacebb0cc8fe1f13691ef43c02bc Mon Sep 17 00:00:00 2001 From: guillermolagos Date: Mon, 21 Dec 2020 11:16:51 -0300 Subject: [PATCH] Respaldo SV-TL v2.3 --- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 18 ++ .../java/guillermo/lagos/svtl/MainActivity.kt | 71 +++++--- .../main/java/guillermo/lagos/svtl/Utils.kt | 36 ++++ .../guillermo/lagos/svtl/servicio/Actions.kt | 6 + .../lagos/svtl/servicio/EndlessService.kt | 164 ++++++++++++++++++ .../lagos/svtl/servicio/ServiceState.kt | 32 ++++ .../lagos/svtl/servicio/StartReceiver.kt | 25 +++ app/src/main/res/values/strings.xml | 2 +- app/src/main/res/values/style.xml | 13 ++ svtl/build.gradle | 7 +- .../src/main/assets/mb_map.json | 2 +- .../java/guillermo/lagos/svtl/DBTLWorker.kt | 30 ++++ .../java/guillermo/lagos/svtl/TLServer.kt | 6 +- .../java/guillermo/lagos/svtl/TLSource.kt | 54 ++---- .../main/java/guillermo/lagos/svtl/TLUtils.kt | 129 ++++++++++++++ 16 files changed, 525 insertions(+), 76 deletions(-) create mode 100644 app/src/main/java/guillermo/lagos/svtl/Utils.kt create mode 100644 app/src/main/java/guillermo/lagos/svtl/servicio/Actions.kt create mode 100644 app/src/main/java/guillermo/lagos/svtl/servicio/EndlessService.kt create mode 100644 app/src/main/java/guillermo/lagos/svtl/servicio/ServiceState.kt create mode 100644 app/src/main/java/guillermo/lagos/svtl/servicio/StartReceiver.kt create mode 100644 app/src/main/res/values/style.xml rename app/src/main/assets/mbStyle.json => svtl/src/main/assets/mb_map.json (99%) create mode 100644 svtl/src/main/java/guillermo/lagos/svtl/DBTLWorker.kt create mode 100644 svtl/src/main/java/guillermo/lagos/svtl/TLUtils.kt diff --git a/app/build.gradle b/app/build.gradle index ef7a790..138a7c5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,11 +44,15 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - // map box implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.5.0' implementation 'com.jakewharton.timber:timber:4.7.1' + implementation 'com.airbnb.android:lottie:3.4.2' + + + implementation "android.arch.work:work-runtime-ktx:2.3.4" implementation project(':svtl') + /*implementation 'com.github.guillermo-lagos:SV-TL:1.0.0'*/ testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 88196e6..659ffa8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,10 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/guillermo/lagos/svtl/MainActivity.kt b/app/src/main/java/guillermo/lagos/svtl/MainActivity.kt index b89bf42..56f498b 100755 --- a/app/src/main/java/guillermo/lagos/svtl/MainActivity.kt +++ b/app/src/main/java/guillermo/lagos/svtl/MainActivity.kt @@ -1,7 +1,10 @@ package guillermo.lagos.svtl -import android.os.Bundle +import android.content.Context +import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import androidx.work.WorkInfo +import androidx.work.WorkManager import com.mapbox.mapboxsdk.Mapbox import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.maps.OnMapReadyCallback @@ -9,6 +12,7 @@ import com.mapbox.mapboxsdk.maps.Style import com.mapbox.mapboxsdk.style.layers.RasterLayer import com.mapbox.mapboxsdk.style.sources.RasterSource import com.mapbox.mapboxsdk.style.sources.TileSet +import guillermo.lagos.svtl.servicio.Actions import kotlinx.android.synthetic.main.activity_main.* import timber.log.Timber import java.io.File @@ -17,43 +21,58 @@ class MainActivity : AppCompatActivity(), OnMapReadyCallback { var m: MapboxMap? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (BuildConfig.DEBUG) { - Timber.plant(Timber.DebugTree()) - } + if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) Mapbox.getInstance(this, getString(R.string.mapbox_access_token)) setContentView(R.layout.activity_main) - map.getMapAsync(this) - } + actionOnService(Actions.START) + init_work() + + + WorkManager.getInstance().getWorkInfosByTagLiveData("WCH") + .observe(this, { workInfo -> + if (workInfo != null && workInfo[0].state == WorkInfo.State.SUCCEEDED) { + map.getMapAsync(this) + } + }) + } + override fun onMapReady(mapboxMap: MapboxMap) { m = mapboxMap - mapboxMap.setStyle(Style.SATELLITE) { style -> // Connect to localhost even when device is not connected to internet - Mapbox.setConnected(true) - addMbtiles(style) + mapboxMap.apply { + setStyle(offTL(this@MainActivity)) { style -> + Mapbox.setConnected(true) + } } + } - fun addMbtiles(style: Style) { - val mbtilesFile = File( "asset://santiago.mbtiles") - val sourceId = "your-mb-id" - val mbSource: TLSource - try { - mbSource = TLSource(this, mbtilesFile.absolutePath,"santiago.mbtiles", sourceId) - mbSource.server_on() - style.addSource(RasterSource(mbSource.id, TileSet(null, - mbSource.url), 256)) // 256 * 256 for raster tiles - val rasterLayer = RasterLayer("raster_layer_id", mbSource.id) - style.addLayer(rasterLayer) - // if mbSource contains vector tiles - m?.setStyle(Style.Builder().fromUri("asset://mbStyle.json")) - } catch (e: TLError.CantReadFile) { - Timber.e("CouldNotReadFileError") - } + fun MapboxMap.offTL(context: Context, f_name: String = "chile.zip", db_name: String = "chile.mbtiles"): Style.Builder { + val mbtilesFile = File("asset://$f_name") + val sourceId = "chile" + val mbSource = TLSource( + context, + mbtilesFile.absolutePath, + db_name, + sourceId + ) + mbSource?.server_on() + style?.addSource( + RasterSource( + mbSource.id, TileSet( + null, + mbSource.url + ), 256 + ) + ) + val rasterLayer = RasterLayer("raster_layer_id", mbSource.id) + style?.addLayer(rasterLayer) + return Style.Builder().fromUri(uri_style) } + } \ No newline at end of file diff --git a/app/src/main/java/guillermo/lagos/svtl/Utils.kt b/app/src/main/java/guillermo/lagos/svtl/Utils.kt new file mode 100644 index 0000000..b77ab07 --- /dev/null +++ b/app/src/main/java/guillermo/lagos/svtl/Utils.kt @@ -0,0 +1,36 @@ +package guillermo.lagos.svtl + +import android.app.Activity +import android.app.Dialog +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.database.sqlite.SQLiteCantOpenDatabaseException +import android.database.sqlite.SQLiteDatabase +import android.os.Build +import android.view.Window +import guillermo.lagos.svtl.servicio.* +import timber.log.Timber +import java.io.BufferedInputStream +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream + +fun Activity.actionOnService(action: Actions) { + if (getServiceState(this) == ServiceState.STOPPED && action == Actions.STOP) return + Intent(this, EndlessService::class.java).also { + it.action = action.name + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Timber.e("Starting the service in >=26 Mode") + startForegroundService(it) + return + } + Timber.e("Starting the service in < 26 Mode") + startService(it) + } +} + + + diff --git a/app/src/main/java/guillermo/lagos/svtl/servicio/Actions.kt b/app/src/main/java/guillermo/lagos/svtl/servicio/Actions.kt new file mode 100644 index 0000000..359d129 --- /dev/null +++ b/app/src/main/java/guillermo/lagos/svtl/servicio/Actions.kt @@ -0,0 +1,6 @@ +package guillermo.lagos.svtl.servicio + +enum class Actions { + START, + STOP +} \ No newline at end of file diff --git a/app/src/main/java/guillermo/lagos/svtl/servicio/EndlessService.kt b/app/src/main/java/guillermo/lagos/svtl/servicio/EndlessService.kt new file mode 100644 index 0000000..aa1a9ae --- /dev/null +++ b/app/src/main/java/guillermo/lagos/svtl/servicio/EndlessService.kt @@ -0,0 +1,164 @@ +package guillermo.lagos.svtl.servicio + +import android.app.* +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Build +import android.os.IBinder +import android.os.PowerManager +import android.os.SystemClock +import android.util.Log +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkInfo +import androidx.work.WorkManager +import androidx.work.workDataOf +import guillermo.lagos.svtl.* +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.* +import timber.log.Timber + + +class EndlessService : Service() { + + private var wakeLock: PowerManager.WakeLock? = null + private var isServiceStarted = false + + override fun onBind(intent: Intent): IBinder? { + Timber.e("Some component want to bind with the service") + // We don't provide binding, so return null + return null + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + Timber.e("onStartCommand executed with startId: $startId") + if (intent != null) { + val action = intent.action + Timber.e("using an intent with action $action") + when (action) { + Actions.START.name -> startService() + Actions.STOP.name -> stopService() + else -> Timber.e("This should never happen. No action in the received intent") + } + } else { + Timber.e( + "with a null intent. It has been probably restarted by the system." + ) + } + // by returning this we make sure the service is restarted if the system kills the service + return START_STICKY + } + + override fun onCreate() { + super.onCreate() + Timber.e("The service has been created".toUpperCase()) + val notification = createNotification() + startForeground(1, notification) + } + + override fun onDestroy() { + super.onDestroy() + Timber.e("The service has been destroyed".toUpperCase()) + } + + override fun onTaskRemoved(rootIntent: Intent) { + val restartServiceIntent = Intent(applicationContext, EndlessService::class.java).also { + it.setPackage(packageName) + }; + val restartServicePendingIntent: PendingIntent = PendingIntent.getService(this, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT); + applicationContext.getSystemService(Context.ALARM_SERVICE); + val alarmService: AlarmManager = applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager; + alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePendingIntent); + } + + private fun startService() { + if (isServiceStarted) return + Timber.e("Starting the foreground service task") + isServiceStarted = true + setServiceState(this, ServiceState.STARTED) + + // we need this lock so our service gets not affected by Doze Mode + wakeLock = + (getSystemService(Context.POWER_SERVICE) as PowerManager).run { + newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "EndlessService::lock").apply { + acquire() + } + } + + // we're starting a loop in a coroutine + GlobalScope.launch(Dispatchers.IO) { + while (isServiceStarted) { + launch(Dispatchers.IO) { + + + } + delay(1 * 60 * 1000) + } + Timber.e("End of the loop for the service") + } + } + + private fun stopService() { + Timber.e("Stopping the foreground service") + try { + wakeLock?.let { + if (it.isHeld) { + it.release() + } + } + stopForeground(true) + stopSelf() + } catch (e: Exception) { + Timber.e("Service stopped without being started: ${e.message}") + } + isServiceStarted = false + setServiceState(this, ServiceState.STOPPED) + } + + + + private fun createNotification(): Notification { + val notificationChannelId = "ENDLESS SERVICE CHANNEL" + + // depending on the Android API that we're dealing with we will have + // to use a specific method to create the notification + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val channel = NotificationChannel( + notificationChannelId, + "Endless Service notifications channel", + NotificationManager.IMPORTANCE_HIGH + ).let { + it.description = "Endless Service channel" + it.enableLights(true) + it.lightColor = Color.RED + it.enableVibration(true) + it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400) + it + } + notificationManager.createNotificationChannel(channel) + } + + val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let { notificationIntent -> + PendingIntent.getActivity(this, 0, notificationIntent, 0) + } + + val builder: Notification.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.Builder( + this, + notificationChannelId + ) else Notification.Builder(this) + + return builder + .setContentTitle("Servidor en linea") + /* .setContentText("This is your favorite endless service working")*/ + .setContentIntent(pendingIntent) + .setSmallIcon(R.mipmap.ic_launcher) + /*.setTicker("Ticker text")*/ + .setPriority(Notification.PRIORITY_HIGH) // for under android 26 compatibility + .build() + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/guillermo/lagos/svtl/servicio/ServiceState.kt b/app/src/main/java/guillermo/lagos/svtl/servicio/ServiceState.kt new file mode 100644 index 0000000..6c783e4 --- /dev/null +++ b/app/src/main/java/guillermo/lagos/svtl/servicio/ServiceState.kt @@ -0,0 +1,32 @@ +package guillermo.lagos.svtl.servicio + +import android.content.Context +import android.content.SharedPreferences +import guillermo.lagos.svtl.getPreferences + +enum class ServiceState { + STARTED, + STOPPED, +} + +private const val name = "SPYSERVICE_KEY" +private const val key = "SPYSERVICE_STATE" + +fun setServiceState(context: Context, state: ServiceState) { + val sharedPrefs = getPreferences(context) + sharedPrefs.edit().let { + it.putString(key, state.name) + it.apply() + } +} + +fun getServiceState(context: Context): ServiceState { + val sharedPrefs = getPreferences(context) + val value = sharedPrefs.getString(key, ServiceState.STOPPED.name) + return ServiceState.valueOf(value!!) +} + +fun getPreferences(context: Context): SharedPreferences { + return context.getSharedPreferences(name, 0) +} + diff --git a/app/src/main/java/guillermo/lagos/svtl/servicio/StartReceiver.kt b/app/src/main/java/guillermo/lagos/svtl/servicio/StartReceiver.kt new file mode 100644 index 0000000..ab040c5 --- /dev/null +++ b/app/src/main/java/guillermo/lagos/svtl/servicio/StartReceiver.kt @@ -0,0 +1,25 @@ +package guillermo.lagos.svtl.servicio + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Build +import timber.log.Timber + +class StartReceiver : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_BOOT_COMPLETED && getServiceState(context) == ServiceState.STARTED) { + Intent(context, EndlessService::class.java).also { + it.action = Actions.START.name + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Timber.e("Starting the service in >=26 Mode from a BroadcastReceiver") + context.startForegroundService(it) + return + } + Timber.e("Starting the service in < 26 Mode from a BroadcastReceiver") + context.startService(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d79cd2a..2ad94bb 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - NAVIGATION + SV \ No newline at end of file diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml new file mode 100644 index 0000000..b1a28c9 --- /dev/null +++ b/app/src/main/res/values/style.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/svtl/build.gradle b/svtl/build.gradle index 66c8f24..30ab081 100644 --- a/svtl/build.gradle +++ b/svtl/build.gradle @@ -45,7 +45,12 @@ dependencies { implementation "org.jetbrains.anko:anko:0.10.8" implementation "org.jetbrains.anko:anko-sqlite:0.10.8" - + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1" + + + implementation "android.arch.work:work-runtime-ktx:2.3.4" + testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/app/src/main/assets/mbStyle.json b/svtl/src/main/assets/mb_map.json similarity index 99% rename from app/src/main/assets/mbStyle.json rename to svtl/src/main/assets/mb_map.json index 269fce0..feb0316 100755 --- a/app/src/main/assets/mbStyle.json +++ b/svtl/src/main/assets/mb_map.json @@ -8,7 +8,7 @@ "openmaptiles": { "type": "vector", "tiles": [ - "http://localhost:8888/your-mb-id/{z}/{x}/{y}.pbf" + "http://localhost:8888/chile/{z}/{x}/{y}.pbf" ] } }, diff --git a/svtl/src/main/java/guillermo/lagos/svtl/DBTLWorker.kt b/svtl/src/main/java/guillermo/lagos/svtl/DBTLWorker.kt new file mode 100644 index 0000000..1f34f42 --- /dev/null +++ b/svtl/src/main/java/guillermo/lagos/svtl/DBTLWorker.kt @@ -0,0 +1,30 @@ +package guillermo.lagos.svtl + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import androidx.work.workDataOf + + +class DBTLWorker(context: Context, parameters: WorkerParameters) + : Worker(context, parameters) { + override fun doWork(): Result { + return try { + + val db_name = inputData.getString("db") + val file_name = inputData.getString("file") + + val db = applicationContext.openDatabase(file_name!!, db_name!!) + + + if (db == null) Result.retry() + else { + applicationContext.setTagW(null) + Result.success() + } + + } catch (e: Exception) { + Result.failure() + } + } +} \ No newline at end of file diff --git a/svtl/src/main/java/guillermo/lagos/svtl/TLServer.kt b/svtl/src/main/java/guillermo/lagos/svtl/TLServer.kt index 2ef17ea..5f05854 100755 --- a/svtl/src/main/java/guillermo/lagos/svtl/TLServer.kt +++ b/svtl/src/main/java/guillermo/lagos/svtl/TLServer.kt @@ -33,15 +33,15 @@ object TLServer : Runnable { serverSocket = ServerSocket(port) while (isRunning) { val socket = serverSocket?.accept() ?: throw Error() - Log.e(TAG,"request handled start") + /*Log.e(TAG,"request handled start")*/ handle(socket) socket.close() - Log.e(TAG,"request handled in while") + /* Log.e(TAG,"request handled in while")*/ } } catch (e: Exception) { Log.e(TAG,e.localizedMessage) } finally { - Log.e(TAG,"request handled") + /* Log.e(TAG,"request handled")*/ } } diff --git a/svtl/src/main/java/guillermo/lagos/svtl/TLSource.kt b/svtl/src/main/java/guillermo/lagos/svtl/TLSource.kt index 0b93410..dbc87cc 100755 --- a/svtl/src/main/java/guillermo/lagos/svtl/TLSource.kt +++ b/svtl/src/main/java/guillermo/lagos/svtl/TLSource.kt @@ -1,14 +1,16 @@ package guillermo.lagos.svtl import android.annotation.SuppressLint +import android.app.Dialog import android.content.Context import android.database.sqlite.SQLiteDatabase import android.util.Log +import kotlinx.coroutines.* import org.jetbrains.anko.db.MapRowParser import org.jetbrains.anko.db.select -import java.io.File -import java.io.FileOutputStream -import java.io.IOException +import java.io.* +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream sealed class TLError : Error() { @@ -28,24 +30,13 @@ class TLSource(context: Context, filePath: String, db_name: String, id: String? var id = id ?: filePath.substringAfterLast("/").substringBefore(".") val url get() = "http://localhost:${TLServer.port}/$id/{z}/{x}/{y}.$format" - private val db: SQLiteDatabase = try { - Log.e(TLServer.TAG,"NOMBRE DB: $filePath") - context.openDatabase(db_name) - } catch (e: RuntimeException) { - throw TLError.CantReadFile() - } + + private val db: SQLiteDatabase = context.openDatabase(db_name) var isVector = false var format = String() -// var tileSize: Int? = null -// var layersJson: String? = "" -// var attributions: String? = "" -// var minZoom: Float? = null -// var maxZoom: Float? = null -// var bounds: LatLngBounds? = null init { - try { format = db.select("metadata") .whereSimple("name = ?", "format") @@ -65,7 +56,7 @@ class TLSource(context: Context, filePath: String, db_name: String, id: String? fun getTile(z: Int, x: Int, y: Int): ByteArray? { return db.select("tiles") .whereArgs("(zoom_level = {z}) and (tile_column = {x}) and (tile_row = {y})", - "z" to z, "x" to x, "y" to y) + "z" to z, "x" to x, "y" to y) .parseList(toTL) .run { if (!isEmpty()) get(0) else null } } @@ -90,37 +81,14 @@ class TLSource(context: Context, filePath: String, db_name: String, id: String? } - @Throws(RuntimeException::class) + /*@Throws(RuntimeException::class)*/ fun Context.openDatabase(db_name: String): SQLiteDatabase { val dbFile = getDatabasePath(db_name) - if (!dbFile.exists()) { - try { - openOrCreateDatabase(db_name, Context.MODE_PRIVATE,null)?.apply { - close() - } - copyDatabase(dbFile, db_name) - } catch (e: IOException) { - throw RuntimeException("Error creating source database", e) - } - - } return SQLiteDatabase.openDatabase(dbFile.path, null, SQLiteDatabase.OPEN_READONLY) } - @SuppressLint("WrongConstant") - private fun Context.copyDatabase(dbFile: File,db_name: String) { - val `is` = assets.open(db_name) - val os = FileOutputStream(dbFile) - val buffer = ByteArray(1024) - while (`is`.read(buffer) > 0) { - os.write(buffer) - Log.e(TLServer.TAG,"copy db....") - } - os.flush() - os.close() - `is`.close() - Log.e(TLServer.TAG, "finish db....") - } + + } \ No newline at end of file diff --git a/svtl/src/main/java/guillermo/lagos/svtl/TLUtils.kt b/svtl/src/main/java/guillermo/lagos/svtl/TLUtils.kt new file mode 100644 index 0000000..a5c5ebf --- /dev/null +++ b/svtl/src/main/java/guillermo/lagos/svtl/TLUtils.kt @@ -0,0 +1,129 @@ +package guillermo.lagos.svtl + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.SharedPreferences +import android.database.sqlite.SQLiteCantOpenDatabaseException +import android.database.sqlite.SQLiteDatabase +import android.util.Log +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.workDataOf +import guillermo.lagos.svtl.TLServer.TAG +import java.io.* +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream + +val uri_style = "asset://mb_map.json" + +fun Context.openDatabase(file_name: String, db_name: String) : SQLiteDatabase? { + val dbFile = getDatabasePath(db_name) + var db: SQLiteDatabase? = null + if (!dbFile.exists()) { + try { + openOrCreateDatabase(db_name, Context.MODE_PRIVATE, null)?.apply { close() } + copyDatabaseZip(dbFile, file_name) + + } catch (e: IOException) { + /*throw RuntimeException("Error creating source database", e)*/ + Log.e(TAG, "ERROR 4: $e") + } + + } + + db = try { + SQLiteDatabase.openDatabase(dbFile.path, null, SQLiteDatabase.OPEN_READONLY) + } catch (e: SQLiteCantOpenDatabaseException) { + Log.e(TAG, "ERROR 3: $e") + deleteDatabase(dbFile.path) + null + } + return db +} + +fun Context.copyDatabaseZip(dbFile: File, file_name: String) { + val fin = assets.open(file_name) + val os = FileOutputStream(dbFile) + + + val zin = ZipInputStream(fin) + val b = ByteArray(1024) + var ze: ZipEntry? + + try { + + while (zin.nextEntry.also { ze = it } != null) { + Log.e(TAG, "descomprimiendo... ${ze!!.name}") + + val `in` = BufferedInputStream(zin) + var n: Int + while (`in`.read(b, 0, 1024).also { n = it } >= 0) { + os.write(b, 0, n) + /*Log.e(TAG,"copiando db....")*/ + } + zin.closeEntry() + } + + + }catch (e: Exception){ + /* deleteDatabase(dbFile.path)*/ + Log.e(TAG, "ERROR 2 AL DESCOMPRIMIR... ${e}") + }finally { + + zin.close() + os.flush() + os.close() + + Log.e(TAG, "finish db....") + } +} + +private fun Context.copyDatabase(dbFile: File, db_name: String) { + val `is` = assets.open(db_name) + val os = FileOutputStream(dbFile) + + val buffer = ByteArray(1024) + while (`is`.read(buffer) > 0) { + os.write(buffer) + Log.e(TAG, "copy db....") + } + + os.flush() + os.close() + `is`.close() + Log.e(TAG, "finish db....") +} + +private const val tag_work = "TAG_WORK" + +fun getPreferences(context: Context): SharedPreferences { + return context.getSharedPreferences(tag_work, 0) +} + +fun Context.setTagW(tag : String?) { + val sharedPrefs = getPreferences(this) + sharedPrefs.edit().let { + it.putString(tag_work, tag) + it.apply() + } +} + +fun Context.getTagW(): String? { + val sharedPrefs = getPreferences(this) + return sharedPrefs.getString(tag_work, null) +} + +fun Activity.init_work(file_name: String = "chile.zip", db_name: String = "chile.mbtiles") { + val tag = "WCH" + val data = workDataOf("file" to file_name, "db" to db_name) + val db_worker = OneTimeWorkRequestBuilder() + .addTag(tag) + .setInputData(data) + .build() + + if (getTagW() == null) { + setTagW(tag) + WorkManager.getInstance().enqueue(db_worker) + } +}