This commit is contained in:
2025-08-27 15:09:05 +09:00
parent 57961d84de
commit a13f66d917
9896 changed files with 2193048 additions and 730 deletions
@@ -52,7 +52,7 @@ internal class LunaticLauncher : Application() {
if (!dir.exists()) {
dir.mkdirs()
} else {
dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
// dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
}
mHourlyLogWriter = HourlyLogWriter(dir)
val cacheSize = 1024L * 1024 * 1024 // 60MB
@@ -384,7 +384,7 @@ class GeckoWeb : BWebview {
if (!dir.exists()) {
dir.mkdirs()
} else {
dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
// dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
}
val outputFile = File(dir, "${url?.host ?: "UnKnown"}_scraped_${SimpleDateFormat("yyyyMMdd-HHmm").format(Date())}.md")
outputFile.writeText(markdownText, Charsets.UTF_8)
@@ -127,7 +127,7 @@ object CommonUtils {
if (!dir.exists()) {
dir.mkdirs()
} else {
dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
// dir.listFiles().forEach { Blog.LOGE("child -> ${it.absolutePath}") }
}
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
@@ -1,10 +1,13 @@
package bums.lunatic.launcher.wall
import android.content.ContentUris
import android.os.Environment
import android.os.Handler
import android.os.HandlerThread
import android.provider.MediaStore
import android.service.wallpaper.WallpaperService
import android.view.SurfaceHolder
import bums.lunatic.launcher.utils.Blog
import java.io.File
class MyWallpaperService : WallpaperService() {
@@ -19,6 +22,7 @@ class MyWallpaperService : WallpaperService() {
private var running = false
private var nativeRenderer: NativeRenderer? = null
private var mediaFiles: List<File> = emptyList()
private var currentMediaIndex = -1
private val frameDelayMs = 16L // 약 60fps
@@ -27,12 +31,89 @@ class MyWallpaperService : WallpaperService() {
private val renderRunnable = object : Runnable {
override fun run() {
if (!running) return
nativeRenderer?.nativeRender()
if (!running || holder.surface == null) return
nativeRenderer?.nativeRender(holder.surface)
handler.postDelayed(this, frameDelayMs)
}
}
private fun loadMediaFiles() {
val mediaDir = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "wallPapers")
val supportedExtensions = videoExtensions + imageExtensions
mediaFiles = if (mediaDir.exists() && mediaDir.isDirectory) {
mediaDir.listFiles()?.filter { supportedExtensions.contains(it.extension.lowercase()) }?.toList() ?: emptyList()
} else {
emptyList()
}
// --- 디버깅 로그 추가 ---
Blog.LOGE("MyWallpaperService", "Found ${mediaFiles.size} media files.")
if (mediaFiles.isNotEmpty()) {
currentMediaIndex = 0
val firstFilePath = mediaFiles[currentMediaIndex].absolutePath
Blog.LOGE("MyWallpaperService", "Attempting to load initial media: $firstFilePath")
getFdFromPath(firstFilePath)?.let { fd ->
Blog.LOGE("MyWallpaperService", "Successfully got fd ($fd) for initial media. Calling nativeSetCurrentMedia.")
nativeRenderer?.nativeSetCurrentMedia(fd)
} ?: run {
// 'let' 블록이 실행되지 않으면 fd가 null이라는 의미
Blog.LOGE("MyWallpaperService", "Failed to get fd for initial media: $firstFilePath")
}
if (mediaFiles.size > 1) {
// Preload 로직도 동일하게 로그 추가 가능
val nextFilePath = mediaFiles[1].absolutePath
Blog.LOGE("MyWallpaperService", "Attempting to preload next media: $nextFilePath")
getFdFromPath(nextFilePath)?.let { fd ->
Blog.LOGE("MyWallpaperService", "Successfully got fd ($fd) for preload. Calling nativeStartNextPreload.")
nativeRenderer?.nativeStartNextPreload(fd)
} ?: run {
Blog.LOGE("MyWallpaperService", "Failed to get fd for preload media: $nextFilePath")
}
}
} else {
Blog.LOGE("MyWallpaperService", "Media files list is empty. No media will be loaded.")
}
}
private val nextMediaCallback = object : NativeRenderer.NextMediaCallback {
override fun onNextMediaRequested() {
if (mediaFiles.isEmpty()) return
currentMediaIndex = (currentMediaIndex + 1) % mediaFiles.size
// 다음 파일 예비 로딩 시에도 파일 디스크립터를 전달
getFdFromPath(mediaFiles[currentMediaIndex].absolutePath)?.let { fd ->
nativeRenderer?.nativeStartNextPreload(fd)
}
}
}
// 파일 경로로 MediaStore를 쿼리하여 File Descriptor를 얻는 함수
private fun getFdFromPath(path: String): Int? {
var fileDescriptor: Int? = null
val uri = MediaStore.Files.getContentUri("external")
val projection = arrayOf(MediaStore.Files.FileColumns._ID)
val selection = "${MediaStore.Files.FileColumns.DATA} = ?"
val selectionArgs = arrayOf(path)
try {
contentResolver.query(uri, projection, selection, selectionArgs, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID))
val fileUri = ContentUris.withAppendedId(uri, id)
contentResolver.openFileDescriptor(fileUri, "r")?.use { pfd ->
fileDescriptor = pfd.detachFd() // 중요: fd 소유권을 네이티브로 넘기기 위해 detach
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return fileDescriptor
}
override fun onCreate(surfaceHolder: SurfaceHolder) {
super.onCreate(surfaceHolder)
holder = surfaceHolder
@@ -41,11 +122,16 @@ class MyWallpaperService : WallpaperService() {
override fun onSurfaceCreated(holder: SurfaceHolder) {
super.onSurfaceCreated(holder)
nativeRenderer = NativeRenderer()
nativeRenderer?.nativeInit(holder.surface)
nativeRenderer?.nativeInit()
handlerThread = HandlerThread("NativeRenderThread").apply { start() }
handler = Handler(handlerThread.looper)
running = true
// 콜백 등록 및 최초 미디어 로딩
nativeRenderer?.nativeSetNextMediaCallback(nextMediaCallback)
loadMediaFiles()
running = true
handler.post(renderRunnable)
}
@@ -57,17 +143,6 @@ class MyWallpaperService : WallpaperService() {
super.onSurfaceDestroyed(holder)
}
private fun loadMediaFiles() {
val mediaDir = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "wallpapers")
val supportedExtensions = videoExtensions + imageExtensions
mediaFiles = if (mediaDir.exists() && mediaDir.isDirectory) {
mediaDir.listFiles()?.filter { supportedExtensions.contains(it.extension.lowercase()) }?.toList() ?: emptyList()
} else {
emptyList()
}
val mediaPaths = mediaFiles.map { it.absolutePath }
nativeRenderer?.nativeSetMediaList(mediaPaths.toTypedArray())
}
}
}
}
@@ -4,15 +4,25 @@ import android.view.Surface
class NativeRenderer {
interface NextMediaCallback {
fun onNextMediaRequested()
}
companion object {
init {
System.loadLibrary("native_renderer")
}
}
external fun nativeInit(surface: Surface?): Boolean
external fun nativeInit(): Boolean
external fun nativeDestroy()
external fun nativeRender()
external fun nativeSetMediaList(paths: Array<String?>?)
external fun nativeRender(surface: Surface)
// ...
// external fun nativeSetCurrentMedia(path: String) // 기존 코드
external fun nativeSetCurrentMedia(fd: Int) // 수정
}
// external fun nativeStartNextPreload(path: String) // 기존 코드
external fun nativeStartNextPreload(fd: Int) // 수정
// ...
external fun nativeSetNextMediaCallback(callback: NextMediaCallback)
}
@@ -65,7 +65,7 @@ class LocationUpdateService : Service(), LocationListener {
try {
//////-1002450229641
val url = PrefString.locationApi.get()
Blog.LOGE("LocationLog ${url}")
// Blog.LOGE("LocationLog ${url}")
if (url.length > 10) {
val client = OkHttpClient.Builder()
.connectionPool(ConnectionPool(5, 60, TimeUnit.SECONDS))
@@ -84,7 +84,7 @@ class LocationUpdateService : Service(), LocationListener {
)
val request: Request = builder.build()
Blog.LOGE("telegram before request ")
// Blog.LOGE("telegram before request ")
// OkHttp 클라이언트로 GET 요청 객체 전송
val response: Response = client.newCall(request).execute()
if (response.isSuccessful()) {