6.7.0 - Alpha17 - 设置页面增加 "屏幕捕获权限申请延迟" 设置选项; 设置页面设置选项更多菜单增加 "了解更多" 菜单项

This commit is contained in:
SuperMonster003
2026-01-20 18:40:23 +08:00
parent 068f8473e7
commit 082f5c0129
25 changed files with 451 additions and 77 deletions

View File

@@ -63,6 +63,18 @@ object Pref {
@JvmStatic
fun get(): SharedPreferences = sPref
@JvmStatic
val screenCaptureRequestDelay: Int
get() {
// Default 350ms is a practical value for most ROMs' permission dialog fade-out animation.
// zh-CN: 默认 350ms 通常可覆盖多数 ROM 授权弹窗的渐隐动画时间.
val defValue = resources.getInteger(R.integer.screen_capture_request_delay_default_value)
val minValue = resources.getInteger(R.integer.screen_capture_request_delay_min_value)
val maxValue = resources.getInteger(R.integer.screen_capture_request_delay_max_value)
val value = getInt(R.string.key_screen_capture_request_delay, defValue)
return value.coerceIn(minValue, maxValue)
}
@JvmStatic
val isExtendingJsBuildInObjectsEnabled
get() = getBoolean(

View File

@@ -12,6 +12,7 @@ import android.media.Image;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Base64;
import android.util.Log;
import android.view.Gravity;
@@ -31,6 +32,7 @@ import org.autojs.autojs.core.image.capture.ScreenCapturerForegroundService;
import org.autojs.autojs.core.opencv.Mat;
import org.autojs.autojs.core.opencv.OpenCVHelper;
import org.autojs.autojs.core.pref.Language;
import org.autojs.autojs.core.pref.Pref;
import org.autojs.autojs.core.ui.inflater.util.Drawables;
import org.autojs.autojs.extension.AnyExtensions;
import org.autojs.autojs.pio.UncheckedIOException;
@@ -101,6 +103,13 @@ public class Images {
private static final String TAG = Images.class.getSimpleName();
private static volatile boolean sOpenCvInitialized;
// Gate first captures/frames until this time.
// zh-CN: 在该时间点之前, 首次截图/异步帧回调将被延迟或丢弃, 以避开授权弹窗渐隐动画.
private volatile long mScreenCaptureReadyUptimeMillis = 0L;
private final int mScreenCaptureRequestDelayMin;
private final int mScreenCaptureRequestDelayMax;
@ScriptVariable
public final RhinoColorFinder colorFinder;
@@ -115,6 +124,8 @@ public class Images {
public Images(Context context, ScriptRuntime scriptRuntime) {
mContext = context;
mScreenCaptureRequestDelayMin = context.getResources().getInteger(R.integer.screen_capture_request_delay_min_value);
mScreenCaptureRequestDelayMax = context.getResources().getInteger(R.integer.screen_capture_request_delay_max_value);
mScreenMetrics = scriptRuntime.getScreenMetrics();
mScriptRuntime = scriptRuntime;
this.colorFinder = new RhinoColorFinder(mScreenMetrics);
@@ -246,6 +257,16 @@ public class Images {
);
mScreenCapturer = new ScreenCapturer(mContext, intent, options, handler);
mScreenCapturer.setImageCaptureCallback(mOnScreenCaptureAvailableListener);
int delayMs = Pref.getScreenCaptureRequestDelay();
if (delayMs < mScreenCaptureRequestDelayMin) delayMs = mScreenCaptureRequestDelayMin;
if (delayMs > mScreenCaptureRequestDelayMax) delayMs = mScreenCaptureRequestDelayMax;
mScreenCaptureReadyUptimeMillis = SystemClock.uptimeMillis() + delayMs;
// @Caution by JetBrains AI Assistant (GPT-5.2) on Jan 19, 2025.
// ! Resolve immediately to avoid breaking ResultAdapter.wait semantics.
// ! zh-CN: 必须立即 resolve, 避免破坏 ResultAdapter.wait 的语义/线程模型.
promiseAdapter.resolve(true);
} catch (SecurityException ex) {
promiseAdapter.reject(ex);
@@ -271,6 +292,17 @@ public class Images {
throw new SecurityException(mContext.getString(R.string.error_no_screen_capture_permission));
}
// Delay first capture to skip the permission dialog fade-out animation.
// zh-CN: 延迟首次取帧, 跳过授权弹窗渐隐动画.
long waitMs = mScreenCaptureReadyUptimeMillis - SystemClock.uptimeMillis();
if (waitMs > 0) {
try {
Thread.sleep(waitMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// Retry in Java side to avoid leaking transient null frames to JS.
// zh-CN: 在 Java 层做重试, 避免把短暂的 null 帧暴露给 JS 层.
Image capture = null;
@@ -613,12 +645,28 @@ public class Images {
return ImageWrapper.ofBitmap(mScriptRuntime, invertedBitmap);
}
public void setImageCaptureCallback(OnScreenCaptureAvailableListener onScreenCaptureAvailableListener) {
mOnScreenCaptureAvailableListener = new ScreenCaptureAvailableHandler(mScriptRuntime, imageWrapper -> {
// Drop early frames before ready time.
// zh-CN: ready 时间点之前的帧直接丢弃, 避免把授权弹窗渐隐截入异步回调.
if (SystemClock.uptimeMillis() < mScreenCaptureReadyUptimeMillis) return;
onScreenCaptureAvailableListener.onCaptureAvailable(imageWrapper);
});
if (mScreenCapturer != null) {
mScreenCapturer.setImageCaptureCallback(mOnScreenCaptureAvailableListener);
}
}
public void releaseScreenCapturer() {
synchronized (this) {
if (mScreenCapturer != null) {
mScreenCapturer.release();
mScreenCapturer = null;
}
// Reset gate.
// zh-CN: 重置延迟门闩.
mScreenCaptureReadyUptimeMillis = 0L;
if (mPreCapture != null) {
mPreCapture.close();
mPreCapture = null;
@@ -777,13 +825,6 @@ public class Images {
}
}
public void setImageCaptureCallback(OnScreenCaptureAvailableListener onScreenCaptureAvailableListener) {
mOnScreenCaptureAvailableListener = new ScreenCaptureAvailableHandler(mScriptRuntime, onScreenCaptureAvailableListener);
if (mScreenCapturer != null) {
mScreenCapturer.setImageCaptureCallback(mOnScreenCaptureAvailableListener);
}
}
public static void shoot(Shootable<?>... shootableArgs) {
Arrays.stream(shootableArgs).filter(Objects::nonNull).forEach(Shootable::shoot);
}

View File

@@ -5,6 +5,7 @@ import android.os.Bundle
import android.text.TextUtils
import android.util.AttributeSet
import com.afollestad.materialdialogs.MaterialDialog
import org.autojs.autojs.app.DialogUtils.showAdaptive
import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs.extension.MaterialDialogExtensions.choiceWidgetThemeColor
import org.autojs.autojs.extension.MaterialDialogExtensions.widgetThemeColor
@@ -103,18 +104,44 @@ open class MaterialListPreference : MaterialDialogPreference {
}
return@itemsCallbackSingleChoice true
}
val options = mutableListOf<MaterialDialog.OptionMenuItemSpec>()
if (defaultEntry != null) {
builder.options(
listOf(
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_use_default)) { dialog ->
dialog.selectedIndex = itemDefaultIndex
},
)
)
options += MaterialDialog.OptionMenuItemSpec(prefContext.getString(R.string.dialog_button_use_default), ::useDefaultOptionMenuItemSpecOnClickListener)
}
if (longClickPrompt != null) {
options += MaterialDialog.OptionMenuItemSpec(prefContext.getString(R.string.dialog_button_details), ::detailsOptionMenuItemSpecOnClickListener)
}
builder.options(options)
}
}
open fun useDefaultOptionMenuItemSpecOnClickListener(dialog: MaterialDialog) {
dialog.selectedIndex = itemDefaultIndex
}
open fun detailsOptionMenuItemSpecOnClickListener(dialog: MaterialDialog) {
MaterialDialog.Builder(prefContext)
.title(dialogTitle ?: prefContext.getString(R.string.text_details))
.content(longClickPrompt ?: "")
.also { builder ->
longClickPromptMore?.let { longClickPromptMore ->
builder.neutralText(R.string.dialog_button_more)
builder.neutralColorRes(R.color.dialog_button_hint)
builder.onNeutral { _, _ ->
MaterialDialog.Builder(prefContext)
.title(R.string.text_details)
.content(longClickPromptMore)
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
.showAdaptive()
}
}
}
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
.showAdaptive()
}
private fun getKeyIndex(keyString: CharSequence?): Int? {
return keyString?.run { mItemKeys.indexOf(this).takeIf { it != -1 } }
}

View File

@@ -2,7 +2,6 @@ package org.autojs.autojs.ui.settings
import android.content.Context
import android.util.AttributeSet
import android.view.View
import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import org.autojs.autojs.theme.preference.MaterialListPreference
@@ -51,14 +50,11 @@ class RestartStrategyPreference : MaterialListPreference {
d.dismiss()
}
}
builder.options(
listOf(
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_use_default)) { dialog ->
dialog.selectedIndex = itemDefaultIndex
dialog.configureNeutralButton()
},
)
)
}
override fun useDefaultOptionMenuItemSpecOnClickListener(dialog: MaterialDialog) {
dialog.selectedIndex = itemDefaultIndex
dialog.configureNeutralButton()
}
private fun MaterialDialog.Builder.configureNeutralButton() {

View File

@@ -65,17 +65,21 @@ class ScheduledRestartSettingsDialogBuilder(context: Context) : MaterialDialog.B
title(R.string.entry_restart_strategy_scheduled)
customView(binding.root, false)
options(listOf(MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_use_default)) {
when (key(R.string.default_key_scheduled_restart_backend)) {
key(R.string.key_scheduled_restart_backend_alarm_manager) -> {
mOptionAlarmManager.isChecked = true
}
else -> {
mOptionWorkManager.isChecked = true
}
}
mSeekBar.progress = (context.resources.getInteger(R.integer.scheduled_restart_start_delay_default_value) - mStartDelayMinValue) / 100
}))
options(
listOf(
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_use_default)) {
when (key(R.string.default_key_scheduled_restart_backend)) {
key(R.string.key_scheduled_restart_backend_alarm_manager) -> {
mOptionAlarmManager.isChecked = true
}
else -> {
mOptionWorkManager.isChecked = true
}
}
mSeekBar.progress = (context.resources.getInteger(R.integer.scheduled_restart_start_delay_default_value) - mStartDelayMinValue) / 100
},
),
)
negativeText(R.string.dialog_button_cancel)
negativeColorRes(R.color.dialog_button_default)
onNegative { d, _ -> d.dismiss() }

