diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index ca42ed89..990ee696 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -16,7 +16,7 @@ "notice 模块缺失 getBuilder 等扩展方法的问题 _[`issue #301`](http://issues.autojs6.com/301)_", "shizuku/shell 等方法无法接受字符串参数的问题 _[`issue #310`](http://issues.autojs6.com/310)_", "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.getClip 可能无法正常获取剪切板内容的问题 _[`issue #341`](http://issues.autojs6.com/341)_", "ui.inflate 返回值丢失 attr/on/click 等原型方法的问题", @@ -49,6 +49,7 @@ "尝试恢复 com.stardust 前缀包以便提升代码兼容性 _[`issue #290`](http://issues.autojs6.com/290)_", "floaty.window/floaty.rawWindow 同时支持主线程和子线程执行", "getClip 全局方法适时借助 floaty.getClip 方法以提升兼容性", + "files.path 及相关方法传入空值路径参数时的兼容性", "同步最新的 Rhino 引擎官方上游代码并进行必要的代码适配", "README.md 完善项目构建与运行相关内容 _[`issue #344`](http://issues.autojs6.com/344)_" ], diff --git a/app/src/main/java/org/autojs/autojs/core/database/Database.java b/app/src/main/java/org/autojs/autojs/core/database/Database.java index fdbe8055..7a6957d8 100644 --- a/app/src/main/java/org/autojs/autojs/core/database/Database.java +++ b/app/src/main/java/org/autojs/autojs/core/database/Database.java @@ -26,7 +26,7 @@ public class Database extends SQLiteOpenHelper implements Closeable { 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) { - 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; mCallback = databaseCallback; mScriptRuntime = scriptRuntime; diff --git a/app/src/main/java/org/autojs/autojs/core/ui/attribute/ImageViewAttributes.kt b/app/src/main/java/org/autojs/autojs/core/ui/attribute/ImageViewAttributes.kt index 48b9949c..8723b5f0 100644 --- a/app/src/main/java/org/autojs/autojs/core/ui/attribute/ImageViewAttributes.kt +++ b/app/src/main/java/org/autojs/autojs/core/ui/attribute/ImageViewAttributes.kt @@ -50,11 +50,11 @@ open class ImageViewAttributes(scriptRuntime: ScriptRuntime, resourceParser: Res } 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 { - 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 { diff --git a/app/src/main/java/org/autojs/autojs/core/ui/inflater/util/Drawables.kt b/app/src/main/java/org/autojs/autojs/core/ui/inflater/util/Drawables.kt index 20d4564e..9fb70db1 100644 --- a/app/src/main/java/org/autojs/autojs/core/ui/inflater/util/Drawables.kt +++ b/app/src/main/java/org/autojs/autojs/core/ui/inflater/util/Drawables.kt @@ -23,6 +23,7 @@ import java.io.File import java.net.URL import java.util.concurrent.Executors import java.util.regex.Pattern +import androidx.core.graphics.drawable.toDrawable /** * Created by Stardust on Nov 3, 2017. @@ -83,7 +84,7 @@ open class Drawables { } 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) diff --git a/app/src/main/java/org/autojs/autojs/extension/AnyExtensions.kt b/app/src/main/java/org/autojs/autojs/extension/AnyExtensions.kt index 5d9bd2f2..1fd36c9a 100644 --- a/app/src/main/java/org/autojs/autojs/extension/AnyExtensions.kt +++ b/app/src/main/java/org/autojs/autojs/extension/AnyExtensions.kt @@ -133,7 +133,7 @@ object AnyExtensions { 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())) - return scriptRuntime.files.path(coerceString(this, ".")) + return scriptRuntime.files.nonNullPath(coerceString(this, ".")) } } diff --git a/app/src/main/java/org/autojs/autojs/pio/PFiles.kt b/app/src/main/java/org/autojs/autojs/pio/PFiles.kt index 683a54c4..940b06cb 100644 --- a/app/src/main/java/org/autojs/autojs/pio/PFiles.kt +++ b/app/src/main/java/org/autojs/autojs/pio/PFiles.kt @@ -109,7 +109,7 @@ object PFiles { @JvmOverloads @JvmStatic - fun read(file: File?, encoding: String? = "utf-8"): String { + fun read(file: File?, encoding: String? = DEFAULT_ENCODING): String { return try { read(FileInputStream(file), encoding) } catch (e: FileNotFoundException) { @@ -118,21 +118,19 @@ object PFiles { } @JvmStatic - fun read(stream: InputStream, encoding: String?): String { + @JvmOverloads + fun read(inputStream: InputStream, encoding: String? = DEFAULT_ENCODING): String { return try { - val bytes = ByteArray(stream.available()) - stream.read(bytes) + val bytes = ByteArray(inputStream.available()) + inputStream.read(bytes) String(bytes, Charset.forName(encoding)) } catch (e: IOException) { throw UncheckedIOException(e) } finally { - closeSilently(stream) + closeSilently(inputStream) } } - @JvmStatic - fun read(inputStream: InputStream) = read(inputStream, "utf-8") - fun readBytes(stream: InputStream): ByteArray { return try { ByteArray(stream.available()).also { stream.read(it) } @@ -203,7 +201,7 @@ object PFiles { } @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?) { try { diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt index 38d86679..82c879ef 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt @@ -616,7 +616,7 @@ class ScriptRuntime private constructor(builder: Builder) { private fun doLoad(filter: FileFilter, vararg paths: String) { for (path in paths) { - val file = File(files.path(path)) + val file = File(files.nonNullPath(path)) if (file.isDirectory) { val filtered = file.listFiles(filter) if (filtered != null) { @@ -636,7 +636,7 @@ class ScriptRuntime private constructor(builder: Builder) { try { val classLoader = sClassLoader for (path in paths) { - val file = File(files.path(path)) + val file = File(files.nonNullPath(path)) if (file.isDirectory) { val filtered = file.listFiles(filter) if (filtered != null) { @@ -657,7 +657,7 @@ class ScriptRuntime private constructor(builder: Builder) { try { val classLoader = sClassLoader for (path in paths) { - val file = File(files.path(path)) + val file = File(files.nonNullPath(path)) if (file.isDirectory) { val filtered = file.listFiles(filter) if (filtered != null) { diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Engines.kt b/app/src/main/java/org/autojs/autojs/runtime/api/Engines.kt index 43f40e38..1896a8b2 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Engines.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Engines.kt @@ -35,12 +35,12 @@ class Engines(private val mScriptRuntime: ScriptRuntime) { return execScriptInternal(name, script, config) } - fun execScriptFile(path: String?, config: ExecutionConfig?): ScriptExecution { - return AutoJs.instance.scriptEngineService.execute(JavaScriptFileSource(mScriptRuntime.files.path(path)), config) + fun execScriptFile(path: String, config: ExecutionConfig?): ScriptExecution { + return AutoJs.instance.scriptEngineService.execute(JavaScriptFileSource(mScriptRuntime.files.nonNullPath(path)), config) } - fun execAutoFile(path: String?, config: ExecutionConfig?): ScriptExecution { - return AutoJs.instance.scriptEngineService.execute(AutoFileSource(mScriptRuntime.files.path(path)), config) + fun execAutoFile(path: String, config: ExecutionConfig?): ScriptExecution { + return AutoJs.instance.scriptEngineService.execute(AutoFileSource(mScriptRuntime.files.nonNullPath(path)), config) } fun all(): NativeArray = engines.toNativeArray() diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Files.kt b/app/src/main/java/org/autojs/autojs/runtime/api/Files.kt index 9ad43ded..a1029ab1 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Files.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Files.kt @@ -1,211 +1,229 @@ -package org.autojs.autojs.runtime.api; +package org.autojs.autojs.runtime.api -import org.autojs.autojs.pio.PFileInterface; -import org.autojs.autojs.pio.PFiles; -import org.autojs.autojs.pio.UncheckedIOException; -import org.autojs.autojs.runtime.ScriptRuntime; -import org.autojs.autojs.tool.Func1; -import org.autojs.autojs.util.EnvironmentUtils; - -import java.io.File; -import java.io.IOException; -import java.util.regex.Pattern; +import android.content.Context +import org.autojs.autojs.pio.PFileInterface +import org.autojs.autojs.pio.PFiles +import org.autojs.autojs.pio.PFiles.getElegantPath +import org.autojs.autojs.pio.PFiles.read +import org.autojs.autojs.pio.UncheckedIOException +import org.autojs.autojs.runtime.ScriptRuntime +import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException +import org.autojs.autojs.tool.Func1 +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. * 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) { - mRuntime = runtime; - } + val sdcardPath: String + get() = externalStoragePath // FIXME by Stardust on Oct 16, 2018. // ! Is not correct in sub-directory? // ! zh-CN (translated by SuperMonster003 on Jul 29, 2024): // ! 子目录的处理不够准确吗? - public String path(String relativePath) { - String cwd = cwd(); - if (cwd == null || relativePath == null || relativePath.startsWith(File.separator)) { - return relativePath; + fun path(relativePath: String?): String? { + relativePath ?: return null + val cwd = cwd() ?: return null + if (relativePath.startsWith(separator)) { + return relativePath } - File f = new File(cwd); - String[] paths = relativePath.split(Pattern.quote(File.separator)); - for (String path : paths) { - if (path.equals(".")) { - continue; + var file = File(cwd) + relativePath.split(separator).forEach { path -> + when { + path == ".." -> { + 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 relativePath.endsWith(File.separator) ? path + File.separator : path; + return when (relativePath.endsWith(separator)) { + true -> file.path + separator + else -> file.path + } } - public String cwd() { - return mRuntime.engines.myEngine().cwd(); + @Throws(IllegalArgumentException::class) + 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) { - return PFiles.open(path(path), mode, encoding, bufferSize); + fun cwd(): String? = scriptRuntime.engines.myEngine().cwd() + + @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) { - return PFiles.open(path(path), mode, encoding); + fun create(path: String?): Boolean { + return PFiles.create(path(path) ?: return false) } - public PFileInterface open(String path, String mode) { - return PFiles.open(path(path), mode); + fun createIfNotExists(path: String?): Boolean { + return PFiles.createIfNotExists(path(path) ?: return false) } - public PFileInterface open(String path) { - return PFiles.open(path(path)); + fun createWithDirs(path: String?): Boolean { + return PFiles.createWithDirs(path(path) ?: return false) } - public boolean create(String path) { - return PFiles.create(path(path)); + fun exists(path: String?): Boolean { + return PFiles.exists(path(path)) } - public boolean createIfNotExists(String path) { - return PFiles.createIfNotExists(path(path)); + fun ensureDir(path: String?): Boolean { + return PFiles.ensureDir(path(path) ?: return false) } - public boolean createWithDirs(String path) { - return PFiles.createWithDirs(path(path)); + @JvmOverloads + fun read(path: String?, encoding: String? = PFiles.DEFAULT_ENCODING): String { + return PFiles.read(path(path), encoding) } - public boolean exists(String path) { - return PFiles.exists(path(path)); - } - - 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) { + @JvmOverloads + fun readAssets(fileName: String?, encoding: String? = PFiles.DEFAULT_ENCODING): String { + val niceFileName = ensureFileNameNotNull(fileName, ::readAssets.name) try { - return PFiles.read(mRuntime.getUiHandler().getApplicationContext().getAssets().open(path), encoding); - } catch (IOException e) { - throw new UncheckedIOException(e); + return read(context.assets.open(niceFileName), encoding) + } catch (e: IOException) { + throw UncheckedIOException(e) } } - public String readAssets(String path) { - return readAssets(path, "UTF-8"); + fun readBytes(path: String?): ByteArray { + return PFiles.readBytes(path(path)) } - public byte[] readBytes(String path) { - return PFiles.readBytes(path(path)); + @JvmOverloads + fun write(path: String?, text: String, encoding: String? = PFiles.DEFAULT_ENCODING) { + PFiles.write(path(path), text, encoding) } - public void write(String path, String text) { - PFiles.write(path(path), text); + @JvmOverloads + 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) { - PFiles.write(path(path), text, encoding); + fun appendBytes(path: String?, bytes: ByteArray?) { + PFiles.appendBytes(ensurePathNotNull(path, ::appendBytes.name), bytes) } - public void append(String path, String text) { - PFiles.append(path(path), text); + fun writeBytes(path: String?, bytes: ByteArray?) { + PFiles.writeBytes(ensurePathNotNull(path, ::writeBytes.name), bytes) } - public void append(String path, String text, String encoding) { - PFiles.append(path(path), text, encoding); + fun copy(pathFrom: String?, pathTo: String?): Boolean = PFiles.copy( + 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) { - PFiles.appendBytes(path(path), bytes); + fun rename(path: String?, newName: String): Boolean { + return PFiles.rename(ensurePathNotNull(path, ::rename.name), newName) } - public void writeBytes(String path, byte[] bytes) { - PFiles.writeBytes(path(path), bytes); + fun move(path: String?, newPath: String): Boolean { + return PFiles.move(ensurePathNotNull(path, ::move.name), newPath) } - public boolean copy(String pathFrom, String pathTo) { - return PFiles.copy(path(pathFrom), path(pathTo)); + fun getExtension(fileName: String?): String { + return PFiles.getExtension(ensureFileNameNotNull(fileName, ::getExtension.name)) } - public boolean renameWithoutExtension(String path, String newName) { - return PFiles.renameWithoutExtension(path(path), newName); + fun getName(filePath: String?): String { + return PFiles.getName(ensurePathNotNull( + pathToCheck = filePath, + funcName = ::getName.name, + pathArgName = "filePath", + shouldWrapWithPathMethod = false, + )) } - public boolean rename(String path, String newName) { - return PFiles.rename(path(path), newName); + fun getNameWithoutExtension(filePath: String?): String { + return PFiles.getNameWithoutExtension(ensurePathNotNull( + pathToCheck = filePath, + funcName = ::getNameWithoutExtension.name, + pathArgName = "filePath", + shouldWrapWithPathMethod = false, + )) } - public boolean move(String path, String newPath) { - return PFiles.move(path(path), newPath); + fun remove(path: String?): Boolean { + return PFiles.remove(path(path)) } - public String getExtension(String fileName) { - return PFiles.getExtension(fileName); + fun removeDir(path: String?): Boolean { + return PFiles.removeDir(path(path)) } - public String getName(String filePath) { - return PFiles.getName(filePath); + fun listDir(path: String?): Array { + return PFiles.listDir(path(path)) } - public String getNameWithoutExtension(String filePath) { - return PFiles.getNameWithoutExtension(filePath); + fun listDir(path: String?, filter: Func1): Array { + return PFiles.listDir(path(path), filter) } - public boolean remove(String path) { - return PFiles.remove(path(path)); + fun isFile(path: String?): Boolean { + return PFiles.isFile(path(path)) } - public boolean removeDir(String path) { - return PFiles.removeDir(path(path)); + fun isDir(path: String?): Boolean { + return PFiles.isDir(path(path)) } - public String getSdcardPath() { - return EnvironmentUtils.getExternalStoragePath(); + fun isEmptyDir(path: String?): Boolean { + return PFiles.isEmptyDir(path(path)) } - public String[] listDir(String path) { - return PFiles.listDir(path(path)); + fun getHumanReadableSize(bytes: Long): String { + return PFiles.getHumanReadableSize(bytes) } - public String[] listDir(String path, Func1 filter) { - return PFiles.listDir(path(path), filter); + fun getSimplifiedPath(path: String?): String { + return getElegantPath(ensurePathNotNull(path, ::getSimplifiedPath.name, shouldWrapWithPathMethod = false)) } - public boolean isFile(String path) { - return PFiles.isFile(path(path)); + private fun ensureFileNameNotNull(fileNameToCheck: String?, funcName: String, fileNameArgName: String = "fileName"): String { + 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) { - return PFiles.isDir(path(path)); + private fun ensurePathNotNull(pathToCheck: String?, funcName: String, pathArgName: String = "path", shouldWrapWithPathMethod: Boolean = true): String { + 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) { - return PFiles.isEmptyDir(path(path)); + companion object { + 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); - } - } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java index 47d71f86..050d0ea3 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Images.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Images.java @@ -244,7 +244,7 @@ public class Images { public boolean captureScreen(String path) { 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) { diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Media.java b/app/src/main/java/org/autojs/autojs/runtime/api/Media.java index 458395dc..b42fec87 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Media.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Media.java @@ -26,7 +26,7 @@ public class Media implements MediaScannerConnection.MediaScannerConnectionClien public void scanFile(String path) { String mimeType = Mime.fromFileOrWildcard(path); - mScannerConnection.scanFile(mRuntime.files.path(path), mimeType); + mScannerConnection.scanFile(mRuntime.files.nonNullPath(path), mimeType); } @Override @@ -43,7 +43,7 @@ public class Media implements MediaScannerConnection.MediaScannerConnectionClien } public void playMusic(String path, float volume, boolean looping) { - path = mRuntime.files.path(path); + path = mRuntime.files.nonNullPath(path); if (mMediaPlayer == null) { mMediaPlayer = new MediaPlayerWrapper(); } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/app/App.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/app/App.kt index 88450a9b..65a5ff94 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/app/App.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/app/App.kt @@ -37,6 +37,7 @@ import org.mozilla.javascript.Undefined import java.io.File import java.net.URI import org.autojs.autojs.util.App as PresetApp +import androidx.core.net.toUri @Suppress("unused", "UNUSED_PARAMETER") 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) { is String -> when { uri.startsWith(PROTOCOL_FILE) -> getUriForFileRhinoWithRuntime(scriptRuntime, uri) - else -> Uri.parse(uri) + else -> uri.toUri() } is Uri -> parseUriRhinoWithRuntime(scriptRuntime, uri.host) else -> null @@ -501,7 +502,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { fun openUrlInternal(url: String) { val prefix = "http://".takeUnless { url.contains("://") } ?: "" Intent(Intent.ACTION_VIEW) - .setData(Uri.parse(prefix + url)) + .setData((prefix + url).toUri()) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .let { globalContext.startActivity(it) } } @@ -510,7 +511,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { private fun openDualUrlInternal(scriptRuntime: ScriptRuntime, url: String) { val prefix = "http://".takeUnless { url.contains("://") } ?: "" Intent(Intent.ACTION_VIEW) - .setData(Uri.parse(prefix + url)) + .setData((prefix + url).toUri()) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .let { startActivityForDualUser(scriptRuntime, it) } } @@ -523,16 +524,15 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { @JvmStatic @RhinoFunctionBody - fun getUriForFileRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: String): Uri? = Uri.fromFile( - File( - scriptRuntime.files.path( - when { - uri.startsWith(PROTOCOL_FILE) -> uri.substring(PROTOCOL_FILE.length) - else -> uri - } - ) - ) - ) + fun getUriForFileRhinoWithRuntime(scriptRuntime: ScriptRuntime, uri: String): Uri? { + val path = scriptRuntime.files.path( + when { + uri.startsWith(PROTOCOL_FILE) -> uri.substring(PROTOCOL_FILE.length) + else -> uri + } + ) ?: return null + return Uri.fromFile(File(path)) + } @JvmStatic @RhinoRuntimeFunctionInterface @@ -702,7 +702,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { path.isJsNullish() -> false path !is String -> throw RuntimeException("Cannot view $path as it isn't a string") else -> { - val nicePath = scriptRuntime.files.path(path) + val nicePath = scriptRuntime.files.nonNullPath(path) if (!scriptRuntime.files.exists(nicePath)) { throw Error("Cannot view $path as it doesn't exist") } @@ -724,7 +724,7 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { path.isJsNullish() -> false path !is String -> throw RuntimeException("Cannot edit $path as it isn't a string") else -> { - val nicePath = scriptRuntime.files.path(path) + val nicePath = scriptRuntime.files.nonNullPath(path) if (!scriptRuntime.files.exists(nicePath)) { 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) { 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) { 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 { if (!o.prop("data").isJsNullish()) { - intent.setData(Uri.parse(Context.toString(o.prop("data")))) + intent.setData(Context.toString(o.prop("data")).toUri()) } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt index 24bc5901..e2a5b479 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt @@ -511,7 +511,7 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { fun setGlobalLogConfig(scriptRuntime: ScriptRuntime, args: Array): Undefined = ensureArgumentsOnlyOne(args) { config -> require(config is NativeObject) { "Argument for console.${::setGlobalLogConfig.name} must be a JavaScript Object" } 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") maxFileSize = config.inquire("maxFileSize", ::coerceLongNumber, 512 * 1024) maxBackupSize = config.inquire("maxBackupSize", ::coerceIntNumber, 5) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt index b59f3bf7..7821a59b 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt @@ -111,14 +111,14 @@ class Engines(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunt val result = ExecutionConfig() when (val config = if (o.isJsNullish()) newNativeObject() else o) { 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.interval = config.interval.takeUnless { it < 0 } ?: 0L result.loopTimes = config.loopTimes.takeUnless { it < 0 } ?: 1 config.arguments.entries.forEach { result.setArgument(it.key, it.value) } } 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.interval = config.inquire("interval", ::coerceLongNumber, 0L) result.loopTimes = config.inquire("loopTimes", ::coerceIntNumber, 1) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/files/Files.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/files/Files.kt index 608dac32..b8ac4d01 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/files/Files.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/files/Files.kt @@ -1,6 +1,7 @@ package org.autojs.autojs.runtime.api.augment.files import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface +import org.autojs.autojs.extension.AnyExtensions.isJsNullish import org.autojs.autojs.extension.FlexibleArray import org.autojs.autojs.pio.PFileInterface import org.autojs.autojs.runtime.ScriptRuntime @@ -16,6 +17,7 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { override val selfAssignmentFunctions = listOf( ::open.name to AS_GLOBAL, + ::path.name, ::join.name, ::toFile.name, ) @@ -34,6 +36,16 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { } } + @JvmStatic + @RhinoRuntimeFunctionInterface + fun path(scriptRuntime: ScriptRuntime, args: Array): String? = ensureArgumentsAtMost(args, 1) { argList -> + val (o) = argList + when { + o.isJsNullish() -> scriptRuntime.files.path(null) + else -> scriptRuntime.files.path(Context.toString(o)) + } + } + @JvmStatic @RhinoRuntimeFunctionInterface fun join(scriptRuntime: ScriptRuntime, args: Array): String = ensureArgumentsAtLeast(args, 1) { @@ -43,7 +55,7 @@ class Files(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { @JvmStatic @RhinoRuntimeFunctionInterface fun toFile(scriptRuntime: ScriptRuntime, args: Array): File = ensureArgumentsOnlyOne(args) { - File(scriptRuntime.files.path(Context.toString(it))) + File(scriptRuntime.files.nonNullPath(Context.toString(it))) } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt index 36f4e7d1..6e965104 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt @@ -179,7 +179,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt @JvmStatic @RhinoRuntimeFunctionInterface fun imread(scriptRuntime: ScriptRuntime, args: Array): AutoJsMat = ensureArgumentsOnlyOne(args) { path -> - ApiImages.imread(scriptRuntime.files.path(coerceString(path))) + ApiImages.imread(scriptRuntime.files.nonNullPath(coerceString(path))) } @JvmStatic @@ -244,7 +244,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt } when { 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(o, true)) else o 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" } - 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 @@ -311,7 +311,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt val image = if (o is String) read(scriptRuntime, arrayOf(o, true)) else o 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" } - 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 @@ -1002,7 +1002,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt val matcher = opt.inquire("matcher") { coerceIntNumber(DescriptorMatcher::class.java.getField(coerceString(it)).get(null)) } ?: 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 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 String -> BitmapFactory.Options().apply { inJustDecodeBounds = true }.let { opt -> 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()) } else -> throw WrappedIllegalArgumentException("Unknown source to parse its size: $o") diff --git a/app/src/main/java/org/autojs/autojs/script/AutoFileSource.java b/app/src/main/java/org/autojs/autojs/script/AutoFileSource.java index beb3a906..518d7b57 100644 --- a/app/src/main/java/org/autojs/autojs/script/AutoFileSource.java +++ b/app/src/main/java/org/autojs/autojs/script/AutoFileSource.java @@ -19,7 +19,7 @@ public class AutoFileSource extends ScriptSource { mFile = file; } - public AutoFileSource(String path) { + public AutoFileSource(@NonNull String path) { this(new File(path)); } diff --git a/app/src/main/java/org/autojs/autojs/script/JavaScriptFileSource.java b/app/src/main/java/org/autojs/autojs/script/JavaScriptFileSource.java index cfdb29aa..80f36709 100644 --- a/app/src/main/java/org/autojs/autojs/script/JavaScriptFileSource.java +++ b/app/src/main/java/org/autojs/autojs/script/JavaScriptFileSource.java @@ -24,11 +24,11 @@ public class JavaScriptFileSource extends JavaScriptSource { mFile = file; } - public JavaScriptFileSource(String path) { + public JavaScriptFileSource(@NonNull String path) { this(new File(path)); } - public JavaScriptFileSource(String name, File file) { + public JavaScriptFileSource(@NonNull String name, File file) { super(name); mCustomsName = true; mFile = file; diff --git a/version.properties b/version.properties index aa072a6c..2c124f91 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Wed Apr 16 14:12:01 CST 2025 -BUILD_TIME=1744783921920 +#Wed Apr 16 14:34:09 CST 2025 +BUILD_TIME=1744785249350 COMPILE_SDK_VERSION=35 JAVA_VERSION=23 JAVA_VERSION_MIN_RADICAL=0