6.6.2 - Alpha7 - 优化 files.path 及相关方法传入空值路径参数时的兼容性

This commit is contained in:
SuperMonster003
2025-04-16 14:43:54 +08:00
parent 325271b060
commit 43d9fa9366
19 changed files with 215 additions and 185 deletions

View File

@@ -16,7 +16,7 @@
"notice 模块缺失 getBuilder 等扩展方法的问题 _[`issue #301`](http://issues.autojs6.com/301)_", "notice 模块缺失 getBuilder 等扩展方法的问题 _[`issue #301`](http://issues.autojs6.com/301)_",
"shizuku/shell 等方法无法接受字符串参数的问题 _[`issue #310`](http://issues.autojs6.com/310)_", "shizuku/shell 等方法无法接受字符串参数的问题 _[`issue #310`](http://issues.autojs6.com/310)_",
"colors.pixel 方法无法接受单通道图像参数的问题 _[`issue #350`](http://issues.autojs6.com/350)_", "colors.pixel 方法无法接受单通道图像参数的问题 _[`issue #350`](http://issues.autojs6.com/350)_",
"engines.execScript/execScriptFile 等方法执行脚本时默认工作路径异常 _[`issue #340`](http://issues.autojs6.com/340)_ _[`issue #339`](http://issues.autojs6.com/339)_", "engines.execScript/execScriptFile 等方法执行脚本时默认工作路径异常 _[`issue #358`](http://issues.autojs6.com/358)_ _[`issue #340`](http://issues.autojs6.com/340)_ _[`issue #339`](http://issues.autojs6.com/339)_",
"floaty.window/floaty.rawWindow 无法在子线程执行的问题", "floaty.window/floaty.rawWindow 无法在子线程执行的问题",
"floaty.getClip 可能无法正常获取剪切板内容的问题 _[`issue #341`](http://issues.autojs6.com/341)_", "floaty.getClip 可能无法正常获取剪切板内容的问题 _[`issue #341`](http://issues.autojs6.com/341)_",
"ui.inflate 返回值丢失 attr/on/click 等原型方法的问题", "ui.inflate 返回值丢失 attr/on/click 等原型方法的问题",
@@ -49,6 +49,7 @@
"尝试恢复 com.stardust 前缀包以便提升代码兼容性 _[`issue #290`](http://issues.autojs6.com/290)_", "尝试恢复 com.stardust 前缀包以便提升代码兼容性 _[`issue #290`](http://issues.autojs6.com/290)_",
"floaty.window/floaty.rawWindow 同时支持主线程和子线程执行", "floaty.window/floaty.rawWindow 同时支持主线程和子线程执行",
"getClip 全局方法适时借助 floaty.getClip 方法以提升兼容性", "getClip 全局方法适时借助 floaty.getClip 方法以提升兼容性",
"files.path 及相关方法传入空值路径参数时的兼容性",
"同步最新的 Rhino 引擎官方上游代码并进行必要的代码适配", "同步最新的 Rhino 引擎官方上游代码并进行必要的代码适配",
"README.md 完善项目构建与运行相关内容 _[`issue #344`](http://issues.autojs6.com/344)_" "README.md 完善项目构建与运行相关内容 _[`issue #344`](http://issues.autojs6.com/344)_"
], ],

View File