View File

@@ -0,0 +1,96 @@
package org.autojs.autojs.ui.settings
import android.content.Context
import android.content.DialogInterface
import android.view.LayoutInflater
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import com.afollestad.materialdialogs.MaterialDialog
import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs.theme.widget.ThemeColorSeekBar
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.DialogScreenCaptureRequestDelaySettingsBinding
import kotlin.properties.Delegates
class ScreenCaptureRequestDelayDialogBuilder(context: Context, onChangeConfirmed: () -> Unit = {}) : MaterialDialog.Builder(context), OnSeekBarChangeListener {
private var _binding: DialogScreenCaptureRequestDelaySettingsBinding? = null
private val binding: DialogScreenCaptureRequestDelaySettingsBinding get() = _binding!!
private var mScreenCaptureRequestDelayTitlePrefix: String
private var mScreenCaptureRequestDelayTitle: String
private var mStartDelayMinValue by Delegates.notNull<Int>()
private var mStartDelayMaxValue by Delegates.notNull<Int>()
private var mSeekBar: ThemeColorSeekBar
init {
var initialRestartDelayValue = Pref.getInt(R.string.key_screen_capture_request_delay, context.resources.getInteger(R.integer.screen_capture_request_delay_default_value))
_binding = DialogScreenCaptureRequestDelaySettingsBinding.inflate(LayoutInflater.from(context)).also { binding ->
mScreenCaptureRequestDelayTitlePrefix = context.getString(R.string.text_delay_time)
mScreenCaptureRequestDelayTitle = "$mScreenCaptureRequestDelayTitlePrefix: ${initialRestartDelayValue}ms"
mStartDelayMinValue = context.resources.getInteger(R.integer.screen_capture_request_delay_min_value).also {
binding.requestScreenCaptureDelayMinValue.text = "$it"
}
mStartDelayMaxValue = context.resources.getInteger(R.integer.screen_capture_request_delay_max_value).also {
binding.requestScreenCaptureDelayMaxValue.text = "$it"
}
mSeekBar = binding.seekBar
}
mSeekBar.setOnSeekBarChangeListener(this)
mSeekBar.max = (mStartDelayMaxValue - mStartDelayMinValue) / 50
mSeekBar.progress = (initialRestartDelayValue - mStartDelayMinValue) / 50
title(R.string.text_screen_capture_request_delay)
customView(binding.root, false)
options(
listOf(
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_use_default)) {
mSeekBar.progress = (context.resources.getInteger(R.integer.screen_capture_request_delay_default_value) - mStartDelayMinValue) / 50
},
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_details)) {
MaterialDialog.Builder(context)
.title(R.string.text_screen_capture_request_delay)
.content(R.string.description_screen_capture_request_delay)
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
.show()
},
),
)
negativeText(R.string.dialog_button_cancel)
negativeColorRes(R.color.dialog_button_default)
onNegative { d, _ -> d.dismiss() }
positiveText(R.string.dialog_button_confirm)
positiveColorRes(R.color.dialog_button_attraction)
onPositive { d, _ ->
Pref.putInt(R.string.key_screen_capture_request_delay, mStartDelayMinValue + mSeekBar.progress * 50)
onChangeConfirmed()
d.dismiss()
}
autoDismiss(false)
}
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
binding.requestScreenCaptureDelayTitle.text = context.getString(R.string.text_property_colon_value_unit, mScreenCaptureRequestDelayTitlePrefix, mStartDelayMinValue + progress * 50, "ms")
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
/* Ignored. */
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
/* Ignored. */
}
override fun dismissListener(listener: DialogInterface.OnDismissListener): MaterialDialog.Builder? {
_binding = null
return super.dismissListener(listener)
}
}

