6.7.0 - Alpha20 - 修复部分设备无法正常启用插件的问题
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package org.autojs.autojs.core.plugin.center
|
package org.autojs.autojs.core.plugin.center
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -14,6 +15,9 @@ import java.io.File
|
|||||||
* Local installed plugin discovery (based on existing PaddleOcrPluginHost.discover).
|
* Local installed plugin discovery (based on existing PaddleOcrPluginHost.discover).
|
||||||
*
|
*
|
||||||
* zh-CN: 本地已安装插件发现 (基于现有的 PaddleOcrPluginHost.discover).
|
* zh-CN: 本地已安装插件发现 (基于现有的 PaddleOcrPluginHost.discover).
|
||||||
|
*
|
||||||
|
* Modified by JetBrains AI Assistant (GPT-5.2-Codex (xhigh)) as of Feb 13, 2026.
|
||||||
|
* Modified by SuperMonster003 as of Feb 13, 2026.
|
||||||
*/
|
*/
|
||||||
class InstalledPluginRepository {
|
class InstalledPluginRepository {
|
||||||
|
|
||||||
@@ -29,6 +33,8 @@ class InstalledPluginRepository {
|
|||||||
val lastUpdateTime: Long?,
|
val lastUpdateTime: Long?,
|
||||||
val icon: Drawable?,
|
val icon: Drawable?,
|
||||||
val pluginInfo: PluginInfo?,
|
val pluginInfo: PluginInfo?,
|
||||||
|
val bindError: Throwable?,
|
||||||
|
val isStopped: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun discoverInstalled(context: Context): List<InstalledPlugin> = withContext(Dispatchers.IO) {
|
suspend fun discoverInstalled(context: Context): List<InstalledPlugin> = withContext(Dispatchers.IO) {
|
||||||
@@ -41,6 +47,7 @@ class InstalledPluginRepository {
|
|||||||
val appInfo = runCatching { pm.getApplicationInfo(packageName, 0) }.getOrNull()
|
val appInfo = runCatching { pm.getApplicationInfo(packageName, 0) }.getOrNull()
|
||||||
val appLabel = appInfo?.loadLabel(pm)?.toString()
|
val appLabel = appInfo?.loadLabel(pm)?.toString()
|
||||||
val icon = appInfo?.loadIcon(pm)
|
val icon = appInfo?.loadIcon(pm)
|
||||||
|
val isStopped = appInfo != null && (appInfo.flags and ApplicationInfo.FLAG_STOPPED) != 0
|
||||||
|
|
||||||
val pkgInfo = runCatching { pm.getPackageInfo(packageName, 0) }.getOrNull()
|
val pkgInfo = runCatching { pm.getPackageInfo(packageName, 0) }.getOrNull()
|
||||||
val versionName = pkgInfo?.versionName ?: d.pluginInfo?.versionName ?: context.getString(R.string.text_unknown)
|
val versionName = pkgInfo?.versionName ?: d.pluginInfo?.versionName ?: context.getString(R.string.text_unknown)
|
||||||
@@ -70,6 +77,8 @@ class InstalledPluginRepository {
|
|||||||
lastUpdateTime = lastUpdateTime,
|
lastUpdateTime = lastUpdateTime,
|
||||||
icon = icon,
|
icon = icon,
|
||||||
pluginInfo = d.pluginInfo,
|
pluginInfo = d.pluginInfo,
|
||||||
|
bindError = d.error,
|
||||||
|
isStopped = isStopped,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,15 @@ import androidx.recyclerview.widget.DividerItemDecoration
|
|||||||
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.autojs.autojs.core.plugin.ocr.PaddleOcrPluginHost
|
||||||
|
import org.autojs.autojs.util.ClipboardUtils
|
||||||
|
import org.autojs.autojs.util.IntentUtils.startSafely
|
||||||
|
import org.autojs.autojs.util.ViewUtils
|
||||||
import org.autojs.autojs.util.ViewUtils.excludePaddingClippableViewFromBottomNavigationBar
|
import org.autojs.autojs.util.ViewUtils.excludePaddingClippableViewFromBottomNavigationBar
|
||||||
import org.autojs.autojs6.R
|
import org.autojs.autojs6.R
|
||||||
import org.autojs.autojs6.databinding.FragmentPluginCenterBinding
|
import org.autojs.autojs6.databinding.FragmentPluginCenterBinding
|
||||||
@@ -62,8 +67,75 @@ class PluginCenterFragment : Fragment(R.layout.fragment_plugin_center) {
|
|||||||
|
|
||||||
adapter = PluginCenterItemAdapter(object : PluginCenterItemAdapter.Listener {
|
adapter = PluginCenterItemAdapter(object : PluginCenterItemAdapter.Listener {
|
||||||
override fun onToggleEnable(item: PluginCenterItem, enabled: Boolean) {
|
override fun onToggleEnable(item: PluginCenterItem, enabled: Boolean) {
|
||||||
vm.setEnabled(contextRef, item.packageName, enabled)
|
if (!enabled) {
|
||||||
item.isEnabled = enabled
|
vm.setEnabled(contextRef, item.packageName, false)
|
||||||
|
item.isEnabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.setEnabled(contextRef, item.packageName, true)
|
||||||
|
item.isEnabled = true
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
val error = runCatching {
|
||||||
|
PaddleOcrPluginHost.probe(contextRef, item.packageName)
|
||||||
|
}.exceptionOrNull()
|
||||||
|
if (error != null && error !is CancellationException) {
|
||||||
|
if (isAdded) {
|
||||||
|
val pm = contextRef.packageManager
|
||||||
|
val launchIntent = pm.getLaunchIntentForPackage(item.packageName)
|
||||||
|
val wakeIntent = PluginWakeManager.buildWakeIntent(contextRef, item.packageName)
|
||||||
|
|
||||||
|
val errorBody = error.message ?: error.toString()
|
||||||
|
val message = listOf(
|
||||||
|
contextRef.getString(R.string.text_exception_info) + contextRef.getString(R.string.symbol_colon_with_blank),
|
||||||
|
errorBody,
|
||||||
|
contextRef.getString(R.string.text_hint) + contextRef.getString(R.string.symbol_colon_with_blank),
|
||||||
|
getString(R.string.hint_try_clicking_the_activate_button_to_activate_the_plugin)
|
||||||
|
).joinToString("\n\n")
|
||||||
|
|
||||||
|
MaterialDialog.Builder(contextRef)
|
||||||
|
.title(R.string.error_failed_to_enable_the_plugin)
|
||||||
|
.content(message)
|
||||||
|
.neutralText(R.string.dialog_button_copy)
|
||||||
|
.neutralColorRes(R.color.dialog_button_hint)
|
||||||
|
.onNeutral { d, _ ->
|
||||||
|
ClipboardUtils.setClip(contextRef, errorBody)
|
||||||
|
ViewUtils.showSnack(d.view, R.string.text_already_copied_to_clip, false)
|
||||||
|
}
|
||||||
|
.negativeText(R.string.dialog_button_dismiss)
|
||||||
|
.negativeColorRes(R.color.dialog_button_default)
|
||||||
|
.onNegative { d, _ -> d.dismiss() }
|
||||||
|
.apply positive@{
|
||||||
|
positiveText(R.string.dialog_button_activate)
|
||||||
|
|
||||||
|
val openIntent = wakeIntent ?: launchIntent ?: run {
|
||||||
|
positiveColorRes(R.color.dialog_button_unavailable)
|
||||||
|
onPositive { d, _ ->
|
||||||
|
ViewUtils.showSnack(d.view, R.string.text_unavailable, false)
|
||||||
|
}
|
||||||
|
return@positive
|
||||||
|
}
|
||||||
|
|
||||||
|
positiveColorRes(R.color.dialog_button_attraction)
|
||||||
|
onPositive { d, _ ->
|
||||||
|
val started = openIntent.startSafely(contextRef, true)
|
||||||
|
d.dismiss()
|
||||||
|
if (started) {
|
||||||
|
ViewUtils.showToast(contextRef, getString(R.string.text_activated_successfully), true)
|
||||||
|
tryEnableAfterWake(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cancelable(false)
|
||||||
|
.autoDismiss(false)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
vm.setEnabled(contextRef, item.packageName, false)
|
||||||
|
item.isEnabled = false
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUninstall(item: PluginCenterItem) {
|
override fun onUninstall(item: PluginCenterItem) {
|
||||||
@@ -292,6 +364,29 @@ class PluginCenterFragment : Fragment(R.layout.fragment_plugin_center) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun tryEnableAfterWake(item: PluginCenterItem) {
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
val delays = longArrayOf(300L, 800L, 1500L)
|
||||||
|
for (delayMs in delays) {
|
||||||
|
delay(delayMs)
|
||||||
|
val error = runCatching {
|
||||||
|
PaddleOcrPluginHost.probe(contextRef, item.packageName)
|
||||||
|
}.exceptionOrNull()
|
||||||
|
if (error == null) {
|
||||||
|
if (isAdded && _binding != null) {
|
||||||
|
vm.setEnabled(contextRef, item.packageName, true)
|
||||||
|
item.isEnabled = true
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
if (error is CancellationException) {
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
pkgReceiver ?: run registerPackageReceiver@{
|
pkgReceiver ?: run registerPackageReceiver@{
|
||||||
@@ -324,6 +419,7 @@ class PluginCenterFragment : Fragment(R.layout.fragment_plugin_center) {
|
|||||||
// Package uninstallation (pre-update phase) does not record "Recently uninstalled" when replacing.
|
// Package uninstallation (pre-update phase) does not record "Recently uninstalled" when replacing.
|
||||||
// zh-CN: 替换卸载 (更新前阶段) 不记录 "最近卸载".
|
// zh-CN: 替换卸载 (更新前阶段) 不记录 "最近卸载".
|
||||||
if (!replacing) {
|
if (!replacing) {
|
||||||
|
PluginWakeManager.clearAutoWakeAttempt(packageName)
|
||||||
PluginRecentStore.setLastUninstalled(packageName)
|
PluginRecentStore.setLastUninstalled(packageName)
|
||||||
vm.load(context, forceRefreshIndex = false)
|
vm.load(context, forceRefreshIndex = false)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.autojs.autojs6.R
|
|||||||
*
|
*
|
||||||
* Created by JetBrains AI Assistant (GPT-5.2) on Nov 26, 2025.
|
* Created by JetBrains AI Assistant (GPT-5.2) on Nov 26, 2025.
|
||||||
* Modified by SuperMonster003 as of Jan 17, 2026.
|
* Modified by SuperMonster003 as of Jan 17, 2026.
|
||||||
|
* Modified by JetBrains AI Assistant (GPT-5.2-Codex (xhigh)) as of Feb 13, 2026.
|
||||||
*/
|
*/
|
||||||
class PluginCenterViewModel : ViewModel() {
|
class PluginCenterViewModel : ViewModel() {
|
||||||
|
|
||||||
@@ -92,6 +93,15 @@ class PluginCenterViewModel : ViewModel() {
|
|||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
installed.forEach { local ->
|
||||||
|
if (local.bindError != null) {
|
||||||
|
enableStore.setEnabled(context, local.packageName, false)
|
||||||
|
}
|
||||||
|
if (local.isStopped) {
|
||||||
|
PluginWakeManager.tryAutoWakeIfNeeded(context, local.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render list using "local only".
|
// Render list using "local only".
|
||||||
// zh-CN: 使用 "仅本地" 渲染列表.
|
// zh-CN: 使用 "仅本地" 渲染列表.
|
||||||
val onlyLocalItems = installed.mapNotNull { local ->
|
val onlyLocalItems = installed.mapNotNull { local ->
|
||||||
@@ -217,4 +227,4 @@ class PluginCenterViewModel : ViewModel() {
|
|||||||
private const val TAG = "PluginCenterViewModel"
|
private const val TAG = "PluginCenterViewModel"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package org.autojs.autojs.core.plugin.center
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import org.autojs.autojs.app.GlobalAppContext
|
||||||
|
import org.autojs.autojs.util.IntentUtils.startSafely
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by JetBrains AI Assistant (GPT-5.2-Codex (xhigh)) on Feb 13, 2026.
|
||||||
|
*/
|
||||||
|
object PluginWakeManager {
|
||||||
|
|
||||||
|
private const val SP = "plugin_center_wake"
|
||||||
|
private const val ACTION_OCR_WAKE = "org.autojs.plugin.PADDLE_OCR.WAKE"
|
||||||
|
private const val WAKE_ACTIVITY_META = "org.autojs.plugin.WAKE_ACTIVITY"
|
||||||
|
|
||||||
|
private val storeContext by lazy { GlobalAppContext.get() }
|
||||||
|
|
||||||
|
fun tryAutoWakeIfNeeded(context: Context, packageName: String): Boolean {
|
||||||
|
if (isAutoWakeAttempted(packageName)) return false
|
||||||
|
val intent = buildWakeIntent(context, packageName) ?: return false
|
||||||
|
val started = intent.startSafely(context, true)
|
||||||
|
markAutoWakeAttempted(packageName)
|
||||||
|
return started
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildWakeIntent(context: Context, packageName: String): Intent? {
|
||||||
|
val pm = context.packageManager
|
||||||
|
val appInfo = runCatching { pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA) }.getOrNull()
|
||||||
|
val metaWakeActivity = appInfo?.metaData?.getString(WAKE_ACTIVITY_META)
|
||||||
|
val metaComponent = metaWakeActivity?.let { className ->
|
||||||
|
val fullName = if (className.startsWith(".")) packageName + className else className
|
||||||
|
ComponentName(packageName, fullName)
|
||||||
|
}
|
||||||
|
val wakeComponent = metaComponent ?: run {
|
||||||
|
val implicitIntent = Intent(ACTION_OCR_WAKE).setPackage(packageName)
|
||||||
|
val info = pm.queryIntentActivities(implicitIntent, 0).firstOrNull()
|
||||||
|
info?.activityInfo?.let { ComponentName(it.packageName, it.name) }
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
wakeComponent != null -> Intent().setComponent(wakeComponent)
|
||||||
|
else -> Intent(ACTION_OCR_WAKE).setPackage(packageName).takeIf { it.resolveActivity(pm) != null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isAutoWakeAttempted(packageName: String): Boolean {
|
||||||
|
val sp = storeContext.getSharedPreferences(SP, Context.MODE_PRIVATE)
|
||||||
|
return sp.getBoolean(key(packageName), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun markAutoWakeAttempted(packageName: String) {
|
||||||
|
val sp = storeContext.getSharedPreferences(SP, Context.MODE_PRIVATE)
|
||||||
|
sp.edit { putBoolean(key(packageName), true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearAutoWakeAttempt(packageName: String) {
|
||||||
|
val sp = storeContext.getSharedPreferences(SP, Context.MODE_PRIVATE)
|
||||||
|
sp.edit { remove(key(packageName)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun key(packageName: String) = "key_\$_auto_wake_attempted_\$_$packageName"
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import android.content.ComponentName
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.ServiceInfo
|
import android.content.pm.ServiceInfo
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
@@ -28,6 +29,9 @@ import org.autojs.plugin.paddle.ocr.api.PluginInfo
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modified by JetBrains AI Assistant (GPT-5.2-Codex (xhigh)) as of Feb 13, 2026.
|
||||||
|
*/
|
||||||
object PaddleOcrPluginHost {
|
object PaddleOcrPluginHost {
|
||||||
|
|
||||||
private const val TAG = "PaddleOcrPluginHost"
|
private const val TAG = "PaddleOcrPluginHost"
|
||||||
@@ -37,29 +41,36 @@ object PaddleOcrPluginHost {
|
|||||||
private const val DEFAULT_BIND_TIMEOUT_MS = 60_000L
|
private const val DEFAULT_BIND_TIMEOUT_MS = 60_000L
|
||||||
private const val DEFAULT_CALL_TIMEOUT_MS = 60_000L
|
private const val DEFAULT_CALL_TIMEOUT_MS = 60_000L
|
||||||
|
|
||||||
|
private val externalServiceFlag = runCatching { ServiceInfo::class.java.getField("FLAG_EXTERNAL_SERVICE").getInt(null) }.getOrNull() ?: 0
|
||||||
|
private val bindExternalServiceFlag = runCatching { Context::class.java.getField("BIND_EXTERNAL_SERVICE").getInt(null) }.getOrNull() ?: 0
|
||||||
|
|
||||||
data class Discovered(
|
data class Discovered(
|
||||||
val serviceInfo: ServiceInfo,
|
val serviceInfo: ServiceInfo,
|
||||||
val pluginInfo: PluginInfo?,
|
val pluginInfo: PluginInfo?,
|
||||||
|
val error: Throwable?,
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun discover(context: Context): List<Discovered> {
|
suspend fun discover(context: Context): List<Discovered> {
|
||||||
val pm = context.packageManager
|
val services = queryOcrServices(context)
|
||||||
val resolveList = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
pm.queryIntentServices(Intent(ACTION_OCR), PackageManager.ResolveInfoFlags.of(0))
|
|
||||||
} else {
|
|
||||||
pm.queryIntentServices(Intent(ACTION_OCR), 0)
|
|
||||||
}
|
|
||||||
val services = resolveList.mapNotNull { it.serviceInfo }
|
|
||||||
Log.i(TAG, "discover: services=${services.size}")
|
Log.i(TAG, "discover: services=${services.size}")
|
||||||
return services.map { svc ->
|
return services.map { svc ->
|
||||||
Log.i(TAG, "discover: ${svc.packageName}/${svc.name}")
|
Log.i(TAG, "discover: ${svc.packageName}/${svc.name}")
|
||||||
val info = runCatching { withService(context, svc, DEFAULT_BIND_TIMEOUT_MS) { it.getInfo() } }
|
val result = runCatching { withService(context, svc, DEFAULT_BIND_TIMEOUT_MS) { it.getInfo() } }
|
||||||
.onFailure { e -> Log.w(TAG, "getInfo failed: ${e.message}") }
|
val info = result.getOrNull()
|
||||||
.getOrNull()
|
val error = result.exceptionOrNull()
|
||||||
Discovered(svc, info)
|
if (error != null) {
|
||||||
|
Log.w(TAG, "getInfo failed: ${error.message}")
|
||||||
|
}
|
||||||
|
Discovered(svc, info, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun probe(context: Context, packageName: String): PluginInfo {
|
||||||
|
val serviceInfo = queryOcrServices(context, packageName).firstOrNull()
|
||||||
|
?: error("No OCR service found for package: $packageName")
|
||||||
|
return withService(context, serviceInfo, DEFAULT_BIND_TIMEOUT_MS) { it.getInfo() }
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun recognizeText(
|
suspend fun recognizeText(
|
||||||
context: Context,
|
context: Context,
|
||||||
target: Discovered,
|
target: Discovered,
|
||||||
@@ -141,6 +152,40 @@ object PaddleOcrPluginHost {
|
|||||||
return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY)
|
return ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun queryOcrServices(context: Context, packageName: String? = null): List<ServiceInfo> {
|
||||||
|
val pm = context.packageManager
|
||||||
|
val intent = Intent(ACTION_OCR).apply {
|
||||||
|
if (!packageName.isNullOrBlank()) {
|
||||||
|
setPackage(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val resolveList = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
pm.queryIntentServices(intent, PackageManager.ResolveInfoFlags.of(0))
|
||||||
|
} else {
|
||||||
|
pm.queryIntentServices(intent, 0)
|
||||||
|
}
|
||||||
|
return resolveList.mapNotNull { it.serviceInfo }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildBindFlags(serviceInfo: ServiceInfo): Int {
|
||||||
|
var flags = Context.BIND_AUTO_CREATE
|
||||||
|
if (externalServiceFlag != 0 && bindExternalServiceFlag != 0 && (serviceInfo.flags and externalServiceFlag) != 0) {
|
||||||
|
flags = flags or bindExternalServiceFlag
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildBindFailureMessage(context: Context, serviceInfo: ServiceInfo, cn: ComponentName, reason: String? = null): String {
|
||||||
|
val pm = context.packageManager
|
||||||
|
val perm = serviceInfo.permission
|
||||||
|
val hasPerm = perm.isNullOrBlank() || pm.checkPermission(perm, context.packageName) == PackageManager.PERMISSION_GRANTED
|
||||||
|
val appInfo = serviceInfo.applicationInfo
|
||||||
|
val appStopped = (appInfo.flags and ApplicationInfo.FLAG_STOPPED) != 0
|
||||||
|
val isExternal = externalServiceFlag != 0 && (serviceInfo.flags and externalServiceFlag) != 0
|
||||||
|
val reasonText = reason?.let { " | reason=$it" } ?: ""
|
||||||
|
return "bindService failed: $cn. exported=${serviceInfo.exported} enabled=${serviceInfo.enabled} appEnabled=${appInfo.enabled} stopped=$appStopped perm=$perm hasPerm=$hasPerm external=$isExternal flags=0x${Integer.toHexString(serviceInfo.flags)}$reasonText"
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun <T> withService(
|
private suspend fun <T> withService(
|
||||||
context: Context,
|
context: Context,
|
||||||
serviceInfo: ServiceInfo,
|
serviceInfo: ServiceInfo,
|
||||||
@@ -180,9 +225,10 @@ object PaddleOcrPluginHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ok = try {
|
val bindFlags = buildBindFlags(serviceInfo)
|
||||||
|
var ok = try {
|
||||||
Log.i(TAG, "bindService: $cn")
|
Log.i(TAG, "bindService: $cn")
|
||||||
appCtx.bindService(intent, conn, Context.BIND_AUTO_CREATE)
|
appCtx.bindService(intent, conn, bindFlags)
|
||||||
} catch (se: SecurityException) {
|
} catch (se: SecurityException) {
|
||||||
Log.e(TAG, "bindService SecurityException: $cn | ${se.message}")
|
Log.e(TAG, "bindService SecurityException: $cn | ${se.message}")
|
||||||
cont.resumeWith(
|
cont.resumeWith(
|
||||||
@@ -194,9 +240,25 @@ object PaddleOcrPluginHost {
|
|||||||
)
|
)
|
||||||
return@suspendCancellableCoroutine
|
return@suspendCancellableCoroutine
|
||||||
}
|
}
|
||||||
|
if (!ok && bindFlags != Context.BIND_AUTO_CREATE) {
|
||||||
|
ok = try {
|
||||||
|
appCtx.bindService(intent, conn, Context.BIND_AUTO_CREATE)
|
||||||
|
} catch (se: SecurityException) {
|
||||||
|
Log.e(TAG, "bindService SecurityException: $cn | ${se.message}")
|
||||||
|
cont.resumeWith(
|
||||||
|
Result.failure(
|
||||||
|
IllegalStateException(
|
||||||
|
"bindService SecurityException: $cn. Please make sure the plugin declares <uses-permission android:name=\"org.autojs.permission.PLUGIN\"/> and the Service uses this permission.", se
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return@suspendCancellableCoroutine
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
Log.e(TAG, "bindService failed: $cn")
|
val msg = buildBindFailureMessage(appCtx, serviceInfo, cn)
|
||||||
cont.resumeWith(Result.failure(IllegalStateException("bindService failed: $cn")))
|
Log.e(TAG, msg)
|
||||||
|
cont.resumeWith(Result.failure(IllegalStateException(msg)))
|
||||||
return@suspendCancellableCoroutine
|
return@suspendCancellableCoroutine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1333,4 +1333,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">لم يتم حفظ الاعدادات. هل تريد الخروج?</string>
|
<string name="warn_exit_without_saving_settings">لم يتم حفظ الاعدادات. هل تريد الخروج?</string>
|
||||||
<string name="error_failed_to_save">فشل الحفظ</string>
|
<string name="error_failed_to_save">فشل الحفظ</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">جارٍ الحفظ...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">جارٍ الحفظ...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">فشل في تفعيل الاضافة</string>
|
||||||
|
<string name="text_exception_info">معلومات الاستثناء</string>
|
||||||
|
<string name="text_hint">تلميح</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">جرّب الضغط على زر \"تفعيل\" لتفعيل الاضافة مرة واحدة.\nاذا نجح التفعيل، فسيتم تشغيل الزر تلقائيا خلال فترة زمنية معينة.</string>
|
||||||
|
<string name="dialog_button_activate">تفعيل</string>
|
||||||
|
<string name="text_activated_successfully">تم التفعيل بنجاح</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1328,4 +1328,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">The settings has not been saved, are you sure to exit?</string>
|
<string name="warn_exit_without_saving_settings">The settings has not been saved, are you sure to exit?</string>
|
||||||
<string name="error_failed_to_save">Failed to save</string>
|
<string name="error_failed_to_save">Failed to save</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">Saving...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">Saving...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">Failed to enable the plugin</string>
|
||||||
|
<string name="text_exception_info">Exception info</string>
|
||||||
|
<string name="text_hint">Hint</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">Try clicking the \"Activate\" button to activate the plugin once.\nIf activation is successful, the button will automatically turn on within a certain period of time.</string>
|
||||||
|
<string name="dialog_button_activate">Activate</string>
|
||||||
|
<string name="text_activated_successfully">Activated successfully</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1331,4 +1331,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">La configuracion no se ha guardado. ¿Seguro que quieres salir?</string>
|
<string name="warn_exit_without_saving_settings">La configuracion no se ha guardado. ¿Seguro que quieres salir?</string>
|
||||||
<string name="error_failed_to_save">Error al guardar</string>
|
<string name="error_failed_to_save">Error al guardar</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">Guardando...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">Guardando...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">No se pudo activar el plugin</string>
|
||||||
|
<string name="text_exception_info">Info de la excepcion</string>
|
||||||
|
<string name="text_hint">Sugerencia</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">Prueba a pulsar el boton \"Activar\" para activar el plugin una vez.\nSi la activacion se realiza correctamente, el boton se activara automaticamente en un periodo de tiempo.</string>
|
||||||
|
<string name="dialog_button_activate">Activar</string>
|
||||||
|
<string name="text_activated_successfully">Activado correctamente</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1331,4 +1331,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">Les parametres ne sont pas enregistres. Quitter?</string>
|
<string name="warn_exit_without_saving_settings">Les parametres ne sont pas enregistres. Quitter?</string>
|
||||||
<string name="error_failed_to_save">Echec de l\'enregistrement</string>
|
<string name="error_failed_to_save">Echec de l\'enregistrement</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">Enregistrement...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">Enregistrement...</string>
|
||||||
|
<string name="symbol_colon_with_blank">" : "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">Echec de l\'activation du plugin</string>
|
||||||
|
<string name="text_exception_info">Infos de l\'exception</string>
|
||||||
|
<string name="text_hint">Astuce</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">Essayez d\'appuyer sur le bouton \"Activer\" pour activer le plugin une fois.\nSi l\'activation reussit, le bouton s\'activera automatiquement dans un certain delai.</string>
|
||||||
|
<string name="dialog_button_activate">Activer</string>
|
||||||
|
<string name="text_activated_successfully">Activation reussie</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1332,4 +1332,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">設定が保存されていません. 終了しますか?</string>
|
<string name="warn_exit_without_saving_settings">設定が保存されていません. 終了しますか?</string>
|
||||||
<string name="error_failed_to_save">保存に失敗しました</string>
|
<string name="error_failed_to_save">保存に失敗しました</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">保存中...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">保存中...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">プラグインの有効化に失敗しました</string>
|
||||||
|
<string name="text_exception_info">例外情報</string>
|
||||||
|
<string name="text_hint">ヒント</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">\"有効化\" ボタンをタップして, プラグインを一度有効化してみてください.\n有効化に成功すると, 一定時間内にボタンが自動的にオンになります.</string>
|
||||||
|
<string name="dialog_button_activate">有効化</string>
|
||||||
|
<string name="text_activated_successfully">有効化しました</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1333,4 +1333,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">설정이 저장되지 않았습니다. 종료할까요?</string>
|
<string name="warn_exit_without_saving_settings">설정이 저장되지 않았습니다. 종료할까요?</string>
|
||||||
<string name="error_failed_to_save">저장에 실패했습니다</string>
|
<string name="error_failed_to_save">저장에 실패했습니다</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">저장 중...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">저장 중...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">플러그인을 활성화하지 못했습니다</string>
|
||||||
|
<string name="text_exception_info">예외 정보</string>
|
||||||
|
<string name="text_hint">힌트</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">\"활성화\" 버튼을 눌러 플러그인을 한 번 활성화해 보세요.\n활성화에 성공하면 일정 시간 내에 버튼이 자동으로 켜집니다.</string>
|
||||||
|
<string name="dialog_button_activate">활성화</string>
|
||||||
|
<string name="text_activated_successfully">활성화되었습니다</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1331,4 +1331,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">Настройки не сохранены. Выйти?</string>
|
<string name="warn_exit_without_saving_settings">Настройки не сохранены. Выйти?</string>
|
||||||
<string name="error_failed_to_save">Не удалось сохранить</string>
|
<string name="error_failed_to_save">Не удалось сохранить</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">Сохранение...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">Сохранение...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">Не удалось включить плагин</string>
|
||||||
|
<string name="text_exception_info">Сведения об исключении</string>
|
||||||
|
<string name="text_hint">Подсказка</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">Попробуйте нажать кнопку \"Активировать\", чтобы активировать плагин один раз.\nЕсли активация пройдет успешно, кнопка автоматически включится в течение некоторого времени.</string>
|
||||||
|
<string name="dialog_button_activate">Активировать</string>
|
||||||
|
<string name="text_activated_successfully">Активация выполнена</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1327,4 +1327,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">設置尚未保存, 確定要退出嗎</string>
|
<string name="warn_exit_without_saving_settings">設置尚未保存, 確定要退出嗎</string>
|
||||||
<string name="error_failed_to_save">保存失敗</string>
|
<string name="error_failed_to_save">保存失敗</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">正在保存...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">正在保存...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">插件啓用失敗</string>
|
||||||
|
<string name="text_exception_info">異常信息</string>
|
||||||
|
<string name="text_hint">提示</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">可嘗試點擊 \"激活\" 按鈕激活一次插件.\n如激活成功, 按鈕將在一定時間內自動開啓.</string>
|
||||||
|
<string name="dialog_button_activate">激活</string>
|
||||||
|
<string name="text_activated_successfully">激活成功</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1327,4 +1327,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">設定尚未儲存, 確定要退出嗎</string>
|
<string name="warn_exit_without_saving_settings">設定尚未儲存, 確定要退出嗎</string>
|
||||||
<string name="error_failed_to_save">儲存失敗</string>
|
<string name="error_failed_to_save">儲存失敗</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">正在儲存...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">正在儲存...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">外掛啟用失敗</string>
|
||||||
|
<string name="text_exception_info">異常資訊</string>
|
||||||
|
<string name="text_hint">提示</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">可嘗試點選 \"啟用\" 按鈕啟用一次外掛.\n如啟用成功, 按鈕將在一定時間內自動開啟.</string>
|
||||||
|
<string name="dialog_button_activate">啟用</string>
|
||||||
|
<string name="text_activated_successfully">啟用成功</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1328,4 +1328,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">设置尚未保存, 确定要退出吗</string>
|
<string name="warn_exit_without_saving_settings">设置尚未保存, 确定要退出吗</string>
|
||||||
<string name="error_failed_to_save">保存失败</string>
|
<string name="error_failed_to_save">保存失败</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">正在保存...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">正在保存...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">插件启用失败</string>
|
||||||
|
<string name="text_exception_info">异常信息</string>
|
||||||
|
<string name="text_hint">提示</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">可尝试点击 \"激活\" 按钮激活一次插件.\n如激活成功, 按钮将在一定时间内自动开启.</string>
|
||||||
|
<string name="dialog_button_activate">激活</string>
|
||||||
|
<string name="text_activated_successfully">激活成功</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1602,4 +1602,11 @@
|
|||||||
<string name="warn_exit_without_saving_settings">The settings has not been saved, are you sure to exit?</string>
|
<string name="warn_exit_without_saving_settings">The settings has not been saved, are you sure to exit?</string>
|
||||||
<string name="error_failed_to_save">Failed to save</string>
|
<string name="error_failed_to_save">Failed to save</string>
|
||||||
<string name="text_saving" tools:ignore="TypographyEllipsis">Saving...</string>
|
<string name="text_saving" tools:ignore="TypographyEllipsis">Saving...</string>
|
||||||
|
<string name="symbol_colon_with_blank">": "</string>
|
||||||
|
<string name="error_failed_to_enable_the_plugin">Failed to enable the plugin</string>
|
||||||
|
<string name="text_exception_info">Exception info</string>
|
||||||
|
<string name="text_hint">Hint</string>
|
||||||
|
<string name="hint_try_clicking_the_activate_button_to_activate_the_plugin">Try clicking the \"Activate\" button to activate the plugin once.\nIf activation is successful, the button will automatically turn on within a certain period of time.</string>
|
||||||
|
<string name="dialog_button_activate">Activate</string>
|
||||||
|
<string name="text_activated_successfully">Activated successfully</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#Thu Feb 12 21:05:03 CST 2026
|
#Fri Feb 13 15:23:40 CST 2026
|
||||||
BUILD_TIME=1770901503083
|
BUILD_TIME=1770967420765
|
||||||
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=3735
|
VERSION_BUILD=3738
|
||||||
VERSION_NAME=6.7.0 Alpha19
|
VERSION_NAME=6.7.0 Alpha20
|
||||||
VSCODE_EXT_REQUIRED_VERSION=1.0.13
|
VSCODE_EXT_REQUIRED_VERSION=1.0.13
|
||||||
|
|||||||
Reference in New Issue
Block a user