bugged FileObserver
This commit is contained in:
@@ -79,6 +79,7 @@ dependencies {
|
|||||||
implementation(libs.ui.graphics)
|
implementation(libs.ui.graphics)
|
||||||
implementation(libs.ui.tooling.preview)
|
implementation(libs.ui.tooling.preview)
|
||||||
implementation(libs.material3)
|
implementation(libs.material3)
|
||||||
|
implementation(project(":devmenu:data"))
|
||||||
testImplementation(libs.junit.v412)
|
testImplementation(libs.junit.v412)
|
||||||
//testImplementation(libs.junit)
|
//testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.test.ext.junit)
|
androidTestImplementation(libs.androidx.test.ext.junit)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.ea.easp.EASPHandler
|
|||||||
import com.ea.games.nfs13_na.BuildConfig
|
import com.ea.games.nfs13_na.BuildConfig
|
||||||
import com.ea.games.nfs13_na.R
|
import com.ea.games.nfs13_na.R
|
||||||
import com.ea.nimble.ApplicationLifecycle
|
import com.ea.nimble.ApplicationLifecycle
|
||||||
|
import com.megboyzz.devmenu.data.util.SaveFileObserver
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileReader
|
import java.io.FileReader
|
||||||
@@ -52,12 +53,15 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
|
|||||||
private lateinit var gameRenderer: GameRenderer
|
private lateinit var gameRenderer: GameRenderer
|
||||||
lateinit var runLoop: RunLoop
|
lateinit var runLoop: RunLoop
|
||||||
lateinit var gameGLSurfaceView: GameGLSurfaceView
|
lateinit var gameGLSurfaceView: GameGLSurfaceView
|
||||||
// get() = field
|
lateinit var accelerometer: Accelerometer
|
||||||
// private set
|
|
||||||
private lateinit var accelerometer: Accelerometer
|
|
||||||
private lateinit var mWakeLock: WakeLock
|
private lateinit var mWakeLock: WakeLock
|
||||||
private lateinit var mAudioManager: AudioManager
|
private lateinit var mAudioManager: AudioManager
|
||||||
|
|
||||||
|
private val saveFile = "/data/data/${BuildConfig.APPLICATION_ID}/files/var/nfstr_save.sb"
|
||||||
|
private val dest = "/sdcard/Android/data/${BuildConfig.APPLICATION_ID}/files/saveTracking"
|
||||||
|
|
||||||
|
private val saveFileObserver = SaveFileObserver(saveFile, dest)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val STATE_RESTORE_CONTEXT = 7
|
const val STATE_RESTORE_CONTEXT = 7
|
||||||
@@ -92,8 +96,6 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
|
|||||||
Log.d(this.localClassName, "Call garbage collector")
|
Log.d(this.localClassName, "Call garbage collector")
|
||||||
System.gc()
|
System.gc()
|
||||||
}
|
}
|
||||||
//fun getGameGLSurfaceView() = gameGLSurfaceView
|
|
||||||
fun getAccelerometer() = accelerometer
|
|
||||||
|
|
||||||
|
|
||||||
private fun ForceHideVirtualKeyboard() {
|
private fun ForceHideVirtualKeyboard() {
|
||||||
@@ -292,6 +294,9 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override fun onCreate(bundle: Bundle?) {
|
public override fun onCreate(bundle: Bundle?) {
|
||||||
|
|
||||||
|
saveFileObserver.startWatching()
|
||||||
|
|
||||||
super.onCreate(bundle)
|
super.onCreate(bundle)
|
||||||
|
|
||||||
val className = this.localClassName
|
val className = this.localClassName
|
||||||
@@ -346,6 +351,9 @@ class GameActivity : ComponentActivity(), DrawFrameListener {
|
|||||||
|
|
||||||
|
|
||||||
public override fun onDestroy() {
|
public override fun onDestroy() {
|
||||||
|
|
||||||
|
saveFileObserver.stopWatching()
|
||||||
|
|
||||||
Log.i("Debug", "onDestroy")
|
Log.i("Debug", "onDestroy")
|
||||||
Log.i(this.localClassName, "onDestroy")
|
Log.i(this.localClassName, "onDestroy")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.megboyzz.devmenu.data.util
|
||||||
|
|
||||||
|
import android.os.FileObserver
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.util.LinkedList
|
||||||
|
import java.util.Queue
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
|
abstract class BaseObserver(source: String) : FileObserver(source) {
|
||||||
|
|
||||||
|
private val eventQueue : Queue<Int> = LinkedList()
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
final override fun onEvent(event: Int, path: String?) {
|
||||||
|
|
||||||
|
if(eventQueue.size < 3) eventQueue.add(event)
|
||||||
|
|
||||||
|
val e = FileEvent.entries.find { it.value == event }
|
||||||
|
|
||||||
|
val fileEvent = e ?: FileEvent.UNKNOWN
|
||||||
|
|
||||||
|
Log.i("BaseObserver", "event code = ${event.toHexString()}, FileEvent is $fileEvent")
|
||||||
|
|
||||||
|
if(hasLastThreeEvents()) onEvent(fileEvent, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasLastThreeEvents() = runCatching {
|
||||||
|
eventQueue.size == 3 && eventQueue.poll() == OPEN && eventQueue.poll() == ACCESS && eventQueue.poll() == CLOSE_NOWRITE
|
||||||
|
}.getOrNull() ?: false
|
||||||
|
|
||||||
|
abstract fun onEvent(event: FileEvent, path: String?)
|
||||||
|
|
||||||
|
protected fun File.list(regex: String = ".") =
|
||||||
|
this.list { dir, _ -> Regex(regex).matches(dir.absolutePath) }?.asList() ?: listOf()
|
||||||
|
|
||||||
|
|
||||||
|
protected infix fun File.copyToThe(destination: File) = this.copyTo(destination, overwrite = true)
|
||||||
|
|
||||||
|
protected fun zipAll(outputFolder: String, filesToCompress: List<String>) {
|
||||||
|
if(filesToCompress.isEmpty()){
|
||||||
|
Log.i("BaseObserver", "no files exit!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Проверяем, существует ли выходная папка. Если нет, создаем её.
|
||||||
|
val outputDir = File(outputFolder)
|
||||||
|
if (!outputDir.exists()) outputDir.mkdirs()
|
||||||
|
|
||||||
|
// Генерируем имя ZIP-архива на основе времени
|
||||||
|
val timestamp = System.currentTimeMillis()
|
||||||
|
val zipFileName = "$outputFolder/saves_$timestamp.zip"
|
||||||
|
val zipOutputStream = ZipOutputStream(FileOutputStream(zipFileName))
|
||||||
|
|
||||||
|
for (fileToCompress in filesToCompress) {
|
||||||
|
// Проверяем, существует ли файл
|
||||||
|
val inputFile = File(fileToCompress)
|
||||||
|
if (inputFile.exists()) {
|
||||||
|
// Создаем объект ZipEntry для каждого файла
|
||||||
|
val zipEntry = ZipEntry(inputFile.name)
|
||||||
|
zipOutputStream.putNextEntry(zipEntry)
|
||||||
|
|
||||||
|
// Читаем содержимое файла и записываем его в ZIP-архив
|
||||||
|
val fileInputStream = FileInputStream(inputFile)
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
var len: Int
|
||||||
|
while (fileInputStream.read(buffer).also { len = it } > 0) {
|
||||||
|
zipOutputStream.write(buffer, 0, len)
|
||||||
|
}
|
||||||
|
fileInputStream.close()
|
||||||
|
|
||||||
|
// Закрываем текущий ZipEntry
|
||||||
|
zipOutputStream.closeEntry()
|
||||||
|
} else {
|
||||||
|
Log.i("SaveFileObserver", "Файл не существует: $fileToCompress")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Закрываем ZipOutputStream
|
||||||
|
zipOutputStream.close()
|
||||||
|
Log.i("SaveFileObserver", "Архивация завершена. Архив создан: $zipFileName")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.megboyzz.devmenu.data.util
|
||||||
|
|
||||||
|
import android.os.FileObserver
|
||||||
|
|
||||||
|
enum class FileEvent(val value: Int) {
|
||||||
|
|
||||||
|
ACCESS(FileObserver.ACCESS),
|
||||||
|
MODIFY(FileObserver.MODIFY),
|
||||||
|
ATTRIB(FileObserver.ATTRIB),
|
||||||
|
CLOSE_WRITE(FileObserver.CLOSE_WRITE),
|
||||||
|
CLOSE_NOWRITE(FileObserver.CLOSE_NOWRITE),
|
||||||
|
OPEN(FileObserver.OPEN),
|
||||||
|
MOVED_FROM(FileObserver.MOVED_FROM),
|
||||||
|
MOVED_TO(FileObserver.MOVED_TO),
|
||||||
|
CREATE(FileObserver.CREATE),
|
||||||
|
DELETE(FileObserver.DELETE),
|
||||||
|
DELETE_SELF(FileObserver.DELETE_SELF),
|
||||||
|
MOVE_SELF(FileObserver.MOVE_SELF),
|
||||||
|
UNKNOWN(-1);
|
||||||
|
|
||||||
|
override fun toString() = this.name
|
||||||
|
}
|
||||||
@@ -1,22 +1,52 @@
|
|||||||
package com.megboyzz.devmenu.data.util
|
package com.megboyzz.devmenu.data.util
|
||||||
|
|
||||||
import android.os.FileObserver
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
class SaveFileObserver(
|
class SaveFileObserver(
|
||||||
private val source: File,
|
private val source: String,
|
||||||
private val destinationFolder: File
|
private val destinationFolder: String
|
||||||
) : FileObserver(source.absolutePath) {
|
) : BaseObserver(source) {
|
||||||
|
|
||||||
override fun onEvent(event: Int, path: String?) {
|
private var countSnapshots: Int = 1
|
||||||
if (event and CREATE != 0 || event and MODIFY != 0) {
|
|
||||||
Log.d("FileObserver", "File created or modified: $source")
|
private val checkList = listOf(
|
||||||
source copyToThe destinationFolder
|
FileEvent.CLOSE_WRITE,
|
||||||
|
FileEvent.MODIFY,
|
||||||
|
FileEvent.DELETE,
|
||||||
|
FileEvent.CREATE,
|
||||||
|
FileEvent.ACCESS,
|
||||||
|
FileEvent.OPEN,
|
||||||
|
FileEvent.CLOSE_NOWRITE
|
||||||
|
)
|
||||||
|
init {
|
||||||
|
val dest = File(destinationFolder)
|
||||||
|
if(dest.isFile) dest.delete()
|
||||||
|
if(!dest.exists()) dest.mkdir()
|
||||||
|
val list = dest.list{
|
||||||
|
dir, name -> name.endsWith(".sb")
|
||||||
|
}
|
||||||
|
list?.forEach { File(dest, it).delete() }
|
||||||
|
File(source) copyToThe File(destinationFolder, "BASE.sb")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEvent(event: FileEvent, path: String?) {
|
||||||
|
Log.i("SaveFileObserver", "onEvent $event")
|
||||||
|
if (event in checkList) {
|
||||||
|
Log.d("SaveFileObserver", "File created or modified: $source")
|
||||||
|
File(source) copyToThe File(destinationFolder, "$event-$countSnapshots.sb")
|
||||||
|
countSnapshots++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private infix fun File.copyToThe(destination: File) = this.copyTo(destination)
|
override fun stopWatching() {
|
||||||
|
super.stopWatching()
|
||||||
|
val filesList = File(destinationFolder).list{ _, name -> name.endsWith(".sb") }?.map { it }
|
||||||
|
if (filesList != null) {
|
||||||
|
zipAll(destinationFolder, filesList)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user