View File

@@ -0,0 +1,54 @@
package org.autojs.autojs.ui.settings
import android.content.Context
import android.util.AttributeSet
import com.afollestad.materialdialogs.MaterialDialog
import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs.theme.preference.MaterialPreference
import org.autojs.autojs6.R
/**
* Created by SuperMonster003 on Jan 19, 2026.
*/
class ScreenCaptureRequestDelayPreference : MaterialPreference {
private var dialog: MaterialDialog? = null
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context) : super(context)
init {
summaryProvider = SummaryProvider<ScreenCaptureRequestDelayPreference> {
prefContext.getString(
R.string.text_property_colon_value_unit,
prefContext.getString(R.string.text_delay_time),
Pref.screenCaptureRequestDelay,
"ms",
)
}
}
override fun onClick() {
run {
if (dialog?.isShowing == true) {
return@run
}
dialog = ScreenCaptureRequestDelayDialogBuilder(prefContext) {
notifyChanged()
}.show()
}
super.onClick()
}
override fun onDetached() {
dialog?.dismiss()
dialog = null
super.onDetached()
}
}

View File

@@ -17,6 +17,7 @@ import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.autojs.autojs.app.DialogUtils
import org.autojs.autojs.app.DialogUtils.showAdaptive
import org.autojs.autojs.storage.file.FileObservable
import org.autojs.autojs.theme.ThemeColorHelper
import org.autojs.autojs.theme.preference.MaterialPreference
@@ -48,7 +49,7 @@ class WorkingDirectoryPreference : MaterialPreference {
}
override fun onClick() {
WorkingDirectoryDialogBuilder().show()
WorkingDirectoryDialogBuilder().showAdaptive()
super.onClick()
}
@@ -67,13 +68,39 @@ class WorkingDirectoryPreference : MaterialPreference {
build()
}
override fun build(): MaterialDialog = MaterialDialog.Builder(context)
override fun build(): MaterialDialog = MaterialDialog.Builder(prefContext)
.title(R.string.text_working_dir_path)
.options(
listOf(
MaterialDialog.OptionMenuItemSpec(prefContext.getString(R.string.dialog_button_use_default)) {
val paths = WorkingDirectoryUtils.getRecommendedDefaultPaths()
when (paths.size) {
1 -> mContentView.setText(paths.first())
else -> MaterialDialog.Builder(prefContext)
.title(R.string.text_multiple_options)
.items(paths)
.itemsCallback { _, _, _, text ->
mContentView.setText(text)
}
.negativeText(R.string.dialog_button_back)
.showAdaptive()
}
},
MaterialDialog.OptionMenuItemSpec(prefContext.getString(R.string.dialog_button_details)) {
MaterialDialog.Builder(prefContext)
.title(R.string.text_working_dir_path)
.content(R.string.description_change_working_dir_preference)
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
.showAdaptive()
},
)
)
.customView(R.layout.pref_working_directory, false)
.neutralText(R.string.dialog_button_history)
.neutralColorRes(R.color.dialog_button_hint)
.onNeutral { _, _ ->
MaterialDialog.Builder(context)
MaterialDialog.Builder(prefContext)
.title(R.string.text_histories)
.content(R.string.text_no_histories)
.items(WorkingDirectoryUtils.histories)
@@ -83,7 +110,7 @@ class WorkingDirectoryPreference : MaterialPreference {
}
.itemsLongCallback { dHistories, _, _, text ->
false.also {
MaterialDialog.Builder(context)
MaterialDialog.Builder(prefContext)
.title(R.string.text_prompt)
.content(R.string.text_confirm_to_delete)
.negativeText(R.string.dialog_button_cancel)
@@ -98,35 +125,14 @@ class WorkingDirectoryPreference : MaterialPreference {
DialogUtils.toggleContentViewByItems(dHistories)
}
}
.show()
}
}
.neutralText(R.string.dialog_button_use_default)
.neutralColorRes(R.color.dialog_button_reset)
.onNeutral { dHistories, _ ->
val paths = WorkingDirectoryUtils.getRecommendedDefaultPaths()
if (paths.size == 1) {
mContentView.setText(paths.first())
dHistories.dismiss()
} else {
MaterialDialog.Builder(context)
.title(R.string.text_multiple_options)
.items(paths)
.itemsCallback { _, _, _, text ->
true.also {
dHistories.dismiss()
mContentView.setText(text)
}
}
.negativeText(R.string.dialog_button_back)
.show()
.showAdaptive()
}
}
.negativeText(R.string.dialog_button_back)
.negativeColorRes(R.color.dialog_button_default)
.onNegative { dHistories, _ -> dHistories.dismiss() }
.autoDismiss(false)
.show()
.showAdaptive()
.also { DialogUtils.toggleContentViewByItems(it) }
}
.negativeText(R.string.dialog_button_cancel)
@@ -156,10 +162,10 @@ class WorkingDirectoryPreference : MaterialPreference {
setOnClickListener {
val initialDir: String? = try {
File(toFullPath(mContentView.text.toString())).path
} catch (ignore: Exception) {
} catch (_: Exception) {
mPrefFullPath
}
FileChooserDialogBuilder(context)
FileChooserDialogBuilder(prefContext)
.title(R.string.text_working_dir_path)
.dir(mExtStoragePath, initialDir ?: WorkingDirectoryUtils.path)
.chooseDir()
@@ -203,13 +209,13 @@ class WorkingDirectoryPreference : MaterialPreference {
when (mRadioGroupView.checkedRadioButtonId) {
R.id.copy -> fileObservable = FileObservable.copy(srcPath, toFullPath(dstPath))
R.id.move -> fileObservable = FileObservable.move(srcPath, toFullPath(dstPath))
else -> ViewUtils.showToast(context, R.string.error_unknown_operation, true)
else -> ViewUtils.showToast(prefContext, R.string.error_unknown_operation, true)
}
fileObservable?.let { showFileProgressDialog(it) }
}
private fun showFileProgressDialog(observable: Observable<File>) {
val dialog = MaterialDialog.Builder(context)
val dialog = MaterialDialog.Builder(prefContext)
.progress(true, 0)
.progressIndeterminateStyle(true)
.title(R.string.text_in_progress)
@@ -235,14 +241,14 @@ class WorkingDirectoryPreference : MaterialPreference {
override fun onError(e: Throwable) {
e.printStackTrace()
dialog.dismiss()
context.getString(R.string.text_error_copy_file, e.message).let {
ViewUtils.showToast(context, it, true)
prefContext.getString(R.string.text_error_copy_file, e.message).let {
ViewUtils.showToast(prefContext, it, true)
}
}
override fun onComplete() {
dialog.dismiss()
ViewUtils.showToast(context, R.string.text_operation_is_completed)
ViewUtils.showToast(prefContext, R.string.text_operation_is_completed)
}
})
}

View File

@@ -5,6 +5,7 @@ import androidx.appcompat.app.AppCompatActivity
import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import org.autojs.autojs.app.DialogUtils
import org.autojs.autojs.app.DialogUtils.showAdaptive
import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs.core.pref.Pref.isAutoCheckForUpdatesEnabled
import org.autojs.autojs.core.pref.Pref.lastNoNewerUpdatesTimestamp
@@ -27,6 +28,18 @@ object UpdateUtils {
fun manageIgnoredUpdates(context: Context) {
MaterialDialog.Builder(context)
.title(R.string.text_ignored_updates)
.options(
listOf(
MaterialDialog.OptionMenuItemSpec(context.getString(R.string.dialog_button_details)) {
MaterialDialog.Builder(context)
.title(R.string.text_details)
.content(R.string.description_manage_ignored_updates_preference)
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
.showAdaptive()
},
),
)
.content(R.string.text_no_ignored_updates)
.items(ignoredVersions)
.itemsLongCallback { dialog, _, _, text ->
@@ -74,7 +87,7 @@ object UpdateUtils {
}
ViewUtils.showSnack(dialogParent.view, R.string.text_all_items_cleared)
}
.show()
.showAdaptive()
}
.positiveText(R.string.dialog_button_dismiss)
.positiveColorRes(R.color.dialog_button_default)
@@ -85,7 +98,7 @@ object UpdateUtils {
DialogUtils.toggleContentViewByItems(it)
DialogUtils.toggleActionButtonAbilityByItems(it, DialogAction.NEUTRAL)
}
.show()
.showAdaptive()
}
private fun showRemoveIgnoredVersionPrompt(context: Context, dialogHoldingItems: MaterialDialog, dialogPromptParent: MaterialDialog?, text: CharSequence) {
@@ -102,7 +115,7 @@ object UpdateUtils {
DialogUtils.toggleContentViewByItems(dialogHoldingItems)
dialogPromptParent?.dismiss()
}
.show()
.showAdaptive()
}
@JvmStatic

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/request_screen_capture_delay_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginVertical="16dp"
android:text="@string/text_screen_capture_request_delay"
android:textColor="@color/day_night"
android:textSize="16sp" />
<org.autojs.autojs.theme.widget.ThemeColorSeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"
tools:progress="10" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginHorizontal="12dp"
android:layout_marginBottom="4dp">
<TextView
android:id="@+id/request_screen_capture_delay_min_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="0"
android:textSize="16sp" />
<TextView
android:id="@+id/request_screen_capture_delay_max_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:text="3000"
android:textSize="16sp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View File

@@ -1192,5 +1192,10 @@
<string name="error_plugin_returned_invalid_variant">أعاد المكوّن الإضافي %1$s variant غير صالح: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">لم يتم العثور على موارد Paddle OCR المضمّنة. يُرجى إعادة الحزم مع تفعيل Paddle OCR.</string>
<string name="dialog_button_minimize">تصغير</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">تأخير طلب إذن التقاط الشاشة</string>
<string name="description_screen_capture_request_delay">عند طلب إذن التقاط الشاشة، قد تحتوي نافذة طلب الإذن المنبثقة على حركة تلاشي عند اختفائها. إذا تم استدعاء `images.captureScreen` مباشرةً، فقد تتضمن لقطة الشاشة الناتجة محتوى نافذة طلب الإذن مما يسبب حجبًا.\n\nتضيف قيمة هذا الخيار مدة تأخير (بالمللي ثانية) قبل التقاط الشاشة مباشرةً بعد الحصول على الإذن، وذلك لتجنب مشكلة الحجب المذكورة أعلاه.\n\nينطبق هذا الخيار فقط على أول عملية التقاط بعد الحصول على الإذن؛ أما عمليات الالتقاط اللاحقة فلن تتأثر بهذه القيمة.</string>
<string name="text_delay_time">مدة التأخير</string>
</resources>

View File

@@ -1187,5 +1187,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s plugin returned invalid variant: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">No embedded Paddle OCR assets found. Please re-package with Paddle OCR enabled.</string>
<string name="dialog_button_minimize">Minimize</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">Screen capture permission request delay</string>
<string name="description_screen_capture_request_delay">When requesting screen capture permission, the permission request window may include a fade-out animation when it disappears. If `images.captureScreen` is called immediately, the captured screenshot may contain the permission request window content and be obstructed.\n\nThe current option value adds a delay (in milliseconds) before capturing the screen immediately after permission is granted, which can be used to avoid the obstruction issue described above.\n\nThis option only applies to the first screenshot after screen capture permission is granted; subsequent screenshots are not affected by this value.</string>
<string name="text_delay_time">Delay time</string>
</resources>

View File

@@ -1190,5 +1190,10 @@
<string name="error_plugin_returned_invalid_variant">El plugin %1$s devolvió una variante no válida: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">No se encontraron recursos integrados de Paddle OCR. Vuelve a empaquetar con Paddle OCR habilitado.</string>
<string name="dialog_button_minimize">Minimizar</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">Retraso de solicitud del permiso de captura de pantalla</string>
<string name="description_screen_capture_request_delay">Al solicitar el permiso de captura de pantalla, la ventana de solicitud de permiso mostrada puede tener una animación de desvanecimiento al desaparecer. Si se llama a `images.captureScreen` inmediatamente, la captura obtenida puede incluir el contenido de dicha ventana y quedar obstruida.\n\nEl valor de esta opción añade un tiempo de espera (en milisegundos) antes de capturar la pantalla inmediatamente después de obtener el permiso, para evitar el problema de obstrucción descrito.\n\nEsta opción solo se aplica a la primera captura tras obtener el permiso; las capturas posteriores no se verán afectadas por este valor.</string>
<string name="text_delay_time">Tiempo de retraso</string>
</resources>

View File

@@ -1190,5 +1190,10 @@
<string name="error_plugin_returned_invalid_variant">Le plugin %1$s a renvoyé une variante invalide: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">Aucune ressource Paddle OCR intégrée n\'a été trouvée. Veuillez reconditionner avec Paddle OCR activé.</string>
<string name="dialog_button_minimize">Réduire</string>
<string name="text_property_colon_value_unit">%1$s : %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s : %2$d %3$s</string>
<string name="text_screen_capture_request_delay">Délai de demande d\'autorisation de capture d\'écran</string>
<string name="description_screen_capture_request_delay">Lors de la demande d\'autorisation de capture d\'écran, la fenêtre de demande affichée peut comporter une animation de fondu lors de sa disparition. Si `images.captureScreen` est appelé immédiatement, la capture obtenue peut contenir le contenu de cette fenêtre et être partiellement masquée.\n\nLa valeur de cette option ajoute un délai (en millisecondes) avant d\'effectuer la capture juste après l\'obtention de l\'autorisation, afin d\'éviter le problème de masquage ci-dessus.\n\nCette option ne s\'applique qu\'à la première capture après l\'obtention de l\'autorisation ; les captures suivantes ne seront plus affectées par cette valeur.</string>
<string name="text_delay_time">Délai</string>
</resources>

View File

@@ -347,7 +347,7 @@
<string name="instruction_install_plugin_from_url">リモートプラグインの URL を入力してください. \n例: \"https://example.com/plugin.apk\"</string>
<string name="label_latest_used_time">最終使用時: %1$s</string>
<string name="logger_ver_history_blob_thread_failure">\"Blob\" スレッドが失敗</string>
<string name="logger_ver_history_blob_thread_success">\"Blob\" スレッドが成功オフラインキャッシュを書き込み</string>
<string name="logger_ver_history_blob_thread_success">\"Blob\" スレッドが成功, オフラインキャッシュを書き込み</string>
<string name="logger_ver_history_data_loaded">データ読み込み完了</string>
<string name="logger_ver_history_initial_content_chosen">初期コンテンツを選択</string>
<string name="logger_ver_history_insert_new_entries">新しい項目を挿入中</string>
@@ -362,7 +362,7 @@
<string name="logger_ver_history_overwrite_date">日付内容を上書き中</string>
<string name="logger_ver_history_overwrite_update_record">更新履歴を上書き中</string>
<string name="logger_ver_history_raw_thread_failure">\"Raw\" スレッドが失敗</string>
<string name="logger_ver_history_raw_thread_success">\"Raw\" スレッドが成功オフラインキャッシュを書き込み</string>
<string name="logger_ver_history_raw_thread_success">\"Raw\" スレッドが成功, オフラインキャッシュを書き込み</string>
<string name="logger_ver_history_start_blob_thread">\"Blob\" 予備リクエストスレッドを開始</string>
<string name="logger_ver_history_start_raw_thread">\"Raw\" リクエストスレッドを開始</string>
<string name="media_info_album_label">アルバム</string>
@@ -1191,5 +1191,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s プラグインが無効な variant を返しました: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">埋め込みの Paddle OCR assets が見つかりません. Paddle OCR を有効にして再パッケージしてください.</string>
<string name="dialog_button_minimize">最小化</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">画面キャプチャ権限リクエスト遅延</string>
<string name="description_screen_capture_request_delay">画面キャプチャ権限を要求する際, 表示される権限リクエスト画面が閉じるときにフェード等のアニメーションが発生する場合があります. この直後に `images.captureScreen` を呼び出すと, 取得したスクリーンショットに権限リクエスト画面の内容が写り込み, 遮蔽が発生することがあります. \n\nこの設定値は, 権限取得直後に最初のスクリーンショットを取得する前に遅延時間(ミリ秒)を追加し, 上記の遮蔽問題を回避するために使用します. \n\nこの設定は権限取得後の最初のスクリーンショットにのみ適用され, 以降のスクリーンショットには影響しません.</string>
<string name="text_delay_time">遅延時間</string>
</resources>

View File

@@ -1192,5 +1192,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s 플러그인이 잘못된 variant를 반환했습니다: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">내장된 Paddle OCR assets를 찾을 수 없습니다. Paddle OCR을 활성화하여 다시 패키징해 주세요.</string>
<string name="dialog_button_minimize">최소화</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">화면 캡처 권한 요청 지연</string>
<string name="description_screen_capture_request_delay">화면 캡처 권한을 요청할 때 표시되는 권한 요청 창은 사라질 때 페이드 등의 전환 애니메이션이 있을 수 있습니다. 이때 `images.captureScreen` 메서드를 즉시 호출하면, 얻은 스크린샷에 권한 요청 창의 내용이 포함되어 화면이 가려질 수 있습니다.\n\n이 설정 값은 권한을 획득한 직후 첫 스크린샷을 캡처하기 전에 지연 시간(밀리초)을 추가하여, 위와 같은 가림 문제를 방지하는 데 사용할 수 있습니다.\n\n이 설정은 권한 획득 후 첫 번째 캡처에만 적용되며, 이후 캡처에는 더 이상 영향을 주지 않습니다.</string>
<string name="text_delay_time">지연 시간</string>
</resources>

View File

@@ -1190,5 +1190,10 @@
<string name="error_plugin_returned_invalid_variant">Плагин %1$s вернул недопустимый variant: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">Не найдены встроенные ресурсы Paddle OCR. Перепакуйте приложение с включённым Paddle OCR.</string>
<string name="dialog_button_minimize">Свернуть</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">Задержка запроса разрешения на захват экрана</string>
<string name="description_screen_capture_request_delay">При запросе разрешения на захват экрана отображаемое окно запроса может иметь анимацию затухания при исчезновении. Если сразу вызвать `images.captureScreen`, полученный снимок может содержать содержимое этого окна и быть частично перекрыт.\n\nЗначение этой опции добавляет задержку (в миллисекундах) перед выполнением снимка экрана сразу после получения разрешения, что позволяет избежать описанной выше проблемы перекрытия.\n\nЭта опция применяется только к первому снимку после получения разрешения; последующие снимки не будут зависеть от этого значения.</string>
<string name="text_delay_time">Время задержки</string>
</resources>

View File

@@ -1188,5 +1188,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s 插件返回的 variant 無效: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">未找到內置 Paddle OCR 資源, 請在打包時勾選並注入 Paddle OCR 後重試.</string>
<string name="dialog_button_minimize">最小化</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">屏幕捕獲權限申請延遲</string>
<string name="description_screen_capture_request_delay">申請屏幕捕獲權限時, 彈出的權限申請窗口消失時可能存在漸變動畫, 此時如果立即調用 `images.captureScreen` 方法, 獲取的屏幕截圖中會出現權限申請的窗口內容而造成遮擋.\n\n當前設置選項值用於在截圖權限申請後立即獲取屏幕截圖前增加一個延遲時間 (單位為毫秒), 可用於避免上述遮擋問題.\n\n當前設置選項僅適用於獲取截圖權限後的首次截圖操作, 後續截圖操作不再受此設置值影響.</string>
<string name="text_delay_time">延遲時間</string>
</resources>

View File

@@ -1188,5 +1188,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s 外掛返回的 variant 無效: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">未找到內建 Paddle OCR 資源, 請在打包時勾選並注入 Paddle OCR 後重試.</string>
<string name="dialog_button_minimize">最小化</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">螢幕捕獲許可權申請延遲</string>
<string name="description_screen_capture_request_delay">申請螢幕捕獲許可權時, 彈出的許可權申請視窗消失時可能存在漸變動畫, 此時如果立即呼叫 `images.captureScreen` 方法, 獲取的螢幕截圖中會出現許可權申請的視窗內容而造成遮擋.\n\n當前設定選項值用於在截圖許可權申請後立即獲取螢幕截圖前增加一個延遲時間 (單位為毫秒), 可用於避免上述遮擋問題.\n\n當前設定選項僅適用於獲取截圖許可權後的首次截圖操作, 後續截圖操作不再受此設定值影響.</string>
<string name="text_delay_time">延遲時間</string>
</resources>

View File

@@ -1187,6 +1187,11 @@
<string name="error_plugin_returned_empty_info">%1$s 插件返回的 info 为空.</string>
<string name="error_plugin_returned_invalid_variant">%1$s 插件返回的 variant 无效: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">未找到内置 Paddle OCR 资源, 请在打包时勾选并注入 Paddle OCR 后重试.</string>
<string name="dialog_button_minimize">Minimize</string>
<string name="dialog_button_minimize">最小化</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">屏幕捕获权限申请延迟</string>
<string name="description_screen_capture_request_delay">申请屏幕捕获权限时, 弹出的权限申请窗口消失时可能存在渐变动画, 此时如果立即调用 `images.captureScreen` 方法, 获取的屏幕截图中会出现权限申请的窗口内容而造成遮挡.\n\n当前设置选项值用于在截图权限申请后立即获取屏幕截图前增加一个延迟时间 (单位为毫秒), 可用于避免上述遮挡问题.\n\n当前设置选项仅适用于获取截图权限后的首次截图操作, 后续截图操作不再受此设置值影响.</string>
<string name="text_delay_time">延迟时间</string>
</resources>

View File

@@ -35,6 +35,10 @@
<integer name="scheduled_restart_start_delay_max_value">3000</integer>
<integer name="scheduled_restart_start_delay_default_value">300</integer>
<integer name="screen_capture_request_delay_min_value">0</integer>
<integer name="screen_capture_request_delay_max_value">2000</integer>
<integer name="screen_capture_request_delay_default_value">350</integer>
<integer name="date_picker_mode">1</integer>
<integer name="time_picker_mode">1</integer>

View File

@@ -157,6 +157,7 @@
<string name="key_scheduled_restart_backend_alarm_manager" translatable="false">key_$_scheduled_restart_backend_alarm_manager</string>
<string name="key_scheduled_restart_backend_work_manager" translatable="false">key_$_scheduled_restart_backend_work_manager</string>
<string name="key_scheduled_restart_delay" translatable="false">key_$_scheduled_restart_delay</string>
<string name="key_screen_capture_request_delay" translatable="false">key_$_screen_capture_request_delay_ms</string>
<string name="key_scripts_after_app_restart" translatable="false">key_$_scripts_after_app_restart</string>
<string name="key_server_address" translatable="false">key_$_server_address</string>
<string name="key_server_socket_normally_closed" translatable="false">key_$_server_socket_normally_closed</string>
@@ -1445,5 +1446,10 @@
<string name="error_plugin_returned_invalid_variant">%1$s plugin returned invalid variant: %2$s.</string>
<string name="error_no_embedded_paddle_ocr_assets_found">No embedded Paddle OCR assets found. Please re-package with Paddle OCR enabled.</string>
<string name="dialog_button_minimize">Minimize</string>
<string name="text_property_colon_value_unit">%1$s: %2$d%3$s</string>
<string name="text_property_colon_value_nbsp_unit">%1$s: %2$d %3$s</string>
<string name="text_screen_capture_request_delay">Screen capture permission request delay</string>
<string name="description_screen_capture_request_delay">When requesting screen capture permission, the permission request window may include a fade-out animation when it disappears. If `images.captureScreen` is called immediately, the captured screenshot may contain the permission request window content and be obstructed.\n\nThe current option value adds a delay (in milliseconds) before capturing the screen immediately after permission is granted, which can be used to avoid the obstruction issue described above.\n\nThis option only applies to the first screenshot after screen capture permission is granted; subsequent screenshots are not affected by this value.</string>
<string name="text_delay_time">Delay time</string>
</resources>

View File

@@ -187,6 +187,12 @@
app:itemDefaultKey="@string/default_key_root_mode"
app:longClickPrompt="@string/description_root_mode_preference" />
<org.autojs.autojs.ui.settings.ScreenCaptureRequestDelayPreference
app:layout="@layout/preference_custom"
app:key="@string/key_screen_capture_request_delay"
app:title="@string/text_screen_capture_request_delay"
app:longClickPrompt="@string/description_screen_capture_request_delay" />
</org.autojs.autojs.theme.preference.ThemeColorPreferenceCategory>
<org.autojs.autojs.theme.preference.ThemeColorPreferenceCategory