From 278efd574e69a59a3395032cac01dbcacee36507 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 29 Oct 2026 00:52:54 +0100 Subject: [PATCH] Run camera handler tasks on real host worker threads with controlled main timers --- .../kotlin/android/annotation/SuppressLint.kt | 3 ++ .../src/main/kotlin/android/os/HostVideoOs.kt | 47 +++++++++++++++++-- .../main/kotlin/android/util/HostGeometry.kt | 4 ++ 3 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 tools/chatgui-android/video-tests/src/main/kotlin/android/annotation/SuppressLint.kt create mode 100644 tools/chatgui-android/video-tests/src/main/kotlin/android/util/HostGeometry.kt diff --git a/tools/chatgui-android/video-tests/src/main/kotlin/android/annotation/SuppressLint.kt b/tools/chatgui-android/video-tests/src/main/kotlin/android/annotation/SuppressLint.kt new file mode 100644 index 00000000..1fb24c12 --- /dev/null +++ b/tools/chatgui-android/video-tests/src/main/kotlin/android/annotation/SuppressLint.kt @@ -0,0 +1,3 @@ +package android.annotation + +annotation class SuppressLint(vararg val value: String) diff --git a/tools/chatgui-android/video-tests/src/main/kotlin/android/os/HostVideoOs.kt b/tools/chatgui-android/video-tests/src/main/kotlin/android/os/HostVideoOs.kt index ac8ba256..550e3f44 100644 --- a/tools/chatgui-android/video-tests/src/main/kotlin/android/os/HostVideoOs.kt +++ b/tools/chatgui-android/video-tests/src/main/kotlin/android/os/HostVideoOs.kt @@ -3,12 +3,18 @@ package android.os import java.util.concurrent.ConcurrentLinkedQueue /** Только JVM: main очередь и таймеры исполняет тест, worker остаётся настоящим Thread. */ -class Looper private constructor() { +class Looper internal constructor(private val threaded: Boolean = false) { private data class Task(val handler: Handler, val action: Runnable, val deadline: Long) private val tasks = ConcurrentLinkedQueue() - private var now = 0L + @Volatile private var now = 0L + @Volatile private var quitting = false + private val monitor = Object() + private fun time(): Long = if (threaded) System.nanoTime() / 1_000_000 else now internal fun post(handler: Handler, action: Runnable, delay: Long): Boolean { - tasks.add(Task(handler, action, now + delay)); return true + synchronized(monitor) { + if (quitting) return false + tasks.add(Task(handler, action, time() + delay)); monitor.notifyAll(); return true + } } internal fun remove(handler: Handler, action: Runnable) { tasks.removeIf { it.handler === handler && it.action === action } } fun advanceBy(delay: Long) { @@ -18,10 +24,41 @@ class Looper private constructor() { if (tasks.remove(next)) next.action.run() } } - companion object { private val main = Looper(); fun getMainLooper() = main } + internal fun loop() { + current.set(this) + while (true) { + val next = synchronized(monitor) { + val ready = tasks.filter { it.deadline <= time() }.minByOrNull { it.deadline } + if (ready == null && quitting) return + if (ready == null) monitor.wait(2) + ready + } + if (next != null && tasks.remove(next)) next.action.run() + } + } + internal fun quit(): Boolean = synchronized(monitor) { quitting = true; monitor.notifyAll(); true } + companion object { + private val main = Looper() + private val mainThread = Thread.currentThread() + private val current = ThreadLocal() + fun getMainLooper() = main + fun myLooper(): Looper? = if (Thread.currentThread() === mainThread) main else current.get() + } } class Handler(private val looper: Looper) { - companion object { var rejectDelayed = false } + companion object { var rejectDelayed = false; var rejectImmediate = false } + fun post(action: Runnable): Boolean = !rejectImmediate && looper.post(this, action, 0) fun postDelayed(action: Runnable, delay: Long): Boolean = !rejectDelayed && looper.post(this, action, delay) fun removeCallbacks(action: Runnable) = looper.remove(this, action) } + +class HandlerThread(name: String) : Thread(name) { + val looper = Looper(true) + init { isDaemon = true } + override fun run() { looper.loop() } + fun quitSafely() = looper.quit() +} +object SystemClock { + fun elapsedRealtime(): Long = System.nanoTime() / 1_000_000 + fun elapsedRealtimeNanos(): Long = System.nanoTime() +} diff --git a/tools/chatgui-android/video-tests/src/main/kotlin/android/util/HostGeometry.kt b/tools/chatgui-android/video-tests/src/main/kotlin/android/util/HostGeometry.kt new file mode 100644 index 00000000..6c5e0a8d --- /dev/null +++ b/tools/chatgui-android/video-tests/src/main/kotlin/android/util/HostGeometry.kt @@ -0,0 +1,4 @@ +package android.util + +data class Size(val width: Int, val height: Int) +data class Range>(val lower: T, val upper: T)