@@ -26,7 +26,7 @@ public class Database extends SQLiteOpenHelper implements Closeable {
private final TypeAdapter mTypeAdapter; private final TypeAdapter mTypeAdapter;
public Database(@NonNull Context context, @NonNull ScriptRuntime scriptRuntime, @NonNull String name, int version, boolean readable, @Nullable DatabaseCallback databaseCallback, @NonNull TypeAdapter typeAdapter) { public Database(@NonNull Context context, @NonNull ScriptRuntime scriptRuntime, @NonNull String name, int version, boolean readable, @Nullable DatabaseCallback databaseCallback, @NonNull TypeAdapter typeAdapter) {
super(context, scriptRuntime.files.path(name), null, version, databaseCallback == null ? null : new DatabaseErrorHandlerWrapper(databaseCallback)); super(context, scriptRuntime.files.nonNullPath(name), null, version, databaseCallback == null ? null : new DatabaseErrorHandlerWrapper(databaseCallback));
mTypeAdapter = typeAdapter; mTypeAdapter = typeAdapter;
mCallback = databaseCallback; mCallback = databaseCallback;
mScriptRuntime = scriptRuntime; mScriptRuntime = scriptRuntime;

View File

@@ -50,11 +50,11 @@ open class ImageViewAttributes(scriptRuntime: ScriptRuntime, resourceParser: Res
} }
private fun ScriptRuntime.getPath(s: String, def: String = s): String { private fun ScriptRuntime.getPath(s: String, def: String = s): String {
return if (this.files.exists(s)) this.files.path(s) else def return if (this.files.exists(s)) this.files.nonNullPath(s) else def
} }
private fun ScriptRuntime.getPath(s: String, def: (String) -> String): String { private fun ScriptRuntime.getPath(s: String, def: (String) -> String): String {
return if (this.files.exists(s)) this.files.path(s) else def(s) return if (this.files.exists(s)) this.files.nonNullPath(s) else def(s)
} }
companion object { companion object {

View File

@@ -23,6 +23,7 @@ import java.io.File
import java.net.URL import java.net.URL
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.regex.Pattern import java.util.regex.Pattern
import androidx.core.graphics.drawable.toDrawable
/** /**
* Created by Stardust on Nov 3, 2017. * Created by Stardust on Nov 3, 2017.
@@ -83,7 +84,7 @@ open class Drawables {
} }
open fun decodeImage(context: Context, path: String?): Drawable? { open fun decodeImage(context: Context, path: String?): Drawable? {
return BitmapDrawable(context.resources, BitmapFactory.decodeFile(path)) return BitmapFactory.decodeFile(path)?.toDrawable(context.resources)
} }
fun parse(view: View, name: String) = parse(view.context, name) fun parse(view: View, name: String) = parse(view.context, name)

View File

@@ -133,7 +133,7 @@ object AnyExtensions {
fun Any?.toRuntimePath(scriptRuntime: ScriptRuntime, isStrict: Boolean = false): String { fun Any?.toRuntimePath(scriptRuntime: ScriptRuntime, isStrict: Boolean = false): String {
if (isStrict && this.isJsNullish()) throw IllegalArgumentException(str(R.string.error_cannot_convert_value_into_a_script_runtime_path, this.jsBrief())) if (isStrict && this.isJsNullish()) throw IllegalArgumentException(str(R.string.error_cannot_convert_value_into_a_script_runtime_path, this.jsBrief()))
return scriptRuntime.files.path(coerceString(this, ".")) return scriptRuntime.files.nonNullPath(coerceString(this, "."))
} }
} }

View File

@@ -109,7 +109,7 @@ object PFiles {
@JvmOverloads @JvmOverloads
@JvmStatic @JvmStatic
fun read(file: File?, encoding: String? = "utf-8"): String { fun read(file: File?, encoding: String? = DEFAULT_ENCODING): String {
return try { return try {
read(FileInputStream(file), encoding) read(FileInputStream(file), encoding)
} catch (e: FileNotFoundException) { } catch (e: FileNotFoundException) {
@@ -118,21 +118,19 @@ object PFiles {
} }
@JvmStatic @JvmStatic
fun read(stream: InputStream, encoding: String?): String { @JvmOverloads
fun read(inputStream: InputStream, encoding: String? = DEFAULT_ENCODING): String {
return try { return try {
val bytes = ByteArray(stream.available()) val bytes = ByteArray(inputStream.available())
stream.read(bytes) inputStream.read(bytes)
String(bytes, Charset.forName(encoding)) String(bytes, Charset.forName(encoding))
} catch (e: IOException) { } catch (e: IOException) {
throw UncheckedIOException(e) throw UncheckedIOException(e)
} finally { } finally {
closeSilently(stream) closeSilently(inputStream)
} }
} }
@JvmStatic
fun read(inputStream: InputStream) = read(inputStream, "utf-8")
fun readBytes(stream: InputStream): ByteArray { fun readBytes(stream: InputStream): ByteArray {
return try { return try {
ByteArray(stream.available()).also { stream.read(it) } ByteArray(stream.available()).also { stream.read(it) }
@@ -203,7 +201,7 @@ object PFiles {
} }
@JvmStatic @JvmStatic
fun write(fileOutputStream: OutputStream, text: String) = write(fileOutputStream, text, "utf-8") fun write(fileOutputStream: OutputStream, text: String) = write(fileOutputStream, text, DEFAULT_ENCODING)
fun write(outputStream: OutputStream, text: String, encoding: String?) { fun write(outputStream: OutputStream, text: String, encoding: String?) {
try { try {

View File

@@ -616,7 +616,7 @@ class ScriptRuntime private constructor(builder: Builder) {
private fun doLoad(filter: FileFilter, vararg paths: String) { private fun doLoad(filter: FileFilter, vararg paths: String) {
for (path in paths) { for (path in paths) {
val file = File(files.path(path)) val file = File(files.nonNullPath(path))
if (file.isDirectory) { if (file.isDirectory) {
val filtered = file.listFiles(filter) val filtered = file.listFiles(filter)
if (filtered != null) { if (filtered != null) {
@@ -636,7 +636,7 @@ class ScriptRuntime private constructor(builder: Builder) {
try { try {
val classLoader = sClassLoader val classLoader = sClassLoader
for (path in paths) { for (path in paths) {
val file = File(files.path(path)) val file = File(files.nonNullPath(path))
if (file.isDirectory) { if (file.isDirectory) {
val filtered = file.listFiles(filter) val filtered = file.listFiles(filter)
if (filtered != null) { if (filtered != null) {
@@ -657,7 +657,7 @@ class ScriptRuntime private constructor(builder: Builder) {
try { try {
val classLoader = sClassLoader val classLoader = sClassLoader
for (path in paths) { for (path in paths) {
val file = File(files.path(path)) val file = File(files.nonNullPath(path))
if (file.isDirectory) { if (file.isDirectory) {
val filtered = file.listFiles(filter) val filtered = file.listFiles(filter)
if (filtered != null) { if (filtered != null) {

View File

@@ -35,12 +35,12 @@ class Engines(private val mScriptRuntime: ScriptRuntime) {
return execScriptInternal(name, script, config) return execScriptInternal(name, script, config)
} }
fun execScriptFile(path: String?, config: ExecutionConfig?): ScriptExecution { fun execScriptFile(path: String, config: ExecutionConfig?): ScriptExecution {
return AutoJs.instance.scriptEngineService.execute(JavaScriptFileSource(mScriptRuntime.files.path(path)), config) return AutoJs.instance.scriptEngineService.execute(JavaScriptFileSource(mScriptRuntime.files.nonNullPath(path)), config)
} }
fun execAutoFile(path: String?, config: ExecutionConfig?): ScriptExecution { fun execAutoFile(path: String, config: ExecutionConfig?): ScriptExecution {
return AutoJs.instance.scriptEngineService.execute(AutoFileSource(mScriptRuntime.files.path(path)), config) return AutoJs.instance.scriptEngineService.execute(AutoFileSource(mScriptRuntime.files.nonNullPath(path)), config)
} }
fun all(): NativeArray = engines.toNativeArray() fun all(): NativeArray = engines.toNativeArray()

View File

@@ -1,211 +1,229 @@
package org.autojs.autojs.runtime.api; package org.autojs.autojs.runtime.api
import org.autojs.autojs.pio.PFileInterface; import android.content.Context
import org.autojs.autojs.pio.PFiles; import org.autojs.autojs.pio.PFileInterface
import org.autojs.autojs.pio.UncheckedIOException; import org.autojs.autojs.pio.PFiles
import org.autojs.autojs.runtime.ScriptRuntime; import org.autojs.autojs.pio.PFiles.getElegantPath
import org.autojs.autojs.tool.Func1; import org.autojs.autojs.pio.PFiles.read
import org.autojs.autojs.util.EnvironmentUtils; import org.autojs.autojs.pio.UncheckedIOException
import org.autojs.autojs.runtime.ScriptRuntime
import java.io.File; import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import java.io.IOException; import org.autojs.autojs.tool.Func1
import java.util.regex.Pattern; import org.autojs.autojs.util.EnvironmentUtils.externalStoragePath
import org.autojs.autojs6.R
import java.io.File
import java.io.File.separator
import java.io.IOException
import java.lang.IllegalArgumentException
/** /**
* Created by Stardust on Jan 23, 2018. * Created by Stardust on Jan 23, 2018.
* Modified by SuperMonster003 as of May 26, 2022. * Modified by SuperMonster003 as of May 26, 2022.
* Transformed by SuperMonster003 on Apr 15, 2025.
*/ */
public class Files { class Files(private val scriptRuntime: ScriptRuntime) {
private final ScriptRuntime mRuntime; val context: Context
get() = scriptRuntime.uiHandler.applicationContext
public Files(ScriptRuntime runtime) { val sdcardPath: String
mRuntime = runtime; get() = externalStoragePath
}
// FIXME by Stardust on Oct 16, 2018. // FIXME by Stardust on Oct 16, 2018.
// ! Is not correct in sub-directory? // ! Is not correct in sub-directory?
// ! zh-CN (translated by SuperMonster003 on Jul 29, 2024): // ! zh-CN (translated by SuperMonster003 on Jul 29, 2024):
// ! 子目录的处理不够准确吗? // ! 子目录的处理不够准确吗?
public String path(String relativePath) { fun path(relativePath: String?): String? {
String cwd = cwd(); relativePath ?: return null
if (cwd == null || relativePath == null || relativePath.startsWith(File.separator)) { val cwd = cwd() ?: return null
return relativePath; if (relativePath.startsWith(separator)) {
return relativePath
} }
File f = new File(cwd); var file = File(cwd)
String[] paths = relativePath.split(Pattern.quote(File.separator)); relativePath.split(separator).forEach { path ->
for (String path : paths) { when {
if (path.equals(".")) { path == ".." -> {
continue; file = file.getParentFile() ?: return null
}
path != "." && path.isNotBlank() -> {
file = File(file, path)
}
} }
if (path.equals("..")) {
f = f.getParentFile();
continue;
}
f = new File(f, path);
} }
String path = f.getPath(); return when (relativePath.endsWith(separator)) {
return relativePath.endsWith(File.separator) ? path + File.separator : path; true -> file.path + separator
else -> file.path
}
} }
public String cwd() { @Throws(IllegalArgumentException::class)
return mRuntime.engines.myEngine().cwd(); fun nonNullPath(relativePath: String): String {
return path(relativePath) ?: throw IllegalArgumentException(context.getString(R.string.error_resolved_path_for_a_relative_path_cannot_be_null))
} }
public PFileInterface open(String path, String mode, String encoding, int bufferSize) { fun cwd(): String? = scriptRuntime.engines.myEngine().cwd()
return PFiles.open(path(path), mode, encoding, bufferSize);
@JvmOverloads
fun open(path: String? = null, mode: String? = null, encoding: String? = null, bufferSize: Int? = null): PFileInterface {
return PFiles.open(path(path), mode, encoding, bufferSize)
} }
public PFileInterface open(String path, String mode, String encoding) { fun create(path: String?): Boolean {
return PFiles.open(path(path), mode, encoding); return PFiles.create(path(path) ?: return false)
} }
public PFileInterface open(String path, String mode) { fun createIfNotExists(path: String?): Boolean {
return PFiles.open(path(path), mode); return PFiles.createIfNotExists(path(path) ?: return false)
} }
public PFileInterface open(String path) { fun createWithDirs(path: String?): Boolean {
return PFiles.open(path(path)); return PFiles.createWithDirs(path(path) ?: return false)
} }
public boolean create(String path) { fun exists(path: String?): Boolean {
return PFiles.create(path(path)); return PFiles.exists(path(path))
} }
public boolean createIfNotExists(String path) { fun ensureDir(path: String?): Boolean {
return PFiles.createIfNotExists(path(path)); return PFiles.ensureDir(path(path) ?: return false)
} }
public boolean createWithDirs(String path) { @JvmOverloads
return PFiles.createWithDirs(path(path)); fun read(path: String?, encoding: String? = PFiles.DEFAULT_ENCODING): String {
return PFiles.read(path(path), encoding)
} }
public boolean exists(String path) { @JvmOverloads
return PFiles.exists(path(path)); fun readAssets(fileName: String?, encoding: String? = PFiles.DEFAULT_ENCODING): String {
} val niceFileName = ensureFileNameNotNull(fileName, ::readAssets.name)
public boolean ensureDir(String path) {
return PFiles.ensureDir(path(path));
}
public String read(String path, String encoding) {
return PFiles.read(path(path), encoding);
}
public String read(String path) {
return PFiles.read(path(path));
}
public String readAssets(String path, String encoding) {
try { try {
return PFiles.read(mRuntime.getUiHandler().getApplicationContext().getAssets().open(path), encoding); return read(context.assets.open(niceFileName), encoding)
} catch (IOException e) { } catch (e: IOException) {
throw new UncheckedIOException(e); throw UncheckedIOException(e)
} }
} }
public String readAssets(String path) { fun readBytes(path: String?): ByteArray {
return readAssets(path, "UTF-8"); return PFiles.readBytes(path(path))
} }
public byte[] readBytes(String path) { @JvmOverloads
return PFiles.readBytes(path(path)); fun write(path: String?, text: String, encoding: String? = PFiles.DEFAULT_ENCODING) {
PFiles.write(path(path), text, encoding)
} }
public void write(String path, String text) { @JvmOverloads
PFiles.write(path(path), text); fun append(path: String?, text: String, encoding: String? = PFiles.DEFAULT_ENCODING) {
PFiles.append(ensurePathNotNull(path, ::append.name), text, encoding)
} }
public void write(String path, String text, String encoding) { fun appendBytes(path: String?, bytes: ByteArray?) {
PFiles.write(path(path), text, encoding); PFiles.appendBytes(ensurePathNotNull(path, ::appendBytes.name), bytes)
} }
public void append(String path, String text) { fun writeBytes(path: String?, bytes: ByteArray?) {
PFiles.append(path(path), text); PFiles.writeBytes(ensurePathNotNull(path, ::writeBytes.name), bytes)
} }
public void append(String path, String text, String encoding) { fun copy(pathFrom: String?, pathTo: String?): Boolean = PFiles.copy(
PFiles.append(path(path), text, encoding); ensurePathNotNull(pathFrom, ::copy.name, "pathFrom"),
ensurePathNotNull(pathTo, ::copy.name, "pathTo"),
)
fun renameWithoutExtension(path: String?, newName: String): Boolean {
return PFiles.renameWithoutExtension(ensurePathNotNull(path, ::renameWithoutExtension.name), newName)
} }
public void appendBytes(String path, byte[] bytes) { fun rename(path: String?, newName: String): Boolean {
PFiles.appendBytes(path(path), bytes); return PFiles.rename(ensurePathNotNull(path, ::rename.name), newName)
} }
public void writeBytes(String path, byte[] bytes) { fun move(path: String?, newPath: String): Boolean {
PFiles.writeBytes(path(path), bytes); return PFiles.move(ensurePathNotNull(path, ::move.name), newPath)
} }
public boolean copy(String pathFrom, String pathTo) { fun getExtension(fileName: String?): String {
return PFiles.copy(path(pathFrom), path(pathTo)); return PFiles.getExtension(ensureFileNameNotNull(fileName, ::getExtension.name))
} }
public boolean renameWithoutExtension(String path, String newName) { fun getName(filePath: String?): String {
return PFiles.renameWithoutExtension(path(path), newName); return PFiles.getName(ensurePathNotNull(
pathToCheck = filePath,
funcName = ::getName.name,
pathArgName = "filePath",
shouldWrapWithPathMethod = false,
))
} }
public boolean rename(String path, String newName) { fun getNameWithoutExtension(filePath: String?): String {
return PFiles.rename(path(path), newName); return PFiles.getNameWithoutExtension(ensurePathNotNull(
pathToCheck = filePath,
funcName = ::getNameWithoutExtension.name,
pathArgName = "filePath",
shouldWrapWithPathMethod = false,
))
} }
public boolean move(String path, String newPath) { fun remove(path: String?): Boolean {
return PFiles.move(path(path), newPath); return PFiles.remove(path(path))
} }
public String getExtension(String fileName) { fun removeDir(path: String?): Boolean {
return PFiles.getExtension(fileName); return PFiles.removeDir(path(path))
} }
public String getName(String filePath) { fun listDir(path: String?): Array<String> {
return PFiles.getName(filePath); return PFiles.listDir(path(path))
} }
public String getNameWithoutExtension(String filePath) { fun listDir(path: String?, filter: Func1<String, Boolean?>): Array<String> {
return PFiles.getNameWithoutExtension(filePath); return PFiles.listDir(path(path), filter)
} }
public boolean remove(String path) { fun isFile(path: String?): Boolean {
return PFiles.remove(path(path)); return PFiles.isFile(path(path))
} }
public boolean removeDir(String path) { fun isDir(path: String?): Boolean {
return PFiles.removeDir(path(path)); return PFiles.isDir(path(path))
} }
public String getSdcardPath() { fun isEmptyDir(path: String?): Boolean {
return EnvironmentUtils.getExternalStoragePath(); return PFiles.isEmptyDir(path(path))
} }
public String[] listDir(String path) { fun getHumanReadableSize(bytes: Long): String {
return PFiles.listDir(path(path)); return PFiles.getHumanReadableSize(bytes)
} }
public String[] listDir(String path, Func1<String, Boolean> filter) { fun getSimplifiedPath(path: String?): String {
return PFiles.listDir(path(path), filter); return getElegantPath(ensurePathNotNull(path, ::getSimplifiedPath.name, shouldWrapWithPathMethod = false))
} }
public boolean isFile(String path) { private fun ensureFileNameNotNull(fileNameToCheck: String?, funcName: String, fileNameArgName: String = "fileName"): String {
return PFiles.isFile(path(path)); fileNameToCheck ?: throw WrappedIllegalArgumentException(
context.getString(
R.string.error_argument_name_for_class_name_and_member_func_name_cannot_be_nullish,
fileNameArgName, Files::class.java.simpleName, funcName,
)
)
return fileNameToCheck
} }
public boolean isDir(String path) { private fun ensurePathNotNull(pathToCheck: String?, funcName: String, pathArgName: String = "path", shouldWrapWithPathMethod: Boolean = true): String {
return PFiles.isDir(path(path)); val path = if (shouldWrapWithPathMethod) path(pathToCheck) else pathToCheck
path ?: throw WrappedIllegalArgumentException(
context.getString(
R.string.error_argument_name_for_class_name_and_member_func_name_cannot_be_nullish,
pathArgName, Files::class.java.simpleName, funcName,
)
)
return path
} }
public boolean isEmptyDir(String path) { companion object {
return PFiles.isEmptyDir(path(path)); fun join(parent: String?, vararg child: String?): String {
return PFiles.join(parent, *child)
}
} }
public static String join(String parent, String... child) {
return PFiles.join(parent, child);
}
public String getHumanReadableSize(long bytes) {
return PFiles.getHumanReadableSize(bytes);
}
public String getSimplifiedPath(String path) {
return PFiles.getElegantPath(path);
}
} }

View File

@@ -244,7 +244,7 @@ public class Images {
public boolean captureScreen(String path) { public boolean captureScreen(String path) {
ImageWrapper image = captureScreen(); ImageWrapper image = captureScreen();
return image != null && image.saveTo(mScriptRuntime.files.path(path)); return image != null && image.saveTo(mScriptRuntime.files.nonNullPath(path));
} }
public ImageWrapper copy(@NonNull ImageWrapper image) { public ImageWrapper copy(@NonNull ImageWrapper image) {

View File

@@ -26,7 +26,7 @@ public class Media implements MediaScannerConnection.MediaScannerConnectionClien
public void scanFile(String path) { public void scanFile(String path) {
String mimeType = Mime.fromFileOrWildcard(path); String mimeType = Mime.fromFileOrWildcard(path);
mScannerConnection.scanFile(mRuntime.files.path(path), mimeType); mScannerConnection.scanFile(mRuntime.files.nonNullPath(path), mimeType);
} }
@Override @Override
@@ -43,7 +43,7 @@ public class Media implements MediaScannerConnection.MediaScannerConnectionClien
} }
public void playMusic(String path, float volume, boolean looping) { public void playMusic(String path, float volume, boolean looping) {
path = mRuntime.files.path(path); path = mRuntime.files.nonNullPath(path);
if (mMediaPlayer == null) { if (mMediaPlayer == null) {
mMediaPlayer = new MediaPlayerWrapper(); mMediaPlayer = new MediaPlayerWrapper();
} }

View File

@@ -37,6 +37,7 @@ import org.mozilla.javascript.Undefined
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import org.autojs.autojs.util.App as PresetApp import org.autojs.autojs.util.App as PresetApp
import androidx.core.net.toUri
@Suppress("unused", "UNUSED_PARAMETER") @Suppress("unused", "UNUSED_PARAMETER")
class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@@ -471,7 +472,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
fun parseUriRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: Any?): Uri? = when (uri) { fun parseUriRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: Any?): Uri? = when (uri) {
is String -> when { is String -> when {
uri.startsWith(PROTOCOL_FILE) -> getUriForFileRhinoWithRuntime(scriptRuntime, uri) uri.startsWith(PROTOCOL_FILE) -> getUriForFileRhinoWithRuntime(scriptRuntime, uri)
else -> Uri.parse(uri) else -> uri.toUri()
} }
is Uri -> parseUriRhinoWithRuntime(scriptRuntime, uri.host) is Uri -> parseUriRhinoWithRuntime(scriptRuntime, uri.host)
else -> null else -> null
@@ -501,7 +502,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
fun openUrlInternal(url: String) { fun openUrlInternal(url: String) {
val prefix = "http://".takeUnless { url.contains("://") } ?: "" val prefix = "http://".takeUnless { url.contains("://") } ?: ""
Intent(Intent.ACTION_VIEW) Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(prefix + url)) .setData((prefix + url).toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { globalContext.startActivity(it) } .let { globalContext.startActivity(it) }
} }
@@ -510,7 +511,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
private fun openDualUrlInternal(scriptRuntime: ScriptRuntime, url: String) { private fun openDualUrlInternal(scriptRuntime: ScriptRuntime, url: String) {
val prefix = "http://".takeUnless { url.contains("://") } ?: "" val prefix = "http://".takeUnless { url.contains("://") } ?: ""
Intent(Intent.ACTION_VIEW) Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(prefix + url)) .setData((prefix + url).toUri())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.let { startActivityForDualUser(scriptRuntime, it) } .let { startActivityForDualUser(scriptRuntime, it) }
} }
@@ -523,16 +524,15 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic @JvmStatic
@RhinoFunctionBody @RhinoFunctionBody
fun getUriForFileRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: String): Uri? = Uri.fromFile( fun getUriForFileRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: String): Uri? {
File( val path = scriptRuntime.files.path(
scriptRuntime.files.path( when {
when { uri.startsWith(PROTOCOL_FILE) -> uri.substring(PROTOCOL_FILE.length)
uri.startsWith(PROTOCOL_FILE) -> uri.substring(PROTOCOL_FILE.length) else -> uri
else -> uri }
} ) ?: return null
) return Uri.fromFile(File(path))
) }
)
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
@@ -702,7 +702,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
path.isJsNullish() -> false path.isJsNullish() -> false
path !is String -> throw RuntimeException("Cannot view $path as it isn't a string") path !is String -> throw RuntimeException("Cannot view $path as it isn't a string")
else -> { else -> {
val nicePath = scriptRuntime.files.path(path) val nicePath = scriptRuntime.files.nonNullPath(path)
if (!scriptRuntime.files.exists(nicePath)) { if (!scriptRuntime.files.exists(nicePath)) {
throw Error("Cannot view $path as it doesn't exist") throw Error("Cannot view $path as it doesn't exist")
} }
@@ -724,7 +724,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
path.isJsNullish() -> false path.isJsNullish() -> false
path !is String -> throw RuntimeException("Cannot edit $path as it isn't a string") path !is String -> throw RuntimeException("Cannot edit $path as it isn't a string")
else -> { else -> {
val nicePath = scriptRuntime.files.path(path) val nicePath = scriptRuntime.files.nonNullPath(path)
if (!scriptRuntime.files.exists(nicePath)) { if (!scriptRuntime.files.exists(nicePath)) {
throw Error("Cannot edit $path as it doesn't exist") throw Error("Cannot edit $path as it doesn't exist")
} }
@@ -908,13 +908,13 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
private fun launchDualSettingsInternal(scriptRuntime: ScriptRuntime, packageName: String) { private fun launchDualSettingsInternal(scriptRuntime: ScriptRuntime, packageName: String) {
startActivityForDualUser(scriptRuntime, Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { startActivityForDualUser(scriptRuntime, Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.parse("package:$packageName") data = "package:$packageName".toUri()
}) })
} }
private fun uninstallDualInternal(scriptRuntime: ScriptRuntime, packageName: String) { private fun uninstallDualInternal(scriptRuntime: ScriptRuntime, packageName: String) {
startActivityForDualUser(scriptRuntime, Intent(Intent.ACTION_DELETE).apply { startActivityForDualUser(scriptRuntime, Intent(Intent.ACTION_DELETE).apply {
data = Uri.parse("package:$packageName") data = "package:$packageName".toUri()
}) })
} }
@@ -995,7 +995,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
} }
} else { } else {
if (!o.prop("data").isJsNullish()) { if (!o.prop("data").isJsNullish()) {
intent.setData(Uri.parse(Context.toString(o.prop("data")))) intent.setData(Context.toString(o.prop("data")).toUri())
} }
} }

View File

@@ -511,7 +511,7 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) {
fun setGlobalLogConfig(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { config -> fun setGlobalLogConfig(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Undefined = ensureArgumentsOnlyOne(args) { config ->
require(config is NativeObject) { "Argument for console.${::setGlobalLogConfig.name} must be a JavaScript Object" } require(config is NativeObject) { "Argument for console.${::setGlobalLogConfig.name} must be a JavaScript Object" }
LogConfigurator().apply { LogConfigurator().apply {
fileName = scriptRuntime.files.path(config.inquire("file", ::coerceString, "android-log4j.log")) fileName = scriptRuntime.files.nonNullPath(config.inquire("file", ::coerceString, "android-log4j.log"))
filePattern = config.inquire("filePattern", ::coerceString, "%m%n") filePattern = config.inquire("filePattern", ::coerceString, "%m%n")
maxFileSize = config.inquire("maxFileSize", ::coerceLongNumber, 512 * 1024) maxFileSize = config.inquire("maxFileSize", ::coerceLongNumber, 512 * 1024)
maxBackupSize = config.inquire("maxBackupSize", ::coerceIntNumber, 5) maxBackupSize = config.inquire("maxBackupSize", ::coerceIntNumber, 5)

View File

@@ -111,14 +111,14 @@ class Engines(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunt
val result = ExecutionConfig() val result = ExecutionConfig()
when (val config = if (o.isJsNullish()) newNativeObject() else o) { when (val config = if (o.isJsNullish()) newNativeObject() else o) {
is ExecutionConfig -> { is ExecutionConfig -> {
result.workingDirectory = config.workingDirectory.takeUnless { it.isEmpty() } ?: scriptRuntime.files.cwd() result.workingDirectory = config.workingDirectory.takeUnless { it.isBlank() } ?: scriptRuntime.files.cwd() ?: ""
result.delay = config.delay.takeUnless { it < 0 } ?: 0L result.delay = config.delay.takeUnless { it < 0 } ?: 0L
result.interval = config.interval.takeUnless { it < 0 } ?: 0L result.interval = config.interval.takeUnless { it < 0 } ?: 0L
result.loopTimes = config.loopTimes.takeUnless { it < 0 } ?: 1 result.loopTimes = config.loopTimes.takeUnless { it < 0 } ?: 1
config.arguments.entries.forEach { result.setArgument(it.key, it.value) } config.arguments.entries.forEach { result.setArgument(it.key, it.value) }
} }
is ScriptableObject -> { is ScriptableObject -> {
result.workingDirectory = config.inquire(listOf("path", "workingDirectory"), { o, _ -> o.toRuntimePath(scriptRuntime) }, scriptRuntime.files.cwd()) result.workingDirectory = config.inquire(listOf("path", "workingDirectory"), { o, _ -> o.toRuntimePath(scriptRuntime) }, scriptRuntime.files.cwd() ?: "")
result.delay = config.inquire("delay", ::coerceLongNumber, 0L) result.delay = config.inquire("delay", ::coerceLongNumber, 0L)
result.interval = config.inquire("interval", ::coerceLongNumber, 0L) result.interval = config.inquire("interval", ::coerceLongNumber, 0L)
result.loopTimes = config.inquire("loopTimes", ::coerceIntNumber, 1) result.loopTimes = config.inquire("loopTimes", ::coerceIntNumber, 1)

View File

@@ -1,6 +1,7 @@
package org.autojs.autojs.runtime.api.augment.files package org.autojs.autojs.runtime.api.augment.files
import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.FlexibleArray import org.autojs.autojs.extension.FlexibleArray
import org.autojs.autojs.pio.PFileInterface import org.autojs.autojs.pio.PFileInterface
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
@@ -16,6 +17,7 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
override val selfAssignmentFunctions = listOf( override val selfAssignmentFunctions = listOf(
::open.name to AS_GLOBAL, ::open.name to AS_GLOBAL,
::path.name,
::join.name, ::join.name,
::toFile.name, ::toFile.name,
) )
@@ -34,6 +36,16 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
} }
} }
@JvmStatic
@RhinoRuntimeFunctionInterface
fun path(scriptRuntime: ScriptRuntime, args: Array<out Any?>): String? = ensureArgumentsAtMost(args, 1) { argList ->
val (o) = argList
when {
o.isJsNullish() -> scriptRuntime.files.path(null)
else -> scriptRuntime.files.path(Context.toString(o))
}
}
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun join(scriptRuntime: ScriptRuntime, args: Array<out Any?>): String = ensureArgumentsAtLeast(args, 1) { fun join(scriptRuntime: ScriptRuntime, args: Array<out Any?>): String = ensureArgumentsAtLeast(args, 1) {
@@ -43,7 +55,7 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun toFile(scriptRuntime: ScriptRuntime, args: Array<out Any?>): File = ensureArgumentsOnlyOne(args) { fun toFile(scriptRuntime: ScriptRuntime, args: Array<out Any?>): File = ensureArgumentsOnlyOne(args) {
File(scriptRuntime.files.path(Context.toString(it))) File(scriptRuntime.files.nonNullPath(Context.toString(it)))
} }
} }

View File

@@ -179,7 +179,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun imread(scriptRuntime: ScriptRuntime, args: Array<out Any?>): AutoJsMat = ensureArgumentsOnlyOne(args) { path -> fun imread(scriptRuntime: ScriptRuntime, args: Array<out Any?>): AutoJsMat = ensureArgumentsOnlyOne(args) { path ->
ApiImages.imread(scriptRuntime.files.path(coerceString(path))) ApiImages.imread(scriptRuntime.files.nonNullPath(coerceString(path)))
} }
@JvmStatic @JvmStatic
@@ -244,7 +244,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
} }
when { when {
path.isJsNullish() -> rtImages.captureScreen() as ImageWrapper path.isJsNullish() -> rtImages.captureScreen() as ImageWrapper
else -> rtImages.captureScreen(scriptRuntime.files.path(coerceString(path))) else -> rtImages.captureScreen(scriptRuntime.files.nonNullPath(coerceString(path)))
} }
} }
@@ -301,7 +301,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
val image = if (o is String) read(scriptRuntime, arrayOf<Any>(o, true)) else o val image = if (o is String) read(scriptRuntime, arrayOf<Any>(o, true)) else o
require(image is ImageWrapper) { "Argument image for images.save must be a ImageWrapper" } require(image is ImageWrapper) { "Argument image for images.save must be a ImageWrapper" }
require(!path.isJsNullish()) { "Argument path for images.save must be non-nullish" } require(!path.isJsNullish()) { "Argument path for images.save must be non-nullish" }
scriptRuntime.images.save(image, scriptRuntime.files.path(coerceString(path)), parseImageFormat(format), parseQuality(quality, DEFAULT_IMAGE_SAVE_QUALITY)) scriptRuntime.images.save(image, scriptRuntime.files.nonNullPath(coerceString(path)), parseImageFormat(format), parseQuality(quality, DEFAULT_IMAGE_SAVE_QUALITY))
} }
@JvmStatic @JvmStatic
@@ -311,7 +311,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
val image = if (o is String) read(scriptRuntime, arrayOf<Any>(o, true)) else o val image = if (o is String) read(scriptRuntime, arrayOf<Any>(o, true)) else o
require(image is ImageWrapper) { "Argument image for images.saveImage must be a ImageWrapper" } require(image is ImageWrapper) { "Argument image for images.saveImage must be a ImageWrapper" }
require(!path.isJsNullish()) { "Argument path for images.saveImage must be non-nullish" } require(!path.isJsNullish()) { "Argument path for images.saveImage must be non-nullish" }
scriptRuntime.images.save(image, scriptRuntime.files.path(coerceString(path)), parseImageFormat(format), parseQuality(quality, DEFAULT_IMAGE_SAVE_QUALITY)) scriptRuntime.images.save(image, scriptRuntime.files.nonNullPath(coerceString(path)), parseImageFormat(format), parseQuality(quality, DEFAULT_IMAGE_SAVE_QUALITY))
} }
@JvmStatic @JvmStatic
@@ -1002,7 +1002,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
val matcher = opt.inquire("matcher") { val matcher = opt.inquire("matcher") {
coerceIntNumber(DescriptorMatcher::class.java.getField(coerceString(it)).get(null)) coerceIntNumber(DescriptorMatcher::class.java.getField(coerceString(it)).get(null))
} ?: DescriptorMatcher.FLANNBASED } ?: DescriptorMatcher.FLANNBASED
val drawMatches = opt.inquire("drawMatches") { scriptRuntime.files.path(coerceString(it)) } val drawMatches = opt.inquire("drawMatches") { scriptRuntime.files.nonNullPath(coerceString(it)) }
val threshold = opt.inquire("threshold", ::coerceFloatNumber, 0.7f) val threshold = opt.inquire("threshold", ::coerceFloatNumber, 0.7f)
val result = ImageFeatureMatching.featureMatching(sceneFeatures.javaObject, objectFeatures.javaObject, matcher, drawMatches, threshold) ?: return@ensureArgumentsLengthInRange null val result = ImageFeatureMatching.featureMatching(sceneFeatures.javaObject, objectFeatures.javaObject, matcher, drawMatches, threshold) ?: return@ensureArgumentsLengthInRange null
@@ -1070,7 +1070,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt
is OpencvMat, is Bitmap -> OpencvSize(getWidth(scriptRuntime, argList), getHeight(scriptRuntime, argList)) is OpencvMat, is Bitmap -> OpencvSize(getWidth(scriptRuntime, argList), getHeight(scriptRuntime, argList))
is String -> BitmapFactory.Options().apply { inJustDecodeBounds = true }.let { opt -> is String -> BitmapFactory.Options().apply { inJustDecodeBounds = true }.let { opt ->
require(scriptRuntime.files.exists(o)) { "Image source ($o) doesn't exist" } require(scriptRuntime.files.exists(o)) { "Image source ($o) doesn't exist" }
BitmapFactory.decodeFile(scriptRuntime.files.path(o), opt) BitmapFactory.decodeFile(scriptRuntime.files.nonNullPath(o), opt)
OpencvSize(opt.outWidth.toDouble(), opt.outHeight.toDouble()) OpencvSize(opt.outWidth.toDouble(), opt.outHeight.toDouble())
} }
else -> throw WrappedIllegalArgumentException("Unknown source to parse its size: $o") else -> throw WrappedIllegalArgumentException("Unknown source to parse its size: $o")

View File

@@ -19,7 +19,7 @@ public class AutoFileSource extends ScriptSource {
mFile = file; mFile = file;
} }
public AutoFileSource(String path) { public AutoFileSource(@NonNull String path) {
this(new File(path)); this(new File(path));
} }

View File

@@ -24,11 +24,11 @@ public class JavaScriptFileSource extends JavaScriptSource {
mFile = file; mFile = file;
} }
public JavaScriptFileSource(String path) { public JavaScriptFileSource(@NonNull String path) {
this(new File(path)); this(new File(path));
} }
public JavaScriptFileSource(String name, File file) { public JavaScriptFileSource(@NonNull String name, File file) {
super(name); super(name);
mCustomsName = true; mCustomsName = true;
mFile = file; mFile = file;

View File

@@ -1,5 +1,5 @@
#Wed Apr 16 14:12:01 CST 2025 #Wed Apr 16 14:34:09 CST 2025
BUILD_TIME=1744783921920 BUILD_TIME=1744785249350
COMPILE_SDK_VERSION=35 COMPILE_SDK_VERSION=35
JAVA_VERSION=23 JAVA_VERSION=23
JAVA_VERSION_MIN_RADICAL=0 JAVA_VERSION_MIN_RADICAL=0