6.7.0 - Alpha18 - 修复 toast 方法因持有 Toast 实例强引用而导致可能得内存泄露问题

This commit is contained in:
SuperMonster003
2026-01-30 20:57:09 +08:00
parent 1dce33b180
commit 8205409c8c
8 changed files with 213 additions and 119 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$data": { "$data": {
"v6.7.0": { "v6.7.0": {
"released_date": "2026/01/29", "released_date": "2026/01/30",
"feature": [ "feature": [
"插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮/主页标签页)", "插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮/主页标签页)",
"Paddle OCR (PP-OCRv5) 插件, 用于光学字符识别", "Paddle OCR (PP-OCRv5) 插件, 用于光学字符识别",
@@ -61,6 +61,7 @@
"console.build 方法的 (title/content)BackgroundColor 选项导致透明度或着色选项被覆盖的问题 _[`issue #458`](http://issues.autojs6.com/458)_", "console.build 方法的 (title/content)BackgroundColor 选项导致透明度或着色选项被覆盖的问题 _[`issue #458`](http://issues.autojs6.com/458)_",
"console/toast 等方法显示 Java Double 时可能丢失末尾零的问题", "console/toast 等方法显示 Java Double 时可能丢失末尾零的问题",
"无法使用 console/toast 等方法显示 BigInt 数据类型的问题", "无法使用 console/toast 等方法显示 BigInt 数据类型的问题",
"toast 方法因持有 Toast 实例强引用而导致可能得内存泄露问题",
"部分全局对象可能丢失 JavaScript 原型属性及方法的问题", "部分全局对象可能丢失 JavaScript 原型属性及方法的问题",
"使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题", "使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题",
"dialogs.build 方法 linkify 选项参数功能失效的问题", "dialogs.build 方法 linkify 选项参数功能失效的问题",

View File

@@ -18,19 +18,18 @@ import org.autojs.autojs.core.console.GlobalConsole
import org.autojs.autojs.core.image.capture.ScreenCaptureRequester import org.autojs.autojs.core.image.capture.ScreenCaptureRequester
import org.autojs.autojs.core.looper.Loopers import org.autojs.autojs.core.looper.Loopers
import org.autojs.autojs.core.pref.Pref import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs.rhino.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop
import org.autojs.autojs.lang.ThreadCompat import org.autojs.autojs.lang.ThreadCompat
import org.autojs.autojs.pio.PFiles import org.autojs.autojs.pio.PFiles
import org.autojs.autojs.pio.UncheckedIOException import org.autojs.autojs.pio.UncheckedIOException
import org.autojs.autojs.rhino.AndroidClassLoader import org.autojs.autojs.rhino.AndroidClassLoader
import org.autojs.autojs.rhino.ProxyObject import org.autojs.autojs.rhino.ProxyObject
import org.autojs.autojs.rhino.TopLevelScope import org.autojs.autojs.rhino.TopLevelScope
import org.autojs.autojs.rhino.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop
import org.autojs.autojs.runtime.api.AbstractShell import org.autojs.autojs.runtime.api.AbstractShell
import org.autojs.autojs.runtime.api.AppUtils import org.autojs.autojs.runtime.api.AppUtils
import org.autojs.autojs.runtime.api.ProcessShell import org.autojs.autojs.runtime.api.ProcessShell
import org.autojs.autojs.runtime.api.ScreenMetrics import org.autojs.autojs.runtime.api.ScreenMetrics
import org.autojs.autojs.runtime.api.ScriptToast
import org.autojs.autojs.runtime.api.WrappedShizuku import org.autojs.autojs.runtime.api.WrappedShizuku
import org.autojs.autojs.runtime.api.augment.app.App import org.autojs.autojs.runtime.api.augment.app.App
import org.autojs.autojs.runtime.api.augment.autojs.Autojs import org.autojs.autojs.runtime.api.augment.autojs.Autojs
@@ -183,7 +182,7 @@ class ScriptRuntime private constructor(builder: Builder) {
private val mJob = SupervisorJob() private val mJob = SupervisorJob()
val coroutineScope = CoroutineScope(Dispatchers.Default + mJob) val coroutineScope = CoroutineScope(Dispatchers.Default + mJob)
val coroutineContext = coroutineScope.coroutineContext val coroutineContext = coroutineScope.coroutineContext
val ownerId = "runtime@${System.identityHashCode(this)}" val ownerId = "runtime@${System.identityHashCode(this)}"
private var mUiHandlerAppContext: Context private var mUiHandlerAppContext: Context
@@ -587,13 +586,13 @@ class ScriptRuntime private constructor(builder: Builder) {
Log.d(TAG, "on exit") Log.d(TAG, "on exit")
this.isExiting = true this.isExiting = true
ignoresException({ ignoresException {
if (console.configurator.isExitOnClose) { if (console.configurator.isExitOnClose) {
console.hideDelayed() console.hideDelayed()
} }
}) }
ignoresException({ CoreWebSocket.onExit("Triggered by $TAG") }) ignoresException { CoreWebSocket.onExit("Triggered by $TAG") }
// @Hint by 抠脚本人 (https://github.com/little-alei) on Jul 10, 2023. // @Hint by 抠脚本人 (https://github.com/little-alei) on Jul 10, 2023.
// ! 清空无障碍事件. // ! 清空无障碍事件.
@@ -604,35 +603,42 @@ class ScriptRuntime private constructor(builder: Builder) {
// ! by the current script to avoid affecting other still-running scripts. // ! by the current script to avoid affecting other still-running scripts.
// ! zh-CN: 只清理当前脚本注册的无障碍事件回调,避免影响其他仍在运行的脚本. // ! zh-CN: 只清理当前脚本注册的无障碍事件回调,避免影响其他仍在运行的脚本.
// # ignoresException({ AccessibilityService.clearAccessibilityEventCallback() }) // # ignoresException({ AccessibilityService.clearAccessibilityEventCallback() })
ignoresException({ automator.removeAllEventsForThisRuntime() }) ignoresException { automator.removeAllEventsForThisRuntime() }
ignoresException({ RootUtils.resetRuntimeOverriddenRootModeState() }) ignoresException { RootUtils.resetRuntimeOverriddenRootModeState() }
/* 回收全部记录的 ImageWrapper 实例. */ // Recycle all recorded ImageWrapper instances.
ignoresException({ CoreImageWrapper.recycleAll() }) // zh-CN: 回收全部记录的 ImageWrapper 实例.
ignoresException { CoreImageWrapper.recycleAll() }
/* 清除 interrupt 状态. */ // Clear interrupt status.
ignoresException({ ThreadCompat.interrupted() }) // zh-CN: 清除 interrupt 状态.
ignoresException { ThreadCompat.interrupted() }
/* 浮动窗口需要第一时间关闭. */ // Floating windows need to be closed immediately.
/* 以免出现恶意脚本全屏浮动窗口遮蔽屏幕并且在 exit 中写死循环的问题. */ // To prevent malicious scripts from creating fullscreen floating windows
ignoresException({ floaty.closeAll() }) // that obscure the screen and write infinite loops in exit.
// zh-CN:
// 浮动窗口需要第一时间关闭.
// 以免出现恶意脚本全屏浮动窗口遮蔽屏幕并且在 exit 中写死循环的问题.
ignoresException { floaty.closeAll() }
ignoresException({ events.emit("exit") }, "Exception on exit: %s") ignoresException("Exception on exit: %s") {
ignoresException({ ScriptToast.clear(this) }, 500) events.emit("exit")
}
ignoresException({ threads.shutDownAll() }) ignoresException { threads.shutDownAll() }
ignoresException({ events.recycle() }) ignoresException { events.recycle() }
ignoresException({ media.recycle() }) ignoresException { media.recycle() }
ignoresException({ loopers.recycle() }) ignoresException { loopers.recycle() }
ignoresException({ this.recycleShell() }) ignoresException { recycleShell() }
ignoresException({ images.releaseScreenCapturer() }) ignoresException { images.releaseScreenCapturer() }
ignoresException({ images.stopScreenCapturerForegroundService() }) ignoresException { images.stopScreenCapturerForegroundService() }
ignoresException({ ocrMLKit.release() }) ignoresException { ocrMLKit.release() }
ignoresException({ sensors.unregisterAll() }) ignoresException { sensors.unregisterAll() }
ignoresException({ timers.recycle() }) ignoresException { timers.recycle() }
ignoresException({ ui.recycle() }) ignoresException { ui.recycle() }
ignoresException({ closeableManager.recycleAll() }) ignoresException { closeableManager.recycleAll() }
} }
fun setScreenMetrics(width: Int, height: Int) { fun setScreenMetrics(width: Int, height: Int) {
@@ -709,11 +715,11 @@ class ScriptRuntime private constructor(builder: Builder) {
} }
} }
private fun ignoresException(r: Runnable, @Suppress("SameParameterValue") delay: Int) { private fun ignoresException(r: Runnable) {
uiHandler.postDelayed(r, delay.toLong()) ignoresException(null, r)
} }
private fun ignoresException(r: Runnable, consoleMessage: String? = null) { private fun ignoresException(consoleMessage: String?, r: Runnable) {
try { try {
r.run() r.run()
} catch (e: Throwable) { } catch (e: Throwable) {

View File

@@ -1,40 +1,155 @@
package org.autojs.autojs.runtime.api package org.autojs.autojs.runtime.api
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.widget.Toast import android.widget.Toast
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import java.lang.ref.WeakReference import java.util.ArrayDeque
import java.util.concurrent.ConcurrentHashMap
/** /**
* Toast global queue manager.
* All scripts share a single global queue because only one toast can be shown at a time.
*
* zh-CN:
*
* Toast 全局队列管理器.
* 所有脚本共享同一个全局队列, 因为同一时间通常只能显示一个 Toast.
*
* Created by SuperMonster003 on Aug 3, 2023. * Created by SuperMonster003 on Aug 3, 2023.
* Modified by SuperMonster003 as of Oct 24, 2023.
* Transformed by SuperMonster003 on Oct 24, 2023. * Transformed by SuperMonster003 on Oct 24, 2023.
* Modified by JetBrains AI Assistant (GPT-5.2) as of Jan 30, 2026.
* Modified by SuperMonster003 as of Jan 30, 2026.
*/ */
object ScriptToast { object ScriptToast {
@JvmField private const val MAX_GLOBAL_QUEUE_SIZE = 17
val pool = ConcurrentHashMap<Toast, WeakReference<ScriptRuntime>>()
private val mainHandler = Handler(Looper.getMainLooper())
private val queue = ArrayDeque<ToastTask>(MAX_GLOBAL_QUEUE_SIZE)
private var isShowing = false
private var currentTask: ToastTask? = null
private var currentToast: Toast? = null
private var currentFinishRunnable: Runnable? = null
private data class ToastTask(
val message: String,
val duration: Int,
val ownerId: String,
)
@JvmStatic @JvmStatic
fun add(t: Toast, scriptRuntime: ScriptRuntime) { fun enqueueToast(context: Context, scriptRuntime: ScriptRuntime, message: String, isLong: Boolean = false) {
pool[t] = WeakReference(scriptRuntime) val duration = if (isLong) Toast.LENGTH_LONG else Toast.LENGTH_SHORT
val ownerId = scriptRuntime.ownerId
// Must be called on the main thread.
// zh-CN: 必须在主线程调用.
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post { enqueueToast(context, scriptRuntime, message, isLong) }
return
}
if (queue.size >= MAX_GLOBAL_QUEUE_SIZE) {
// Discard newest task when the queue is full.
// zh-CN: 当队列已满时丢弃最新任务.
return
}
queue.addLast(ToastTask(message, duration, ownerId))
tryShowNextLocked(context.applicationContext)
} }
@JvmStatic @JvmStatic
fun dismissAll(scriptRuntime: ScriptRuntime) { fun dismissAll(scriptRuntime: ScriptRuntime) {
pool.entries.forEach { entry -> val ownerId = scriptRuntime.ownerId
if (entry.value.get() == scriptRuntime) { mainHandler.post {
pool.remove(entry.key) queue.removeAll { it.ownerId == ownerId }
entry.key.cancel()
if (currentTask?.ownerId == ownerId) {
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
currentFinishRunnable = null
currentToast?.cancel()
currentToast = null
currentTask = null
isShowing = false
tryShowNextLocked(scriptRuntime.uiHandler.applicationContext)
} }
} }
} }
@JvmStatic @JvmStatic
fun clear(scriptRuntime: ScriptRuntime) { fun clear(scriptRuntime: ScriptRuntime) {
pool.entries val ownerId = scriptRuntime.ownerId
.filter { it.value.get() == scriptRuntime } mainHandler.post {
.forEach { pool.remove(it.key) } queue.removeAll { it.ownerId == ownerId }
}
}
@JvmStatic
fun destroy() {
mainHandler.post {
queue.clear()
currentFinishRunnable?.let { mainHandler.removeCallbacks(it) }
currentFinishRunnable = null
currentToast?.cancel()
currentToast = null
currentTask = null
isShowing = false
}
}
private fun tryShowNextLocked(appCtx: Context) {
if (isShowing) return
val task = queue.removeFirstOrNull() ?: return
isShowing = true
currentTask = task
val toast = Toast.makeText(appCtx, task.message, task.duration)
currentToast = toast
val finish = Runnable {
currentFinishRunnable = null
currentToast = null
currentTask = null
isShowing = false
tryShowNextLocked(appCtx)
}
currentFinishRunnable = finish
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
toast.addCallback(object : Toast.Callback() {
override fun onToastHidden() {
super.onToastHidden()
finish.run()
}
})
} else {
val delay = if (task.duration == Toast.LENGTH_LONG) 3_500L else 2_000L
mainHandler.postDelayed(finish, delay)
}
toast.show()
}
private fun <E> ArrayDeque<E>.removeFirstOrNull(): E? =
if (isEmpty()) null else removeFirst()
private inline fun <E> ArrayDeque<E>.removeAll(predicate: (E) -> Boolean) {
if (isEmpty()) return
val it = iterator()
while (it.hasNext()) {
if (predicate(it.next())) it.remove()
}
} }
} }

View File

@@ -1,13 +1,13 @@
package org.autojs.autojs.runtime.api.augment.toast package org.autojs.autojs.runtime.api.augment.toast
import org.autojs.autojs.AutoJs
import org.autojs.autojs.annotation.RhinoFunctionBody
import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
import org.autojs.autojs.rhino.ArgumentGuards import org.autojs.autojs.rhino.ArgumentGuards
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.ScriptToast
import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.Invokable import org.autojs.autojs.runtime.api.augment.Invokable
import org.autojs.autojs.util.RhinoUtils.undefined import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils.UNDEFINED
import org.mozilla.javascript.Undefined import org.mozilla.javascript.Undefined
class Toast(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable { class Toast(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable {
@@ -35,26 +35,22 @@ class Toast(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntim
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun call(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsLengthInRange(args, 0..3) { fun call(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsLengthInRange(args, 0..3) {
undefined { val toastParser = when (it.size) {
when (it.size) { 0 -> ToastParser(globalContext, "")
0 -> ToastParser("").show(scriptRuntime) 1 -> ToastParser(globalContext, args[0])
1 -> ToastParser(args[0]).show(scriptRuntime) 2 -> ToastParser(globalContext, args[0], args[1])
2 -> ToastParser(args[0], args[1]).show(scriptRuntime) 3 -> ToastParser(globalContext, args[0], args[1], args[2])
3 -> ToastParser(args[0], args[1], args[2]).show(scriptRuntime) else -> throw WrappedIllegalArgumentException("Invalid arguments length ${args.size} for global.toast")
}
} }
toastParser.show(scriptRuntime)
return@ensureArgumentsLengthInRange UNDEFINED
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun dismissAll(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsIsEmpty(args) { fun dismissAll(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsIsEmpty(args) {
dismissAllRhino(scriptRuntime) ScriptToast.dismissAll(scriptRuntime)
} return@ensureArgumentsIsEmpty UNDEFINED
@JvmStatic
@RhinoFunctionBody
fun dismissAllRhino(scriptRuntime: ScriptRuntime) = undefined {
AutoJs.instance.uiHandler.dismissAllToasts(scriptRuntime)
} }
} }

View File

@@ -1,14 +1,18 @@
package org.autojs.autojs.runtime.api.augment.toast package org.autojs.autojs.runtime.api.augment.toast
import org.autojs.autojs.AutoJs
import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.util.RhinoUtils.coerceString import org.autojs.autojs.runtime.api.ScriptToast
import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable.NOT_FOUND import org.mozilla.javascript.Scriptable.NOT_FOUND
import org.mozilla.javascript.Undefined import org.mozilla.javascript.Undefined
import android.content.Context as AndroidContext
import org.mozilla.javascript.Context as RhinoContext
class ToastParser(private val msg: Any?, long: Any? = null, forcible: Any? = null) { /**
* Created by SuperMonster003 on Dec 2, 2024.
* Modified by SuperMonster003 as of Jan 30, 2026.
*/
class ToastParser(private val context: AndroidContext, private val msg: Any?, isLong: Any? = null, isForcible: Any? = null) {
private val badge = object { private val badge = object {
val long = Regex("^l(ong)?$", RegexOption.IGNORE_CASE) val long = Regex("^l(ong)?$", RegexOption.IGNORE_CASE)
@@ -20,42 +24,42 @@ class ToastParser(private val msg: Any?, long: Any? = null, forcible: Any? = nul
var isForcible = false var isForcible = false
init { init {
parseIsLong(long) parseIsLong(isLong)
parseIsForcible(forcible) parseIsForcible(isForcible)
} }
fun show(scriptRuntime: ScriptRuntime) { fun show(scriptRuntime: ScriptRuntime) {
if (isForcible) Toast.dismissAllRhino(scriptRuntime) if (this@ToastParser.isForcible) ScriptToast.dismissAll(scriptRuntime)
val niceMsg = when { val niceMsg = when {
Undefined.isUndefined(msg) || msg == NOT_FOUND -> "undefined" Undefined.isUndefined(msg) || msg == NOT_FOUND -> "undefined"
msg == null -> "null" msg == null -> "null"
else -> Context.toString(msg) else -> RhinoContext.toString(msg)
} }
AutoJs.instance.uiHandler.toast(scriptRuntime, niceMsg, isLong) ScriptToast.enqueueToast(context, scriptRuntime, niceMsg, this@ToastParser.isLong)
} }
private fun parseIsLong(o: Any?) = when (o) { private fun parseIsLong(o: Any?) = when (o) {
is Boolean -> o is Boolean -> o
is Number -> Context.toBoolean(o) is Number -> RhinoContext.toBoolean(o)
is String -> when { is String -> when {
badge.long.matches(o) -> true badge.long.matches(o) -> true
badge.short.matches(o) -> false badge.short.matches(o) -> false
badge.forcible.matches(o) -> isLong.also { this.isForcible = true } badge.forcible.matches(o) -> this@ToastParser.isLong.also { this.isForcible = true }
else -> throw IllegalArgumentException("Argument \"isLong\" ${o.jsBrief()} for Toast.Parser is invalid") else -> throw IllegalArgumentException("Argument \"isLong\" ${o.jsBrief()} for Toast.Parser is invalid")
} }
else -> isLong else -> this@ToastParser.isLong
}.also { isLong = it } }.also { this@ToastParser.isLong = it }
private fun parseIsForcible(o: Any?) = when (o) { private fun parseIsForcible(o: Any?) = when (o) {
is Boolean -> o is Boolean -> o
is Number -> Context.toBoolean(o) is Number -> RhinoContext.toBoolean(o)
is String -> when { is String -> when {
badge.forcible.matches(o) -> true badge.forcible.matches(o) -> true
badge.long.matches(o) -> isForcible.also { this.isLong = true } badge.long.matches(o) -> this@ToastParser.isForcible.also { this.isLong = true }
badge.short.matches(o) -> isForcible.also { this.isLong = false } badge.short.matches(o) -> this@ToastParser.isForcible.also { this.isLong = false }
else -> throw IllegalArgumentException("Argument \"isForcible\" ${o.jsBrief()} for Toast.Parser is invalid") else -> throw IllegalArgumentException("Argument \"isForcible\" ${o.jsBrief()} for Toast.Parser is invalid")
} }
else -> isForcible else -> this@ToastParser.isForcible
}.also { isForcible = it } }.also { this@ToastParser.isForcible = it }
} }

View File

@@ -3,33 +3,10 @@ package org.autojs.autojs.tool
import android.content.Context import android.content.Context
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import android.widget.Toast.LENGTH_SHORT
import org.autojs.autojs.AutoJs
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.ScriptToast
import org.autojs.autojs.util.RhinoUtils.isMainThread
/** /**
* Created by Stardust on May 2, 2017. * Created by Stardust on May 2, 2017.
* Transformed by SuperMonster003 on Oct 25, 2023. * Transformed by SuperMonster003 on Oct 25, 2023.
* Modified by SuperMonster003 as of Jan 30, 2026.
*/ */
class UiHandler(val applicationContext: Context) : Handler(Looper.getMainLooper()) { class UiHandler(val applicationContext: Context) : Handler(Looper.getMainLooper())
fun toast(scriptRuntime: ScriptRuntime, message: String, isLong: Boolean = false) {
val showRunnable = Runnable {
val toastLength = if (isLong) LENGTH_LONG else LENGTH_SHORT
Toast.makeText(AutoJs.instance.application, message, toastLength)
.also { ScriptToast.add(it, scriptRuntime) }
.show()
}
when {
isMainThread() -> showRunnable.run()
else -> this@UiHandler.post(showRunnable)
}
}
fun dismissAllToasts(scriptRuntime: ScriptRuntime) = ScriptToast.dismissAll(scriptRuntime)
}

View File

@@ -6,8 +6,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Gravity import android.view.Gravity
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@@ -347,12 +345,9 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity {
} }
private fun setUpStatusBarIconLight() { private fun setUpStatusBarIconLight() {
Handler(Looper.getMainLooper()).post { when (sIsActionBarDrawerOpened) {
if (sIsActionBarDrawerOpened) { true -> setUpStatusBarIconLightByNightMode()
setUpStatusBarIconLightByNightMode() else -> setUpStatusBarIconLightByThemeColor()
} else {
setUpStatusBarIconLightByThemeColor()
}
} }
} }

View File

@@ -1,5 +1,5 @@
#Wed Jan 28 21:05:38 CST 2026 #Fri Jan 30 20:56:33 CST 2026
BUILD_TIME=1769605538543 BUILD_TIME=1769777793096
COMPILE_SDK_VERSION=36 COMPILE_SDK_VERSION=36
IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125 IMAGE_QUANT_NDK_VERSION=26.1.10909125
@@ -27,6 +27,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13
RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3
TARGET_SDK_VERSION=36 TARGET_SDK_VERSION=36
TARGET_SDK_VERSION_INRT=29 TARGET_SDK_VERSION_INRT=29
VERSION_BUILD=3666 VERSION_BUILD=3673
VERSION_NAME=6.7.0 Alpha18 VERSION_NAME=6.7.0 Alpha18
VSCODE_EXT_REQUIRED_VERSION=1.0.13 VSCODE_EXT_REQUIRED_VERSION=1.0.13